diff --git a/packages/wyatt_authentication_bloc/example/lib/sign_up/widgets/sign_up_form.dart b/packages/wyatt_authentication_bloc/example/lib/sign_up/widgets/sign_up_form.dart index 36f2e231..8672edbe 100644 --- a/packages/wyatt_authentication_bloc/example/lib/sign_up/widgets/sign_up_form.dart +++ b/packages/wyatt_authentication_bloc/example/lib/sign_up/widgets/sign_up_form.dart @@ -149,7 +149,7 @@ class _PasswordInput extends StatelessWidget { .read() .state .data - .valueOf(formFieldConfirmedPassword), + .valueOf(formFieldConfirmedPassword), ), ); }, @@ -202,7 +202,7 @@ class _CheckIsProInput extends StatelessWidget { trailing: BlocBuilder( builder: (context, state) { return Checkbox( - value: state.data.valueOf(formFieldPro), + value: state.data.valueOf(formFieldPro), onChanged: (isPro) { final value = isPro!; // tristate is false, so value can't be null @@ -296,7 +296,7 @@ class SignUpForm extends StatelessWidget { const SizedBox(height: 8), BlocBuilder( builder: (context, state) { - if (state.data.valueOf(formFieldPro)) { + if (state.data.valueOf(formFieldPro)) { return Column(children: [ _SirenInput(), const SizedBox(height: 8), diff --git a/packages/wyatt_authentication_bloc/example_router/.gitignore b/packages/wyatt_authentication_bloc/example_router/.gitignore new file mode 100644 index 00000000..a8e938c0 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/wyatt_authentication_bloc/example_router/.metadata b/packages/wyatt_authentication_bloc/example_router/.metadata new file mode 100644 index 00000000..2544bab1 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: android + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/wyatt_authentication_bloc/example_router/.vscode/launch.json b/packages/wyatt_authentication_bloc/example_router/.vscode/launch.json new file mode 100644 index 00000000..61fa495d --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/.vscode/launch.json @@ -0,0 +1,25 @@ +/* + * Author: Hugo Pointcheval + * Email: git@pcl.ovh + * ----- + * File: launch.json + * Created Date: 19/08/2022 15:12:25 + * Last Modified: 19/08/2022 15:22:02 + * ----- + * Copyright (c) 2022 + */ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "example_router", + "request": "launch", + "type": "dart", + "program": "lib/main.dart", + "flutterMode": "debug" + } + ] +} \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/example_router/README.md b/packages/wyatt_authentication_bloc/example_router/README.md new file mode 100644 index 00000000..139e82ee --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/README.md @@ -0,0 +1,16 @@ +# example_router + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/wyatt_authentication_bloc/example_router/analysis_options.yaml b/packages/wyatt_authentication_bloc/example_router/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/wyatt_authentication_bloc/example_router/android/.gitignore b/packages/wyatt_authentication_bloc/example_router/android/.gitignore new file mode 100644 index 00000000..6f568019 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/build.gradle b/packages/wyatt_authentication_bloc/example_router/android/app/build.gradle new file mode 100644 index 00000000..c0822b30 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/build.gradle @@ -0,0 +1,74 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +// START: FlutterFire Configuration +apply plugin: 'com.google.gms.google-services' +// END: FlutterFire Configuration +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example_router" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion 21 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/debug/AndroidManifest.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..4ee1d947 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/AndroidManifest.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..7c354a29 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/kotlin/com/example/example_router/MainActivity.kt b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/kotlin/com/example/example_router/MainActivity.kt new file mode 100644 index 00000000..a6e9ae0a --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/kotlin/com/example/example_router/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example_router + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable/launch_background.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values-night/styles.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values/styles.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/app/src/profile/AndroidManifest.xml b/packages/wyatt_authentication_bloc/example_router/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..4ee1d947 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/packages/wyatt_authentication_bloc/example_router/android/build.gradle b/packages/wyatt_authentication_bloc/example_router/android/build.gradle new file mode 100644 index 00000000..9192654d --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/build.gradle @@ -0,0 +1,34 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + // START: FlutterFire Configuration + classpath 'com.google.gms:google-services:4.3.10' + // END: FlutterFire Configuration + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/wyatt_authentication_bloc/example_router/android/gradle.properties b/packages/wyatt_authentication_bloc/example_router/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/wyatt_authentication_bloc/example_router/android/gradle/wrapper/gradle-wrapper.properties b/packages/wyatt_authentication_bloc/example_router/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..cc5527d7 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/packages/wyatt_authentication_bloc/example_router/android/settings.gradle b/packages/wyatt_authentication_bloc/example_router/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/wyatt_authentication_bloc/example_router/lib/bootstrap.dart b/packages/wyatt_authentication_bloc/example_router/lib/bootstrap.dart new file mode 100644 index 00000000..cc0ab97e --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/bootstrap.dart @@ -0,0 +1,40 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: bootstrap.dart +// Created Date: 19/08/2022 15:05:17 +// Last Modified: 19/08/2022 15:21:47 +// ----- +// Copyright (c) 2022 + +import 'dart:async'; + +import 'package:example_router/core/utils/app_bloc_observer.dart'; +import 'package:example_router/firebase_options.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; + +Future bootstrap(FutureOr Function() builder) async { + await runZonedGuarded( + () async { + WidgetsFlutterBinding.ensureInitialized(); + + FlutterError.onError = (details) { + debugPrint(details.toString()); + }; + + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + + GoRouter.setUrlPathStrategy(UrlPathStrategy.path); + + Bloc.observer = AppBlocObserver(); + + runApp(await builder()); + }, + (error, stackTrace) => debugPrint(error.toString()), + ); +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/example_router/lib/core/constants/form_field.dart new file mode 100644 index 00000000..e371dfb6 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/core/constants/form_field.dart @@ -0,0 +1,12 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: form_field.dart +// Created Date: 19/08/2022 11:52:33 +// Last Modified: 19/08/2022 16:35:39 +// ----- +// Copyright (c) 2022 + +abstract class AppFormField { + static const confirmedPassword = 'confirmedPassword'; +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/core/routes/router.dart b/packages/wyatt_authentication_bloc/example_router/lib/core/routes/router.dart new file mode 100644 index 00000000..85545c34 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/core/routes/router.dart @@ -0,0 +1,79 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: router.dart +// Created Date: 19/08/2022 11:52:22 +// Last Modified: 19/08/2022 16:39:07 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/presentation/features/home/home_page.dart'; +import 'package:example_router/presentation/features/sign_in/sign_in_page.dart'; +import 'package:example_router/presentation/features/sign_up/sign_up_page.dart'; +import 'package:example_router/presentation/features/sub/sub_page.dart'; +import 'package:example_router/presentation/features/welcome/welcome_page.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; + +class AppRouter { + /// Default transition for all pages + static Page defaultTransition( + BuildContext context, + GoRouterState state, + Widget child, + ) => + CupertinoPage( + key: state.pageKey, + child: child, + ); + + static final publicRoutes = ['/', '/sign_in', '/sign_up']; + + static final List routes = [ + GoRoute( + path: '/', + name: WelcomePage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const WelcomePage(), + ), + ), + GoRoute( + path: '/sign_in', + name: SignInPage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const SignInPage(), + ), + ), + GoRoute( + path: '/sign_up', + name: SignUpPage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const SignUpPage(), + ), + ), + GoRoute( + path: '/home', + name: HomePage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const HomePage(), + ), + ), + GoRoute( + path: '/home/sub', + name: SubPage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const SubPage(), + ), + ), + ]; +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/core/utils/app_bloc_observer.dart b/packages/wyatt_authentication_bloc/example_router/lib/core/utils/app_bloc_observer.dart new file mode 100644 index 00000000..1b44c4e8 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/core/utils/app_bloc_observer.dart @@ -0,0 +1,37 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: app_bloc_observer.dart +// Created Date: 19/08/2022 12:02:23 +// Last Modified: 19/08/2022 12:02:45 +// ----- +// Copyright (c) 2022 + +import 'package:flutter/foundation.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class AppBlocObserver extends BlocObserver { + @override + void onEvent(Bloc bloc, Object? event) { + super.onEvent(bloc, event); + debugPrint(event.toString()); + } + + @override + void onError(BlocBase bloc, Object error, StackTrace stackTrace) { + debugPrint(error.toString()); + super.onError(bloc, error, stackTrace); + } + + @override + void onChange(BlocBase bloc, Change change) { + super.onChange(bloc, change); + debugPrint('curr:\t${change.currentState}\nnext:\t${change.nextState}'); + } + + @override + void onTransition(Bloc bloc, Transition transition) { + super.onTransition(bloc, transition); + debugPrint(transition.toString()); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/core/utils/forms.dart b/packages/wyatt_authentication_bloc/example_router/lib/core/utils/forms.dart new file mode 100644 index 00000000..ead7fb45 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/core/utils/forms.dart @@ -0,0 +1,21 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: forms.dart +// Created Date: 19/08/2022 12:00:31 +// Last Modified: 19/08/2022 16:35:52 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/core/constants/form_field.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +class Forms { + static FormData getNormalData() => const FormData([ + FormInput( + AppFormField.confirmedPassword, + ConfirmedPassword.pure(), + metadata: FormInputMetadata(export: false), + ), + ]); +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/firebase_options.dart b/packages/wyatt_authentication_bloc/example_router/lib/firebase_options.dart new file mode 100644 index 00000000..20a9ebf6 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/firebase_options.dart @@ -0,0 +1,63 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for ios - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk', + appId: '1:136771801992:android:ac3cfeb99fb0763e97203d', + messagingSenderId: '136771801992', + projectId: 'tchat-beta', + databaseURL: 'https://tchat-beta.firebaseio.com', + storageBucket: 'tchat-beta.appspot.com', + ); +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/main.dart b/packages/wyatt_authentication_bloc/example_router/lib/main.dart new file mode 100644 index 00000000..06b15c7c --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/main.dart @@ -0,0 +1,6 @@ +import 'package:example_router/bootstrap.dart'; +import 'package:example_router/presentation/features/app/app.dart'; + +void main() { + bootstrap(App.new); +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/app/app.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/app/app.dart new file mode 100644 index 00000000..291387e7 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/app/app.dart @@ -0,0 +1,115 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: app.dart +// Created Date: 19/08/2022 12:05:38 +// Last Modified: Fri Aug 26 2022 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/core/routes/router.dart'; +import 'package:example_router/core/utils/forms.dart'; +import 'package:example_router/presentation/features/home/home_page.dart'; +import 'package:example_router/presentation/features/welcome/welcome_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +class App extends StatelessWidget { + final AuthenticationRepository authenticationRepository = + AuthenticationRepositoryFirebase(); + + App({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + AuthenticationState? previous; + + final AuthenticationCubit authenticationCubit = AuthenticationCubit( + authenticationRepository: authenticationRepository, + onAuthSuccess: (user) async { + debugPrint(user.toString()); + return {}; + }, + ); + + final GoRouter router = GoRouter( + initialLocation: '/', + routes: AppRouter.routes, + debugLogDiagnostics: true, + errorBuilder: (_, __) => const ColoredBox( + color: Colors.red, + ), + refreshListenable: GoRouterRefreshStream(authenticationCubit.stream), + redirect: (state) { + final authState = authenticationCubit.state; + + if (authState != previous) { + previous = authState; + // Check if current user is logged in + final loggedIn = + authState.status == AuthenticationStatus.authenticated; + + // Checking if current path is onboarding or not + final isOnboarding = AppRouter.publicRoutes.contains(state.subloc); + + if (!loggedIn) { + debugPrint('Not logged'); + if (isOnboarding) { + return null; + } else { + return state.namedLocation(WelcomePage.pageName); + } + } else { + final email = authState.user?.email; + debugPrint('Logged as: $email'); + if (isOnboarding) { + return state.namedLocation(HomePage.pageName); + } else { + return null; + } + } + } + return null; + }, + ); + + return MultiRepositoryProvider( + providers: [ + RepositoryProvider.value( + value: authenticationRepository, + ), + ], + child: MultiBlocProvider( + providers: [ + BlocProvider.value( + value: authenticationCubit..init(), + ), + BlocProvider( + create: (_) => SignUpCubit( + authenticationRepository: authenticationRepository, + formData: Forms.getNormalData(), + onSignUpSuccess: (state, uid) async { + debugPrint(state.toString()); + debugPrint(uid); + }, + ), + ), + BlocProvider( + create: (_) => SignInCubit( + authenticationRepository: authenticationRepository, + ), + ), + ], + child: MaterialApp.router( + title: 'Demo Authentication', + debugShowCheckedModeBanner: false, + routerDelegate: router.routerDelegate, + routeInformationParser: router.routeInformationParser, + routeInformationProvider: router.routeInformationProvider, + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/home/home_page.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/home/home_page.dart new file mode 100644 index 00000000..316598cb --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/home/home_page.dart @@ -0,0 +1,55 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: home_page.dart +// Created Date: 19/08/2022 14:38:24 +// Last Modified: 19/08/2022 16:12:22 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/presentation/features/sub/sub_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +class HomePage extends StatelessWidget { + const HomePage({Key? key}) : super(key: key); + + static String pageName = 'Home'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Home'), + actions: [ + IconButton( + onPressed: () => context.read().logOut(), + icon: const Icon(Icons.logout_rounded)) + ], + ), + body: Padding( + padding: const EdgeInsets.all(8), + child: SingleChildScrollView( + child: Column( + children: [ + BlocBuilder( + builder: (context, state) { + final email = state.user?.email; + return Text('Logged as $email'); + }, + ), + const SizedBox( + height: 8, + ), + ElevatedButton( + onPressed: () => context.pushNamed(SubPage.pageName), + child: const Text('Go to sub page')), + ], + ), + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/sign_in_page.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/sign_in_page.dart new file mode 100644 index 00000000..39fd0463 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/sign_in_page.dart @@ -0,0 +1,30 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: sign_in_page.dart +// Created Date: 19/08/2022 12:41:42 +// Last Modified: 19/08/2022 15:26:36 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/presentation/features/sign_in/widgets/sign_in_form.dart'; +import 'package:flutter/material.dart'; + +class SignInPage extends StatelessWidget { + const SignInPage({Key? key}) : super(key: key); + + static String pageName = 'SignIn'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Sign In')), + body: const Padding( + padding: EdgeInsets.all(8), + child: SingleChildScrollView( + child: SignInForm(), + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/widgets/sign_in_form.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/widgets/sign_in_form.dart new file mode 100644 index 00000000..ea785177 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_in/widgets/sign_in_form.dart @@ -0,0 +1,105 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: sign_in_form.dart +// Created Date: 19/08/2022 15:24:37 +// Last Modified: 19/08/2022 16:35:01 +// ----- +// Copyright (c) 2022 + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +class _EmailInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.email != current.email, + builder: (context, state) { + return TextField( + onChanged: (email) => context.read().emailChanged(email), + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + labelText: 'Email', + helperText: '', + errorText: state.email.invalid ? 'Invalid email' : null, + ), + ); + }, + ); + } +} + +class _PasswordInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.password != current.password, + builder: (context, state) { + return TextField( + onChanged: (password) { + context.read().passwordChanged(password); + }, + obscureText: true, + decoration: InputDecoration( + labelText: 'Password', + helperText: '', + errorText: state.password.invalid ? 'Invalid password' : null, + ), + ); + }, + ); + } +} + +class _SignInButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return state.status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: state.status.isValidated + ? () => + context.read().signInWithEmailAndPassword() + : null, + child: const Text('Sign in'), + ); + }, + ); + } +} + +class SignInForm extends StatelessWidget { + const SignInForm({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) { + if (state.status.isSubmissionSuccess) { + Navigator.of(context).pop(); + } else if (state.status.isSubmissionFailure) { + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar( + SnackBar(content: Text(state.errorMessage ?? 'Sign In Failure')), + ); + } + }, + child: SingleChildScrollView( + child: Column( + children: [ + _EmailInput(), + const SizedBox(height: 8), + _PasswordInput(), + const SizedBox(height: 16), + _SignInButton(), + ], + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/sign_up_page.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/sign_up_page.dart new file mode 100644 index 00000000..31f18bb6 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/sign_up_page.dart @@ -0,0 +1,30 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: sign_up_page.dart +// Created Date: 19/08/2022 12:41:27 +// Last Modified: 19/08/2022 14:58:51 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/presentation/features/sign_up/widgets/sign_up_form.dart'; +import 'package:flutter/material.dart'; + +class SignUpPage extends StatelessWidget { + const SignUpPage({Key? key}) : super(key: key); + + static String pageName = 'SignUp'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Sign Up')), + body: const Padding( + padding: EdgeInsets.all(8), + child: SingleChildScrollView( + child: SignUpForm(), + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/widgets/sign_up_form.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/widgets/sign_up_form.dart new file mode 100644 index 00000000..4a7faf42 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sign_up/widgets/sign_up_form.dart @@ -0,0 +1,149 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: sign_up_form.dart +// Created Date: 19/08/2022 14:41:08 +// Last Modified: Fri Aug 26 2022 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/core/constants/form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +class _EmailInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.email != current.email, + builder: (context, state) { + return TextField( + onChanged: (email) => context.read().emailChanged(email), + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + labelText: 'Email', + helperText: '', + errorText: state.email.invalid ? 'Invalid email' : null, + ), + ); + }, + ); + } +} + +class _PasswordInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.password != current.password, + builder: (context, state) { + return TextField( + onChanged: (password) { + context.read().passwordChanged(password); + context.read().dataChanged( + AppFormField.confirmedPassword, + ConfirmedPassword.dirty( + password: password, + value: context + .read() + .state + .data + .valueOf( + AppFormField.confirmedPassword), + ), + ); + }, + obscureText: true, + decoration: InputDecoration( + labelText: 'Password', + helperText: '', + errorText: state.password.invalid ? 'Invalid password' : null, + ), + ); + }, + ); + } +} + +class _ConfirmPasswordInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return TextField( + onChanged: (confirmPassword) => context + .read() + .dataChanged( + AppFormField.confirmedPassword, + ConfirmedPassword.dirty( + password: context.read().state.password.value, + value: confirmPassword, + ), + ), + obscureText: true, + decoration: InputDecoration( + labelText: 'Confirm password', + helperText: '', + errorText: state.data.isNotValid(AppFormField.confirmedPassword) + ? 'Passwords do not match' + : null, + ), + ); + }, + ); + } +} + +class _SignUpButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return state.status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: state.status.isValidated + ? () => context.read().signUpFormSubmitted() + : null, + child: const Text('Sign up'), + ); + }, + ); + } +} + +class SignUpForm extends StatelessWidget { + const SignUpForm({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) { + if (state.status.isSubmissionSuccess) { + Navigator.of(context).pop(); + } else if (state.status.isSubmissionFailure) { + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar( + SnackBar(content: Text(state.errorMessage ?? 'Sign Up Failure')), + ); + } + }, + child: SingleChildScrollView( + child: Column( + children: [ + _EmailInput(), + const SizedBox(height: 8), + _PasswordInput(), + const SizedBox(height: 8), + _ConfirmPasswordInput(), + const SizedBox(height: 16), + _SignUpButton(), + ], + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sub/sub_page.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sub/sub_page.dart new file mode 100644 index 00000000..34f4558f --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/sub/sub_page.dart @@ -0,0 +1,38 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: sub_page.dart +// Created Date: 19/08/2022 16:10:05 +// Last Modified: 19/08/2022 16:10:44 +// ----- +// Copyright (c) 2022 + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +class SubPage extends StatelessWidget { + const SubPage({Key? key}) : super(key: key); + + static String pageName = 'Sub'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Sub'), + actions: [ + IconButton( + onPressed: () => context.read().logOut(), + icon: const Icon(Icons.logout_rounded)) + ], + ), + body: const Padding( + padding: EdgeInsets.all(8), + child: SingleChildScrollView( + child: Text('Another page'), + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/welcome/welcome_page.dart b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/welcome/welcome_page.dart new file mode 100644 index 00000000..aa3a10c4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example_router/lib/presentation/features/welcome/welcome_page.dart @@ -0,0 +1,53 @@ +// Author: Hugo Pointcheval +// Email: git@pcl.ovh +// ----- +// File: welcome_page.dart +// Created Date: 19/08/2022 12:33:21 +// Last Modified: 19/08/2022 15:56:05 +// ----- +// Copyright (c) 2022 + +import 'package:example_router/presentation/features/sign_in/sign_in_page.dart'; +import 'package:example_router/presentation/features/sign_up/sign_up_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +class WelcomePage extends StatelessWidget { + const WelcomePage({Key? key}) : super(key: key); + + static String pageName = 'Welcome'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Welcome'), + actions: [ + IconButton( + onPressed: () => context.read().changeStatus( + context.read().state.user!), + icon: const Icon(Icons.refresh_rounded)) + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + ElevatedButton( + onPressed: () => context.pushNamed(SignUpPage.pageName), + child: const Text('Sign Up')), + ElevatedButton( + onPressed: () => context.pushNamed(SignInPage.pageName), + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(Colors.white), + foregroundColor: + MaterialStateProperty.all(Colors.blue)), + child: const Text('Sign In')) + ], + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example_router/test/widget_test.dart b/packages/wyatt_authentication_bloc/example_router/test/widget_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_cubit.dart deleted file mode 100644 index 018eb566..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_cubit.dart +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2022 WYATT GROUP -// Please see the AUTHORS file for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -import 'dart:async'; - -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:wyatt_authentication_bloc/src/models/user/user_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; - -part 'authentication_state.dart'; - -class AuthenticationCubit extends Cubit { - final AuthenticationRepositoryInterface _authenticationRepository; - - StreamSubscription? _userSubscription; - - final Future> Function(UserInterface user)? - _onAuthSuccess; - - AuthenticationCubit({ - required AuthenticationRepositoryInterface authenticationRepository, - Future> Function(UserInterface user)? onAuthSuccess, - }) : _authenticationRepository = authenticationRepository, - _onAuthSuccess = onAuthSuccess, - super(const AuthenticationState.unknown()); - - Future init() async { - final _firstUser = await _authenticationRepository.user.first; - start(); - return changeStatus(_firstUser); - } - - bool start() { - _userSubscription = _authenticationRepository.user.listen(changeStatus); - return true; - } - - bool stop() { - _userSubscription?.cancel(); - return true; - } - - Future changeStatus(UserInterface user) async { - if (user.isNotEmpty) { - final Map? userData = await _onAuthSuccess?.call(user); - emit(AuthenticationState.authenticated(user, userData)); - } else { - stop(); - emit(const AuthenticationState.unauthenticated()); - } - } - - void logOut() { - unawaited(_authenticationRepository.signOut()); - } - - @override - Future close() { - _userSubscription?.cancel(); - return super.close(); - } -} diff --git a/packages/wyatt_authentication_bloc/lib/src/models/user/user.dart b/packages/wyatt_authentication_bloc/lib/src/core/enum/auth_cubit_status.dart similarity index 92% rename from packages/wyatt_authentication_bloc/lib/src/models/user/user.dart rename to packages/wyatt_authentication_bloc/lib/src/core/enum/auth_cubit_status.dart index 2a470388..37448fa1 100644 --- a/packages/wyatt_authentication_bloc/lib/src/models/user/user.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/enum/auth_cubit_status.dart @@ -14,5 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'user_firebase.dart'; -export 'user_interface.dart'; +enum AuthCubitStatus { + started, + stoped, +} diff --git a/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions_interface.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions_interface.dart rename to packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart similarity index 86% rename from packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions_firebase.dart rename to packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart index eade1e10..83c911a1 100644 --- a/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions_firebase.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; class ApplyActionCodeFailureFirebase extends ApplyActionCodeFailureInterface { ApplyActionCodeFailureFirebase([String? code, String? message]) @@ -148,32 +148,28 @@ class SignInWithCredentialFailureFirebase class SignInWithGoogleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithGoogleFailureInterface { - SignInWithGoogleFailureFirebase([String? code, String? message]) - : super(code, message); - SignInWithGoogleFailureFirebase.fromCode(String code) : super.fromCode(code); + SignInWithGoogleFailureFirebase([super.code, super.message]); + SignInWithGoogleFailureFirebase.fromCode(super.code) : super.fromCode(); } class SignInWithFacebookFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithFacebookFailureInterface { - SignInWithFacebookFailureFirebase([String? code, String? message]) - : super(code, message); - SignInWithFacebookFailureFirebase.fromCode(String code) - : super.fromCode(code); + SignInWithFacebookFailureFirebase([super.code, super.message]); + SignInWithFacebookFailureFirebase.fromCode(super.code) + : super.fromCode(); } class SignInWithAppleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { - SignInWithAppleFailureFirebase([String? code, String? message]) - : super(code, message); - SignInWithAppleFailureFirebase.fromCode(String code) : super.fromCode(code); + SignInWithAppleFailureFirebase([super.code, super.message]); + SignInWithAppleFailureFirebase.fromCode(super.code) : super.fromCode(); } class SignInWithTwitterFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { - SignInWithTwitterFailureFirebase([String? code, String? message]) - : super(code, message); - SignInWithTwitterFailureFirebase.fromCode(String code) : super.fromCode(code); + SignInWithTwitterFailureFirebase([super.code, super.message]); + SignInWithTwitterFailureFirebase.fromCode(super.code) : super.fromCode(); } @@ -233,16 +229,16 @@ class SendEmailVerificationFailureFirebase SendEmailVerificationFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - SendEmailVerificationFailureFirebase.fromCode(String code) - : super.fromCode(code); + SendEmailVerificationFailureFirebase.fromCode(super.code) + : super.fromCode(); } class SendPasswordResetEmailFailureFirebase extends SendPasswordResetEmailFailureInterface { SendPasswordResetEmailFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - SendPasswordResetEmailFailureFirebase.fromCode(String code) - : super.fromCode(code); + SendPasswordResetEmailFailureFirebase.fromCode(super.code) + : super.fromCode(); } class SendSignInLinkEmailFailureFirebase @@ -250,8 +246,8 @@ class SendSignInLinkEmailFailureFirebase SendSignInLinkEmailFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - SendSignInLinkEmailFailureFirebase.fromCode(String code) - : super.fromCode(code); + SendSignInLinkEmailFailureFirebase.fromCode(super.code) + : super.fromCode(); } class ConfirmPasswordResetFailureFirebase @@ -259,8 +255,8 @@ class ConfirmPasswordResetFailureFirebase ConfirmPasswordResetFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - ConfirmPasswordResetFailureFirebase.fromCode(String code) - : super.fromCode(code); + ConfirmPasswordResetFailureFirebase.fromCode(super.code) + : super.fromCode(); } class VerifyPasswordResetCodeFailureFirebase @@ -268,19 +264,19 @@ class VerifyPasswordResetCodeFailureFirebase VerifyPasswordResetCodeFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - VerifyPasswordResetCodeFailureFirebase.fromCode(String code) - : super.fromCode(code); + VerifyPasswordResetCodeFailureFirebase.fromCode(super.code) + : super.fromCode(); } class RefreshFailureFirebase extends RefreshFailureInterface { RefreshFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - RefreshFailureFirebase.fromCode(String code) : super.fromCode(code); + RefreshFailureFirebase.fromCode(super.code) : super.fromCode(); } class SignOutFailureFirebase extends SignOutFailureInterface { SignOutFailureFirebase([String? code, String? message]) : super(code ?? 'unknown', message ?? 'An unknown error occurred.'); - SignOutFailureFirebase.fromCode(String code) : super.fromCode(code); + SignOutFailureFirebase.fromCode(super.code) : super.fromCode(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/repositories/repositories.dart b/packages/wyatt_authentication_bloc/lib/src/core/extensions/firebase_auth_user_x.dart similarity index 76% rename from packages/wyatt_authentication_bloc/lib/src/repositories/repositories.dart rename to packages/wyatt_authentication_bloc/lib/src/core/extensions/firebase_auth_user_x.dart index 2f4f5294..70b870c3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/repositories/repositories.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/extensions/firebase_auth_user_x.dart @@ -14,5 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'authentication_repository_firebase.dart'; -export 'authentication_repository_interface.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:wyatt_authentication_bloc/src/data/models/user_firebase.dart'; + +extension FirebaseAuthUserX on User { + UserFirebase get model => UserFirebase(this); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/utils/cryptography.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/cryptography.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/utils/cryptography.dart rename to packages/wyatt_authentication_bloc/lib/src/core/utils/cryptography.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/models/user/user_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/user_firebase.dart similarity index 94% rename from packages/wyatt_authentication_bloc/lib/src/models/user/user_firebase.dart rename to packages/wyatt_authentication_bloc/lib/src/data/models/user_firebase.dart index 53908ab2..31139cf3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/models/user/user_firebase.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/models/user_firebase.dart @@ -1,24 +1,23 @@ // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . import 'package:firebase_auth/firebase_auth.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/user.dart' as wyatt; -import 'package:wyatt_authentication_bloc/src/models/user/user_interface.dart'; - -class UserFirebase implements UserInterface { +class UserFirebase implements wyatt.User { final User? _user; const UserFirebase(User user) : _user = user; diff --git a/packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_firebase.dart similarity index 87% rename from packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_firebase.dart rename to packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_firebase.dart index f2838122..0cf6d5dc 100644 --- a/packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_firebase.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_firebase.dart @@ -14,19 +14,24 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'dart:async'; + import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:twitter_login/twitter_login.dart'; -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_firebase.dart'; -import 'package:wyatt_authentication_bloc/src/models/user/user_firebase.dart'; -import 'package:wyatt_authentication_bloc/src/models/user/user_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; -import 'package:wyatt_authentication_bloc/src/utils/cryptography.dart'; +import 'package:wyatt_authentication_bloc/src/core/enum/auth_cubit_status.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions_firebase.dart'; +import 'package:wyatt_authentication_bloc/src/core/extensions/firebase_auth_user_x.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/cryptography.dart'; +import 'package:wyatt_authentication_bloc/src/data/models/user_firebase.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/user.dart' + as wyatt; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; -class AuthenticationRepositoryFirebase - implements AuthenticationRepositoryInterface { +class AuthenticationRepositoryFirebase implements AuthenticationRepository { + final _controller = StreamController(); final FirebaseAuth _firebaseAuth; final TwitterLogin? _twitterLogin; @@ -36,23 +41,30 @@ class AuthenticationRepositoryFirebase FirebaseAuth? firebaseAuth, TwitterLogin? twitterLogin, }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance, - _twitterLogin = twitterLogin; - - @override - Stream get user { - return _firebaseAuth.userChanges().map((User? firebaseUser) { - final UserFirebase user = firebaseUser == null - ? const UserFirebase.empty() - : firebaseUser.model; - _userCache = user; - return user; - }); + _twitterLogin = twitterLogin { + _controller.sink.add(AuthCubitStatus.stoped); } @override - UserInterface get currentUser { - return _userCache; - } + Stream get cubitStatus => + _controller.stream.asBroadcastStream(); + + @override + void changeCubitStatus(AuthCubitStatus status) => + _controller.sink.add(status); + + @override + Stream get user => + _firebaseAuth.userChanges().map((firebaseUser) { + final UserFirebase user = (firebaseUser == null) + ? const UserFirebase.empty() + : firebaseUser.model; + _userCache = user; + return user; + }); + + @override + wyatt.User get currentUser => _userCache; @override Future applyActionCode(String code) async { @@ -324,9 +336,3 @@ class AuthenticationRepositoryFirebase } } } - -extension on User { - UserFirebase get model { - return UserFirebase(this); - } -} diff --git a/packages/wyatt_authentication_bloc/lib/src/models/user/user_interface.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/user.dart similarity index 97% rename from packages/wyatt_authentication_bloc/lib/src/models/user/user_interface.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/user.dart index 43b926bf..40c0c7b9 100644 --- a/packages/wyatt_authentication_bloc/lib/src/models/user/user_interface.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/user.dart @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -abstract class UserInterface { +abstract class User { /// The empty user constructor. - const UserInterface.empty(); + const User.empty(); /// The users display name. /// diff --git a/packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_interface.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart similarity index 84% rename from packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_interface.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart index 4a2dc295..35c80a72 100644 --- a/packages/wyatt_authentication_bloc/lib/src/repositories/authentication_repository_interface.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart @@ -14,22 +14,29 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; -import 'package:wyatt_authentication_bloc/src/models/user/user_interface.dart'; +import 'package:wyatt_authentication_bloc/src/core/enum/auth_cubit_status.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/user.dart'; /// {@template authentication_repository} /// Repository which manages user authentication. /// {@endtemplate} -abstract class AuthenticationRepositoryInterface { - /// Stream of [UserInterface] which will emit the current user when +abstract class AuthenticationRepository { + /// Stream of [AuthCubitStatus] wich will emit the current cubit status. + Stream get cubitStatus; + + /// Changes cubit status.(Useful to start or stop the engine.) + void changeCubitStatus(AuthCubitStatus status); + + /// Stream of [User] which will emit the current user when /// the authentication state changes. /// - /// Emits [UserInterface.empty] if the user is not authenticated. - Stream get user; + /// Emits [User.empty] if the user is not authenticated. + Stream get user; /// Returns the current cached account. - /// Defaults to [UserInterface.empty] if there is no cached user. - UserInterface get currentUser; + /// Defaults to [User.empty] if there is no cached user. + User get currentUser; /// Applies action code /// @@ -122,7 +129,7 @@ abstract class AuthenticationRepositoryInterface { Future verifyPasswordResetCode({required String code}); /// Signs out the current user which will emit - /// [UserInterface.empty] from the [user] Stream. + /// [User.empty] from the [user] Stream. Future signOut(); /// Refreshes the current user. diff --git a/packages/wyatt_authentication_bloc/lib/src/authentication/authentication.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/authentication/authentication.dart rename to packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/authentication/builder/authentication_builder.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart similarity index 58% rename from packages/wyatt_authentication_bloc/lib/src/authentication/builder/authentication_builder.dart rename to packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart index a0dc8079..f10c88c3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/authentication/builder/authentication_builder.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart @@ -16,41 +16,40 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wyatt_authentication_bloc/src/authentication/cubit/authentication_cubit.dart'; -import 'package:wyatt_authentication_bloc/src/models/user/user_interface.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/user.dart'; +import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; -class AuthenticationBuilder extends StatelessWidget { +class AuthenticationBuilder extends StatelessWidget { const AuthenticationBuilder({ - Key? key, required this.authenticated, required this.unauthenticated, required this.unknown, - }) : super(key: key); + super.key, + }); final Widget Function( BuildContext context, - UserInterface user, - Map? userData, + User user, + Extra? extra, ) authenticated; final Widget Function(BuildContext context) unauthenticated; final Widget Function(BuildContext context) unknown; @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state.status == AuthenticationStatus.authenticated) { - if (state.user != null) { - return authenticated(context, state.user!, state.userData); - } else { + Widget build(BuildContext context) => + BlocBuilder, AuthenticationState>( + builder: (context, state) { + if (state.status == AuthenticationStatus.authenticated) { + if (state.user != null) { + return authenticated(context, state.user!, state.extra); + } else { + return unauthenticated(context); + } + } else if (state.status == AuthenticationStatus.unauthenticated) { return unauthenticated(context); + } else { + return unknown(context); } - } else if (state.status == AuthenticationStatus.unauthenticated) { - return unauthenticated(context); - } else { - return unknown(context); - } - }, - ); - } + }, + ); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart new file mode 100644 index 00000000..f773ab48 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart @@ -0,0 +1,98 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/core/enum/auth_cubit_status.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/user.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; + +part 'authentication_state.dart'; + +class AuthenticationCubit extends Cubit> { + final AuthenticationRepository _authenticationRepository; + late final StreamSubscription _statusSubscription; + + StreamSubscription? _userSubscription; + + final Future Function(User user)? _onAuthSuccess; + + AuthenticationCubit({ + required AuthenticationRepository authenticationRepository, + Future Function(User user)? onAuthSuccess, + }) : _authenticationRepository = authenticationRepository, + _onAuthSuccess = onAuthSuccess, + super(const AuthenticationState.unknown()) { + _subscribeStatus(); + } + + Future get status async => + _authenticationRepository.cubitStatus.last; + + void _subscribeStatus() { + _statusSubscription = _authenticationRepository.cubitStatus.listen( + (status) { + switch (status) { + case AuthCubitStatus.started: + start(); + break; + case AuthCubitStatus.stoped: + stop(); + break; + } + }, + ); + } + + Future init() async { + final firstUser = await _authenticationRepository.user.first; + _authenticationRepository.changeCubitStatus(AuthCubitStatus.started); + return changeStatus(firstUser); + } + + bool start() { + _userSubscription = _authenticationRepository.user.listen(changeStatus); + return true; + } + + bool stop() { + _userSubscription?.cancel(); + return true; + } + + Future changeStatus(User user) async { + if (user.isNotEmpty) { + final Extra? extra = await _onAuthSuccess?.call(user); + emit(AuthenticationState.authenticated(user, extra)); + } else { + _authenticationRepository.changeCubitStatus(AuthCubitStatus.stoped); + emit(const AuthenticationState.unauthenticated()); + } + } + + void logOut() { + unawaited(_authenticationRepository.signOut()); + } + + @override + Future close() { + _userSubscription?.cancel(); + _statusSubscription.cancel(); + return super.close(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart similarity index 77% rename from packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_state.dart rename to packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart index 4e2de515..d01fdfb7 100644 --- a/packages/wyatt_authentication_bloc/lib/src/authentication/cubit/authentication_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart @@ -22,37 +22,36 @@ enum AuthenticationStatus { unauthenticated, } -class AuthenticationState extends Equatable { +class AuthenticationState extends Equatable { final AuthenticationStatus status; - final UserInterface? user; - final Map? userData; + final User? user; + final Extra? extra; const AuthenticationState._({ required this.status, this.user, - this.userData, + this.extra, }); const AuthenticationState.unknown() : this._(status: AuthenticationStatus.unknown); const AuthenticationState.authenticated( - UserInterface user, - Map? userData, + User user, + Extra? extra, ) : this._( status: AuthenticationStatus.authenticated, user: user, - userData: userData, + extra: extra, ); const AuthenticationState.unauthenticated() : this._(status: AuthenticationStatus.unauthenticated); @override - List get props => [status, user, userData]; + List get props => [status, user, extra]; @override - // ignore: lines_longer_than_80_chars String toString() => - 'AuthenticationState(status: $status, user: $user, userData: $userData)'; + 'AuthenticationState(status: $status, user: $user, extra: $extra)'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart similarity index 81% rename from packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_cubit.dart rename to packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart index b5dca156..2ef607a0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart @@ -14,19 +14,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart' show FormStatus; part 'email_verification_state.dart'; class EmailVerificationCubit extends Cubit { - final AuthenticationRepositoryInterface _authenticationRepository; + final AuthenticationRepository _authenticationRepository; - EmailVerificationCubit(this._authenticationRepository) - : super(const EmailVerificationState()); + EmailVerificationCubit({ + required AuthenticationRepository authenticationRepository, + }) : _authenticationRepository = authenticationRepository, + super(const EmailVerificationState()); Future sendEmailVerification() async { emit(state.copyWith(status: FormStatus.submissionInProgress)); diff --git a/packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart similarity index 96% rename from packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_state.dart rename to packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart index 0470429e..f05f2caf 100644 --- a/packages/wyatt_authentication_bloc/lib/src/email_verification/cubit/email_verification_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart @@ -31,13 +31,11 @@ class EmailVerificationState extends Equatable { bool? isVerified, FormStatus? status, String? errorMessage, - }) { - return EmailVerificationState( + }) => EmailVerificationState( isVerified: isVerified ?? this.isVerified, status: status ?? this.status, errorMessage: errorMessage ?? this.errorMessage, ); - } @override List get props => [isVerified, status]; diff --git a/packages/wyatt_authentication_bloc/lib/src/email_verification/email_verification.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/email_verification/email_verification.dart rename to packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart similarity index 68% rename from packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_cubit.dart rename to packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart index 2252cc3d..66ab6545 100644 --- a/packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart @@ -14,32 +14,40 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; part 'password_reset_state.dart'; class PasswordResetCubit extends Cubit { - final AuthenticationRepositoryInterface _authenticationRepository; + final AuthenticationRepository _authenticationRepository; - PasswordResetCubit(this._authenticationRepository) - : super(const PasswordResetState()); + final FormValidator _validationStrategy; + + PasswordResetCubit({ + required AuthenticationRepository authenticationRepository, + FormValidator validationStrategy = const EveryInputValidator(), + }) : _authenticationRepository = authenticationRepository, + _validationStrategy = validationStrategy, + super(const PasswordResetState()); void emailChanged(String value) { final Email email = Email.dirty(value); emit( state.copyWith( email: email, - status: FormStatus.validate([email]), + status: _validationStrategy.rawValidate([email]), ), ); } Future sendPasswordResetEmail() async { - if (!state.status.isValidated) return; + if (!state.status.isValidated) { + return; + } emit(state.copyWith(status: FormStatus.submissionInProgress)); try { await _authenticationRepository.sendPasswordResetEmail( diff --git a/packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart similarity index 96% rename from packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_state.dart rename to packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart index 5d3d7179..e8100c8e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/password_reset/cubit/password_reset_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart @@ -31,13 +31,11 @@ class PasswordResetState extends Equatable { Email? email, FormStatus? status, String? errorMessage, - }) { - return PasswordResetState( + }) => PasswordResetState( email: email ?? this.email, status: status ?? this.status, errorMessage: errorMessage ?? this.errorMessage, ); - } @override List get props => [email, status]; diff --git a/packages/wyatt_authentication_bloc/lib/src/password_reset/password_reset.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/password_reset/password_reset.dart rename to packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart similarity index 75% rename from packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_cubit.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart index b30dbab9..2891dc57 100644 --- a/packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart @@ -14,24 +14,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:wyatt_authentication_bloc/src/authentication/cubit/authentication_cubit.dart'; -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/core/enum/auth_cubit_status.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; part 'sign_in_state.dart'; class SignInCubit extends Cubit { - final AuthenticationRepositoryInterface _authenticationRepository; - final AuthenticationCubit _authenticationCubit; + final AuthenticationRepository _authenticationRepository; + + final FormValidator _validationStrategy; SignInCubit({ - required AuthenticationRepositoryInterface authenticationRepository, - required AuthenticationCubit authenticationCubit, + required AuthenticationRepository authenticationRepository, + FormValidator validationStrategy = const EveryInputValidator(), }) : _authenticationRepository = authenticationRepository, - _authenticationCubit = authenticationCubit, + _validationStrategy = validationStrategy, super(const SignInState()); void emailChanged(String value) { @@ -39,7 +40,7 @@ class SignInCubit extends Cubit { emit( state.copyWith( email: email, - status: FormStatus.validate([email, state.password]), + status: _validationStrategy.rawValidate([email, state.password]), ), ); } @@ -49,7 +50,7 @@ class SignInCubit extends Cubit { emit( state.copyWith( password: password, - status: FormStatus.validate([state.email, password]), + status: _validationStrategy.rawValidate([state.email, password]), ), ); } @@ -62,7 +63,7 @@ class SignInCubit extends Cubit { emit(state.copyWith(status: FormStatus.submissionInProgress)); try { await _authenticationRepository.signInAnonymously(); - _authenticationCubit.start(); + _authenticationRepository.changeCubitStatus(AuthCubitStatus.started); emit(state.copyWith(status: FormStatus.submissionSuccess)); } on SignInAnonymouslyFailureInterface catch (e) { emit( @@ -84,7 +85,7 @@ class SignInCubit extends Cubit { emit(state.copyWith(status: FormStatus.submissionInProgress)); try { await _authenticationRepository.signInWithGoogle(); - _authenticationCubit.start(); + _authenticationRepository.changeCubitStatus(AuthCubitStatus.started); emit(state.copyWith(status: FormStatus.submissionSuccess)); } on SignInWithGoogleFailureInterface catch (e) { emit( @@ -99,14 +100,16 @@ class SignInCubit extends Cubit { } Future signInWithEmailAndPassword() async { - if (!state.status.isValidated) return; + if (!state.status.isValidated) { + return; + } emit(state.copyWith(status: FormStatus.submissionInProgress)); try { await _authenticationRepository.signInWithEmailAndPassword( email: state.email.value, password: state.password.value, ); - _authenticationCubit.start(); + _authenticationRepository.changeCubitStatus(AuthCubitStatus.started); emit(state.copyWith(status: FormStatus.submissionSuccess)); } on SignInWithEmailAndPasswordFailureInterface catch (e) { emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart similarity index 84% rename from packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_state.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart index f59c536c..0e407276 100644 --- a/packages/wyatt_authentication_bloc/lib/src/sign_in/cubit/sign_in_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart @@ -34,25 +34,22 @@ class SignInState extends Equatable { Password? password, FormStatus? status, String? errorMessage, - }) { - return SignInState( - email: email ?? this.email, - password: password ?? this.password, - status: status ?? this.status, - errorMessage: errorMessage ?? this.errorMessage, - ); - } + }) => + SignInState( + email: email ?? this.email, + password: password ?? this.password, + status: status ?? this.status, + errorMessage: errorMessage ?? this.errorMessage, + ); @override List get props => [email, password, status]; @override - String toString() { - return ''' + String toString() => ''' email: $email, password: $password, status: $status, errorMessage: $errorMessage, '''; - } } diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_in/sign_in.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/sign_in/sign_in.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart similarity index 64% rename from packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_cubit.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart index 31556053..3e79b7a8 100644 --- a/packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart @@ -16,30 +16,31 @@ import 'dart:async'; -import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; -import 'package:wyatt_authentication_bloc/src/authentication/cubit/authentication_cubit.dart'; -import 'package:wyatt_authentication_bloc/src/models/exceptions/exceptions_interface.dart'; -import 'package:wyatt_authentication_bloc/src/repositories/authentication_repository_interface.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/core/enum/auth_cubit_status.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; part 'sign_up_state.dart'; class SignUpCubit extends Cubit { - final AuthenticationRepositoryInterface _authenticationRepository; - final AuthenticationCubit _authenticationCubit; + final AuthenticationRepository _authenticationRepository; - final Future Function(SignUpState state, String? uid)? _onSignUpSuccess; + final Future Function(SignUpState state, String? uid)? _onSignUpSuccess; + final FormValidator _validationStrategy; SignUpCubit({ - required AuthenticationRepositoryInterface authenticationRepository, - required AuthenticationCubit authenticationCubit, - required FormData entries, - Future Function(SignUpState state, String? uid)? onSignUpSuccess, + required AuthenticationRepository authenticationRepository, + required FormData formData, + FormValidator validationStrategy = const EveryInputValidator(), + Future Function(SignUpState state, String? uid)? onSignUpSuccess, }) : _authenticationRepository = authenticationRepository, - _authenticationCubit = authenticationCubit, _onSignUpSuccess = onSignUpSuccess, - super(SignUpState(data: entries)); + _validationStrategy = validationStrategy, + super(SignUpState(data: formData)); void emailChanged(String value) { final Email email = Email.dirty(value); @@ -53,7 +54,7 @@ class SignUpCubit extends Cubit { emit( state.copyWith( email: email, - status: FormStatus.validate(toValidate), + status: _validationStrategy.rawValidate(toValidate), ), ); } @@ -70,25 +71,28 @@ class SignUpCubit extends Cubit { emit( state.copyWith( password: password, - status: FormStatus.validate(toValidate), + status: _validationStrategy.rawValidate(toValidate), ), ); } // Take from wyatt_form_bloc/wyatt_form_bloc.dart - void dataChanged(String field, FormInputValidator dirtyValue) { - final _form = state.data.clone(); + void dataChanged( + String field, + FormInputValidator dirtyValue, + ) { + final form = state.data.clone(); - if (_form.contains(field)) { - _form.updateValidator(field, dirtyValue); + if (form.contains(field)) { + form.updateValidator(field, dirtyValue); } else { throw Exception('Form field $field not found'); } emit( state.copyWith( - data: _form, - status: FormStatus.validate( + data: form, + status: _validationStrategy.rawValidate( [ state.email, state.password, @@ -104,27 +108,27 @@ class SignUpCubit extends Cubit { FormData data, { SetOperation operation = SetOperation.replace, }) { - FormData _form = data; + FormData form = data; switch (operation) { case SetOperation.replace: - _form = data; + form = data; break; case SetOperation.difference: - _form = state.data.difference(data); + form = state.data.difference(data); break; case SetOperation.intersection: - _form = state.data.intersection(data); + form = state.data.intersection(data); break; case SetOperation.union: - _form = state.data.union(data); + form = state.data.union(data); break; } emit( state.copyWith( - data: _form, - status: FormStatus.validate( + data: form, + status: _validationStrategy.rawValidate( [ state.email, state.password, @@ -136,7 +140,9 @@ class SignUpCubit extends Cubit { } Future signUpFormSubmitted() async { - if (!state.status.isValidated) return; + if (!state.status.isValidated) { + return; + } emit(state.copyWith(status: FormStatus.submissionInProgress)); try { final uid = await _authenticationRepository.signUp( @@ -144,16 +150,8 @@ class SignUpCubit extends Cubit { password: state.password.value, ); await _onSignUpSuccess?.call(state, uid); - if (_authenticationCubit.start()) { - emit(state.copyWith(status: FormStatus.submissionSuccess)); - } else { - emit( - state.copyWith( - errorMessage: 'Failed to start authentication cubit', - status: FormStatus.submissionFailure, - ), - ); - } + _authenticationRepository.changeCubitStatus(AuthCubitStatus.started); + emit(state.copyWith(status: FormStatus.submissionSuccess)); } on SignUpWithEmailAndPasswordFailureInterface catch (e) { emit( state.copyWith( diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart similarity index 57% rename from packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_state.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart index ce493838..fefe5325 100644 --- a/packages/wyatt_authentication_bloc/lib/src/sign_up/cubit/sign_up_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart @@ -16,8 +16,7 @@ part of 'sign_up_cubit.dart'; -@immutable -class SignUpState { +class SignUpState extends Equatable { final Email email; final Password password; final FormStatus status; @@ -25,10 +24,10 @@ class SignUpState { final String? errorMessage; const SignUpState({ + required this.data, this.email = const Email.pure(), this.password = const Password.pure(), this.status = FormStatus.pure, - required this.data, this.errorMessage, }); @@ -38,40 +37,19 @@ class SignUpState { FormStatus? status, FormData? data, String? errorMessage, - }) { - return SignUpState( - email: email ?? this.email, - password: password ?? this.password, - status: status ?? this.status, - data: data ?? this.data, - errorMessage: errorMessage ?? this.errorMessage, - ); - } + }) => + SignUpState( + email: email ?? this.email, + password: password ?? this.password, + status: status ?? this.status, + data: data ?? this.data, + errorMessage: errorMessage ?? this.errorMessage, + ); @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is SignUpState && - other.email == email && - other.password == password && - other.status == status && - other.data == data && - other.errorMessage == errorMessage; - } + String toString() => 'SignUpState(email: $email, password: $password, ' + 'status: $status, data: $data, errorMessage: $errorMessage)'; @override - int get hashCode { - return email.hashCode ^ - password.hashCode ^ - status.hashCode ^ - data.hashCode ^ - errorMessage.hashCode; - } - - @override - String toString() { - // ignore: lines_longer_than_80_chars - return 'SignUpState(email: $email, password: $password, status: $status, data: $data, errorMessage: $errorMessage)'; - } + List get props => [email, password, status, data, errorMessage]; } diff --git a/packages/wyatt_authentication_bloc/lib/src/sign_up/sign_up.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart similarity index 100% rename from packages/wyatt_authentication_bloc/lib/src/sign_up/sign_up.dart rename to packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions.dart b/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions.dart deleted file mode 100644 index 75da2bc7..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/models/exceptions/exceptions.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2022 WYATT GROUP -// Please see the AUTHORS file for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -export 'exceptions_firebase.dart'; -export 'exceptions_interface.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/models/models.dart b/packages/wyatt_authentication_bloc/lib/src/models/models.dart deleted file mode 100644 index 1bd2db89..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/models/models.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2022 WYATT GROUP -// Please see the AUTHORS file for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -export 'exceptions/exceptions.dart'; -export 'user/user.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/src.dart b/packages/wyatt_authentication_bloc/lib/src/src.dart index 6b879865..62ba6ef9 100644 --- a/packages/wyatt_authentication_bloc/lib/src/src.dart +++ b/packages/wyatt_authentication_bloc/lib/src/src.dart @@ -14,10 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'authentication/authentication.dart'; -export 'email_verification/email_verification.dart'; -export 'models/models.dart'; -export 'password_reset/password_reset.dart'; -export 'repositories/repositories.dart'; -export 'sign_in/sign_in.dart'; -export 'sign_up/sign_up.dart'; +export 'core/enum/auth_cubit_status.dart'; +export 'core/exceptions/exceptions.dart'; +export 'core/exceptions/exceptions_firebase.dart'; +export 'core/extensions/firebase_auth_user_x.dart'; +export 'core/utils/cryptography.dart'; +export 'data/models/user_firebase.dart'; +export 'data/repositories/authentication_repository_firebase.dart'; +export 'domain/entities/user.dart'; +export 'domain/repositories/authentication_repository.dart'; +export 'features/authentication/authentication.dart'; +export 'features/email_verification/email_verification.dart'; +export 'features/password_reset/password_reset.dart'; +export 'features/sign_in/sign_in.dart'; +export 'features/sign_up/sign_up.dart'; diff --git a/packages/wyatt_authentication_bloc/pubspec.yaml b/packages/wyatt_authentication_bloc/pubspec.yaml index ac4ae6aa..c4b299b6 100644 --- a/packages/wyatt_authentication_bloc/pubspec.yaml +++ b/packages/wyatt_authentication_bloc/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/mas version: 0.2.1+3 environment: - sdk: ">=2.15.1 <3.0.0" + sdk: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" dependencies: @@ -31,6 +31,7 @@ dev_dependencies: flutter_test: sdk: flutter bloc_test: ^9.0.3 + mocktail: ^0.3.0 wyatt_analysis: git: diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart index 3b743aaf..95708942 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart @@ -20,66 +20,87 @@ import 'package:mocktail/mocktail.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepositoryInterface {} + implements AuthenticationRepository {} -class MockUser extends Mock implements UserInterface {} +class MockUser extends Mock implements User {} void main() { - group('AuthenticationCubit', () { + group('AuthenticationCubit', () { final MockUser user = MockUser(); - late AuthenticationRepositoryInterface authenticationRepository; + late AuthenticationRepository authenticationRepository; setUp(() { authenticationRepository = MockAuthenticationRepository(); when(() => authenticationRepository.user).thenAnswer( (_) => const Stream.empty(), ); + when(() => authenticationRepository.cubitStatus).thenAnswer( + (_) => Stream.fromIterable([AuthCubitStatus.stoped]), + ); when( () => authenticationRepository.currentUser, - ).thenReturn(const UserFirebase.empty()); + ).thenReturn(user); }); - test('initial state is unknown', () { + test('initial auth state is `unknown`', () { expect( - AuthenticationCubit(authenticationRepository: authenticationRepository) - .state, - const AuthenticationState.unknown(), + AuthenticationCubit( + authenticationRepository: authenticationRepository, + ).state, + const AuthenticationState.unknown(), + ); + }); + + test('initial cubit status is `stoped`', () async { + expect( + await AuthenticationCubit( + authenticationRepository: authenticationRepository, + ).status, + AuthCubitStatus.stoped, ); }); group('UserChanged', () { - blocTest( + blocTest, AuthenticationState>( 'emits authenticated when user is not empty', setUp: () { when(() => user.isNotEmpty).thenReturn(true); when(() => authenticationRepository.user).thenAnswer( (_) => Stream.value(user), ); - }, - build: () => AuthenticationCubit( - authenticationRepository: authenticationRepository, - )..init(), - seed: () => const AuthenticationState.unknown(), - expect: () => [AuthenticationState.authenticated(user, null)], - ); - - blocTest( - 'emits unauthenticated when user is empty', - setUp: () { - when(() => authenticationRepository.user).thenAnswer( - (_) => Stream.value(const UserFirebase.empty()), + when(() => authenticationRepository.cubitStatus).thenAnswer( + (_) => Stream.value(AuthCubitStatus.started), ); }, build: () => AuthenticationCubit( authenticationRepository: authenticationRepository, )..init(), seed: () => const AuthenticationState.unknown(), - expect: () => [const AuthenticationState.unauthenticated()], + expect: () => [AuthenticationState.authenticated(user, null)], + ); + + blocTest, AuthenticationState>( + 'emits unauthenticated when user is empty', + setUp: () { + when(() => user.isEmpty).thenReturn(true); + when(() => user.isNotEmpty).thenReturn(false); + when(() => authenticationRepository.user).thenAnswer( + (_) => Stream.value(user), + ); + when(() => authenticationRepository.cubitStatus).thenAnswer( + (_) => Stream.value(AuthCubitStatus.started), + ); + }, + build: () => AuthenticationCubit( + authenticationRepository: authenticationRepository, + )..init(), + seed: () => const AuthenticationState.unknown(), + expect: () => [const AuthenticationState.unauthenticated()], ); }); group('LogoutRequested', () { - blocTest( + blocTest, AuthenticationState>( 'invokes signOut', setUp: () { when( @@ -89,7 +110,7 @@ void main() { build: () => AuthenticationCubit( authenticationRepository: authenticationRepository, ), - act: (AuthenticationCubit cubit) => cubit.logOut(), + act: (cubit) => cubit.logOut(), verify: (_) { verify(() => authenticationRepository.signOut()).called(1); }, diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart index 69279523..d7ce2cb2 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart @@ -18,13 +18,14 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -class MockUser extends Mock implements UserInterface {} +class MockUser extends Mock implements User {} void main() { group('AuthenticationState', () { group('unauthenticated', () { test('has correct status', () { - const AuthenticationState state = AuthenticationState.unauthenticated(); + const AuthenticationState state = + AuthenticationState.unauthenticated(); expect(state.status, AuthenticationStatus.unauthenticated); expect(state.user, null); }); @@ -33,11 +34,23 @@ void main() { group('authenticated', () { test('has correct status', () { final MockUser user = MockUser(); - final AuthenticationState state = + final AuthenticationState state = AuthenticationState.authenticated(user, null); expect(state.status, AuthenticationStatus.authenticated); expect(state.user, user); }); }); + + group('authenticated with extra data', () { + test('has correct status', () { + final MockUser user = MockUser(); + const String extra = 'AwesomeExtraData'; + final AuthenticationState state = + AuthenticationState.authenticated(user, extra); + expect(state.status, AuthenticationStatus.authenticated); + expect(state.user, user); + expect(state.extra, extra); + }); + }); }); } diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart index c3c0757e..866ed2ca 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart @@ -21,9 +21,10 @@ import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepositoryInterface {} + implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit {} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} void main() { const String invalidEmailString = 'invalid'; @@ -39,8 +40,8 @@ void main() { const Password validPassword = Password.dirty(validPasswordString); group('SignInCubit', () { - late AuthenticationRepositoryInterface authenticationRepository; - late AuthenticationCubit authenticationCubit; + late AuthenticationRepository authenticationRepository; + late AuthenticationCubit authenticationCubit; setUp(() { authenticationRepository = MockAuthenticationRepository(); @@ -62,7 +63,6 @@ void main() { expect( SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ).state, const SignInState(), ); @@ -73,9 +73,8 @@ void main() { 'emits [invalid] when email/password are invalid', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), - act: (SignInCubit cubit) => cubit.emailChanged(invalidEmailString), + act: (cubit) => cubit.emailChanged(invalidEmailString), expect: () => const [ SignInState(email: invalidEmail, status: FormStatus.invalid), ], @@ -85,10 +84,9 @@ void main() { 'emits [valid] when email/password are valid', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), seed: () => const SignInState(password: validPassword), - act: (SignInCubit cubit) => cubit.emailChanged(validEmailString), + act: (cubit) => cubit.emailChanged(validEmailString), expect: () => const [ SignInState( email: validEmail, @@ -104,10 +102,8 @@ void main() { 'emits [invalid] when email/password are invalid', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), - act: (SignInCubit cubit) => - cubit.passwordChanged(invalidPasswordString), + act: (cubit) => cubit.passwordChanged(invalidPasswordString), expect: () => const [ SignInState( password: invalidPassword, @@ -120,10 +116,9 @@ void main() { 'emits [valid] when email/password are valid', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), seed: () => const SignInState(email: validEmail), - act: (SignInCubit cubit) => cubit.passwordChanged(validPasswordString), + act: (cubit) => cubit.passwordChanged(validPasswordString), expect: () => const [ SignInState( email: validEmail, @@ -139,9 +134,8 @@ void main() { 'does nothing when status is not validated', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), - act: (SignInCubit cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.signInWithEmailAndPassword(), expect: () => const [], ); @@ -149,14 +143,13 @@ void main() { 'calls signInWithEmailAndPassword with correct email/password', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), seed: () => const SignInState( status: FormStatus.valid, email: validEmail, password: validPassword, ), - act: (SignInCubit cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.signInWithEmailAndPassword(), verify: (_) { verify( () => authenticationRepository.signInWithEmailAndPassword( @@ -172,14 +165,13 @@ void main() { 'when signInWithEmailAndPassword succeeds', build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), seed: () => const SignInState( status: FormStatus.valid, email: validEmail, password: validPassword, ), - act: (SignInCubit cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.signInWithEmailAndPassword(), expect: () => const [ SignInState( status: FormStatus.submissionInProgress, @@ -207,14 +199,13 @@ void main() { }, build: () => SignInCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, ), seed: () => const SignInState( status: FormStatus.valid, email: validEmail, password: validPassword, ), - act: (SignInCubit cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.signInWithEmailAndPassword(), expect: () => const [ SignInState( status: FormStatus.submissionInProgress, diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart index 08977706..0e3de2d5 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart @@ -21,9 +21,10 @@ import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepositoryInterface {} + implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit {} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} void main() { const String invalidEmailString = 'invalid'; @@ -39,8 +40,8 @@ void main() { const Password validPassword = Password.dirty(validPasswordString); group('SignUpCubit', () { - late AuthenticationRepositoryInterface authenticationRepository; - late AuthenticationCubit authenticationCubit; + late AuthenticationRepository authenticationRepository; + late AuthenticationCubit authenticationCubit; setUp(() { authenticationRepository = MockAuthenticationRepository(); @@ -50,9 +51,7 @@ void main() { email: any(named: 'email'), password: any(named: 'password'), ), - ).thenAnswer((_) async { - return 'uid'; - }); + ).thenAnswer((_) async => 'uid'); when( () => authenticationCubit.start(), @@ -67,8 +66,7 @@ void main() { expect( SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ).state, const SignUpState(data: FormData.empty()), ); @@ -79,10 +77,9 @@ void main() { 'emits [invalid] when email/password are invalid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.emailChanged(invalidEmailString), + act: (cubit) => cubit.emailChanged(invalidEmailString), expect: () => [ const SignUpState( email: invalidEmail, @@ -96,14 +93,13 @@ void main() { 'emits [valid] when email/password are valid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), seed: () => const SignUpState( password: validPassword, data: FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.emailChanged(validEmailString), + act: (cubit) => cubit.emailChanged(validEmailString), expect: () => [ const SignUpState( email: validEmail, @@ -120,11 +116,9 @@ void main() { 'emits [invalid] when email/password are invalid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), - act: (SignUpCubit cubit) => - cubit.passwordChanged(invalidPasswordString), + act: (cubit) => cubit.passwordChanged(invalidPasswordString), expect: () => [ const SignUpState( password: invalidPassword, @@ -138,14 +132,13 @@ void main() { 'emits [valid] when email/password are valid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), seed: () => const SignUpState( email: validEmail, data: FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.passwordChanged(validPasswordString), + act: (cubit) => cubit.passwordChanged(validPasswordString), expect: () => [ const SignUpState( email: validEmail, @@ -162,10 +155,9 @@ void main() { 'does nothing when status is not validated', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.signUpFormSubmitted(), expect: () => const [], ); @@ -173,8 +165,7 @@ void main() { 'calls signUp with correct email/password/confirmedPassword', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), seed: () => const SignUpState( status: FormStatus.valid, @@ -182,7 +173,7 @@ void main() { password: validPassword, data: FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.signUpFormSubmitted(), verify: (_) { verify( () => authenticationRepository.signUp( @@ -198,8 +189,7 @@ void main() { 'when signUp succeeds', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), seed: () => const SignUpState( status: FormStatus.valid, @@ -207,7 +197,7 @@ void main() { password: validPassword, data: FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.signUpFormSubmitted(), expect: () => [ const SignUpState( status: FormStatus.submissionInProgress, @@ -237,8 +227,7 @@ void main() { }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - authenticationCubit: authenticationCubit, - entries: const FormData.empty(), + formData: const FormData.empty(), ), seed: () => const SignUpState( status: FormStatus.valid, @@ -246,7 +235,7 @@ void main() { password: validPassword, data: FormData.empty(), ), - act: (SignUpCubit cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.signUpFormSubmitted(), expect: () => [ const SignUpState( status: FormStatus.submissionInProgress,