diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..357e21e5 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,37 @@ +# 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 . + +kind: pipeline +type: docker +name: default + +steps: + - name: quality-check + image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:latest + commands: + - melos run quality-check + - melos run publish:validate + # - name: publish + # image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:2.9.0-1 + # commands: + # - melos run publish:validate + # + +trigger: + branch: + - master + event: + - pull_request diff --git a/.gitignore b/.gitignore index 37e175bc..f9b92095 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,47 @@ # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,android,androidstudio,dart,fastlane,firebase,flutter,java,jetbrains+all,kotlin,objective-c,swift,xcode +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,android,androidstudio,dart,fastlane,firebase,flutter,java,jetbrains+all,kotlin,objective-c,swift,xcode -# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,dart,flutter,linux,windows -# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,dart,flutter,linux,windows +### Android ### +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof + +### Android Patch ### +gen-external-apklibs + +# Replacement of .externalNativeBuild directories introduced +# with Android Studio 3.5. ### Dart ### # See https://www.dartlang.org/guides/libraries/private-files @@ -9,22 +49,17 @@ # Files and directories created by pub .dart_tool/ .packages -build/ # If you're building an application, you may want to check-in your pubspec.lock pubspec.lock -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - # dotenv environment variables file .env* # Avoid committing generated Javascript files: *.dart.js -*.info.json # Produced by the --dump-info flag. -*.js # When generated by dart2js. Don't specify *.js if your - # project includes source files written in JavaScript. +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your +# project includes source files written in JavaScript. *.js_ *.js.deps *.js.map @@ -36,15 +71,47 @@ doc/api/ # dotenv environment variables file .env +### fastlane ### +# fastlane - A streamlined workflow tool for Cocoa deployment +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +# fastlane specific +**/fastlane/report.xml + +# deliver temporary files +**/fastlane/Preview.html + +# snapshot generated screenshots +**/fastlane/screenshots + +# scan temporary files +**/fastlane/test_output + +# Fastlane.swift runner binary +**/fastlane/FastlaneRunner + +### Firebase ### +.idea +**/node_modules/* +**/.firebaserc + +### Firebase Patch ### +.runtimeconfig.json +.firebase/ + ### Flutter ### # Flutter/Dart/Pub related **/doc/api/ -.fvm/ +.fvm/flutter_sdk .pub-cache/ .pub/ coverage/ lib/generated_plugin_registrant.dart -# For library packages, don’t commit the pubspec.lock file. +# For library packages, don't commit the pubspec.lock file. # Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. # See https://dart.dev/guides/libraries/private-files#pubspeclock #pubspec.lock @@ -95,20 +162,131 @@ lib/generated_plugin_registrant.dart !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -### Linux ### -*~ +### Java ### +# Compiled class file +*.class -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* +# Log file -# KDE directory preferences -.directory +# BlueJ files +*.ctxt -# Linux trash folder which might appear on any partition or disk -.Trash-* +# Mobile Tools for Java (J2ME) +.mtj.tmp/ -# .nfs files are created when an open file is removed but is still being accessed -.nfs* +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Kotlin ### +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml ### macOS ### # General @@ -119,7 +297,6 @@ lib/generated_plugin_registrant.dart # Icon must end with two \r Icon - # Thumbnails ._* @@ -143,6 +320,116 @@ Temporary Items # iCloud generated files *.icloud +### Objective-C ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Objective-C Patch ### + +### Swift ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + ### VisualStudioCode ### .vscode/* !.vscode/settings.json @@ -162,35 +449,129 @@ Temporary Items .history .ionide -# Support for Project snippet scope +### Xcode ### -### Windows ### -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db +## Xcode 8 and earlier -# Dump file -*.stackdump +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings -# Folder config file -[Dd]esktop.ini +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# Built application files +*.ap_ +*.aab -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp +# Files for the ART/Dalvik VM +*.dex -# Windows shortcuts -*.lnk +# Java class files -# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,dart,flutter,linux,windows +# Generated files +bin/ +gen/ + +# Gradle files +.gradle + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +.navigation/ +*.ipr +*~ +*.swp + +# Keystore files + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,android,androidstudio,dart,fastlane,firebase,flutter,java,jetbrains+all,kotlin,objective-c,swift,xcode # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) @@ -200,4 +581,4 @@ google-services.json pubspec_overrides.yaml # Mason -.mason/ \ No newline at end of file +.mason/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..9ca476d0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v2.1.1 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: [build, ci, docs, feat, fix, perf, refactor, style, test, chore] diff --git a/.pubignore b/.pubignore new file mode 100644 index 00000000..e6ce7445 --- /dev/null +++ b/.pubignore @@ -0,0 +1,589 @@ + +### Android ### +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof + +### Android Patch ### +gen-external-apklibs + +# Replacement of .externalNativeBuild directories introduced +# with Android Studio 3.5. + +### Dart ### +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# dotenv environment variables file +.env* + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your +# project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +.flutter-plugins +.flutter-plugins-dependencies + +### Dart Patch ### +# dotenv environment variables file +.env + +### fastlane ### +# fastlane - A streamlined workflow tool for Cocoa deployment +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +# fastlane specific +**/fastlane/report.xml + +# deliver temporary files +**/fastlane/Preview.html + +# snapshot generated screenshots +**/fastlane/screenshots + +# scan temporary files +**/fastlane/test_output + +# Fastlane.swift runner binary +**/fastlane/FastlaneRunner + +### Firebase ### +.idea +**/node_modules/* +**/.firebaserc + +### Firebase Patch ### +.runtimeconfig.json +.firebase/ + +### Flutter ### +# Flutter/Dart/Pub related +**/doc/api/ +.fvm/flutter_sdk +.pub-cache/ +.pub/ +coverage/ +lib/generated_plugin_registrant.dart +# For library packages, don't commit the pubspec.lock file. +# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. +# See https://dart.dev/guides/libraries/private-files#pubspeclock +#pubspec.lock + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/key.properties +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +### Java ### +# Compiled class file +*.class + +# Log file + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Kotlin ### +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Objective-C ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Objective-C Patch ### + +### Swift ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Xcode ### + +## Xcode 8 and earlier + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + +# Built application files +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +.navigation/ +*.ipr +*~ +*.swp + +# Keystore files + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,android,androidstudio,dart,fastlane,firebase,flutter,java,jetbrains+all,kotlin,objective-c,swift,xcode + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + +.idea/ +*.iml +google-services.json +pubspec_overrides.yaml + +# Mason +.mason/ + +new_version.sh +.latest_version +.vscode/ +example/ +build/ +*.iml + diff --git a/AUTHORS b/AUTHORS index f9506138..a1c2a78d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,5 +4,5 @@ # Name/Organization Wyatt Group S.A.S -Hugo Pointcheval -Malo Léon \ No newline at end of file +Hugo Pointcheval +Malo Léon diff --git a/CHANGELOG.md b/CHANGELOG.md index 41bcd1b0..a298c3b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,537 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 2023-05-06 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_authentication_bloc` - `v0.5.0+1`](#wyatt_authentication_bloc---v0501) + +--- + +#### `wyatt_authentication_bloc` - `v0.5.0+1` + + - **REFACTOR**(authentication): controle cache checking. + + +## 2023-05-04 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_ui_components` - `v0.2.1`](#wyatt_ui_components---v021) + - [`wyatt_bloc_layout` - `v0.1.0+1`](#wyatt_bloc_layout---v0101) + - [`wyatt_ui_kit` - `v3.0.1`](#wyatt_ui_kit---v301) + - [`wyatt_ui_layout` - `v0.1.0+1`](#wyatt_ui_layout---v0101) + +Packages with dependency updates only: + +> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project. + + - `wyatt_bloc_layout` - `v0.1.0+1` + - `wyatt_ui_kit` - `v3.0.1` + - `wyatt_ui_layout` - `v0.1.0+1` + +--- + +#### `wyatt_ui_components` - `v0.2.1` + + - **FEAT**: add floating action button component (close #191). (d3184eb3) + + +## 2023-05-03 + +### Changes + +--- + +Packages with breaking changes: + + - [`wyatt_bloc_layout` - `v0.1.0`](#wyatt_bloc_layout---v010) + - [`wyatt_ui_components` - `v0.2.0`](#wyatt_ui_components---v020) + - [`wyatt_ui_kit` - `v3.0.0`](#wyatt_ui_kit---v300) + - [`wyatt_ui_layout` - `v0.1.0`](#wyatt_ui_layout---v010) + +Packages with other changes: + + - [`wyatt_analysis` - `v2.5.0`](#wyatt_analysis---v250) + - [`wyatt_component_copy_with_extension` - `v2.0.1`](#wyatt_component_copy_with_extension---v201) + - [`wyatt_component_copy_with_gen` - `v2.0.1`](#wyatt_component_copy_with_gen---v201) + +--- + +#### `wyatt_bloc_layout` - `v0.1.0` + + - **BREAKING** **FEAT**(layout): update layout plugins with new components system. (e76857f1) + +#### `wyatt_ui_components` - `v0.2.0` + + - **FIX**(gen): rename builder correctly. (cef73aa6) + - **FEAT**(ui_components): make textwrapper toString useful. (96369e24) + - **FEAT**(ui): add pricing card. (bfbeabe7) + - **FEAT**(ui): update default extension implementation. (01a5619d) + - **FEAT**(ui): add animated decorated box + animate all buttons + customize duration in style. (4ebb679a) + - **FEAT**(ui): add colors and rework ComponentThemeData. (abd5e1b5) + - **FEAT**(ui): make components more coherent + docs. (01269027) + - **FEAT**(ui): make gradient as component. (0d5109fc) + - **FEAT**(ui): fix, rename, rewrite some helpers. (3fb40205) + - **BREAKING** **FEAT**(ui): move last extensions + add extension provider. (4097a420) + - **BREAKING** **FEAT**(ui): rework theme resolver mechanism + move theme extension implementations. (8f5e3923) + +#### `wyatt_ui_kit` - `v3.0.0` + + - **FIX**(gen): rename builder correctly. (cef73aa6) + - **FEAT**(ui): add pricing card. (bfbeabe7) + - **FEAT**(ui): update default extension implementation. (01a5619d) + - **FEAT**(ui): add animated decorated box + animate all buttons + customize duration in style. (4ebb679a) + - **FEAT**(ui): add colors and rework ComponentThemeData. (abd5e1b5) + - **FEAT**(ui_kit): update example by removing adaptative theme. (a024b7e7) + - **FEAT**(ui): make components more coherent + docs. (01269027) + - **FEAT**(ui): make gradient as component. (0d5109fc) + - **FEAT**(ui): fix, rename, rewrite some helpers. (3fb40205) + - **FEAT**(ui_kit): make flat button fade on transition. (32cc6e82) + - **FEAT**(ui_kit): add more control over flat button prefix/suffix color. (2baaf5c0) + - **BREAKING** **FEAT**(ui): move last extensions + add extension provider. (4097a420) + - **BREAKING** **FEAT**(ui): rework theme resolver mechanism + move theme extension implementations. (8f5e3923) + +#### `wyatt_ui_layout` - `v0.1.0` + + - **BREAKING** **FEAT**(layout): update layout plugins with new components system. (e76857f1) + +#### `wyatt_analysis` - `v2.5.0` + + - **FIX**(analysis): remove depencies sort. (4e3b288e) + - **FEAT**(analysis): update version. (0720a145) + - **FEAT**(analysis): upgrade. (2692c607) + +#### `wyatt_component_copy_with_extension` - `v2.0.1` + + - **FIX**(gen): rename builder correctly. (cef73aa6) + +#### `wyatt_component_copy_with_gen` - `v2.0.1` + + - **FIX**(gen): rename builder correctly. (cef73aa6) + + +## 2023-04-14 + +### Changes + +--- + +Packages with breaking changes: + + - [`wyatt_architecture` - `v0.2.0`](#wyatt_architecture---v020) + - [`wyatt_authentication_bloc` - `v0.5.0`](#wyatt_authentication_bloc---v050) + - [`wyatt_component_copy_with_extension` - `v2.0.0`](#wyatt_component_copy_with_extension---v200) + - [`wyatt_component_copy_with_gen` - `v2.0.0`](#wyatt_component_copy_with_gen---v200) + - [`wyatt_http_client` - `v2.0.0`](#wyatt_http_client---v200) + - [`wyatt_i18n` - `v2.0.0`](#wyatt_i18n---v200) + - [`wyatt_ui_components` - `v0.1.0`](#wyatt_ui_components---v010) + - [`wyatt_ui_kit` - `v2.0.0`](#wyatt_ui_kit---v200) + +Packages with other changes: + + - [`wyatt_analysis` - `v2.4.2`](#wyatt_analysis---v242) + - [`wyatt_bloc_helper` - `v2.0.1`](#wyatt_bloc_helper---v201) + - [`wyatt_bloc_layout` - `v0.0.2`](#wyatt_bloc_layout---v002) + - [`wyatt_crud_bloc` - `v0.1.1`](#wyatt_crud_bloc---v011) + - [`wyatt_form_bloc` - `v0.2.0+3`](#wyatt_form_bloc---v0203) + - [`wyatt_type_utils` - `v0.0.5`](#wyatt_type_utils---v005) + - [`wyatt_ui_layout` - `v0.0.2`](#wyatt_ui_layout---v002) + +--- + +#### `wyatt_architecture` - `v0.2.0` + + - **REFACTOR**: move to dart package. + - **FIX**: remove wyatt arch ios example. + - **DOCS**: change some documentation. + - **DOCS**: add documentation. + - **DOCS**: update readme. + - **BREAKING** **REFACTOR**: fix cascade dart good practices + docs. + +#### `wyatt_authentication_bloc` - `v0.5.0` + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: remove cross package export. + - **REFACTOR**: use custom user changes stream. + - **REFACTOR**: make signup/in, passwordreset cubit extendable. + - **FIX**: make sur access token is available on every steps. + - **FIX**: anonymous sign in event. + - **FIX**: initialize account stream transformer. + - **FIX**: stream on null account. + - **FIX**: handle empty provider list (closes #113). + - **FEAT**: add mock + local storage. + - **FEAT**: remove session wrapper for AuthenticationSession. + - **FEAT**: add account edit cubit. + - **FEAT**: add custom routine, and documentation. + - **FEAT**: add full event support. + - **DOCS**: update example with multiple data sources. + - **DOCS**: add full dartdoc. + - **DOCS**: add wiki script. + - **DOCS**: update example. + - **DOCS**: update example. + - **BREAKING** **REFACTOR**: split data sources (cache, session, external). + - **BREAKING** **REFACTOR**: use mixins, and remove use of onSignUpSuccess. + - **BREAKING** **FEAT**: add event type on auth change. + +#### `wyatt_component_copy_with_extension` - `v2.0.0` + + - **FIX**: remove wyatt arch ios example. + - **FEAT**: add class annotation for component code generators. + - **DOCS**: add some documentation. + - **BREAKING** **REFACTOR**: rename file. + +#### `wyatt_component_copy_with_gen` - `v2.0.0` + + - **REFACTOR**: migrate components using code generator packages (#115). + - **FIX**: remove wyatt arch ios example. + - **FIX**: change example to be compatible with new AppTopBar and TextWrapper. + - **FIX**: fix textwrapper. + - **FIX**: update example (#118). + - **FIX**: copywith method takes non nullable fields too (#118). + - **FEAT**: add generators for components proxy and mixins to enable copywith methods. + - **DOCS**: add some documentation. + - **BREAKING** **REFACTOR**: rename file. + +#### `wyatt_http_client` - `v2.0.0` + + - **DOCS**: add simple example. + - **BREAKING** **REFACTOR**: fix cascade dart good practices + docs. + +#### `wyatt_i18n` - `v2.0.0` + + - **FEAT**: change gitignore for symbolic link. + - **FEAT**: add i18n delegate + example. + - **FEAT**: implements network data source. + - **FEAT**: add default locale. + - **FEAT**: add getter/setter. + - **FEAT**: add ICU parser. + - **FEAT**: add arb, json and yaml parsers. + - **DOCS**: add docstrings on every classes. + - **BREAKING** **FEAT**: rename few files + add clearer documentation. + +#### `wyatt_ui_components` - `v0.1.0` + + - **REFACTOR**: update example (#92). + - **REFACTOR**: replace ThemeResolver by ThemeHelper in Loader / RichTextBuilder (closes #148). + - **REFACTOR**: migrate top nav bar using generify top bar. + - **REFACTOR**: move borderColors type. + - **REFACTOR**: add CopyWith method in ThemeStyle. + - **REFACTOR**: update colors using Multicolor class (#138). + - **REFACTOR**: rework text gradient and text wrapper. + - **REFACTOR**: remove CopyWith extension. + - **REFACTOR**: move extensions. + - **REFACTOR**: merge flat and outline buttons in only one style. + - **REFACTOR**: update example (close #115). + - **REFACTOR**: migrate components using code generator packages (#115). + - **REFACTOR**: update example (#92). + - **FIX**: fix extra value in compute extension function. + - **FIX**: remove darkmode enable field in cards. + - **FIX**: add loader to theme data (close #152). + - **FIX**: inverse merge in TextInputStyle. + - **FIX**: use multicolor in cards. + - **FIX**: fix MultiColor lerp method. + - **FIX**: remove null check operator in RichTextBuilder component. + - **FIX**: remove wyatt arch ios example. + - **FIX**: add style merge in Theme Resolver. + - **FIX**: generate new files after generator fixes (close #118). + - **FIX**: move theme_resolver in compnoent to fix code generation. + - **FIX**: add generated component with theme resolver. + - **FEAT**: add text input components, theme extension and worked on utils (#138). + - **FEAT**: add isColor getter in multicolor helper. + - **FEAT**: add loading & error widget to component theme (close #69). + - **FEAT**: add text input abstract class (#138). + - **FEAT**: add rich text builder / parser. + - **FEAT**: update example & move configure function (#69). + - **FEAT**: add top navigation bar component to theme data. + - **FEAT**: add extra state. + - **FEAT**: update layouts to allow more control on components. + - **FEAT**: add some useful text customization in TextWrapper (closes #149). + - **FEAT**: update attributs and proxy most of appbar attributs. + - **FEAT**: add new components to theme data (close #152). + - **FEAT**: move style implementation from component to ui_kit with theme resolver. + - **FEAT**: add copyWith gen and make button style lerping. + - **FEAT**: make component theme data copyable. + - **FEAT**: add loader component and style. + - **FEAT**: add file selection component. + - **FEAT**: add simple icon button and dimension style. + - **FEAT**: add symbol button. + - **FEAT**: implement top nav bar. + - **FEAT**: add tapped control state. + - **FEAT**: add MultiColor util class. + - **FEAT**: create new package to split components and layouts. + - **FEAT**: add button components. + - **FEAT**: make app bar leading & actions customizable. + - **FEAT**: add quote / skill / portfolio cards (#126). + - **FEAT**: add gradient attribut to text wrapper. + - **FEAT**: add string extension to easely wrap text. + - **FEAT**: export cards #126. + - **FEAT**: add portfolio & skill cards #126. + - **FEAT**: make text wrapper constructor constant. + - **FEAT**: add text wrapper instead of String/Widget for Texts. + - **FEAT**: make fields nullable and not required in quote card. + - **FEAT**: add card theme extension, fix bugs & update example (close #126). + - **FEAT**: export components and add license header. + - **FEAT**: add information_card & quote_card (#126). + - **FEAT**: add Top Navigation Bar Component. + - **FEAT**: generate new skillcard component. + - **FEAT**: generify bars. + - **FEAT**: rework on structure using new components and layouts. + - **FEAT**: add centerTitle property to app bar component. + - **FEAT**: make component data field nullable (#92). + - **FEAT**: add lerp on multicolor. + - **FEAT**: add flat/outlined button styles. + - **DOCS**: add some documentation + readme. + - **DOCS**: update models. + - **BREAKING** **REFACTOR**: remove bloc export in buttons to be state management solution agnostic (closes #147). + +#### `wyatt_ui_kit` - `v2.0.0` + + - **REFACTOR**: use tapped state and merged styles. + - **REFACTOR**: remove selection area of rich text, its not his reponsibility. + - **REFACTOR**: replace ThemeResolver by ThemeHelper in Loader / RichTextBuilder (closes #148). + - **REFACTOR**: adapt ui_kit. + - **REFACTOR**: use ThemeHelper in cards. + - **REFACTOR**: rename GradientBoxBorder. + - **REFACTOR**: update textinput component using borderColors as Color. + - **REFACTOR**: rework text gradient and text wrapper. + - **REFACTOR**: move exportable bloc from mixin to widget. + - **REFACTOR**: make resolve private and dotter child a widget. + - **FIX**: fix text align, add selection and update example for rich text builder. + - **FIX**: remove useless file. + - **FIX**: fix tab action focus on textinputs. + - **FIX**: inverse merge in TextInputStyle. + - **FIX**: use multicolor in cards. + - **FIX**: fix export theme file. + - **FIX**: remove wyatt arch ios example. + - **FIX**: remove null check operator in RichTextBuilder component. + - **FIX**: remove null check operator in Loader component. + - **FIX**: fix conflicts in card component after rebase. + - **FIX**: move theme_resolver in compnoent to fix code generation. + - **FIX**: make card core stateless. + - **FIX**: add cacheExtend as a trade-off in listview example. + - **FIX**: add local font assets + compress images. + - **FEAT**: make top bar selector customizable. + - **FEAT**: update example (#138). + - **FEAT**: implemement text inputs (#138). + - **FEAT**: add text input theme extension (#138). + - **FEAT**: add some useful text customization in TextWrapper (closes #149). + - **FEAT**: implement rich text builder (closes #141). + - **FEAT**: remove .raw call. + - **FEAT**: add loader implementation. + - **FEAT**: export ui kit as component theme data. + - **FEAT**: implement top app bar and update example. + - **FEAT**: update example with full studio button theme. + - **FEAT**: add theme control in example. + - **FEAT**: finalize material ready buttons. + - **FEAT**: implement information card (#126). + - **FEAT**: implement flat button. + - **FEAT**: add theme extension support in buttons + theme negociation. + - **FEAT**: add theme extension shortcut. + - **FEAT**: add card theme extension, fix bugs & update example (close #126). + - **FEAT**: add quote / skill / portfolio cards (#126). + - **FEAT**: make skillcard header icon customizable. + - **FEAT**: update example with drawer and custom launch parameters. + - **FEAT**: add multicolor support in linear gradient helper. + - **FEAT**: implement file selection button with invalid cubit and dotted package. + - **FEAT**: implement simple icon button and use dimension style. + - **FEAT**: add symbol button + enhance bloc control over state. + - **FEAT**: implement top nav bar. + - **FEAT**: use MultiColor in button style. + - **FEAT**: implement flat/outlined button. + - **FEAT**: move style implementation from component to ui_kit with theme resolver. + - **FEAT**: allow to cascade styles in ThemeHelper. + - **DOCS**: add some documentation + readme. + - **DOCS**: add theme negociation explaination. + - **BREAKING** **REFACTOR**: remove bloc export in buttons to be state management solution agnostic (closes #147). + +#### `wyatt_analysis` - `v2.4.2` + + - **REFACTOR**: remove cross package export. + - **DOCS**: change some documentation. + +#### `wyatt_bloc_helper` - `v2.0.1` + + - **REFACTOR**: docs + nullable multiprovider attributes. + +#### `wyatt_bloc_layout` - `v0.0.2` + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: migrate bloc layouts using copywith component method (close #121). + - **REFACTOR**: update example (#92). + - **REFACTOR**: update package using nullable component data (#92). + - **REFACTOR**: update example with new app bar entity (#90). + - **FIX**: remove wyatt arch ios example. + - **FIX**: change example to be compatible with new AppTopBar and TextWrapper. + - **FIX**: fix textwrapper. + - **FIX**: update export file. + - **FIX**: rename file. + - **FEAT**: add attributs available for grid bloc layouts. + - **FEAT**: add grid content implementations. + - **FEAT**: rework on structure using new components and layouts. + - **FEAT**: make package compatible with crud cubit (close #111). + - **FEAT**: export layout_package & adapt imports. + - **FEAT**: export useful packages (close #88). + - **FEAT**: add all layout avalaible with crud bloc. + - **FEAT**: link error widget to error state. + - **FEAT**: add new package to combine bloc_helper, crud_bloc, ui_components, and ui_layout. + +#### `wyatt_crud_bloc` - `v0.1.1` + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: update package using new architecture usecase execute method (close #77). + - **FEAT**: change responsibility of blocs (closes #45, closes #44). + +#### `wyatt_form_bloc` - `v0.2.0+3` + + - **REFACTOR**: remove cross package export. + - **FIX**: fix textController rebuild. + +#### `wyatt_type_utils` - `v0.0.5` + + - **FEAT**: add nullable num comparison. + - **DOCS**: change some documentation. + - **DOCS**: add some documentation. + +#### `wyatt_ui_layout` - `v0.0.2` + + - **REFACTOR**: update exemple (close #116). + - **REFACTOR**: migrate layouts using copywith component method (#116). + - **REFACTOR**: update example (#92). + - **REFACTOR**: update package using nullable component data (#92). + - **REFACTOR**: update example with components updates (close #90). + - **REFACTOR**: update appbar component (close #78). + - **REFACTOR**: update field name. + - **FIX**: remove wyatt arch ios example. + - **FIX**: change example to be compatible with new AppTopBar and TextWrapper. + - **FIX**: fix textwrapper. + - **FIX**: fix emample after splititng packages. + - **FIX**: remove unecessary dependencies. + - **FEAT**: add grid content implementations. + - **FEAT**: update layouts to allow more control on components. + - **FEAT**: make field nullable & add new app bar fields (#97). + - **FEAT**: add frame layout (close #67). + - **FEAT**: add new package for app compenant and start implementing layouts. + - **DOCS**: add some documentation + readme. + - **DOCS**: add doc. + - **DOCS**: update models. + + +## 2023-02-24 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_analysis` - `v2.4.1`](#wyatt_analysis---v241) + +--- + +#### `wyatt_analysis` - `v2.4.1` + + - **FEAT**: add latest version persistence between script executions. + - **FEAT**: ignore todo's. + + +## 2023-02-07 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_analysis` - `v2.4.0`](#wyatt_analysis---v240) + +--- + +#### `wyatt_analysis` - `v2.4.0` + + - **FEAT**: add new lint rules. + - **DOCS**: add instructions to create a new version (closes #104). + + +## 2022-12-13 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_authentication_bloc` - `v0.4.1`](#wyatt_authentication_bloc---v041) + +--- + +#### `wyatt_authentication_bloc` - `v0.4.1` + + - **REFACTOR**: use fromFirebaseUser factory to parse user. + - **REFACTOR**: update deps and re-export them. + - **FIX**: fix mock on register. + - **FEAT**: add google sign in in signIn cubit. + - **FEAT**: add google sign in parameter in firebase data source constructor. + - **FEAT**: add google sign_in support (closes #59). + - **FEAT**: add reauthenticate, updateEmail and updatePassword. + - **DOCS**: add correct header. + + +## 2022-12-12 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`wyatt_analysis` - `v2.3.0`](#wyatt_analysis---v230) + +--- + +#### `wyatt_analysis` - `v2.3.0` + + - **REFACTOR**: follow melos versioning. + - **FIX**: change file include to keep coherence. + - **FEAT**: exclude generated code, and add dart>2.16 rules. + - **FEAT**: add overwrite protection. + - **FEAT**: add 2.2.2 files for archive. + - **FEAT**: add utils script to easely bump version. + + ## 2022-12-04 ### Changes diff --git a/README.md b/README.md index babeca68..a12acec8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- - - - - - - +

Wyatt Packages

- - Style: Wyatt Analysis - - - Maintained with Melos - + Style: Wyatt Analysis + Maintained with Melos

--- @@ -42,12 +32,39 @@ --- + + + + +* [About](#about) +* [Contribution](#contribution) + + [Prerequisite](#prerequisite) + + [Create a new package](#create-a-new-package) + - [Naming](#naming) + + [Create issues](#create-issues) + + [Branches](#branches) + + [Commits](#commits) + - [Before pushing](#before-pushing) + + [Merge your work](#merge-your-work) + + [Update version.](#update-version) + + [Publish your package](#publish-your-package) + + [Badging](#badging) +* [Usage](#usage) +* [Simple work flow diagramm](#simple-work-flow-diagramm) +* [Status](#status) +* [License](#license) + + + +--- + ## About -Here is it a set of [Flutter plugins](https://flutter.io/platform-plugins/) that power up your applications. +Here is a set of [Flutter plugins](https://flutter.io/platform-plugins/) that enhance your applications. -[Flutter](https://flutter.dev) is Google's UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase. Flutter is used by developers and organizations around the world, and is free -and open source. +[Flutter](https://flutter.dev) is Google's UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop using a single codebase. It is used by developers and organizations worldwide and is free and open-source. + +Those packages are developed by [Wyatt Studio](https://wyatt-studio.fr) and are available exclusively on this repository. --- @@ -61,185 +78,192 @@ git clone ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-packages.git ### Prerequisite -- [Flutter](https://github.com/flutter/flutter). +1. [Flutter](https://github.com/flutter/flutter). It is a UI toolkit developed by Google for building beautiful and natively compiled applications for mobile, web, and desktop from a single codebase. -- [Melos](https://github.com/invertase/melos). Used to manage Dart projects with multiple packages. +2. [Melos](https://github.com/invertase/melos). Melos is a tool that helps in managing Dart projects that have multiple packages. It can be installed using the following command: ```shell dart pub global activate melos ``` -- [Mason](https://github.com/felangel/mason). Used for code generation. +3. [Mason](https://github.com/felangel/mason). Mason is used for code generation purposes. It can be installed by running the following command: ```shell dart pub global activate mason_cli ``` -- [Lcov](https://github.com/linux-test-project/lcov). Used to generate coverage data. +4. [Lcov](https://github.com/linux-test-project/lcov). Lcov is a tool used to generate coverage data. It can be installed on macOS by running the following command: ```shell # on macos brew install lcov ``` -- genhtml. Used to convert coverage data into html pages. +* genhtml. Used to convert coverage data into html pages. -After installing all these packages, bootstrap with `melos bs`. +After installation of all these packages, the project can be bootstrapped using the command `melos bs` . ### Create a new package Create a new package in `packages/` folder. +To create a new package in the packages/ folder, run the following command in the terminal: ```shell -mason make wyatt_package --package_name wyatt_ --description A new Wyatt package --flutter_only false +mason make wyatt_package_template --package_name --description A new Wyatt package --flutter false ``` -Then bootstrap project with `melos bs` command. +> Browse our [bricks](https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-bricks) for more information. + +The variable in the above command is important and must be clear and understandable. + +After creating the package, bootstrap the project with the `melos bs` command. #### Naming In the previous instructions `` variable is important. It have to be clear and intelligible. -You **MUST** use underscores. +1. You must use underscores in the name. +2. You must use the wyatt prefix for the package name. -You **MUST** use `wyatt` prefix for package. +For example, if the name is `CRUD BLOC` the following naming conventions should be used: -You **MUST** name example with specific name. - -For example, if name is CRUD BLOC - -- name will be crud_bloc -- so the package will be: `wyatt_crud_bloc` -- and the example will be: `crud_bloc_example` +1. package name: `wyatt_crud_bloc` +2. example name: `example` ### Create issues -Add the issues directly related to what you want to develop and label them correctly. +Create an issue for each specific feature or task you want to work on and label it correctly using the following labels: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/labels. -``` -Type(scope): issue. -``` - -For example, on notification bloc package : - -- `Feature(notification_bloc): add firebase messaging data source.` -- `Test(notification_bloc): add test for pushwoosh datasource.` +For example, if you want to work on the `i18n` package, you should create an issue with the `i18n` label. ### Branches -Master is protected. You can't push on it. Please develop your feature on another branch. The name of your branch has to match with the issue opened. +The `master` branch is protected and cannot be pushed to directly. Please create a separate branch for each feature or task, with a name that corresponds to the related issue. The branch name should follow this format: -`type(scope):issue` + `scope/type/short-name` -Example : -Issue : - -- `Feature(notification_bloc): add firebase messaging data source.` - -Branch related to this issue : - -- `feature(notification_bloc)/add_firebase_messaging_data_source` +For example, if you are working on the `i18n` package and you want to add a new feature, you should create a branch named `i18n/feat/add-new-feature` . ### Commits See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -tl;dr : `type(scope): description #issue`. +tldr : `type(scope): description #issue` . + Here allowed values: -- **feat** for a new feature for the user, not a new feature for build script. Such commit will trigger a release bumping a MINOR version. -- **fix** for a bug fix for the user, not a fix to a build script. Such commit will trigger a release bumping a PATCH version. -- **perf** for performance improvements. Such commit will trigger a release bumping a PATCH version. -- **docs** for changes to the documentation. -- **style** for formatting changes, missing semicolons, etc. -- **refactor** for refactoring production code, e.g. renaming a variable. -- **test** for adding missing tests, refactoring tests; no production code change. -- **build** for updating build configuration, development tools or other changes irrelevant to the user. +* **build** for updating build configuration, development tools or other changes irrelevant to the user. +* **ci** for changes to our CI configuration files and scripts. +* **docs** for changes to documentation. +* **feat** for a new feature for the user, not a new feature for build script. Such commit will trigger a release bumping a MINOR version. +* **fix** for a bug fix for the user, not a fix to a build script. Such commit will trigger a release bumping a PATCH version. +* **perf** for performance improvements. Such commit will trigger a release bumping a PATCH version. +* **refactor** for refactoring production code, e.g. renaming a variable. +* **style** for formatting changes, missing semicolons, etc. +* **test** for adding missing tests, refactoring tests; no production code change. +* **chore** for updating grunt tasks etc; no production code change. + +> Check `.pre-commit-config.yaml` and [pre-commit](https://pre-commit.com/) for more information about commit hooks. Some examples : -- `feat(auth): add AWS support. (#31)` = add a feature in authentication_bloc package, linked to the 31st issue. -- `docs: update readme.` = update **this** readme file. -- `fix(crud)!: fix bug in awesome() function. (#32)` = fix a bug, `!` is important and indicate `BREAKING CHANGES` linked with the 32nd issue. +* `feat(auth): add AWS support. (#31)` = add a feature in authentication_bloc package, linked to the 31st issue. +* `docs: update readme.` = update **this** readme file. +* `fix(crud)!: fix bug in awesome() function. (closes #32)` = fix a bug, `!` is important and indicate `BREAKING CHANGES` linked with the 32nd issue. -When you have finished developing, and are ready to close the issue, close it via your commit : - -`feat(auth): add AWS support. (close #31)` - -Note that your issue will be close after merging on master. -Before closing the issue, please check tests and update coverage. You might run : +When you have completed your development work and are ready to resolve the related issue, you can close it via your commit message by including (closes #issue_number). For example: ```shell -melos run test -melos run gen_coverage +feat(auth): add AWS support. (closes #31) ``` -#### Merge your work +> You can use `close` , `closes` , `closed` , `fix` , `fixes` , `fixed` , `resolve` , `resolves` or `resolved` . -After closing your issue, some work may have been done on master in the meantime. To keep a clean git history, please rebase before opening a change request. +#### Before pushing + +```shell +melos run test:all # this will run all tests in this project +melos run gen-coverage # this will generate coverage report +melos run gen-class-models # this will generate plantuml class diagrams +melos run quality-check # this will run all targets generally expected in CI +melos run publish:validate # this will run a validation before publish packages +# melos run publish:validate-local # same as above but without Drone env variables +melos run publish # this will publish packages +``` + +Please note that the issue will only be closed after it has been merged into the master branch. Before closing the issue, it is important to verify that all tests have been run and that coverage has been updated. + +### Merge your work + +When you have completed your work and closed the related issue, it's possible that some changes may have been made to the master branch in the meantime. To maintain a clean Git history, it's recommended to rebase before creating a change request (pull request). Two situations : -- You have not yet created your branch and have committed locally : +* You haven't created a branch yet and have made local commits: ```shell git pull --rebase ``` -- You are already working on your branch : +* You are already working on a branch: ```shell git rebase -i master ``` -If possible, please use `--fixup` on your commit in interactive rebase. +It's recommended to use the `--fixup` option during the interactive rebase to keep the Git history clean. -Then, opend your PR, get the necessary approval and merge your work. Then you're done ✅. +Once you have rebased, you can create a pull request, receive the necessary approvals, and then merge your work. And with that, you're done! 🎉 -#### Update version. +### Update version. -Once your work is on the master, you can update your package version. Please filter packages to update only your package. `--scope` is used to do it. -For example, after merging changes on `wyatt_otification_bloc` package, you might run : +When your work has been merged into the master branch, it's time to update the package version. To update only your specific package, use the --scope option. For example, after merging changes into the `wyatt_notification_bloc` package, you can run the following command: ```shell melos version --scope="*wyatt_notification_bloc*" ``` -In fact, melos will filter all packages that match the `wyatt_notification_block` pattern. +This will filter all packages that match the `wyatt_notification_bloc` pattern and update only that package. -You can update check all packages tests by running : +You can then verify that all packages and their tests are working correctly by running: ```shell -melos run test +melos run test:all ``` -#### Publish your package +### Publish your package -If package is ready for procution, publish it runnig : +If package is ready for production, publish it by running the following command : ```shell melos publish --scope"*package*" ``` -#### Badging +### Badging In the package `readme.md` file, please specify the supported SDK: ![SDK: Dart & Flutter](https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square) ```markdown + ![SDK: Dart & Flutter](https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square) + ``` or -![SDK: Dart](https://img.shields.io/badge/SDK-Dart-blue?style=flat-square) +![SDK: Flutter](https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square) ```markdown -![SDK: Dart](https://img.shields.io/badge/SDK-Dart-blue?style=flat-square) + +![SDK: Flutter](https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square) + ``` +> Some packages requires Flutter, so please specify it. + --- ## Usage @@ -249,24 +273,44 @@ You can add any package of the `packages/` sub directory in your project. ```yaml dependencies: wyatt_analysis: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_analysis-v2.0.0 - path: packages/wyatt_analysis + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ + version: ^2.4.1 ``` -Here you can change `package name` and `package version`. +> You can also use the `git` protocol. But it's not recommended since it's not handle version constraints. --- +## Simple work flow diagramm + +To sum up, here a simple work flow diagramm. + +```plantuml +@startuml Simple Developpment Workflow +start +:Create an issue; +:Create branch related to the issue; +repeat :Commit related to the issue; +repeat while (feature is done) +:Update coverage; +:Close issue via last commit; +:Rebase from `master`; +:Create pull request; +:Merge branches; +:Update version; +:Publish package; +stop +@enduml +``` + ## Status ![Status: Experimental](https://img.shields.io/badge/Status-WIP-red?style=flat-square) This repository is maintained by Wyatt Studio but work is in progress. -## Simple work flow diagramm +## License -To sum up, here a simple work flow diagramm. +[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) -![Dev Wokflow](doc/workflow.svg) +Thoses packages are licensed under the GNU General Public License v3.0. See the [LICENSE](LICENSE) file for details. diff --git a/doc/work_flow.puml b/doc/work_flow.puml deleted file mode 100644 index 5e6e983d..00000000 --- a/doc/work_flow.puml +++ /dev/null @@ -1,15 +0,0 @@ -@startuml Simple Developpment Workflow -start -:Create an issue; -:Create branch related to the issue; -repeat :Commit related to the issue; -repeat while (feature is done) -:Update coverage; -:Close issue via last commit; -:Rebase from `master`; -:Create pull request; -:Merge branches; -:Update version; -:Publish package; -stop -@enduml \ No newline at end of file diff --git a/doc/workflow.svg b/doc/workflow.svg deleted file mode 100644 index c8443191..00000000 --- a/doc/workflow.svg +++ /dev/null @@ -1,25 +0,0 @@ -Create an issueCreate branch related to the issueCommit related to the issuefeature is doneUpdate coverageClose issue via last commitRebase from `master`Create pull requestMerge branchesUpdate versionPublish package \ No newline at end of file diff --git a/mason-lock.json b/mason-lock.json index 229f2288..83cb506c 100644 --- a/mason-lock.json +++ b/mason-lock.json @@ -1 +1 @@ -{"bricks":{"wyatt_clean_code":{"git":{"url":"ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git","path":"bricks/wyatt_clean_code","ref":"033baa65408ec6b68e6a2ef43e64c24708ef16a1"}},"wyatt_feature_brick":{"git":{"url":"ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git","path":"bricks/wyatt_feature_brick","ref":"033baa65408ec6b68e6a2ef43e64c24708ef16a1"}},"wyatt_package":{"git":{"url":"ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git","path":"bricks/wyatt_package","ref":"033baa65408ec6b68e6a2ef43e64c24708ef16a1"}}}} \ No newline at end of file +{"bricks":{"wyatt_component_template":{"git":{"url":"ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git","path":"bricks/wyatt_component_template","ref":"7cea909470ce75b91840f479649b93f953ded596"}}}} \ No newline at end of file diff --git a/mason.yaml b/mason.yaml index c9c22317..4c3df4a0 100644 --- a/mason.yaml +++ b/mason.yaml @@ -1,13 +1,25 @@ +# Copyright (C) 2023 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 . + bricks: - wyatt_clean_code: + wyatt_package_template: git: - url: ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git - path: bricks/wyatt_clean_code - wyatt_feature_brick: + url: "ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git" + path: bricks/wyatt_package_template + wyatt_component_template: git: - url: ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git - path: bricks/wyatt_feature_brick - wyatt_package: - git: - url: ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git - path: bricks/wyatt_package \ No newline at end of file + url: "ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-bricks.git" + path: bricks/wyatt_component_template \ No newline at end of file diff --git a/melos.yaml b/melos.yaml index 5d814ff0..ddcd24ef 100644 --- a/melos.yaml +++ b/melos.yaml @@ -1,56 +1,106 @@ name: Wyatt-Packages -#repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages Gitea not yet supported +# repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages + +sdkPath: auto packages: - packages/** +ide: + intellij: + enabled: false + command: - bootstrap: - usePubspecOverrides: true - version: updateGitTagRefs: true linkToCommits: false # Gitea not yet supported workspaceChangelog: true + includeCommitId: false # Generate error in Melos 3... branch: master + message: | + chore(release): publish packages + + {new_package_versions} + + clean: + hooks: + post: melos exec --flutter --concurrency=3 -- "flutter clean" scripts: + analyze: + run: | + melos exec --flutter --concurrency=1 -- flutter analyze --fatal-infos + description: Run `flutter analyze` for all flutter packages. + + fix:apply: + run: melos exec --concurrency=1 -- dart fix . --apply + description: Run and apply `dart fix` for all packages. + + fix:check: + run: melos exec --concurrency=1 -- dart fix . --set-exit-if-changed + description: Run `dart fix` checks for all packages. + + format: + run: melos exec --concurrency=1 -- dart format . + description: Run `dart format` for all packages. + lint:all: run: melos run analyze && melos run format description: Run all static analysis checks. - analyze: - run: | - melos exec -c 10 -- \ - flutter analyze --fatal-infos - description: Run `flutter analyze` for all packages. - - format: - run: melos exec flutter format . --fix - description: Run `flutter format` for all packages. - - format-check: - run: melos exec flutter format . --set-exit-if-changed - description: Run `flutter format` checks for all packages. - clean:deep: run: git clean -x -d -f -q description: Clean things very deeply with `git clean`. test:selective_unit_test: - run: melos exec --dir-exists="test" -- flutter test --no-pub --coverage + run: melos exec --concurrency=1 -- flutter test --no-pub --coverage description: Run Flutter tests for a specific package in this project. - select-package: - flutter: true + packageFilters: + dirExists: + - test + ignore: + - "*example*" - test: + test:all: run: melos run test:selective_unit_test --no-select description: Run all Flutter tests in this project. - gen-coverage: melos exec -- sh "\$MELOS_ROOT_PATH/combine_coverage.sh" && genhtml coverage/lcov.info -o coverage/html + gen:coverage: + run: | + melos exec --concurrency=1 -- sh "\$MELOS_ROOT_PATH/combine_coverage.sh" && \ + genhtml coverage/lcov.info -o coverage/html + description: | + Generate coverage report for all packages. + Requires `lcov` and `genhtml`. - gen-class-models: melos exec --scope="*wyatt_*" -- dart pub global run dcdg -o models/class-models.puml - - # Additional cleanup lifecycle script, executed when `melos clean` is run. - postclean: > - melos exec -c 6 -- "flutter clean" \ No newline at end of file + gen:class_models: + run: melos exec --concurrency=1 -- dart pub global run dcdg -o models/class-models.puml + description: | + Generate class models for all packages. + Requires `dcdg`. (https://pub.dev/packages/dcdg) + packageFilters: + ignore: + - "*example*" + + quality-check: + run: | + melos clean && \ + melos bootstrap && \ + melos run test:all + description: Run all targets generally expected in CI for a full local quality check. + + publish:validate: + run: melos publish --diff="origin/$DRONE_COMMIT_BRANCH...HEAD" --yes + description: | + Validate that all packages are ready to be published. + Requires DRONE_COMMIT_BRANCH to be set. + Note: This will not actually publish anything. + + publish:validate-local: + run: melos publish --yes + description: | + Validate that all packages are ready to be published. + Note: This will not actually publish anything. + + # publish: + # run: melos publish --diff="origin/$DRONE_COMMIT_BRANCH...HEAD" --no-dry-run --yes diff --git a/packages/wyatt_analysis/.gitignore b/packages/wyatt_analysis/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_analysis/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_analysis/.gitignore b/packages/wyatt_analysis/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_analysis/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_analysis/.latest_version b/packages/wyatt_analysis/.latest_version new file mode 100644 index 00000000..437459cd --- /dev/null +++ b/packages/wyatt_analysis/.latest_version @@ -0,0 +1 @@ +2.5.0 diff --git a/packages/wyatt_analysis/.pubignore b/packages/wyatt_analysis/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_analysis/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_analysis/.vscode/extensions.json b/packages/wyatt_analysis/.vscode/extensions.json index 30cd2233..bc053a4b 100644 --- a/packages/wyatt_analysis/.vscode/extensions.json +++ b/packages/wyatt_analysis/.vscode/extensions.json @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 WYATT GROUP + * Copyright (C) 2023 WYATT GROUP * Please see the AUTHORS file for details. * * This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_analysis/AUTHORS b/packages/wyatt_analysis/AUTHORS deleted file mode 100644 index b6d7d765..00000000 --- a/packages/wyatt_analysis/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_analysis/AUTHORS b/packages/wyatt_analysis/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_analysis/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_analysis/CHANGELOG.md b/packages/wyatt_analysis/CHANGELOG.md index a3151d1f..b8a588f9 100644 --- a/packages/wyatt_analysis/CHANGELOG.md +++ b/packages/wyatt_analysis/CHANGELOG.md @@ -1,3 +1,33 @@ +## 2.5.0 + + - **FIX**(analysis): remove depencies sort. (4e3b288e) + - **FEAT**(analysis): update version. (0720a145) + - **FEAT**(analysis): upgrade. (2692c607) + +## 2.4.2 + + - **REFACTOR**: remove cross package export. + - **DOCS**: change some documentation. + +## 2.4.1 + + - **FEAT**: add latest version persistence between script executions. + - **FEAT**: ignore todo's. + +## 2.4.0 + + - **FEAT**: add new lint rules. + - **DOCS**: add instructions to create a new version (closes #104). + +## 2.3.0 + + - **REFACTOR**: follow melos versioning. + - **FIX**: change file include to keep coherence. + - **FEAT**: exclude generated code, and add dart>2.16 rules. + - **FEAT**: add overwrite protection. + - **FEAT**: add 2.2.2 files for archive. + - **FEAT**: add utils script to easely bump version. + ## 2.2.2 - **DOCS**: add publish_to self hosted pub server. diff --git a/packages/wyatt_analysis/LICENSE b/packages/wyatt_analysis/LICENSE deleted file mode 100644 index e72bfdda..00000000 --- a/packages/wyatt_analysis/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_analysis/LICENSE b/packages/wyatt_analysis/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_analysis/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_analysis/README.md b/packages/wyatt_analysis/README.md index b403cf66..4ff74056 100644 --- a/packages/wyatt_analysis/README.md +++ b/packages/wyatt_analysis/README.md @@ -1,5 +1,5 @@ -# Flutter - Wyatt Architecture +# Wyatt Architecture

- - - Style: Wyatt Analysis - - - SDK: Flutter + Style: Wyatt Analysis + SDK: Dart & Flutter

-The Wyatt Architecture for Flutter. +The Wyatt Architecture for Flutter. Contains useful classes to help you to create a clean architecture following the Wyatt Architecture. (core, data, domain, presentation). ## Features -- Usecase -- Repository -- DataSource -- Entity +* Usecase +* Repository +* DataSource +* Entity ## Usage @@ -79,7 +75,7 @@ And finaly create your different usecases : Several use cases are supported : -- Classic usecase : +* Classic usecase : ```dart class Test extends AsyncUseCase>> { @@ -109,7 +105,6 @@ class SearchPhotos extends AsyncUseCase>> { return photos; } - @override FutureOr onStart(QueryParameters? params) { if(params.start == null || params.limit == null){ @@ -120,9 +115,9 @@ class SearchPhotos extends AsyncUseCase>> { } ``` -You can implement error scenarios overriding `onError`, or check postconditions by overriding `onComplete` . +You can implement error scenarios overriding `onError` , or check postconditions by overriding `onComplete` . -- Stream usecase : +* Stream usecase : ```dart class SearchPhotos extends StreamUseCase>> { @@ -139,9 +134,9 @@ class SearchPhotos extends StreamUseCase>> { } ``` -On this case, observers allow you to add alternative scénarios when data changed, overriding `onData` or `onDone`. +On this case, observers allow you to add alternative scenarios when data changed, overriding `onData` or `onDone` . -Please note that to use handlers, call `call` method and not `execute`. +Please note that to use handlers, call `call` method and not `execute` . > In fact, here we need a new parameter object, so let's create it: @@ -156,7 +151,7 @@ class QueryParameters { ### Data -We start by creating models for photos and list of photos. You can use `freezed`. The `PhotoModel` extends `Photo` with some de/serializer capabilities. And those are used only in data layer. +We start by creating models for photos and list of photos. You can use `freezed` . The `PhotoModel` extends `Photo` with some de/serializer capabilities. And those are used only in data layer. Then implements your data sources: diff --git a/packages/wyatt_architecture/analysis_options.yaml b/packages/wyatt_architecture/analysis_options.yaml index 9f5b6860..53aca98a 100644 --- a/packages/wyatt_architecture/analysis_options.yaml +++ b/packages/wyatt_architecture/analysis_options.yaml @@ -1,21 +1,17 @@ -# Copyright (C) 2022 WYATT GROUP +# Copyright (C) 2023 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 . - -include: package:wyatt_analysis/analysis_options.flutter.yaml - -analyzer: - exclude: "!example/**" +include: package:wyatt_analysis/analysis_options.yaml diff --git a/packages/wyatt_architecture/example/ios/.gitignore b/packages/wyatt_architecture/example/ios/.gitignore deleted file mode 100644 index 7a7f9873..00000000 --- a/packages/wyatt_architecture/example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/wyatt_architecture/example/ios/Flutter/AppFrameworkInfo.plist b/packages/wyatt_architecture/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9625e105..00000000 --- a/packages/wyatt_architecture/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 11.0 - - diff --git a/packages/wyatt_architecture/example/ios/Runner.xcodeproj/project.pbxproj b/packages/wyatt_architecture/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 080f6a48..00000000 --- a/packages/wyatt_architecture/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,552 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 9D08BF82920EBA33F23464F5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E946B0F0AD8828F4A7866A40 /* Pods_Runner.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 06DDDDC67790BA3B67292B88 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 082A1BEB8CE5B02C4AABB40D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 0B7103FC187D9782DF68E292 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E946B0F0AD8828F4A7866A40 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9D08BF82920EBA33F23464F5 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2C514ED236D54DCA1D9DFFC4 /* Frameworks */ = { - isa = PBXGroup; - children = ( - E946B0F0AD8828F4A7866A40 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - AD70810057DA8269974A316F /* Pods */, - 2C514ED236D54DCA1D9DFFC4 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - AD70810057DA8269974A316F /* Pods */ = { - isa = PBXGroup; - children = ( - 0B7103FC187D9782DF68E292 /* Pods-Runner.debug.xcconfig */, - 082A1BEB8CE5B02C4AABB40D /* Pods-Runner.release.xcconfig */, - 06DDDDC67790BA3B67292B88 /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - FBD8EC5BAF7097A0A31AD63E /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 374960F8815E0EA685AB7576 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 374960F8815E0EA685AB7576 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - FBD8EC5BAF7097A0A31AD63E /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6Z5P8GG96U; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6Z5P8GG96U; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6Z5P8GG96U; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/wyatt_architecture/example/ios/Runner/AppDelegate.swift b/packages/wyatt_architecture/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada47..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cde1211..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index dcdc2306..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d3..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 6a84f41e..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f585..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/wyatt_architecture/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/wyatt_architecture/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/wyatt_architecture/example/ios/Runner/Base.lproj/Main.storyboard b/packages/wyatt_architecture/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/wyatt_architecture/example/ios/Runner/Info.plist b/packages/wyatt_architecture/example/ios/Runner/Info.plist deleted file mode 100644 index 7f553465..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Example - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/packages/wyatt_architecture/example/ios/Runner/Runner-Bridging-Header.h b/packages/wyatt_architecture/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/packages/wyatt_architecture/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/packages/wyatt_architecture/example/lib/core/dependency_injection/get_it.dart b/packages/wyatt_architecture/example/lib/core/dependency_injection/get_it.dart index e43a12a1..a3e2bc25 100644 --- a/packages/wyatt_architecture/example/lib/core/dependency_injection/get_it.dart +++ b/packages/wyatt_architecture/example/lib/core/dependency_injection/get_it.dart @@ -52,13 +52,13 @@ abstract class GetItInitializer { ) ..registerLazySingleton(() { final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( - protocol: Protocols.https, - authority: 'jsonplaceholder.typicode.com', - ), - ) - .addMiddleware(BodyToJsonMiddleware()); + ..addMiddleware( + const UriPrefixMiddleware( + protocol: Protocols.https, + authority: 'jsonplaceholder.typicode.com', + ), + ) + ..addMiddleware(const BodyToJsonMiddleware()); return MiddlewareClient(pipeline: pipeline); }) ..registerLazySingleton( diff --git a/packages/wyatt_architecture/example/lib/data/data_sources/remote/album_api_data_source_impl.dart b/packages/wyatt_architecture/example/lib/data/data_sources/remote/album_api_data_source_impl.dart index 435ee052..3c4cdcdf 100644 --- a/packages/wyatt_architecture/example/lib/data/data_sources/remote/album_api_data_source_impl.dart +++ b/packages/wyatt_architecture/example/lib/data/data_sources/remote/album_api_data_source_impl.dart @@ -24,9 +24,8 @@ import 'package:wyatt_http_client/wyatt_http_client.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class AlbumApiDataSourceImpl extends AlbumRemoteDataSource { - final MiddlewareClient _client; - AlbumApiDataSourceImpl(this._client); + final MiddlewareClient _client; @override Future getAlbum(int id) async { diff --git a/packages/wyatt_architecture/example/lib/data/data_sources/remote/photo_api_data_source_impl.dart b/packages/wyatt_architecture/example/lib/data/data_sources/remote/photo_api_data_source_impl.dart index 425ab652..3f559fe8 100644 --- a/packages/wyatt_architecture/example/lib/data/data_sources/remote/photo_api_data_source_impl.dart +++ b/packages/wyatt_architecture/example/lib/data/data_sources/remote/photo_api_data_source_impl.dart @@ -24,9 +24,8 @@ import 'package:wyatt_http_client/wyatt_http_client.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { - final MiddlewareClient _client; - PhotoApiDataSourceImpl(this._client); + final MiddlewareClient _client; @override Future getPhoto(int id) async { diff --git a/packages/wyatt_architecture/example/lib/data/models/list_photo_model.dart b/packages/wyatt_architecture/example/lib/data/models/list_photo_model.dart index 1112389a..38350986 100644 --- a/packages/wyatt_architecture/example/lib/data/models/list_photo_model.dart +++ b/packages/wyatt_architecture/example/lib/data/models/list_photo_model.dart @@ -15,7 +15,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - import 'package:architecture_example/data/models/photo_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/packages/wyatt_architecture/example/lib/data/repositories/photo_repository_impl.dart b/packages/wyatt_architecture/example/lib/data/repositories/photo_repository_impl.dart index 7cec10fa..274502f1 100644 --- a/packages/wyatt_architecture/example/lib/data/repositories/photo_repository_impl.dart +++ b/packages/wyatt_architecture/example/lib/data/repositories/photo_repository_impl.dart @@ -24,20 +24,19 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class PhotoRepositoryImpl extends PhotoRepository { - final PhotoRemoteDataSource _photoRemoteDataSource; - final AlbumRemoteDataSource _albumRemoteDataSource; - final FavoriteLocalDataSource _favoriteLocalDataSource; - PhotoRepositoryImpl( this._photoRemoteDataSource, this._albumRemoteDataSource, this._favoriteLocalDataSource, ); + final PhotoRemoteDataSource _photoRemoteDataSource; + final AlbumRemoteDataSource _albumRemoteDataSource; + final FavoriteLocalDataSource _favoriteLocalDataSource; @override FutureOrResult addPhotoToFavorites(Photo photo) => Result.tryCatchAsync( () => _favoriteLocalDataSource.addPhotoToFavorites(photo), - (error) => ClientException('Cannot add photo to favorites.'), + (error) => const ClientException('Cannot add photo to favorites.'), ); @override @@ -64,14 +63,14 @@ class PhotoRepositoryImpl extends PhotoRepository { FutureOrResult> getAllAlbums({int? start, int? limit}) => Result.tryCatchAsync( () => _albumRemoteDataSource.getAllAlbums(start: start, limit: limit), - (error) => ServerException('Cannot retrieve all albums.'), + (error) => const ServerException('Cannot retrieve all albums.'), ); @override FutureOrResult> getAllPhotos({int? start, int? limit}) async => Result.tryCatchAsync( () => _photoRemoteDataSource.getAllPhotos(start: start, limit: limit), - (error) => ServerException('Cannot retrieve all photos.'), + (error) => const ServerException('Cannot retrieve all photos.'), ); @override @@ -89,7 +88,7 @@ class PhotoRepositoryImpl extends PhotoRepository { } return Ok(response); } catch (_) { - return Err( + return const Err( ClientException('Cannot retrieve all photos from favorites.'), ); } diff --git a/packages/wyatt_architecture/example/lib/domain/data_sources/local/favorite_local_data_source.dart b/packages/wyatt_architecture/example/lib/domain/data_sources/local/favorite_local_data_source.dart index c9b06187..587a99ee 100644 --- a/packages/wyatt_architecture/example/lib/domain/data_sources/local/favorite_local_data_source.dart +++ b/packages/wyatt_architecture/example/lib/domain/data_sources/local/favorite_local_data_source.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/example/lib/domain/data_sources/remote/album_remote_data_source.dart b/packages/wyatt_architecture/example/lib/domain/data_sources/remote/album_remote_data_source.dart index 996f76b2..fbef7f9a 100644 --- a/packages/wyatt_architecture/example/lib/domain/data_sources/remote/album_remote_data_source.dart +++ b/packages/wyatt_architecture/example/lib/domain/data_sources/remote/album_remote_data_source.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/example/lib/domain/data_sources/remote/photo_remote_data_source.dart b/packages/wyatt_architecture/example/lib/domain/data_sources/remote/photo_remote_data_source.dart index 5b1d79a9..81d03a9a 100644 --- a/packages/wyatt_architecture/example/lib/domain/data_sources/remote/photo_remote_data_source.dart +++ b/packages/wyatt_architecture/example/lib/domain/data_sources/remote/photo_remote_data_source.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/add_photo_to_favorites.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/add_photo_to_favorites.dart index da2bbf17..ef8a0ec9 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/add_photo_to_favorites.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/add_photo_to_favorites.dart @@ -21,9 +21,8 @@ import 'package:architecture_example/domain/repositories/photo_repository.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; class AddPhotoToFavorites extends AsyncUseCase> { - final PhotoRepository _photoRepository; - AddPhotoToFavorites(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult> execute(Photo? params) async { @@ -34,7 +33,7 @@ class AddPhotoToFavorites extends AsyncUseCase> { @override FutureOr onStart(Photo? params) { if (params == null) { - throw ClientException('Photo cannot be null'); + throw const ClientException('Photo cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/check_if_photo_is_in_favorites.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/check_if_photo_is_in_favorites.dart index 9417f9fd..f0dcfa5c 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/check_if_photo_is_in_favorites.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/check_if_photo_is_in_favorites.dart @@ -20,9 +20,8 @@ import 'package:architecture_example/domain/repositories/photo_repository.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; class CheckIfPhotoIsInFavorites extends AsyncUseCase { - final PhotoRepository _photoRepository; - CheckIfPhotoIsInFavorites(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult execute(int? params) async => @@ -31,7 +30,7 @@ class CheckIfPhotoIsInFavorites extends AsyncUseCase { @override FutureOr onStart(int? params) { if (params == null) { - throw ClientException('id cannot be null'); + throw const ClientException('id cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_favorites.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_favorites.dart index f8c387cb..8bdf027f 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_favorites.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_favorites.dart @@ -19,9 +19,8 @@ import 'package:architecture_example/domain/repositories/photo_repository.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; class DisplayFavorites extends AsyncUseCase> { - final PhotoRepository _photoRepository; - DisplayFavorites(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult> execute(void params) { diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_photo.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_photo.dart index 6a9e84eb..79a06b8a 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_photo.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/display_photo.dart @@ -21,9 +21,8 @@ import 'package:architecture_example/domain/repositories/photo_repository.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; class DisplayPhoto extends AsyncUseCase { - final PhotoRepository _photoRepository; - DisplayPhoto(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult execute(int? params) { @@ -34,7 +33,7 @@ class DisplayPhoto extends AsyncUseCase { @override FutureOr onStart(int? params) { if (params == null) { - throw ClientException('id cannot be null'); + throw const ClientException('id cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/open_album.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/open_album.dart index beab95f8..358e86a2 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/open_album.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/open_album.dart @@ -22,9 +22,8 @@ import 'package:architecture_example/domain/usecases/photos/params/query_paramet import 'package:wyatt_architecture/wyatt_architecture.dart'; class OpenAlbum extends AsyncUseCase> { - final PhotoRepository _photoRepository; - OpenAlbum(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult> execute(QueryParameters? params) { @@ -40,7 +39,7 @@ class OpenAlbum extends AsyncUseCase> { @override FutureOr onStart(QueryParameters? params) { if (params == null) { - throw ClientException('params cannot be null'); + throw const ClientException('params cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/params/query_parameters.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/params/query_parameters.dart index e6fb7f30..4ac96e8e 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/params/query_parameters.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/params/query_parameters.dart @@ -15,9 +15,8 @@ // along with this program. If not, see . class QueryParameters { + QueryParameters(this.start, this.limit, {this.albumId = -1}); final int albumId; final int? start; final int? limit; - - QueryParameters(this.start, this.limit, {this.albumId = -1}); } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/remove_photo_from_favorites.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/remove_photo_from_favorites.dart index d2e5bbb1..e73206b3 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/remove_photo_from_favorites.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/remove_photo_from_favorites.dart @@ -21,9 +21,8 @@ import 'package:architecture_example/domain/repositories/photo_repository.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; class RemovePhotoFromFavorites extends AsyncUseCase> { - final PhotoRepository _photoRepository; - RemovePhotoFromFavorites(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult> execute(int? params) async { @@ -34,7 +33,7 @@ class RemovePhotoFromFavorites extends AsyncUseCase> { @override FutureOr onStart(int? params) { if (params == null) { - throw ClientException('id cannot be null'); + throw const ClientException('id cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/domain/usecases/photos/retrieve_all_albums.dart b/packages/wyatt_architecture/example/lib/domain/usecases/photos/retrieve_all_albums.dart index 548cdd53..e88f8a12 100644 --- a/packages/wyatt_architecture/example/lib/domain/usecases/photos/retrieve_all_albums.dart +++ b/packages/wyatt_architecture/example/lib/domain/usecases/photos/retrieve_all_albums.dart @@ -22,9 +22,8 @@ import 'package:architecture_example/domain/usecases/photos/params/query_paramet import 'package:wyatt_architecture/wyatt_architecture.dart'; class RetrieveAllAlbums extends AsyncUseCase> { - final PhotoRepository _photoRepository; - RetrieveAllAlbums(this._photoRepository); + final PhotoRepository _photoRepository; @override FutureOrResult> execute(QueryParameters? params) { @@ -38,7 +37,7 @@ class RetrieveAllAlbums extends AsyncUseCase> { @override FutureOr onStart(QueryParameters? params) { if (params == null) { - throw ClientException('params cannot be null'); + throw const ClientException('params cannot be null'); } } } diff --git a/packages/wyatt_architecture/example/lib/presentation/features/albums/blocs/album/album_bloc.dart b/packages/wyatt_architecture/example/lib/presentation/features/albums/blocs/album/album_bloc.dart index 9cb62860..896a06dd 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/albums/blocs/album/album_bloc.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/albums/blocs/album/album_bloc.dart @@ -33,14 +33,13 @@ EventTransformer throttleDroppable(Duration duration) => (events, mapper) => droppable().call(events.throttle(duration), mapper); class AlbumBloc extends Bloc { - final RetrieveAllAlbums _retrieveAllAlbums; - AlbumBloc(this._retrieveAllAlbums) : super(const AlbumState()) { on( _onAlbumFetched, transformer: throttleDroppable(throttleDuration), ); } + final RetrieveAllAlbums _retrieveAllAlbums; Future _onAlbumFetched( AlbumFetched event, diff --git a/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/albums_screen.dart b/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/albums_screen.dart index 2aae70fd..b180827e 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/albums_screen.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/albums_screen.dart @@ -35,7 +35,7 @@ class AlbumsScreen extends BlocScreen { bloc..add(AlbumFetched()); @override - Widget onWrap(BuildContext context, Widget child) => AlbumsWrapperWidget( + Widget parent(BuildContext context, Widget child) => AlbumsWrapperWidget( child: child, ); diff --git a/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/widgets/albums_list.dart b/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/widgets/albums_list.dart index 82af8ecd..5e2db9f6 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/widgets/albums_list.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/albums/state_management/widgets/albums_list.dart @@ -22,8 +22,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AlbumsList extends StatefulWidget { - const AlbumsList( - {required this.albums, required this.hasReachedMax, super.key,}); + const AlbumsList({ + required this.albums, + required this.hasReachedMax, + super.key, + }); final List albums; final bool hasReachedMax; diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photo_details/blocs/photo_details/photo_details_state.dart b/packages/wyatt_architecture/example/lib/presentation/features/photo_details/blocs/photo_details/photo_details_state.dart index 251c54d4..980678c0 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photo_details/blocs/photo_details/photo_details_state.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photo_details/blocs/photo_details/photo_details_state.dart @@ -26,19 +26,17 @@ abstract class PhotoDetailsState extends Equatable { class PhotoDetailsInitial extends PhotoDetailsState {} class PhotoDetailsSuccess extends PhotoDetailsState { + const PhotoDetailsSuccess(this.photo, {required this.isFavorite}); final Photo photo; final bool isFavorite; - const PhotoDetailsSuccess(this.photo, {required this.isFavorite}); - @override List get props => [photo, isFavorite]; } class PhotoDetailsFailure extends PhotoDetailsState { - final String error; - const PhotoDetailsFailure(this.error); + final String error; @override List get props => [error]; diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photo_details/state_management/photo_details_screen.dart b/packages/wyatt_architecture/example/lib/presentation/features/photo_details/state_management/photo_details_screen.dart index 4cbc2e83..98a41c54 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photo_details/state_management/photo_details_screen.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photo_details/state_management/photo_details_screen.dart @@ -43,7 +43,7 @@ class PhotoDetailsScreen bloc..load(photoId); @override - Widget onWrap(BuildContext context, Widget child) => + Widget parent(BuildContext context, Widget child) => PhotoDetailsWrapperWidget(child: child); @override diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_cubit.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_cubit.dart index 75b34d4a..7999f3a4 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_cubit.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_cubit.dart @@ -23,10 +23,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; part 'favorite_checker_state.dart'; class FavoriteCheckerCubit extends Cubit { - final CheckIfPhotoIsInFavorites _checkIfPhotoIsInFavorites; - FavoriteCheckerCubit(this._checkIfPhotoIsInFavorites) : super(FavoriteCheckerInitial()); + final CheckIfPhotoIsInFavorites _checkIfPhotoIsInFavorites; FutureOr checkIfPhotoIsInFavorites(int photoId) async { final response = await _checkIfPhotoIsInFavorites.call(photoId); diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_state.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_state.dart index 30f545c6..08a58826 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_state.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/favorite_checker/favorite_checker_state.dart @@ -10,19 +10,17 @@ abstract class FavoriteCheckerState extends Equatable { class FavoriteCheckerInitial extends FavoriteCheckerState {} class FavoriteCheckerSuccess extends FavoriteCheckerState { + const FavoriteCheckerSuccess(this.photoId, {required this.isFavorite}); final int photoId; final bool isFavorite; - const FavoriteCheckerSuccess(this.photoId, {required this.isFavorite}); - @override List get props => [photoId, isFavorite]; } class FavoriteCheckerFailure extends FavoriteCheckerState { - final String error; - const FavoriteCheckerFailure(this.error); + final String error; @override List get props => [error]; diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_bloc.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_bloc.dart index 9c76b8d8..a0893eca 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_bloc.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_bloc.dart @@ -33,14 +33,13 @@ EventTransformer throttleDroppable(Duration duration) => (events, mapper) => droppable().call(events.throttle(duration), mapper); class PhotoBloc extends Bloc { - final OpenAlbum _openAlbum; - PhotoBloc(this._openAlbum) : super(const PhotoState()) { on( _onPhotoFetched, transformer: throttleDroppable(throttleDuration), ); } + final OpenAlbum _openAlbum; Future _onPhotoFetched( PhotoFetched event, diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_event.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_event.dart index ea167d0d..7f52aa44 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_event.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/blocs/photo/photo_event.dart @@ -24,7 +24,6 @@ abstract class PhotoEvent extends Equatable { } class PhotoFetched extends PhotoEvent { - final int albumId; - const PhotoFetched(this.albumId); + final int albumId; } diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/photos_screen.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/photos_screen.dart index 57ceef4e..bf9352dd 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/photos_screen.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/photos_screen.dart @@ -37,7 +37,7 @@ class PhotosScreen extends BlocScreen { bloc..add(PhotoFetched(albumId)); @override - Widget onWrap(BuildContext context, Widget child) => PhotosWrapperWidget( + Widget parent(BuildContext context, Widget child) => PhotosWrapperWidget( child: child, ); diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid.dart index 80e6ad99..8f1d125a 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid.dart @@ -71,17 +71,17 @@ class _PhotosGridState extends State { @override Widget build(BuildContext context) => GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisSpacing: 4, - mainAxisSpacing: 4, - crossAxisCount: 4, - ), - itemCount: widget.hasReachedMax - ? widget.photos.length - : widget.photos.length + 1, - controller: _scrollController, - itemBuilder: (context, index) => index >= widget.photos.length - ? const BottomLoader() - : PhotosGridThumbnail(photo: widget.photos[index]), - ); + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisSpacing: 4, + mainAxisSpacing: 4, + crossAxisCount: 4, + ), + itemCount: widget.hasReachedMax + ? widget.photos.length + : widget.photos.length + 1, + controller: _scrollController, + itemBuilder: (context, index) => index >= widget.photos.length + ? const BottomLoader() + : PhotosGridThumbnail(photo: widget.photos[index]), + ); } diff --git a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid_thumbnail.dart b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid_thumbnail.dart index ab312ca2..021227ff 100644 --- a/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid_thumbnail.dart +++ b/packages/wyatt_architecture/example/lib/presentation/features/photos/state_management/widgets/photos_grid_thumbnail.dart @@ -55,7 +55,10 @@ class PhotosGridThumbnail ), if (state is FavoriteCheckerSuccess && state.isFavorite) ...[ const Positioned( - bottom: 10, right: 10, child: Icon(Icons.favorite),) + bottom: 10, + right: 10, + child: Icon(Icons.favorite), + ) ] ], ), diff --git a/packages/wyatt_architecture/example/pubspec.yaml b/packages/wyatt_architecture/example/pubspec.yaml index 902ed5d8..39c10464 100644 --- a/packages/wyatt_architecture/example/pubspec.yaml +++ b/packages/wyatt_architecture/example/pubspec.yaml @@ -27,48 +27,41 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: - flutter: - sdk: flutter + flutter: { sdk: flutter } - flutter_bloc: ^8.1.1 wyatt_architecture: path: "../" - wyatt_type_utils: - hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub - version: ^0.0.4 - - wyatt_http_client: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_http_client-v1.2.0 - path: packages/wyatt_http_client + flutter_bloc: ^8.1.1 get_it: ^7.2.0 hive: ^2.2.3 hive_flutter: ^1.1.0 - - wyatt_bloc_helper: - hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^2.0.0 equatable: ^2.0.5 stream_transform: ^2.1.0 bloc_concurrency: ^0.2.0 freezed_annotation: ^2.2.0 json_annotation: ^4.7.0 + wyatt_bloc_helper: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ + version: ^2.0.1 + wyatt_http_client: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ + version: ^2.0.0 + wyatt_type_utils: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.0.5 + dev_dependencies: build_runner: ^2.3.2 - flutter_test: - sdk: flutter - + flutter_test: { sdk: flutter } freezed: ^2.2.1 hive_generator: ^2.0.0 json_serializable: ^6.5.4 + wyatt_analysis: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_analysis-v2.2.2 - path: packages/wyatt_analysis + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ + version: ^2.5.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/packages/wyatt_architecture/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_architecture/lib/src/core/exceptions/exceptions.dart index 96a3bf8c..e1fa8e9a 100644 --- a/packages/wyatt_architecture/lib/src/core/exceptions/exceptions.dart +++ b/packages/wyatt_architecture/lib/src/core/exceptions/exceptions.dart @@ -16,10 +16,14 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +/// {@template app_exception} +/// [AppException] is a base class for all exceptions in the wyatt architecture. +/// {@endtemplate} abstract class AppException implements Exception { - final String? message; + /// {@macro app_exception} + const AppException([this.message]); - AppException([this.message]); + final String? message; @override String toString() { @@ -31,10 +35,20 @@ abstract class AppException implements Exception { } } +/// {@template client_exception} +/// [ClientException] is a base class for all client exceptions in the wyatt +/// architecture. +/// {@endtemplate} class ClientException extends AppException { - ClientException([super.message]); + /// {@macro client_exception} + const ClientException([super.message]); } +/// {@template server_exception} +/// [ServerException] is a base class for all server exceptions in the wyatt +/// architecture. +/// {@endtemplate} class ServerException extends AppException { - ServerException([super.message]); + /// {@macro server_exception} + const ServerException([super.message]); } diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/base_data_source.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/base_data_source.dart index f6a0688a..f5002603 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/base_data_source.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/base_data_source.dart @@ -1,19 +1,24 @@ // 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 . +/// {@template base_data_source} +/// [BaseDataSource] is a base class for all data sources in the wyatt +/// architecture. +/// {@endtemplate} abstract class BaseDataSource { + /// {@macro base_data_source} const BaseDataSource(); } diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/data_sources.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/data_sources.dart index c226b67b..17ffc5c8 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/data_sources.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/data_sources.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/local/base_local_data_source.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/local/base_local_data_source.dart index 820a5fd3..b091a13f 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/local/base_local_data_source.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/local/base_local_data_source.dart @@ -1,21 +1,26 @@ // 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:wyatt_architecture/src/domain/data_sources/base_data_source.dart'; +/// {@template base_local_data_source} +/// [BaseLocalDataSource] is a base class for all local data sources in the +/// wyatt architecture. +/// {@endtemplate} abstract class BaseLocalDataSource extends BaseDataSource { + /// {@macro base_local_data_source} const BaseLocalDataSource(); } diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/local/local.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/local/local.dart index 08fce718..e45c6a57 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/local/local.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/local/local.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/remote/base_remote_data_source.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/remote/base_remote_data_source.dart index 08e10d36..8ed880c4 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/remote/base_remote_data_source.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/remote/base_remote_data_source.dart @@ -1,21 +1,26 @@ // 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:wyatt_architecture/src/domain/data_sources/base_data_source.dart'; +/// {@template base_remote_data_source} +/// [BaseRemoteDataSource] is a base class for all remote data sources in the +/// wyatt architecture. +/// {@endtemplate} abstract class BaseRemoteDataSource extends BaseDataSource { + /// {@macro base_remote_data_source} const BaseRemoteDataSource(); } diff --git a/packages/wyatt_architecture/lib/src/domain/data_sources/remote/remote.dart b/packages/wyatt_architecture/lib/src/domain/data_sources/remote/remote.dart index 81d8f125..7403e595 100644 --- a/packages/wyatt_architecture/lib/src/domain/data_sources/remote/remote.dart +++ b/packages/wyatt_architecture/lib/src/domain/data_sources/remote/remote.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/src/domain/entities/entities.dart b/packages/wyatt_architecture/lib/src/domain/entities/entities.dart index 47ef61fa..937b195e 100644 --- a/packages/wyatt_architecture/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_architecture/lib/src/domain/entities/entities.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/src/domain/entities/entity.dart b/packages/wyatt_architecture/lib/src/domain/entities/entity.dart index 67df1106..41a8ca17 100644 --- a/packages/wyatt_architecture/lib/src/domain/entities/entity.dart +++ b/packages/wyatt_architecture/lib/src/domain/entities/entity.dart @@ -1,19 +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 . +/// {@template entity} +/// [Entity] is a base class for all entities in the domain layer. +/// {@endtemplate} abstract class Entity { + /// {@macro entity} const Entity(); } diff --git a/packages/wyatt_architecture/lib/src/domain/repositories/base_repository.dart b/packages/wyatt_architecture/lib/src/domain/repositories/base_repository.dart index 4a08a0db..a7e26b12 100644 --- a/packages/wyatt_architecture/lib/src/domain/repositories/base_repository.dart +++ b/packages/wyatt_architecture/lib/src/domain/repositories/base_repository.dart @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// {@template base_repository} +/// [BaseRepository] is a base class for all repositories in the domain layer. +/// {@endtemplate} abstract class BaseRepository { + /// {@macro base_repository} const BaseRepository(); } diff --git a/packages/wyatt_architecture/lib/src/domain/repositories/repositories.dart b/packages/wyatt_architecture/lib/src/domain/repositories/repositories.dart index bc97c14e..bac1ea4c 100644 --- a/packages/wyatt_architecture/lib/src/domain/repositories/repositories.dart +++ b/packages/wyatt_architecture/lib/src/domain/repositories/repositories.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/src/domain/usecases/no_param.dart b/packages/wyatt_architecture/lib/src/domain/usecases/no_param.dart index 7452af67..4509bd59 100644 --- a/packages/wyatt_architecture/lib/src/domain/usecases/no_param.dart +++ b/packages/wyatt_architecture/lib/src/domain/usecases/no_param.dart @@ -16,6 +16,11 @@ import 'package:wyatt_architecture/src/domain/entities/entity.dart'; +/// {@template no_param} +/// [NoParam] is a class that is used when a use case does not require any +/// parameters. +/// {@endtemplate} class NoParam extends Entity { + /// {@macro no_param} const NoParam(); } diff --git a/packages/wyatt_architecture/lib/src/domain/usecases/observers.dart b/packages/wyatt_architecture/lib/src/domain/usecases/observers.dart index 370546fe..a1925577 100644 --- a/packages/wyatt_architecture/lib/src/domain/usecases/observers.dart +++ b/packages/wyatt_architecture/lib/src/domain/usecases/observers.dart @@ -21,16 +21,17 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; /// Usecase observers mixin Observer { /// Called before usecase is runned. - /// Usefull to check the preconditions + /// Useful to check the preconditions FutureOr onStart(Parameters? params) {} /// Called when error occures during main scenario - /// Usefull to run alternative scenario + /// Useful to run alternative scenario FutureOr onError(AppException? error) {} } /// Specific observer for classic usecase mixin AsyncObserver { + /// Called when usecase is completed FutureOr onComplete(ReturnType? data) {} } @@ -39,6 +40,6 @@ mixin StreamObserver { /// Replaces the data event handler of this subscription. void onDone() {} - /// Replaces the done event handler of this subscription. + /// Replaces the done event handler of this subscription. void onData(ReturnType? data) {} } diff --git a/packages/wyatt_architecture/lib/src/domain/usecases/usecase.dart b/packages/wyatt_architecture/lib/src/domain/usecases/usecase.dart index c406535d..75c4c905 100644 --- a/packages/wyatt_architecture/lib/src/domain/usecases/usecase.dart +++ b/packages/wyatt_architecture/lib/src/domain/usecases/usecase.dart @@ -23,8 +23,13 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; typedef FutureOrResult = FutureOr>; typedef StreamResult = Stream>; -/// Abstract class of a use case +/// {@template base_usecase} +/// Abstract class of any use case. +/// {@endtemplate} abstract class BaseUseCase { + /// {@macro base_usecase} + const BaseUseCase(); + /// Run use case scenarios ReturnType call(Parameters parameters); @@ -33,11 +38,16 @@ abstract class BaseUseCase { ReturnType execute(Parameters params); } +/// {@template usecase} /// Abstract class of a use case that deals specifically /// with the response and its state. +/// {@endtemplate} abstract class UseCase extends BaseUseCase> with Observer { + /// {@macro usecase} + const UseCase(); + FutureOr _onSuccess(ReturnType data); /// Supports the result of the main scenario and integrates @@ -59,17 +69,27 @@ abstract class UseCase } } -/// Abtstract classic usecase. +/// {@template async_usecase} +/// Abtstract classic usecase bases on futures +/// {@endtemplate} abstract class AsyncUseCase extends UseCase with AsyncObserver { + /// {@macro async_usecase} + const AsyncUseCase(); + @override FutureOr _onSuccess(ReturnType data) => onComplete(data); } +/// {@template stream_usecase} /// Abstract specific usecase bases on streams +/// {@endtemplate} abstract class StreamUseCase extends UseCase> with StreamObserver { + /// {@macro stream_usecase} + const StreamUseCase(); + @override FutureOr _onSuccess(Stream data) { data.listen( diff --git a/packages/wyatt_architecture/lib/src/src.dart b/packages/wyatt_architecture/lib/src/src.dart index 50ef204e..2a39a026 100644 --- a/packages/wyatt_architecture/lib/src/src.dart +++ b/packages/wyatt_architecture/lib/src/src.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_architecture/lib/wyatt_architecture.dart b/packages/wyatt_architecture/lib/wyatt_architecture.dart index 54c20e0d..f07613aa 100644 --- a/packages/wyatt_architecture/lib/wyatt_architecture.dart +++ b/packages/wyatt_architecture/lib/wyatt_architecture.dart @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -/// Architecture +/// Wyatt Architecture for Flutter library wyatt_architecture; export 'src/src.dart'; diff --git a/packages/wyatt_architecture/pubspec.yaml b/packages/wyatt_architecture/pubspec.yaml index e0711e40..eefe4408 100644 --- a/packages/wyatt_architecture/pubspec.yaml +++ b/packages/wyatt_architecture/pubspec.yaml @@ -1,27 +1,35 @@ +# Copyright (C) 2023 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 . + name: wyatt_architecture -description: A new Wyatt package +description: Wyatt Architecture contains useful classes to help you to create a clean architecture following the Wyatt Architecture principles. repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_architecture -version: 0.1.0+1 +version: 0.2.0 publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub environment: - sdk: '>=2.17.0 <3.0.0' + sdk: ">=2.17.0 <3.0.0" dependencies: - - flutter: - sdk: flutter - wyatt_type_utils: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub - version: ^0.0.4 + version: ^0.0.5 dev_dependencies: - - flutter_test: - sdk: flutter - wyatt_analysis: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub - version: ^2.2.2 \ No newline at end of file + version: ^2.5.0 diff --git a/packages/wyatt_authentication_bloc/.gitignore b/packages/wyatt_authentication_bloc/.gitignore deleted file mode 100644 index 23d156c3..00000000 --- a/packages/wyatt_authentication_bloc/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# 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 -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ -.flutter-plugins* -coverage/ \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/.gitignore b/packages/wyatt_authentication_bloc/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_authentication_bloc/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/.pubignore b/packages/wyatt_authentication_bloc/.pubignore deleted file mode 100644 index 11610c5a..00000000 --- a/packages/wyatt_authentication_bloc/.pubignore +++ /dev/null @@ -1,2 +0,0 @@ -firebase_options.dart -.vscode \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/.pubignore b/packages/wyatt_authentication_bloc/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_authentication_bloc/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/AUTHORS b/packages/wyatt_authentication_bloc/AUTHORS deleted file mode 100644 index b6d7d765..00000000 --- a/packages/wyatt_authentication_bloc/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/AUTHORS b/packages/wyatt_authentication_bloc/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_authentication_bloc/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/CHANGELOG.md b/packages/wyatt_authentication_bloc/CHANGELOG.md index 934f9b7f..d86391e5 100644 --- a/packages/wyatt_authentication_bloc/CHANGELOG.md +++ b/packages/wyatt_authentication_bloc/CHANGELOG.md @@ -1,3 +1,45 @@ +## 0.5.0+1 + + - **REFACTOR**(authentication): controle cache checking. + +## 0.5.0 + +> Note: This release has breaking changes. + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: remove cross package export. + - **REFACTOR**: use custom user changes stream. + - **REFACTOR**: make signup/in, passwordreset cubit extendable. + - **FIX**: make sur access token is available on every steps. + - **FIX**: anonymous sign in event. + - **FIX**: initialize account stream transformer. + - **FIX**: stream on null account. + - **FIX**: handle empty provider list (closes #113). + - **FEAT**: add mock + local storage. + - **FEAT**: remove session wrapper for AuthenticationSession. + - **FEAT**: add account edit cubit. + - **FEAT**: add custom routine, and documentation. + - **FEAT**: add full event support. + - **DOCS**: update example with multiple data sources. + - **DOCS**: add full dartdoc. + - **DOCS**: add wiki script. + - **DOCS**: update example. + - **DOCS**: update example. + - **BREAKING** **REFACTOR**: split data sources (cache, session, external). + - **BREAKING** **REFACTOR**: use mixins, and remove use of onSignUpSuccess. + - **BREAKING** **FEAT**: add event type on auth change. + +## 0.4.1 + + - **REFACTOR**: use fromFirebaseUser factory to parse user. + - **REFACTOR**: update deps and re-export them. + - **FIX**: fix mock on register. + - **FEAT**: add google sign in in signIn cubit. + - **FEAT**: add google sign in parameter in firebase data source constructor. + - **FEAT**: add google sign_in support (closes #59). + - **FEAT**: add reauthenticate, updateEmail and updatePassword. + - **DOCS**: add correct header. + ## 0.4.0+3 - Update a dependency to the latest release. diff --git a/packages/wyatt_authentication_bloc/LICENSE b/packages/wyatt_authentication_bloc/LICENSE deleted file mode 100644 index e72bfdda..00000000 --- a/packages/wyatt_authentication_bloc/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/LICENSE b/packages/wyatt_authentication_bloc/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_authentication_bloc/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/README.md b/packages/wyatt_authentication_bloc/README.md index 755c77e0..9d58adfb 100644 --- a/packages/wyatt_authentication_bloc/README.md +++ b/packages/wyatt_authentication_bloc/README.md @@ -1,5 +1,5 @@ -# Flutter - Authentication BLoC +# Authentication BLoC

- - Style: Wyatt Analysis - + Style: Wyatt Analysis SDK: Flutter

@@ -29,37 +27,195 @@ Authentication Bloc for Flutter. ## Features -- Wyatt Architecture -- Entities: - - Account : AccountModel -> Contains account information from provider - - AccountWrapper : AccountWrapperModel -> Contains account and extra data. -- Data Sources: - - Local: - - Cached Authentication Data : AuthenticationCacheDataSourceImpl -> Provides a cache implementation - - Remote: - - Remote Authentication Data : AuthenticationFirebaseDataSourceImpl -> Provides a proxy to FirebaseAuth -- Repositories: - - AuthenticationRepository : AuthenticationRepositoryImpl -> Provides all authentication methods -- Features: - - Authentication: - - AuthenticationBuilder : widget to build reactive view from authentication state - - AuthenticationCubit : tracks every auth changes, have sign out capability. - - SignUp: - - SignUpCubit: implementation of a FormDataCubit from `wyatt_form_bloc` for the sign up - - SignIn: - - SignUpCubit: implementation of a FormDataCubit from `wyatt_form_bloc` for the sign in -- Consistent - * Every class have same naming convention -- Tested +* 🧐 Wyatt Architecture +* 🧱 Entities + - Account -> Contains account information from provider. + - Session -> Contains account and associated data retrieved from an external source. + - AuthenticationChangeEvent -> Describes an event in authentication change (sign in, sign up, sign out, etc...) + - SessionWrapper -> Contains latest authentication change event and session. +* 🔑 Powerful and secured authentication repository +* 🔥 Multiple data sources + - Mock + - Firebase +* 🧊 Cubits, why make it complicated when you can make it simple? + - Goes to the essential. +* 📐 Consistent + - Every class have same naming convention +* 🧪 Tested +* 📚 Documented: [available here](./doc/api/index.md) ## Getting started -Simply add `wyatt_authentication_bloc` in `pubspec.yaml`, then +Simply add `wyatt_authentication_bloc` in `pubspec.yaml` , then ```dart import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; ``` -## Usage +### Data source -// TODO \ No newline at end of file +The first step is to provide a data source. + +```dart +getIt.registerLazySingleton>( + () => AuthenticationFirebaseDataSourceImpl( + firebaseAuth: FirebaseAuth.instance, + googleSignIn: + GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)), +); +``` + +> Here we use GetIt (see example project) + +### Repository + +Then you can configure your repository. + +```dart +final AuthenticationRepository authenticationRepository = AuthenticationRepositoryImpl( + authenticationRemoteDataSource: + getIt>(), + customPasswordValidator: const CustomPassword.pure(), + extraSignUpInputs: [ + FormInput( + AuthFormField.confirmPassword, + const ConfirmedPassword.pure(), + metadata: const FormInputMetadata(export: false), + ), + ], +); +``` + +> Here we pass some extra inputs for the sign up, and a custom password validator. + +### Cubits + +It is necessary to implement each cubit. Don't panic, most of the work is already done 😊 you just have to customize the logic of these. + +In each of these cubits it is necessary to overload the various callbacks. + +> Here the associated data `Data` is a `int` + +#### Authentication + +In the authentication are managed, the refresh, the deletion of account or the disconnection. + +```dart +class ExampleAuthenticationCubit extends AuthenticationCubit { + ExampleAuthenticationCubit({required super.authenticationRepository}); + + @override + FutureOrResult onReauthenticate(Result result) async { + // TODO + } + + @override + FutureOrResult onRefresh(Result result) { + // TODO + } + + @override + FutureOrResult onSignInFromCache(SessionWrapper wrapper) { + // TODO + } + + @override + FutureOrResult onSignOut() { + // TODO + } + + @override + FutureOrResult onDelete() { + // TODO + } +} +``` + +#### Sign Up + +```dart +class ExampleSignUpCubit extends SignUpCubit { + ExampleSignUpCubit({ + required super.authenticationRepository, + }); + + @override + FutureOrResult onSignUpWithEmailAndPassword(Result result, WyattForm form) async { + // TODO + } +} + +``` + +#### Sign In + +```dart +class ExampleSignInCubit extends SignInCubit { + ExampleSignInCubit({ + required super.authenticationRepository, + }); + + @override + FutureOrResult onSignInWithEmailAndPassword(Result result, WyattForm form) { + // TODO + } + + @override + FutureOrResult onSignInAnonymously(Result result, WyattForm form) { + // TODO + } + + @override + FutureOrResult onSignInWithGoogle(Result result, WyattForm form) { + // TODO + } +} +``` + +After setting up all these cubits you can provide them in the application. And that's it! + +```dart +BlocProvider>( + create: (_) => ExampleSignUpCubit( + authenticationRepository: authenticationRepository, + ), +), +BlocProvider>( + create: (_) => ExampleSignInCubit( + authenticationRepository: authenticationRepository, + ), +), +``` + +### Widgets + +Widgets are provided to make your life easier. Starting with the `AuthenticationBuilder` which allows you to build according to the authentication state. + +```dart +AuthenticationBuilder( + authenticated: (context, sessionWrapper) => Text( + 'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'), + unauthenticated: (context) => + const Text('Not logged (unauthenticated)'), + unknown: (context) => const Text('Not logged (unknown)'), +), +``` + +A `BuildContext` extension is also available to access certain attributes more quickly. + +```dart +Text('Home | ${context.account, int>()?.email}'), +``` + +Listeners are used to listen to the status of the sign in and sign up forms. + +```dart +return SignInListener( + onError: (context, status, errorMessage) => ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar( + SnackBar(content: Text(errorMessage ?? 'Sign In Failure')), + ), + child: ... +); +``` diff --git a/packages/wyatt_authentication_bloc/analysis_options.yaml b/packages/wyatt_authentication_bloc/analysis_options.yaml index b0c6aced..82177cd5 100644 --- a/packages/wyatt_authentication_bloc/analysis_options.yaml +++ b/packages/wyatt_authentication_bloc/analysis_options.yaml @@ -1,4 +1 @@ -include: package:wyatt_analysis/analysis_options.flutter.yaml - -analyzer: - exclude: "!example/**" \ No newline at end of file +include: package:wyatt_analysis/analysis_options.flutter.yaml \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/docs.sh b/packages/wyatt_authentication_bloc/docs.sh new file mode 100755 index 00000000..1b8931fc --- /dev/null +++ b/packages/wyatt_authentication_bloc/docs.sh @@ -0,0 +1,17 @@ +sed -i -e "s/export 'package:firebase_auth\/firebase_auth.dart';/\/\/export 'package:firebase_auth\/firebase_auth.dart';/g" lib/wyatt_authentication_bloc.dart +sed -i -e "s/export 'package:google_sign_in\/google_sign_in.dart';/\/\/export 'package:google_sign_in\/google_sign_in.dart';/g" lib/wyatt_authentication_bloc.dart + +dart pub global activate dartdoc +dart pub global run dartdoc --format md \ + --exclude package:firebase_auth,package:google_sign_in, \ + dart:async,dart:collection,dart:convert,dart:core,dart:developer, \ + dart:io,dart:isolate,dart:math,dart:typed_data,dart:ui,dart:ffi, \ + dart:html,dart:js,dart:js_util \ + --no-auto-include-dependencies \ + --no-validate-links \ + --show-progress \ + +sed -i -e "s/\/\/export 'package:firebase_auth\/firebase_auth.dart';/export 'package:firebase_auth\/firebase_auth.dart';/g" lib/wyatt_authentication_bloc.dart +sed -i -e "s/\/\/export 'package:google_sign_in\/google_sign_in.dart';/export 'package:google_sign_in\/google_sign_in.dart';/g" lib/wyatt_authentication_bloc.dart + +rm lib/wyatt_authentication_bloc.dart-e \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/example/.gitignore b/packages/wyatt_authentication_bloc/example/.gitignore index f0edd542..6df3a32a 100644 --- a/packages/wyatt_authentication_bloc/example/.gitignore +++ b/packages/wyatt_authentication_bloc/example/.gitignore @@ -22,7 +22,6 @@ migrate_working_dir/ #.vscode/ # Flutter/Dart/Pub related -**/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins @@ -44,6 +43,4 @@ app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile -/android/app/release - -firebase_options.dart \ No newline at end of file +/android/app/release \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/example/.vscode/launch.json b/packages/wyatt_authentication_bloc/example/.vscode/launch.json index 61fa495d..11233cfe 100644 --- a/packages/wyatt_authentication_bloc/example/.vscode/launch.json +++ b/packages/wyatt_authentication_bloc/example/.vscode/launch.json @@ -4,7 +4,7 @@ * ----- * File: launch.json * Created Date: 19/08/2022 15:12:25 - * Last Modified: 19/08/2022 15:22:02 + * Last Modified: Tue Dec 13 2022 * ----- * Copyright (c) 2022 */ @@ -15,11 +15,18 @@ "version": "0.2.0", "configurations": [ { - "name": "example_router", + "name": "Mock", "request": "launch", "type": "dart", "program": "lib/main.dart", "flutterMode": "debug" + }, + { + "name": "Firebase", + "request": "launch", + "type": "dart", + "program": "lib/main_firebase.dart", + "flutterMode": "debug" } ] } \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/example/README.md b/packages/wyatt_authentication_bloc/example/README.md index 139e82ee..df389404 100644 --- a/packages/wyatt_authentication_bloc/example/README.md +++ b/packages/wyatt_authentication_bloc/example/README.md @@ -1,16 +1,6 @@ # 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. +```sh +firebase emulators:start --only auth +flutter run --target lib/main_development.dart --dart-define="dev_mode=emulator" +``` diff --git a/packages/wyatt_authentication_bloc/example/firebase.json b/packages/wyatt_authentication_bloc/example/firebase.json new file mode 100644 index 00000000..c8738c2c --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/firebase.json @@ -0,0 +1,14 @@ +{ + "emulators": { + "auth": { + "port": 9099 + }, + "firestore": { + "port": 8080 + }, + "ui": { + "enabled": true + }, + "singleProjectMode": true + } +} diff --git a/packages/wyatt_authentication_bloc/example/ios/Podfile.lock b/packages/wyatt_authentication_bloc/example/ios/Podfile.lock index 1a4d1789..4e5cbe34 100644 --- a/packages/wyatt_authentication_bloc/example/ios/Podfile.lock +++ b/packages/wyatt_authentication_bloc/example/ios/Podfile.lock @@ -5,40 +5,31 @@ PODS: - AppAuth/Core (1.6.0) - AppAuth/ExternalUserAgent (1.6.0): - AppAuth/Core - - FBAEMKit (14.1.0): - - FBSDKCoreKit_Basics (= 14.1.0) - - FBSDKCoreKit (14.1.0): - - FBAEMKit (= 14.1.0) - - FBSDKCoreKit_Basics (= 14.1.0) - - FBSDKCoreKit_Basics (14.1.0) - - FBSDKLoginKit (14.1.0): - - FBSDKCoreKit (= 14.1.0) - - Firebase/Auth (10.0.0): + - Firebase/Auth (10.3.0): - Firebase/CoreOnly - - FirebaseAuth (~> 10.0.0) - - Firebase/CoreOnly (10.0.0): - - FirebaseCore (= 10.0.0) - - firebase_auth (4.1.1): - - Firebase/Auth (= 10.0.0) + - FirebaseAuth (~> 10.3.0) + - Firebase/CoreOnly (10.3.0): + - FirebaseCore (= 10.3.0) + - firebase_auth (4.2.9): + - Firebase/Auth (= 10.3.0) - firebase_core - Flutter - - firebase_core (2.1.1): - - Firebase/CoreOnly (= 10.0.0) + - firebase_core (2.7.0): + - Firebase/CoreOnly (= 10.3.0) - Flutter - - FirebaseAuth (10.0.0): + - FirebaseAuth (10.3.0): - FirebaseCore (~> 10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - GoogleUtilities/Environment (~> 7.8) - - GTMSessionFetcher/Core (~> 2.1) - - FirebaseCore (10.0.0): + - GTMSessionFetcher/Core (< 4.0, >= 2.1) + - FirebaseCore (10.3.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreInternal (10.1.0): + - FirebaseCoreInternal (10.3.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - Flutter (1.0.0) - - flutter_facebook_auth (4.4.1): - - FBSDKLoginKit (= 14.1.0) + - flutter_secure_storage (6.0.0): - Flutter - google_sign_in_ios (0.0.1): - Flutter @@ -47,47 +38,37 @@ PODS: - AppAuth (~> 1.5) - GTMAppAuth (~> 1.3) - GTMSessionFetcher/Core (< 3.0, >= 1.1) - - GoogleUtilities/AppDelegateSwizzler (7.8.0): + - GoogleUtilities/AppDelegateSwizzler (7.10.0): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.8.0): + - GoogleUtilities/Environment (7.10.0): - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.8.0): + - GoogleUtilities/Logger (7.10.0): - GoogleUtilities/Environment - - GoogleUtilities/Network (7.8.0): + - GoogleUtilities/Network (7.10.0): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.8.0)" - - GoogleUtilities/Reachability (7.8.0): + - "GoogleUtilities/NSData+zlib (7.10.0)" + - GoogleUtilities/Reachability (7.10.0): - GoogleUtilities/Logger - GTMAppAuth (1.3.1): - AppAuth/Core (~> 1.6) - GTMSessionFetcher/Core (< 3.0, >= 1.5) - - GTMSessionFetcher/Core (2.1.0) + - GTMSessionFetcher/Core (2.3.0) - PromisesObjC (2.1.1) - - sign_in_with_apple (0.0.1): - - Flutter - - twitter_login (0.0.1): - - Flutter DEPENDENCIES: - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - - flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/ios`) - - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`) - - twitter_login (from `.symlinks/plugins/twitter_login/ios`) SPEC REPOS: trunk: - AppAuth - - FBAEMKit - - FBSDKCoreKit - - FBSDKCoreKit_Basics - - FBSDKLoginKit - Firebase - FirebaseAuth - FirebaseCore @@ -105,37 +86,27 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter - flutter_facebook_auth: - :path: ".symlinks/plugins/flutter_facebook_auth/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" google_sign_in_ios: :path: ".symlinks/plugins/google_sign_in_ios/ios" - sign_in_with_apple: - :path: ".symlinks/plugins/sign_in_with_apple/ios" - twitter_login: - :path: ".symlinks/plugins/twitter_login/ios" SPEC CHECKSUMS: AppAuth: 8fca6b5563a5baef2c04bee27538025e4ceb2add - FBAEMKit: a899515e45476027f73aef377b5cffadcd56ca3a - FBSDKCoreKit: 24f8bc8d3b5b2a8c5c656a1329492a12e8efa792 - FBSDKCoreKit_Basics: 6e578c9bdc7aa1365dbbbde633c9ebb536bcaa98 - FBSDKLoginKit: 787de205d524c3a4b17d527916f1d066e4361660 - Firebase: 1b810f3d0c0532e27a48f1961f8c0400a668a2cf - firebase_auth: dd33e93fce72a1c72040f7380dacf06e89db5705 - firebase_core: 5c0bb0ca7d0e70480a68a6e9ad9bf55d1edd5305 - FirebaseAuth: 493382cf533cc45e2862b00e9aa4cfe4c98daf71 - FirebaseCore: 97f48a3a567a72b8d4daa0f03c3aadb78df4e995 - FirebaseCoreInternal: 96d75228e10fd369564da51bd898414eb0f54df5 + Firebase: f92fc551ead69c94168d36c2b26188263860acd9 + firebase_auth: 4e8c693e848ed13b263de2d702d55fa82ed04a79 + firebase_core: 128d8c43c3a453a4a67463314fc3761bedff860b + FirebaseAuth: 0e415d29d846c1dce2fb641e46f35e9888d9bec6 + FirebaseCore: 988754646ab3bd4bdcb740f1bfe26b9f6c0d5f2a + FirebaseCoreInternal: 29b76f784d607df8b2a1259d73c3f04f1210137b Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_facebook_auth: 361ac7a57263ebf327f26089507ead0d66558ee8 - google_sign_in_ios: 4f85eb9f937450765c8573bb85fd8cd6a5af675c + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be + google_sign_in_ios: 1256ff9d941db546373826966720b0c24804bcdd GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a - GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7 + GoogleUtilities: bad72cb363809015b1f7f19beb1f1cd23c589f95 GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd - GTMSessionFetcher: ffbb25ec00ebcb5201adab0a56d808f6f1902d9f + GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb - sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440 - twitter_login: 2794db69b7640681171b17b3c2c84ad9dfb4a57f PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 diff --git a/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj b/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj index 11d0d0ad..eda3ed8b 100644 --- a/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,12 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 44F5B6790A35D9BA26574F6B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F6E17622FCECE9BFC2543397 /* GoogleService-Info.plist */; }; 69F3BBCD5DEB05A456F6B74F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0A061B2E527F311149C3581 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -46,6 +47,7 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B0A061B2E527F311149C3581 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F0D7945BAE0BEA457137ED73 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F6E17622FCECE9BFC2543397 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; F9340E3A859C31E59380BD0F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -91,6 +93,7 @@ 97C146EF1CF9000F007C117D /* Products */, 66B357379C2757D2844F12BB /* Pods */, BC1E25CE0DADDF7B7201CCF8 /* Frameworks */, + F6E17622FCECE9BFC2543397 /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -192,6 +195,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + 44F5B6790A35D9BA26574F6B /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -200,6 +204,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -236,6 +241,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/packages/wyatt_authentication_bloc/example/ios/Runner/GoogleService-Info.plist b/packages/wyatt_authentication_bloc/example/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..ac60a458 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,38 @@ + + + + + CLIENT_ID + 136771801992-p629tpo9bk3hcm2955s5ahivdla57ln9.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.136771801992-p629tpo9bk3hcm2955s5ahivdla57ln9 + ANDROID_CLIENT_ID + 136771801992-n2pq8oqutvrqj58e05hbavvc7n1jdfjb.apps.googleusercontent.com + API_KEY + AIzaSyCDbbhjbFrQwLXuIANdJzjkDk8uOETnn7w + GCM_SENDER_ID + 136771801992 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.exampleRouter + PROJECT_ID + tchat-beta + STORAGE_BUCKET + tchat-beta.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:136771801992:ios:bcdca68d2b7d227097203d + DATABASE_URL + https://tchat-beta.firebaseio.com + + \ No newline at end of file diff --git a/packages/wyatt_authentication_bloc/example/ios/Runner/Info.plist b/packages/wyatt_authentication_bloc/example/ios/Runner/Info.plist index e2987027..e8c1f83a 100644 --- a/packages/wyatt_authentication_bloc/example/ios/Runner/Info.plist +++ b/packages/wyatt_authentication_bloc/example/ios/Runner/Info.plist @@ -28,6 +28,17 @@ LaunchScreen UIMainStoryboardFile Main + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.405351917235-2jv4ff02kovoim58f8d6d0rsa14apgkj + + + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart index 84bb68c4..948e01fd 100644 --- a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart +++ b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart @@ -1,11 +1,18 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: bootstrap.dart -// Created Date: 19/08/2022 15:05:17 -// Last Modified: Fri Nov 11 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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'; @@ -14,6 +21,42 @@ import 'package:example_router/core/utils/app_bloc_observer.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +class MockSettings { + static MockSettings? _instance; + + /// Data source mode + late bool enable = false; + + MockSettings._(this.enable); + + factory MockSettings.enable() { + _instance ??= MockSettings._(true); + if (_instance!.enable != true) { + throw Exception('Mock already initialized in: ${_instance!.enable}'); + } + return _instance!; + } + + factory MockSettings.disable() { + _instance ??= MockSettings._(false); + if (_instance!.enable != false) { + throw Exception('Mock already initialized in: ${_instance!.enable}'); + } + return _instance!; + } + + static bool isEnable() { + if (_instance == null) { + throw Exception('MockSettings not initialized!'); + } + return _instance!.enable == true; + } + + static bool isDisable() { + return !isEnable(); + } +} + Future bootstrap(FutureOr Function() builder) async { await runZonedGuarded( () async { @@ -23,6 +66,7 @@ Future bootstrap(FutureOr Function() builder) async { FlutterError.onError = (details) { debugPrint(details.toString()); }; + await GetItInitializer.init(); runApp(await builder()); diff --git a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart deleted file mode 100644 index e371dfb6..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart +++ /dev/null @@ -1,12 +0,0 @@ -// 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/lib/core/dependency_injection/get_it.dart b/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart index a665ccb7..2961e7cb 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,42 +14,83 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'dart:async'; + +import 'package:example_router/core/enums/dev_mode.dart'; +import 'package:example_router/core/flavors/flavor.dart'; +import 'package:example_router/firebase_options.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:get_it/get_it.dart'; +import 'package:google_sign_in/google_sign_in.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; final getIt = GetIt.I; +/// Service and Data Source locator abstract class GetItInitializer { - static Future init() async { + static FutureOr _initCommon() async { + // Initialize common sources/services + getIt.registerLazySingleton>( + () => AuthenticationSessionDataSourceImpl(), + ); + } + + static FutureOr _initEmulator() async { + // Initialize emulator sources/services + final firebaseAuth = FirebaseAuth.instance; + await firebaseAuth.useAuthEmulator('localhost', 9099); getIt - ..registerLazySingleton( - () => AuthenticationMockDataSourceImpl(registeredAccounts: [ - Pair( - AccountModel( - uid: '1', - emailVerified: true, - isAnonymous: false, - providerId: 'wyatt', - email: 'toto@test.fr', - ), - 'toto1234', - ), - Pair( - AccountModel( - uid: '2', - emailVerified: false, - isAnonymous: false, - providerId: 'wyatt', - email: 'tata@test.fr', - ), - 'tata1234', - ), - ]), + ..registerLazySingleton>( + () => AuthenticationFirebaseDataSourceImpl( + firebaseAuth: firebaseAuth, + googleSignIn: + GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)), ) ..registerLazySingleton>( - () => AuthenticationCacheDataSourceImpl(), + () => AuthenticationFirebaseCacheDataSourceImpl( + firebaseAuth: firebaseAuth, + ), ); + } + + static FutureOr _initFirebase() async { + // Initialize firebase sources/services. + getIt + ..registerLazySingleton>( + () => AuthenticationFirebaseDataSourceImpl( + firebaseAuth: FirebaseAuth.instance, + googleSignIn: + GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)), + ) + ..registerLazySingleton>( + () => AuthenticationFirebaseCacheDataSourceImpl( + firebaseAuth: FirebaseAuth.instance, + ), + ); + } + + static FutureOr _initRest() async { + // Initialize rest api sources/services + } + + static FutureOr init() async { + await _initCommon(); + final flavor = Flavor.get(); + + if (flavor.devMode == DevMode.rest) { + await _initRest(); + } else if (flavor.devMode == DevMode.emulator) { + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + await _initEmulator(); + } else { + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + await _initFirebase(); + } await getIt.allReady(); } diff --git a/packages/wyatt_authentication_bloc/example/lib/core/enums/dev_mode.dart b/packages/wyatt_authentication_bloc/example/lib/core/enums/dev_mode.dart new file mode 100644 index 00000000..5c99b7f8 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/core/enums/dev_mode.dart @@ -0,0 +1,44 @@ +// Copyright (C) 2023 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 . + +enum DevMode { + /// Mocked values + mock, + + /// Real values from REST API + rest, + + /// Emulated values with Firebase Emulator + emulator, + + /// Real values from Firebase + real; + + @override + String toString() => name; + + /// Tries to parse String and returns mode. Fallback is returned if there + /// is an error during parsing. + static DevMode fromString(String? mode, {DevMode fallback = DevMode.mock}) { + for (final m in values) { + if (m.name == mode) { + return m; + } + } + + return fallback; + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/core/flavors/flavor.dart b/packages/wyatt_authentication_bloc/example/lib/core/flavors/flavor.dart new file mode 100644 index 00000000..9fef201a --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/core/flavors/flavor.dart @@ -0,0 +1,72 @@ +// Copyright (C) 2023 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:example_router/core/enums/dev_mode.dart'; +import 'package:flutter/material.dart'; + +abstract class Flavor { + Flavor._({ + this.banner, + this.bannerColor = Colors.red, + this.devMode, + }) { + _instance = this; + } + + static Flavor? _instance; + + final String? banner; + final Color bannerColor; + final DevMode? devMode; + + /// Returns [Flavor] instance. + static Flavor get() { + if (_instance == null) { + throw Exception('Flavor not initialized!'); + } + + return _instance!; + } + + @override + String toString() => runtimeType.toString().replaceAll('Flavor', ''); +} + +class DevelopmentFlavor extends Flavor { + factory DevelopmentFlavor() { + const modeString = String.fromEnvironment('dev_mode', defaultValue: 'mock'); + final mode = DevMode.fromString(modeString); + + return DevelopmentFlavor._(devMode: mode); + } + DevelopmentFlavor._({ + required super.devMode, + }) : super._( + banner: 'Dev', + ); +} + +class StagingFlavor extends Flavor { + StagingFlavor() + : super._( + banner: 'Staging', + bannerColor: Colors.green, + ); +} + +class ProductionFlavor extends Flavor { + ProductionFlavor() : super._(); +} diff --git a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart index 85545c34..f38047f3 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart @@ -1,15 +1,23 @@ -// 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 +// Copyright (C) 2023 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:example_router/presentation/features/authentication/sign_in/sign_in_page.dart'; +import 'package:example_router/presentation/features/authentication/sign_up/sign_up_page.dart'; +import 'package:example_router/presentation/features/edit_account/edit_account_page.dart'; 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'; @@ -58,22 +66,32 @@ class AppRouter { ), ), 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(), - ), - ), + path: '/home', + name: HomePage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const HomePage(), + ), + routes: [ + GoRoute( + path: 'sub', + name: SubPage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const SubPage(), + ), + ), + GoRoute( + path: 'edit_account', + name: EditAccountPage.pageName, + pageBuilder: (context, state) => defaultTransition( + context, + state, + const EditAccountPage(), + ), + ), + ]), ]; } diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart index 1b44c4e8..abc209cb 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart @@ -1,11 +1,18 @@ -// 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 +// Copyright (C) 2023 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:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart index bdbb3552..a7e1c7c8 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/example/lib/firebase_options.dart b/packages/wyatt_authentication_bloc/example/lib/firebase_options.dart new file mode 100644 index 00000000..0725ddb4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/firebase_options.dart @@ -0,0 +1,74 @@ +// 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: + return ios; + 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', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyCDbbhjbFrQwLXuIANdJzjkDk8uOETnn7w', + appId: '1:136771801992:ios:bcdca68d2b7d227097203d', + messagingSenderId: '136771801992', + projectId: 'tchat-beta', + databaseURL: 'https://tchat-beta.firebaseio.com', + storageBucket: 'tchat-beta.appspot.com', + androidClientId: + '136771801992-n2pq8oqutvrqj58e05hbavvc7n1jdfjb.apps.googleusercontent.com', + iosClientId: + '136771801992-p629tpo9bk3hcm2955s5ahivdla57ln9.apps.googleusercontent.com', + iosBundleId: 'com.example.exampleRouter', + ); +} diff --git a/packages/wyatt_authentication_bloc/example/lib/main.dart b/packages/wyatt_authentication_bloc/example/lib/main.dart index 06b15c7c..a8d69968 100644 --- a/packages/wyatt_authentication_bloc/example/lib/main.dart +++ b/packages/wyatt_authentication_bloc/example/lib/main.dart @@ -1,6 +1,27 @@ +// Copyright (C) 2023 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:example_router/bootstrap.dart'; +import 'package:example_router/core/flavors/flavor.dart'; import 'package:example_router/presentation/features/app/app.dart'; -void main() { +void main(List args) { + // Define environment + ProductionFlavor(); + + // Initialize environment and variables bootstrap(App.new); } diff --git a/packages/wyatt_authentication_bloc/example/lib/main_development.dart b/packages/wyatt_authentication_bloc/example/lib/main_development.dart new file mode 100644 index 00000000..9025e30f --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/main_development.dart @@ -0,0 +1,27 @@ +// Copyright (C) 2023 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:example_router/bootstrap.dart'; +import 'package:example_router/core/flavors/flavor.dart'; +import 'package:example_router/presentation/features/app/app.dart'; + +void main(List args) { + // Define environment + DevelopmentFlavor(); + + // Initialize environment and variables + bootstrap(App.new); +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart index a2afa06e..51b038d9 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart @@ -1,64 +1,46 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: app.dart -// Created Date: 19/08/2022 12:05:38 -// Last Modified: Sat Dec 03 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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 'dart:math'; -import 'package:example_router/core/constants/form_field.dart'; import 'package:example_router/core/dependency_injection/get_it.dart'; import 'package:example_router/core/routes/router.dart'; import 'package:example_router/core/utils/custom_password.dart'; +import 'package:example_router/presentation/features/authentication/authentication_cubit.dart'; +import 'package:example_router/presentation/features/authentication/sign_in/blocs/sign_in_cubit.dart'; +import 'package:example_router/presentation/features/authentication/sign_up/blocs/sign_up_cubit.dart'; +import 'package:example_router/presentation/features/edit_account/blocs/edit_account_cubit.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'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -import 'package:wyatt_architecture/wyatt_architecture.dart'; - -FutureOrResult onSignUpSuccess( - AuthenticationRepository repo, - Account? account, - WyattForm form, -) async { - const id = -1; - final confirmedPassword = - form.valueOf(AppFormField.confirmedPassword); - - debugPrint( - 'onSignUpSuccess: $account, generatedId: $id, extraFormData: $confirmedPassword'); - return const Ok(id); -} - -FutureOrResult onAccountChanges( - AuthenticationRepository repo, - Account? account, -) async { - final id = Random().nextInt(1000); - final token = - await repo.getIdentityToken().fold((value) => value, (error) => 'null'); - - debugPrint('onAccountChanges: $account, token: $token, generatedId: $id'); - return Ok(id); -} class App extends StatelessWidget { final AuthenticationRepository authenticationRepository = AuthenticationRepositoryImpl( + authenticationRemoteDataSource: + getIt>(), + authenticationSessionDataSource: + getIt>(), authenticationCacheDataSource: getIt>(), - authenticationRemoteDataSource: getIt(), - onSignUpSuccess: onSignUpSuccess, - onAuthChange: onAccountChanges, customPasswordValidator: const CustomPassword.pure(), extraSignUpInputs: [ FormInput( - AppFormField.confirmedPassword, + AuthFormField.confirmPassword, const ConfirmedPassword.pure(), metadata: const FormInputMetadata(export: false), ), @@ -69,10 +51,11 @@ class App extends StatelessWidget { @override Widget build(BuildContext context) { - AuthenticationState? previous; + AuthenticationState? previous; final AuthenticationCubit authenticationCubit = - AuthenticationCubit(authenticationRepository: authenticationRepository); + ExampleAuthenticationCubit( + authenticationRepository: authenticationRepository); final GoRouter router = GoRouter( initialLocation: '/', @@ -85,40 +68,32 @@ class App extends StatelessWidget { redirect: (context, state) { final authState = authenticationCubit.state; - if (authState != previous) { + if (authState.status != previous?.status) { 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) { + if (authState.status == AuthenticationStatus.unauthenticated) { debugPrint('Not logged'); - if (isOnboarding) { - return null; - } else { + if (!isOnboarding) { return '/'; } - } else { + } else if (authState.status == AuthenticationStatus.authenticated) { debugPrint('Logged'); - if (isOnboarding) { - return '/home'; - } else { - return null; - } + return '/home'; } } - return null; + return state.name; }, ); return MultiRepositoryProvider( providers: [ - RepositoryProvider.value( + RepositoryProvider>.value( value: authenticationRepository, ), + RepositoryProvider( + create: (context) => FormRepositoryImpl(), + ) ], child: MultiBlocProvider( providers: [ @@ -126,12 +101,17 @@ class App extends StatelessWidget { value: authenticationCubit, ), BlocProvider>( - create: (_) => SignUpCubit( + create: (_) => ExampleSignUpCubit( authenticationRepository: authenticationRepository, ), ), BlocProvider>( - create: (_) => SignInCubit( + create: (_) => ExampleSignInCubit( + authenticationRepository: authenticationRepository, + ), + ), + BlocProvider>( + create: (_) => ExampleEditAccountCubit( authenticationRepository: authenticationRepository, ), ), diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart similarity index 51% rename from packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart rename to packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart index 57b1191a..04153f31 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,54 +14,47 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'package:flutter/foundation.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -class AuthenticationCacheDataSourceImpl - extends AuthenticationCacheDataSource { - Account? _account; - T? _data; - - AuthenticationCacheDataSourceImpl(); +class ExampleAuthenticationCubit extends AuthenticationCubit { + ExampleAuthenticationCubit({required super.authenticationRepository}); @override - Future storeAccount(Account? account) async { - _account = account; + FutureOrResult onReauthenticate( + Result result) async { + debugPrint('onReauthenticate'); + + return const Ok(1); } @override - Future storeData(T? data) async { - _data = data; + FutureOrResult onRefresh(Result result) { + debugPrint('onRefresh'); + + return const Ok(1); } @override - Future loadAccount() async { - if (_account.isNotNull) { - return _account!; - } - throw ClientException('Cached account is invalid'); + FutureOrResult onSignInFromCache(AuthenticationSession session) { + debugPrint('onSignInFromCache'); + + return const Ok(1); } @override - Future loadData() async { - if (_data.isNotNull) { - return _data!; - } - throw ClientException('Cached data is invalid'); + FutureOrResult onSignOut() { + debugPrint('onSignOut'); + + return const Ok(null); } @override - Future destroy() async { - _data = null; - _account = null; - } + FutureOrResult onDelete() { + debugPrint('onDelete'); - @override - Future> load() async { - if (_account.isNull) { - throw ClientException('Cached account is invalid'); - } - return AccountWrapperModel(_account, _data); + return const Ok(null); } } diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/blocs/sign_in_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/blocs/sign_in_cubit.dart new file mode 100644 index 00000000..0b391624 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/blocs/sign_in_cubit.dart @@ -0,0 +1,51 @@ +// Copyright (C) 2023 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:flutter/foundation.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +class ExampleSignInCubit extends SignInCubit { + ExampleSignInCubit({ + required super.authenticationRepository, + }); + + @override + FutureOrResult onSignInWithEmailAndPassword( + Result result, WyattForm form) { + debugPrint('onSignInWithEmailAndPassword: ${result.ok?.accessToken}'); + + return const Ok(1); + } + + @override + FutureOrResult onSignInAnonymously( + Result result, WyattForm form) { + debugPrint('onSignInAnonymously'); + + return const Ok(1); + } + + @override + FutureOrResult onSignInWithGoogle( + Result result, WyattForm form) { + debugPrint('onSignInWithGoogle'); + + return const Ok(1); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/sign_in_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/sign_in_page.dart new file mode 100644 index 00000000..5294fed0 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/sign_in_page.dart @@ -0,0 +1,37 @@ +// Copyright (C) 2023 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:example_router/presentation/features/authentication/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/lib/presentation/features/sign_in/widgets/sign_in_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/widgets/sign_in_form.dart similarity index 64% rename from packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart rename to packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/widgets/sign_in_form.dart index 45a45c4a..ebb65583 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_in/widgets/sign_in_form.dart @@ -1,11 +1,18 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: sign_in_form.dart -// Created Date: 19/08/2022 15:24:37 -// Last Modified: Sat Dec 03 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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:example_router/core/utils/custom_password.dart'; import 'package:flutter/material.dart'; @@ -87,6 +94,22 @@ class _SignInAnonymouslyButton extends StatelessWidget { } } +class _SignInWithGoogleButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SubmitBuilder>( + builder: ((context, cubit, status) { + return status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: () => cubit.signInWithGoogle(), + child: const Text('Sign in Google'), + ); + }), + ); + } +} + class SignInForm extends StatelessWidget { const SignInForm({Key? key}) : super(key: key); @@ -98,19 +121,19 @@ class SignInForm extends StatelessWidget { ..showSnackBar( SnackBar(content: Text(errorMessage ?? 'Sign In Failure')), ), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _EmailInput(), - const SizedBox(height: 8), - _PasswordInput(), - const SizedBox(height: 16), - _SignInButton(), - const SizedBox(height: 16), - _SignInAnonymouslyButton(), - ], - ), + child: ListView( + shrinkWrap: true, + children: [ + _EmailInput(), + const SizedBox(height: 8), + _PasswordInput(), + const SizedBox(height: 16), + _SignInButton(), + const SizedBox(height: 16), + _SignInAnonymouslyButton(), + const SizedBox(height: 16), + _SignInWithGoogleButton(), + ], ), ); } diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/blocs/sign_up_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/blocs/sign_up_cubit.dart new file mode 100644 index 00000000..93c4509e --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/blocs/sign_up_cubit.dart @@ -0,0 +1,35 @@ +// Copyright (C) 2023 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:flutter/foundation.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +class ExampleSignUpCubit extends SignUpCubit { + ExampleSignUpCubit({ + required super.authenticationRepository, + }); + + @override + FutureOrResult onSignUpWithEmailAndPassword( + Result result, WyattForm form) async { + debugPrint('onSignUpWithEmailAndPassword'); + + return const Ok(1); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/sign_up_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/sign_up_page.dart new file mode 100644 index 00000000..d9963142 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/sign_up_page.dart @@ -0,0 +1,37 @@ +// Copyright (C) 2023 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:example_router/presentation/features/authentication/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/lib/presentation/features/sign_up/widgets/sign_up_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/widgets/sign_up_form.dart similarity index 71% rename from packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart rename to packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/widgets/sign_up_form.dart index 0a512fb8..4c13a491 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/sign_up/widgets/sign_up_form.dart @@ -1,13 +1,19 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: sign_up_form.dart -// Created Date: 19/08/2022 14:41:08 -// Last Modified: Sat Dec 03 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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:example_router/core/constants/form_field.dart'; import 'package:example_router/core/utils/custom_password.dart'; import 'package:flutter/material.dart' hide FormField; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; @@ -44,11 +50,11 @@ class _PasswordInput extends StatelessWidget { cubit.passwordCustomChanged( CustomPassword.dirty(pwd)); cubit.dataChanged( - AppFormField.confirmedPassword, + AuthFormField.confirmPassword, ConfirmedPassword.dirty( password: pwd, value: state.form - .valueOf(AppFormField.confirmedPassword))); + .valueOf(AuthFormField.confirmPassword))); }, obscureText: true, decoration: InputDecoration( @@ -66,7 +72,7 @@ class _ConfirmPasswordInput extends StatelessWidget { @override Widget build(BuildContext context) { return InputBuilder>( - field: AppFormField.confirmedPassword, + field: AuthFormField.confirmPassword, builder: ((context, cubit, state, field, input) { return TextField( onChanged: (pwd) { @@ -99,7 +105,9 @@ class _SignUpButton extends StatelessWidget { return status.isSubmissionInProgress ? const CircularProgressIndicator() : ElevatedButton( - onPressed: status.isValidated ? () => cubit.submit() : null, + onPressed: status.isValidated + ? () => cubit.signUpWithEmailPassword() + : null, child: const Text('Sign up'), ); }), @@ -119,18 +127,17 @@ class SignUpForm extends StatelessWidget { ..showSnackBar( SnackBar(content: Text(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(), - ], - ), + child: ListView( + shrinkWrap: true, + 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/lib/presentation/features/edit_account/blocs/edit_account_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/blocs/edit_account_cubit.dart new file mode 100644 index 00000000..ae964202 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/blocs/edit_account_cubit.dart @@ -0,0 +1,41 @@ +// Copyright (C) 2023 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:flutter/foundation.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +class ExampleEditAccountCubit extends EditAccountCubit { + ExampleEditAccountCubit({required super.authenticationRepository}); + + @override + FutureOrResult onEmailUpdated( + Result result, WyattForm form) async { + debugPrint('onEmailUpdated'); + + return const Ok(1); + } + + @override + FutureOrResult onPasswordUpdated( + Result result, WyattForm form) async { + debugPrint('onPasswordUpdated'); + + return const Ok(1); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/edit_account_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/edit_account_page.dart new file mode 100644 index 00000000..11b0f987 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/edit_account_page.dart @@ -0,0 +1,37 @@ +// Copyright (C) 2023 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:example_router/presentation/features/edit_account/widgets/edit_account_form.dart'; +import 'package:flutter/material.dart'; + +class EditAccountPage extends StatelessWidget { + const EditAccountPage({Key? key}) : super(key: key); + + static String pageName = 'EditAccount'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Edit Account')), + body: const Padding( + padding: EdgeInsets.all(8), + child: SingleChildScrollView( + child: EditAccountForm(), + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/widgets/edit_account_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/widgets/edit_account_form.dart new file mode 100644 index 00000000..c80439a9 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_account/widgets/edit_account_form.dart @@ -0,0 +1,151 @@ +// Copyright (C) 2023 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:example_router/core/utils/custom_password.dart'; +import 'package:flutter/material.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 InputBuilder>( + field: AuthFormField.email, + builder: ((context, cubit, state, field, input) { + return TextField( + onChanged: (email) => cubit.emailChanged(email), + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + labelText: 'Email', + helperText: '', + errorText: input.validator.invalid ? 'Invalid email' : null, + ), + ); + }), + ); + } +} + +class _PasswordInput extends StatelessWidget { + @override + Widget build(BuildContext context) { + return InputBuilder>( + field: AuthFormField.password, + builder: ((context, cubit, state, field, input) { + return TextField( + onChanged: (pwd) => cubit + .passwordCustomChanged(CustomPassword.dirty(pwd)), + obscureText: true, + decoration: InputDecoration( + labelText: 'Password', + helperText: '', + errorText: input.validator.invalid ? 'Invalid password' : null, + ), + ); + }), + ); + } +} + +class _EditAccountButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SubmitBuilder>( + builder: ((context, cubit, status) { + return status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: status.isValidated + ? () { + cubit.updateEmail(); + cubit.updatePassword(); + } + : null, + child: const Text('Update Account'), + ); + }), + ); + } +} + +class _EditAccountEmailButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SubmitBuilder>( + builder: ((context, cubit, status) { + return status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: status.isValidated + ? () { + cubit.updateEmail(); + } + : null, + child: const Text('Update Account Email'), + ); + }), + ); + } +} + +class _EditAccountPasswordButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SubmitBuilder>( + builder: ((context, cubit, status) { + return status.isSubmissionInProgress + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: status.isValidated + ? () { + cubit.updatePassword(); + } + : null, + child: const Text('Update Account Password'), + ); + }), + ); + } +} + +class EditAccountForm extends StatelessWidget { + const EditAccountForm({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return EditAccountListener( + onError: (context, status, errorMessage) => ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar( + SnackBar(content: Text(errorMessage ?? 'Account edition Failure')), + ), + child: ListView( + shrinkWrap: true, + children: [ + _EmailInput(), + const SizedBox(height: 8), + _PasswordInput(), + const SizedBox(height: 16), + _EditAccountButton(), + const SizedBox(height: 16), + _EditAccountEmailButton(), + const SizedBox(height: 16), + _EditAccountPasswordButton(), + ], + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart index e271c7e1..463ea902 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart @@ -1,12 +1,20 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: home_page.dart -// Created Date: 19/08/2022 14:38:24 -// Last Modified: Wed Nov 09 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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:example_router/presentation/features/edit_account/edit_account_page.dart'; import 'package:example_router/presentation/features/sub/sub_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -22,33 +30,37 @@ class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Home'), + title: Text('Home | ${context.watchAccount()?.email}'), actions: [ IconButton( - onPressed: () => context.read>().signOut(), + onPressed: () => + context.read>().signOut(), icon: const Icon(Icons.logout_rounded)) ], ), body: Padding( padding: const EdgeInsets.all(8), - child: SingleChildScrollView( - child: Column( - children: [ - AuthenticationBuilder( - authenticated: (context, accountWrapper) => - Text('Logged as ${accountWrapper.account?.email} | GeneratedId is ${accountWrapper.data}'), - unauthenticated: (context) => - const Text('Not logged (unauthenticated)'), - unknown: (context) => const Text('Not logged (unknown)'), - ), - const SizedBox( - height: 8, - ), - ElevatedButton( - onPressed: () => context.pushNamed(SubPage.pageName), - child: const Text('Go to sub page')), - ], - ), + child: ListView( + children: [ + AuthenticationBuilder( + authenticated: (context, session) => Text( + 'Logged as ${session.account?.email} | GeneratedId is ${session.data}'), + unauthenticated: (context) => + const Text('Not logged (unauthenticated)'), + unknown: (context) => const Text('Not logged (unknown)'), + ), + const SizedBox( + height: 8, + ), + ElevatedButton( + onPressed: () => context.pushNamed(SubPage.pageName), + child: const Text('Go to sub page'), + ), + ElevatedButton( + onPressed: () => context.pushNamed(EditAccountPage.pageName), + child: const Text('Go to edit account page'), + ), + ], ), ), ); diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart deleted file mode 100644 index 39fd0463..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart +++ /dev/null @@ -1,30 +0,0 @@ -// 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/lib/presentation/features/sign_up/sign_up_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart deleted file mode 100644 index 31f18bb6..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart +++ /dev/null @@ -1,30 +0,0 @@ -// 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/lib/presentation/features/sub/sub_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart index 14b340b8..f56df50b 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart @@ -1,11 +1,18 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: sub_page.dart -// Created Date: 19/08/2022 16:10:05 -// Last Modified: Wed Nov 09 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -23,14 +30,26 @@ class SubPage extends StatelessWidget { title: const Text('Sub'), actions: [ IconButton( - onPressed: () => context.read>().signOut(), - icon: const Icon(Icons.logout_rounded)) + onPressed: () => + context.read>().signOut(), + icon: const Icon(Icons.logout_rounded)), + IconButton( + onPressed: () => + context.read>().refresh(), + icon: const Icon(Icons.refresh)) ], ), - body: const Padding( - padding: EdgeInsets.all(8), - child: SingleChildScrollView( - child: Text('Another page'), + body: Padding( + padding: const EdgeInsets.all(8), + child: ListView( + children: [ + const Text('Another page'), + ElevatedButton( + onPressed: () => + context.read>().delete(), + child: const Text('Delete account'), + ), + ], ), ), ); diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart index 3794f971..2d2ab4bc 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart @@ -1,14 +1,21 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: welcome_page.dart -// Created Date: 19/08/2022 12:33:21 -// Last Modified: Wed Nov 09 2022 -// ----- -// Copyright (c) 2022 +// Copyright (C) 2023 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: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/authentication/sign_in/sign_in_page.dart'; +import 'package:example_router/presentation/features/authentication/sign_up/sign_up_page.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -23,22 +30,26 @@ class WelcomePage extends StatelessWidget { appBar: AppBar( title: const Text('Welcome'), ), - body: SingleChildScrollView( - child: Column( - children: [ - ElevatedButton( + body: ListView( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( onPressed: () => context.pushNamed(SignUpPage.pageName), child: const Text('Sign Up')), - ElevatedButton( + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( onPressed: () => context.pushNamed(SignInPage.pageName), style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: MaterialStateProperty.all(Colors.blue)), - child: const Text('Sign In')) - ], - ), + child: const Text('Sign In')), + ) + ], ), ); } diff --git a/packages/wyatt_authentication_bloc/example/pubspec.yaml b/packages/wyatt_authentication_bloc/example/pubspec.yaml index 28001220..b269e5d6 100644 --- a/packages/wyatt_authentication_bloc/example/pubspec.yaml +++ b/packages/wyatt_authentication_bloc/example/pubspec.yaml @@ -33,6 +33,8 @@ dependencies: go_router: ^5.1.5 firebase_core: ^2.1.1 flutter_bloc: ^8.1.1 + firebase_auth: ^4.2.0 + google_sign_in: ^5.4.2 get_it: ^7.2.0 wyatt_authentication_bloc: @@ -40,15 +42,15 @@ dependencies: wyatt_form_bloc: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 0.2.0+2 + version: 0.2.0+3 wyatt_architecture: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 0.1.0+1 + version: 0.2.0 wyatt_type_utils: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 0.0.4 + version: 0.0.5 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/packages/wyatt_authentication_bloc/example/test/widget_test.dart b/packages/wyatt_authentication_bloc/example/test/widget_test.dart index e69de29b..8b137891 100644 --- a/packages/wyatt_authentication_bloc/example/test/widget_test.dart +++ b/packages/wyatt_authentication_bloc/example/test/widget_test.dart @@ -0,0 +1 @@ + diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart index 295cfc2f..590e9ae6 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Default authentication form fields name abstract class AuthFormField { + /// Email field: `wyattEmailField` static const email = 'wyattEmailField'; + + /// Password field: `wyattPasswordField` static const password = 'wyattPasswordField'; + + /// Confirm Password field: `wyattConfirmPasswordField` + static const confirmPassword = 'wyattConfirmPasswordField'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart index af623e70..17281b1e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,8 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Default authentication form name abstract class AuthFormName { + /// Sign Up form: `wyattSignUpForm` static const String signUpForm = 'wyattSignUpForm'; + + /// Sign In form: `wyattSignInForm` static const String signInForm = 'wyattSignInForm'; + + /// Password reset form: `wyattPasswordResetForm` static const String passwordResetForm = 'wyattPasswordResetForm'; + + /// Edit account form: `wyattEditAccountForm` + static const String editAccountForm = 'wyattEditAccountForm'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/storage.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/storage.dart new file mode 100644 index 00000000..5211fe72 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/storage.dart @@ -0,0 +1,30 @@ +// Copyright (C) 2023 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 . + +/// Default name for storage keys +abstract class AuthStorage { + /// Refresh token, `wyattRefreshToken` + static const String refreshToken = 'wyattRefreshToken'; + + /// Access token, `wyattAccessToken` + static const String accessToken = 'wyattAccessToken'; + + /// User email, `wyattEmail` + static const String email = 'wyattEmail'; + + /// User id, `wyattId` + static const String id = 'wyattId'; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/core.dart b/packages/wyatt_authentication_bloc/lib/src/core/core.dart index 16b0264b..da22baa1 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/core.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/core.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,4 +18,5 @@ export 'constants/form_field.dart'; export 'constants/form_name.dart'; export 'enums/enums.dart'; export 'exceptions/exceptions.dart'; -export 'utils/utils.dart'; +export 'extensions/build_context_extension.dart'; +export 'utils/custom_routine.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart b/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart index af10ceae..4a96cc46 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart @@ -1,21 +1,27 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . +/// Different authentication status enum AuthenticationStatus { + /// At the application launch. unknown, + + /// When the user is logged authenticated, + + /// When the user is not logged unauthenticated, } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart b/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart index 67d107d6..de021091 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart index dbe4b429..0fb036f7 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,19 +16,21 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; +part 'exceptions_base.dart'; part 'exceptions_firebase.dart'; +part 'exceptions_mock.dart'; +/// Base exception used in Wyatt Authentication abstract class AuthenticationFailureInterface extends AppException implements Exception { + AuthenticationFailureInterface(this.code, this.msg); + AuthenticationFailureInterface.fromCode(this.code) + : msg = 'An unknown error occurred.'; String code; String msg; @override String get message => msg; - - AuthenticationFailureInterface(this.code, this.msg); - AuthenticationFailureInterface.fromCode(this.code) - : msg = 'An unknown error occurred.'; } /// {@template apply_action_code_failure} @@ -250,9 +252,52 @@ abstract class SignOutFailureInterface extends AuthenticationFailureInterface { SignOutFailureInterface.fromCode(super.code) : super.fromCode(); } -abstract class GetIdTokenFailureInterface +/// {@template reauthenticate_failure} +/// Thrown during the reauthentication process if a failure occurs. +/// {@endtemplate} +abstract class ReauthenticateFailureInterface extends AuthenticationFailureInterface { - GetIdTokenFailureInterface(super.code, super.msg); + ReauthenticateFailureInterface(super.code, super.msg); - GetIdTokenFailureInterface.fromCode(super.code) : super.fromCode(); + ReauthenticateFailureInterface.fromCode(super.code) : super.fromCode(); +} + +/// {@template update_email_failure} +/// Thrown during the email modification process if a failure occurs. +/// {@endtemplate} +abstract class UpdateEmailFailureInterface + extends AuthenticationFailureInterface { + UpdateEmailFailureInterface(super.code, super.msg); + + UpdateEmailFailureInterface.fromCode(super.code) : super.fromCode(); +} + +/// {@template update_password_failure} +/// Thrown during the password modification process if a failure occurs. +/// {@endtemplate} +abstract class UpdatePasswordFailureInterface + extends AuthenticationFailureInterface { + UpdatePasswordFailureInterface(super.code, super.msg); + + UpdatePasswordFailureInterface.fromCode(super.code) : super.fromCode(); +} + +/// {@template model_parsing_failure} +/// Thrown during the model parsing process if a failure occurs. +/// {@endtemplate} +abstract class ModelParsingFailureInterface + extends AuthenticationFailureInterface { + ModelParsingFailureInterface(super.code, super.msg); + + ModelParsingFailureInterface.fromCode(super.code) : super.fromCode(); +} + +/// {@template delete_account_failure} +/// Thrown during the account deletion if a failure occurs. +/// {@endtemplate} +abstract class DeleteAccountFailureInterface + extends AuthenticationFailureInterface { + DeleteAccountFailureInterface(super.code, super.msg); + + DeleteAccountFailureInterface.fromCode(super.code) : super.fromCode(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_base.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_base.dart new file mode 100644 index 00000000..cd994be5 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_base.dart @@ -0,0 +1,382 @@ +// Copyright (C) 2023 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 . + +part of 'exceptions.dart'; + +/// {@macro apply_action_code_failure} +class ApplyActionCodeFailureBase extends ApplyActionCodeFailureInterface { + ApplyActionCodeFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + ApplyActionCodeFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'expired-action-code': + msg = 'Action code has expired.'; + break; + case 'invalid-action-code': + msg = 'Action code is invalid.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_up_with_email_and_password_failure} +class SignUpWithEmailAndPasswordFailureBase + extends SignUpWithEmailAndPasswordFailureInterface { + SignUpWithEmailAndPasswordFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignUpWithEmailAndPasswordFailureBase.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'The email address is badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'email-already-in-use': + msg = 'An account already exists for that email.'; + break; + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + case 'weak-password': + msg = 'Please enter a stronger password.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro fetch_sign_in_methods_failure} +class FetchSignInMethodsForEmailFailureBase + extends FetchSignInMethodsForEmailFailureInterface { + FetchSignInMethodsForEmailFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + FetchSignInMethodsForEmailFailureBase.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'The email address is badly formatted.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_anonymously_failure} +class SignInAnonymouslyFailureBase extends SignInAnonymouslyFailureInterface { + SignInAnonymouslyFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInAnonymouslyFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_credential_failure} +class SignInWithCredentialFailureBase + extends SignInWithCredentialFailureInterface { + SignInWithCredentialFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithCredentialFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'account-exists-with-different-credential': + msg = 'Account exists with different credentials.'; + break; + case 'invalid-credential': + msg = 'The credential received is malformed or has expired.'; + break; + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + case 'invalid-verification-code': + msg = 'The credential verification code received is invalid.'; + break; + case 'invalid-verification-id': + msg = 'The credential verification ID received is invalid.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_google_failure} +class SignInWithGoogleFailureBase extends SignInWithCredentialFailureBase + implements SignInWithGoogleFailureInterface { + SignInWithGoogleFailureBase([super.code, super.msg]); + SignInWithGoogleFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_facebook_failure} +class SignInWithFacebookFailureBase extends SignInWithCredentialFailureBase + implements SignInWithFacebookFailureInterface { + SignInWithFacebookFailureBase([super.code, super.msg]); + SignInWithFacebookFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_apple_failure} +class SignInWithAppleFailureBase extends SignInWithCredentialFailureBase + implements SignInWithAppleFailureInterface { + SignInWithAppleFailureBase([super.code, super.msg]); + SignInWithAppleFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_twitter_failure} +class SignInWithTwitterFailureBase extends SignInWithCredentialFailureBase + implements SignInWithAppleFailureInterface { + SignInWithTwitterFailureBase([super.code, super.msg]); + SignInWithTwitterFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_email_link_failure} +class SignInWithEmailLinkFailureBase + extends SignInWithEmailLinkFailureInterface { + SignInWithEmailLinkFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithEmailLinkFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'expired-action-code': + msg = 'Action code has expired.'; + break; + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_email_and_password_failure} +class SignInWithEmailAndPasswordFailureBase + extends SignInWithEmailAndPasswordFailureInterface { + SignInWithEmailAndPasswordFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithEmailAndPasswordFailureBase.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro send_email_verification_failure} +class SendEmailVerificationFailureBase + extends SendEmailVerificationFailureInterface { + SendEmailVerificationFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SendEmailVerificationFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro send_password_reset_email_failure} +class SendPasswordResetEmailFailureBase + extends SendPasswordResetEmailFailureInterface { + SendPasswordResetEmailFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SendPasswordResetEmailFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro send_sign_in_link_email_failure} +class SendSignInLinkEmailFailureBase + extends SendSignInLinkEmailFailureInterface { + SendSignInLinkEmailFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SendSignInLinkEmailFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro confirm_password_reset_failure} +class ConfirmPasswordResetFailureBase + extends ConfirmPasswordResetFailureInterface { + ConfirmPasswordResetFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + ConfirmPasswordResetFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro verify_password_reset_code_failure} +class VerifyPasswordResetCodeFailureBase + extends VerifyPasswordResetCodeFailureInterface { + VerifyPasswordResetCodeFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + VerifyPasswordResetCodeFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro refresh_failure} +class RefreshFailureBase extends RefreshFailureInterface { + RefreshFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + RefreshFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_out_failure} +class SignOutFailureBase extends SignOutFailureInterface { + SignOutFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SignOutFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro reauthenticate_failure} +class ReauthenticateFailureBase extends ReauthenticateFailureInterface { + ReauthenticateFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + ReauthenticateFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'user-mismatch': + msg = 'Given credential does not correspond to the user.'; + break; + case 'user-not-found': + msg = 'User is not found, please create an account.'; + break; + case 'invalid-credential': + msg = 'The credential received is malformed or has expired.'; + break; + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + case 'invalid-verification-code': + msg = 'The credential verification code received is invalid.'; + break; + case 'invalid-verification-id': + msg = 'The credential verification ID received is invalid.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_email_failure} +class UpdateEmailFailureBase extends UpdateEmailFailureInterface { + UpdateEmailFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdateEmailFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'email-already-in-use': + msg = 'An account already exists for that email.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_password_failure} +class UpdatePasswordFailureBase extends UpdatePasswordFailureInterface { + UpdatePasswordFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdatePasswordFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'weak-password': + msg = 'Please enter a stronger password.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro model_parsing_failure} +class ModelParsingFailureBase extends ModelParsingFailureInterface { + ModelParsingFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + ModelParsingFailureBase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro delete_account_failure} +class DeleteAccountFailureBase extends DeleteAccountFailureInterface { + DeleteAccountFailureBase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + DeleteAccountFailureBase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart index 7a6e37b4..7b17e606 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ part of 'exceptions.dart'; +/// {@macro apply_action_code_failure} class ApplyActionCodeFailureFirebase extends ApplyActionCodeFailureInterface { ApplyActionCodeFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -41,6 +42,7 @@ class ApplyActionCodeFailureFirebase extends ApplyActionCodeFailureInterface { } } +/// {@macro sign_up_with_email_and_password_failure} class SignUpWithEmailAndPasswordFailureFirebase extends SignUpWithEmailAndPasswordFailureInterface { SignUpWithEmailAndPasswordFailureFirebase([String? code, String? msg]) @@ -70,6 +72,7 @@ class SignUpWithEmailAndPasswordFailureFirebase } } +/// {@macro fetch_sign_in_methods_failure} class FetchSignInMethodsForEmailFailureFirebase extends FetchSignInMethodsForEmailFailureInterface { FetchSignInMethodsForEmailFailureFirebase([String? code, String? msg]) @@ -87,6 +90,7 @@ class FetchSignInMethodsForEmailFailureFirebase } } +/// {@macro sign_in_anonymously_failure} class SignInAnonymouslyFailureFirebase extends SignInAnonymouslyFailureInterface { SignInAnonymouslyFailureFirebase([String? code, String? msg]) @@ -104,6 +108,7 @@ class SignInAnonymouslyFailureFirebase } } +/// {@macro sign_in_with_credential_failure} class SignInWithCredentialFailureFirebase extends SignInWithCredentialFailureInterface { SignInWithCredentialFailureFirebase([String? code, String? msg]) @@ -142,6 +147,7 @@ class SignInWithCredentialFailureFirebase } } +/// {@macro sign_in_with_google_failure} class SignInWithGoogleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithGoogleFailureInterface { @@ -149,6 +155,7 @@ class SignInWithGoogleFailureFirebase SignInWithGoogleFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_facebook_failure} class SignInWithFacebookFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithFacebookFailureInterface { @@ -156,12 +163,14 @@ class SignInWithFacebookFailureFirebase SignInWithFacebookFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_apple_failure} class SignInWithAppleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { SignInWithAppleFailureFirebase([super.code, super.msg]); SignInWithAppleFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_twitter_failure} class SignInWithTwitterFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { @@ -169,6 +178,7 @@ class SignInWithTwitterFailureFirebase SignInWithTwitterFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_email_link_failure} class SignInWithEmailLinkFailureFirebase extends SignInWithEmailLinkFailureInterface { SignInWithEmailLinkFailureFirebase([String? code, String? msg]) @@ -192,6 +202,7 @@ class SignInWithEmailLinkFailureFirebase } } +/// {@macro sign_in_with_email_and_password_failure} class SignInWithEmailAndPasswordFailureFirebase extends SignInWithEmailAndPasswordFailureInterface { SignInWithEmailAndPasswordFailureFirebase([String? code, String? msg]) @@ -218,6 +229,7 @@ class SignInWithEmailAndPasswordFailureFirebase } } +/// {@macro send_email_verification_failure} class SendEmailVerificationFailureFirebase extends SendEmailVerificationFailureInterface { SendEmailVerificationFailureFirebase([String? code, String? msg]) @@ -226,6 +238,7 @@ class SendEmailVerificationFailureFirebase SendEmailVerificationFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro send_password_reset_email_failure} class SendPasswordResetEmailFailureFirebase extends SendPasswordResetEmailFailureInterface { SendPasswordResetEmailFailureFirebase([String? code, String? msg]) @@ -233,6 +246,7 @@ class SendPasswordResetEmailFailureFirebase SendPasswordResetEmailFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro send_sign_in_link_email_failure} class SendSignInLinkEmailFailureFirebase extends SendSignInLinkEmailFailureInterface { SendSignInLinkEmailFailureFirebase([String? code, String? msg]) @@ -241,6 +255,7 @@ class SendSignInLinkEmailFailureFirebase SendSignInLinkEmailFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro confirm_password_reset_failure} class ConfirmPasswordResetFailureFirebase extends ConfirmPasswordResetFailureInterface { ConfirmPasswordResetFailureFirebase([String? code, String? msg]) @@ -249,6 +264,7 @@ class ConfirmPasswordResetFailureFirebase ConfirmPasswordResetFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro verify_password_reset_code_failure} class VerifyPasswordResetCodeFailureFirebase extends VerifyPasswordResetCodeFailureInterface { VerifyPasswordResetCodeFailureFirebase([String? code, String? msg]) @@ -258,12 +274,14 @@ class VerifyPasswordResetCodeFailureFirebase : super.fromCode(); } +/// {@macro refresh_failure} class RefreshFailureFirebase extends RefreshFailureInterface { RefreshFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); RefreshFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_out_failure} class SignOutFailureFirebase extends SignOutFailureInterface { SignOutFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -271,9 +289,102 @@ class SignOutFailureFirebase extends SignOutFailureInterface { SignOutFailureFirebase.fromCode(super.code) : super.fromCode(); } -class GetIdTokenFailureFirebase extends GetIdTokenFailureInterface { - GetIdTokenFailureFirebase([String? code, String? msg]) +/// {@macro reauthenticate_failure} +class ReauthenticateFailureFirebase extends ReauthenticateFailureInterface { + ReauthenticateFailureFirebase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + ReauthenticateFailureFirebase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'user-mismatch': + msg = 'Given credential does not correspond to the user.'; + break; + case 'user-not-found': + msg = 'User is not found, please create an account.'; + break; + case 'invalid-credential': + msg = 'The credential received is malformed or has expired.'; + break; + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + case 'invalid-verification-code': + msg = 'The credential verification code received is invalid.'; + break; + case 'invalid-verification-id': + msg = 'The credential verification ID received is invalid.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_email_failure} +class UpdateEmailFailureFirebase extends UpdateEmailFailureInterface { + UpdateEmailFailureFirebase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdateEmailFailureFirebase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'email-already-in-use': + msg = 'An account already exists for that email.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_password_failure} +class UpdatePasswordFailureFirebase extends UpdatePasswordFailureInterface { + UpdatePasswordFailureFirebase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdatePasswordFailureFirebase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'weak-password': + msg = 'Please enter a stronger password.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro model_parsing_failure} +class ModelParsingFailureFirebase extends ModelParsingFailureInterface { + ModelParsingFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); - GetIdTokenFailureFirebase.fromCode(super.code) : super.fromCode(); + ModelParsingFailureFirebase.fromCode(super.code) : super.fromCode(); +} + +/// {@macro delete_account_failure} +class DeleteAccountFailureFirebase extends DeleteAccountFailureInterface { + DeleteAccountFailureFirebase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + DeleteAccountFailureFirebase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_mock.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_mock.dart new file mode 100644 index 00000000..57a960e4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_mock.dart @@ -0,0 +1,382 @@ +// Copyright (C) 2023 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 . + +part of 'exceptions.dart'; + +/// {@macro apply_action_code_failure} +class ApplyActionCodeFailureMock extends ApplyActionCodeFailureInterface { + ApplyActionCodeFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + ApplyActionCodeFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'expired-action-code': + msg = 'Action code has expired.'; + break; + case 'invalid-action-code': + msg = 'Action code is invalid.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_up_with_email_and_password_failure} +class SignUpWithEmailAndPasswordFailureMock + extends SignUpWithEmailAndPasswordFailureInterface { + SignUpWithEmailAndPasswordFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignUpWithEmailAndPasswordFailureMock.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'The email address is badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'email-already-in-use': + msg = 'An account already exists for that email.'; + break; + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + case 'weak-password': + msg = 'Please enter a stronger password.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro fetch_sign_in_methods_failure} +class FetchSignInMethodsForEmailFailureMock + extends FetchSignInMethodsForEmailFailureInterface { + FetchSignInMethodsForEmailFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + FetchSignInMethodsForEmailFailureMock.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'The email address is badly formatted.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_anonymously_failure} +class SignInAnonymouslyFailureMock extends SignInAnonymouslyFailureInterface { + SignInAnonymouslyFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInAnonymouslyFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_credential_failure} +class SignInWithCredentialFailureMock + extends SignInWithCredentialFailureInterface { + SignInWithCredentialFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithCredentialFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'account-exists-with-different-credential': + msg = 'Account exists with different credentials.'; + break; + case 'invalid-credential': + msg = 'The credential received is malformed or has expired.'; + break; + case 'operation-not-allowed': + msg = 'Operation is not allowed. Please contact support.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + case 'invalid-verification-code': + msg = 'The credential verification code received is invalid.'; + break; + case 'invalid-verification-id': + msg = 'The credential verification ID received is invalid.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_google_failure} +class SignInWithGoogleFailureMock extends SignInWithCredentialFailureMock + implements SignInWithGoogleFailureInterface { + SignInWithGoogleFailureMock([super.code, super.msg]); + SignInWithGoogleFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_facebook_failure} +class SignInWithFacebookFailureMock extends SignInWithCredentialFailureMock + implements SignInWithFacebookFailureInterface { + SignInWithFacebookFailureMock([super.code, super.msg]); + SignInWithFacebookFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_apple_failure} +class SignInWithAppleFailureMock extends SignInWithCredentialFailureMock + implements SignInWithAppleFailureInterface { + SignInWithAppleFailureMock([super.code, super.msg]); + SignInWithAppleFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_twitter_failure} +class SignInWithTwitterFailureMock extends SignInWithCredentialFailureMock + implements SignInWithAppleFailureInterface { + SignInWithTwitterFailureMock([super.code, super.msg]); + SignInWithTwitterFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_in_with_email_link_failure} +class SignInWithEmailLinkFailureMock + extends SignInWithEmailLinkFailureInterface { + SignInWithEmailLinkFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithEmailLinkFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'expired-action-code': + msg = 'Action code has expired.'; + break; + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro sign_in_with_email_and_password_failure} +class SignInWithEmailAndPasswordFailureMock + extends SignInWithEmailAndPasswordFailureInterface { + SignInWithEmailAndPasswordFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SignInWithEmailAndPasswordFailureMock.fromCode(String code) + : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'user-disabled': + msg = 'This user has been disabled. Please contact support for help.'; + break; + case 'user-not-found': + msg = 'Email is not found, please create an account.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro send_email_verification_failure} +class SendEmailVerificationFailureMock + extends SendEmailVerificationFailureInterface { + SendEmailVerificationFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SendEmailVerificationFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro send_password_reset_email_failure} +class SendPasswordResetEmailFailureMock + extends SendPasswordResetEmailFailureInterface { + SendPasswordResetEmailFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + SendPasswordResetEmailFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro send_sign_in_link_email_failure} +class SendSignInLinkEmailFailureMock + extends SendSignInLinkEmailFailureInterface { + SendSignInLinkEmailFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SendSignInLinkEmailFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro confirm_password_reset_failure} +class ConfirmPasswordResetFailureMock + extends ConfirmPasswordResetFailureInterface { + ConfirmPasswordResetFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + ConfirmPasswordResetFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro verify_password_reset_code_failure} +class VerifyPasswordResetCodeFailureMock + extends VerifyPasswordResetCodeFailureInterface { + VerifyPasswordResetCodeFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + VerifyPasswordResetCodeFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro refresh_failure} +class RefreshFailureMock extends RefreshFailureInterface { + RefreshFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + RefreshFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro sign_out_failure} +class SignOutFailureMock extends SignOutFailureInterface { + SignOutFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + SignOutFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro reauthenticate_failure} +class ReauthenticateFailureMock extends ReauthenticateFailureInterface { + ReauthenticateFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + ReauthenticateFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'user-mismatch': + msg = 'Given credential does not correspond to the user.'; + break; + case 'user-not-found': + msg = 'User is not found, please create an account.'; + break; + case 'invalid-credential': + msg = 'The credential received is malformed or has expired.'; + break; + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'wrong-password': + msg = 'Incorrect password, please try again.'; + break; + case 'invalid-verification-code': + msg = 'The credential verification code received is invalid.'; + break; + case 'invalid-verification-id': + msg = 'The credential verification ID received is invalid.'; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_email_failure} +class UpdateEmailFailureMock extends UpdateEmailFailureInterface { + UpdateEmailFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdateEmailFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'invalid-email': + msg = 'Email is not valid or badly formatted.'; + break; + case 'email-already-in-use': + msg = 'An account already exists for that email.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro update_password_failure} +class UpdatePasswordFailureMock extends UpdatePasswordFailureInterface { + UpdatePasswordFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + UpdatePasswordFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'weak-password': + msg = 'Please enter a stronger password.'; + break; + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} + +/// {@macro model_parsing_failure} +class ModelParsingFailureMock extends ModelParsingFailureInterface { + ModelParsingFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + ModelParsingFailureMock.fromCode(super.code) : super.fromCode(); +} + +/// {@macro delete_account_failure} +class DeleteAccountFailureMock extends DeleteAccountFailureInterface { + DeleteAccountFailureMock([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + DeleteAccountFailureMock.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart b/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart new file mode 100644 index 00000000..d473dace --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart @@ -0,0 +1,98 @@ +// Copyright (C) 2023 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:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart'; +import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; + +/// Extension that helps to quickly access useful resources +/// from the context. +extension BuildContextExtension on BuildContext { + /// Read session in context from a specific AuthenticationCubit type [T] + AuthenticationSession? + readSessionFrom, Data>() => + read().currentSession(); + + /// Watch session in context from a specific AuthenticationCubit type [T] + AuthenticationSession? + watchSessionFrom, Data>() => + watch().currentSession(); + + /// Read session in context from generic AuthenticationCubit type + AuthenticationSession? readSession() => + read>().currentSession(); + + /// Watch session in context from generic AuthenticationCubit type + AuthenticationSession? watchSession() => + watch>().currentSession(); + + /// Read event in context from a specific AuthenticationCubit type [T] + AuthenticationChangeEvent? + readEventFrom, Data>() => + readSessionFrom()?.latestEvent; + + /// Watch event in context from a specific AuthenticationCubit type [T] + AuthenticationChangeEvent? + watchEventFrom, Data>() => + watchSessionFrom()?.latestEvent; + + /// Read event in context from generic AuthenticationCubit type + AuthenticationChangeEvent? readEvent() => + readSession()?.latestEvent; + + /// Watch event in context from generic AuthenticationCubit type + AuthenticationChangeEvent? watchEvent() => + watchSession()?.latestEvent; + + /// Read account in context from a specific AuthenticationCubit type [T] + Account? readAccountFrom, Data>() => + readSessionFrom()?.account; + + /// Watch account in context from a specific AuthenticationCubit type [T] + Account? watchAccountFrom, Data>() => + watchSessionFrom()?.account; + + /// Read account in context from generic AuthenticationCubit type + Account? readAccount() => readSession()?.account; + + /// Watch account in context from generic AuthenticationCubit type + Account? watchAccount() => watchSession()?.account; + + /// Read data in context from a specific AuthenticationCubit type [T] + Data? readDataFrom, Data>() => + readSessionFrom()?.data; + + /// Watch data in context from a specific AuthenticationCubit type [T] + Data? watchDataFrom, Data>() => + watchSessionFrom()?.data; + + /// Read data in context from generic AuthenticationCubit type + Data? readData() => readSession()?.data; + + /// Watch data in context from generic AuthenticationCubit type + Data? watchData() => watchSession()?.data; + + /// Check if user is authenticated from a + /// specific AuthenticationCubit type [T] + bool isAuthenticatedFrom, Data>() => + readEventFrom() is AuthenticatedChangeEvent; + + /// Check if user is authenticated from generic AuthenticationCubit type + bool isAuthenticated() => readEvent() is AuthenticatedChangeEvent; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/cryptography.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/cryptography.dart deleted file mode 100644 index f9a0b247..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/core/utils/cryptography.dart +++ /dev/null @@ -1,39 +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:convert'; -import 'dart:math'; - -import 'package:crypto/crypto.dart'; - -class Cryptography { - /// Generates a cryptographically secure random nonce, to be included in a - /// credential request. - static String generateNonce([int length = 32]) { - const charset = - '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; - final random = Random.secure(); - return List.generate(length, (_) => charset[random.nextInt(charset.length)]) - .join(); - } - - /// Returns the sha256 hash of [input] in hex notation. - static String sha256ofString(String input) { - final bytes = utf8.encode(input); - final digest = sha256.convert(bytes); - return digest.toString(); - } -} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart new file mode 100644 index 00000000..ff58f8df --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart @@ -0,0 +1,72 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// {@template custom_routine} +/// A custom routine that can be used to call a routine and +/// attach custom logic to it. +/// {@endtemplate} +class CustomRoutine { + /// {@macro custom_routine} + const CustomRoutine({ + required this.routine, + required this.attachedLogic, + required this.onError, + required this.onSuccess, + }); + + /// The routine to be called + final FutureOr> Function() routine; + + /// The custom logic to be attached to the routine + final FutureOr> Function( + Result routineResult, + ) attachedLogic; + + /// The callback to be called when an error occurs + final void Function(AppException exception) onError; + + /// The callback to be called when no error occurs + final void Function(R result, Data? data) onSuccess; + + /// Calls the routine and calls the custom attached logic + FutureOr call() async { + final result = await routine.call(); + + // Call custom logic + final customRoutineResult = await attachedLogic.call(result); + + // Check for errors + if (result.isErr) { + onError.call(result.err!); + + return; + } + if (customRoutineResult.isErr) { + onError.call(customRoutineResult.err!); + + return; + } + + // If no error + return onSuccess.call(result.ok as R, customRoutineResult.ok); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart new file mode 100644 index 00000000..ec95768b --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart @@ -0,0 +1,101 @@ +// Copyright (C) 2023 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:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +/// This class contains all the forms used in the authentication process. +abstract class Forms { + /// Builds a sign in form. + static WyattForm buildSignInForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + ) + ], + name: AuthFormName.signInForm, + ); + + /// Builds a sign up form. + static WyattForm buildSignUpForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + // ignore: strict_raw_type + List? extraSignUpInputs, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + ), + ...extraSignUpInputs ?? [] + ], + name: AuthFormName.signUpForm, + ); + + /// Builds a password reset form. + static WyattForm buildPasswordResetForm( + FormInputValidator? customEmailValidator, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + ], + name: AuthFormName.passwordResetForm, + ); + + /// Builds an edit account form. + static WyattForm buildEditAccountForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + // ignore: strict_raw_type + List? extraEditAccountInputs, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + metadata: const FormInputMetadata(isRequired: false), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + metadata: const FormInputMetadata(isRequired: false), + ), + ...extraEditAccountInputs ?? [] + ], + validationStrategy: const OnlyRequiredInputValidator(), + name: AuthFormName.editAccountForm, + ); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data.dart b/packages/wyatt_authentication_bloc/lib/src/data/data.dart index 42218c55..581cd9c5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart index 24eff56f..843f681b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,6 +14,5 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'local/authentication_cache_data_source_impl.dart'; -export 'remote/authentication_firebase_data_source_impl.dart'; -export 'remote/authentication_mock_data_source_impl.dart'; +export 'local/local.dart'; +export 'remote/remote.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart new file mode 100644 index 00000000..a02c224f --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart @@ -0,0 +1,60 @@ +// Copyright (C) 2023 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/wyatt_authentication_bloc.dart'; + +/// {@template authentication_firebase_cache_data_source_impl} +/// A data source that manages the cache strategy. +/// This implementation uses Firebase. +/// {@endtemplate} +class AuthenticationFirebaseCacheDataSourceImpl + extends AuthenticationCacheDataSource { + /// {@macro authentication_firebase_cache_data_source_impl} + AuthenticationFirebaseCacheDataSourceImpl({ + FirebaseAuth? firebaseAuth, + }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance; + + final FirebaseAuth _firebaseAuth; + + // Already done by Firebase + @override + Future cacheAccount(Account account) => Future.value(); + + @override + Future getCachedAccount() async { + final currentUser = _firebaseAuth.currentUser; + if (currentUser == null) { + return null; + } + + try { + final jwt = await currentUser.getIdToken(true); + final currentAccount = AccountModel.fromFirebaseUser( + currentUser, + accessToken: jwt, + ); + + return currentAccount; + } catch (e) { + return null; + } + } + + // Already done by Firebase + @override + Future removeCachedAccount() => Future.value(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_mock_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_mock_cache_data_source_impl.dart new file mode 100644 index 00000000..3c23a866 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_mock_cache_data_source_impl.dart @@ -0,0 +1,41 @@ +// Copyright (C) 2023 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:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_mock_cache_data_source_impl} +/// A data source that manages the cache strategy. +/// This implementation is mocked. +/// {@endtemplate} +class AuthenticationMockCacheDataSourceImpl + extends AuthenticationCacheDataSource { + /// {@macro authentication_mock_cache_data_source_impl} + AuthenticationMockCacheDataSourceImpl(); + + @override + Future cacheAccount(Account account) => Future.value(); + + /// Always returns null. + @override + Future getCachedAccount() async { + await Future.delayed(const Duration(milliseconds: 200)); + +return null; + } + + @override + Future removeCachedAccount() => Future.value(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_secure_storage_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_secure_storage_cache_data_source_impl.dart new file mode 100644 index 00000000..a59f3383 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_secure_storage_cache_data_source_impl.dart @@ -0,0 +1,75 @@ +// Copyright (C) 2023 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:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/storage.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_secure_storage_cache_data_source_impl} +/// A data source that manages the cache strategy. +/// This implementation uses Secure Storage. +/// {@endtemplate} +class AuthenticationSecureStorageCacheDataSourceImpl + extends AuthenticationCacheDataSource { + /// {@macro authentication_secure_storage_cache_data_source_impl} + const AuthenticationSecureStorageCacheDataSourceImpl({ + FlutterSecureStorage? secureStorage, + }) : _secureStorage = secureStorage ?? const FlutterSecureStorage(); + + final FlutterSecureStorage _secureStorage; + + @override + Future cacheAccount(Account account) async { + await _secureStorage.write( + key: AuthStorage.id, + value: account.id, + ); + await _secureStorage.write( + key: AuthStorage.email, + value: account.email, + ); + await _secureStorage.write( + key: AuthStorage.accessToken, + value: account.accessToken, + ); + } + + @override + Future getCachedAccount() async { + final id = await _secureStorage.read(key: AuthStorage.id); + final email = await _secureStorage.read(key: AuthStorage.email); + final accessToken = await _secureStorage.read(key: AuthStorage.accessToken); + + if (id == null || email == null || accessToken == null) { + return null; + } + + final currentAccount = AccountModel.fromSecureStorage( + id: id, + email: email, + accessToken: accessToken, + ); + + return currentAccount; + } + + @override + Future removeCachedAccount() async { + await _secureStorage.delete(key: AuthStorage.id); + await _secureStorage.delete(key: AuthStorage.email); + await _secureStorage.delete(key: AuthStorage.accessToken); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart new file mode 100644 index 00000000..1287d889 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart @@ -0,0 +1,45 @@ +// Copyright (C) 2023 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:rxdart/subjects.dart'; +import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_session_data_source.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; + +/// {@template authentication_session_data_source_impl} +/// A data source that manages the current session. +/// {@endtemplate} +class AuthenticationSessionDataSourceImpl + extends AuthenticationSessionDataSource { + /// {@macro authentication_session_data_source_impl} + AuthenticationSessionDataSourceImpl(); + + final StreamController> _sessionStream = + BehaviorSubject(); + + @override + void addSession(AuthenticationSession session) { + _sessionStream.add(session); + } + + @override + Future> currentSession() => sessionStream().last; + + @override + Stream> sessionStream() => + _sessionStream.stream.asBroadcastStream(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart new file mode 100644 index 00000000..53cb73e5 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart @@ -0,0 +1,20 @@ +// Copyright (C) 2023 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 'authentication_firebase_cache_data_source_impl.dart'; +export 'authentication_mock_cache_data_source_impl.dart'; +export 'authentication_secure_storage_cache_data_source_impl.dart'; +export 'authentication_session_data_source_impl.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_base_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_base_data_source.dart new file mode 100644 index 00000000..bbdd8dd9 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_base_data_source.dart @@ -0,0 +1,106 @@ +// Copyright (C) 2023 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:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_base_data_source} +/// Base class for custom [AuthenticationRemoteDataSource] implementations. +/// It implements all methods as throwing [UnimplementedError]s. +/// {@endtemplate} +class AuthenticationBaseDataSource + extends AuthenticationRemoteDataSource { + /// {@macro authentication_base_data_source} + const AuthenticationBaseDataSource(); + + @override + Future confirmPasswordReset({ + required String code, + required String newPassword, + }) { + throw UnimplementedError(); + } + + @override + Future delete() { + throw UnimplementedError(); + } + + @override + Future reauthenticate() { + throw UnimplementedError(); + } + + @override + Future refresh() { + throw UnimplementedError(); + } + + @override + Future sendEmailVerification() { + throw UnimplementedError(); + } + + @override + Future sendPasswordResetEmail({required String email}) { + throw UnimplementedError(); + } + + @override + Future signInAnonymously() { + throw UnimplementedError(); + } + + @override + Future signInWithEmailAndPassword({ + required String email, + required String password, + }) { + throw UnimplementedError(); + } + + @override + Future signInWithGoogle() { + throw UnimplementedError(); + } + + @override + Future signOut() { + throw UnimplementedError(); + } + + @override + Future signUpWithEmailAndPassword({ + required String email, + required String password, + }) { + throw UnimplementedError(); + } + + @override + Future updateEmail({required String email}) { + throw UnimplementedError(); + } + + @override + Future updatePassword({required String password}) { + throw UnimplementedError(); + } + + @override + Future verifyPasswordResetCode({required String code}) { + throw UnimplementedError(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart index 565b76cc..f2552b87 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,33 +14,74 @@ // 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:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:rxdart/subjects.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/src/data/models/models.dart'; +import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -class AuthenticationFirebaseDataSourceImpl - extends AuthenticationRemoteDataSource { +/// {@template authentication_firebase_data_source_impl} +/// Implementation of [AuthenticationRemoteDataSource] using Firebase. +/// {@endtemplate} +class AuthenticationFirebaseDataSourceImpl + extends AuthenticationRemoteDataSource { + /// {@macro authentication_firebase_data_source_impl} + AuthenticationFirebaseDataSourceImpl({ + FirebaseAuth? firebaseAuth, + GoogleSignIn? googleSignIn, + }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance, + _googleSignIn = googleSignIn ?? GoogleSignIn() { + _latestCredentials = BehaviorSubject(); + } + + late StreamController _latestCredentials; + final FirebaseAuth _firebaseAuth; + final GoogleSignIn _googleSignIn; - AuthenticationFirebaseDataSourceImpl({FirebaseAuth? firebaseAuth}) - : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance; + Future _addToCredentialStream( + UserCredential userCredential, + ) async { + final currentUser = _firebaseAuth.currentUser; + final jwt = await currentUser?.getIdToken(true); + final account = AccountModel.fromFirebaseUserCredential( + userCredential, + accessToken: jwt, + ); - Account _mapper(User user) => AccountModel( - uid: user.uid, - emailVerified: user.emailVerified, - isAnonymous: user.isAnonymous, - providerId: user.providerData.first.providerId, - creationTime: user.metadata.creationTime, - lastSignInTime: user.metadata.lastSignInTime, - isNewUser: (user.metadata.creationTime != null && - user.metadata.lastSignInTime != null) - ? user.metadata.lastSignInTime! == user.metadata.creationTime! - : null, - email: user.email, - phoneNumber: user.phoneNumber, - photoURL: user.photoURL, + _latestCredentials.add(userCredential); + + return account; + } + + // SignUp/SignIn methods ==================================================== + + /// {@macro signup_pwd} + @override + Future signUpWithEmailAndPassword({ + required String email, + required String password, + }) async { + try { + final userCredential = await _firebaseAuth.createUserWithEmailAndPassword( + email: email, + password: password, ); + return _addToCredentialStream(userCredential); + } on FirebaseAuthException catch (e) { + throw SignUpWithEmailAndPasswordFailureFirebase.fromCode(e.code); + } catch (_) { + throw SignUpWithEmailAndPasswordFailureFirebase(); + } + } + + /// {@macro signin_pwd} @override Future signInWithEmailAndPassword({ required String email, @@ -51,12 +92,8 @@ class AuthenticationFirebaseDataSourceImpl email: email, password: password, ); - final user = userCredential.user; - if (user.isNotNull) { - return _mapper(user!); - } else { - throw Exception(); // Get caught just after. - } + + return _addToCredentialStream(userCredential); } on FirebaseAuthException catch (e) { throw SignInWithEmailAndPasswordFailureFirebase.fromCode(e.code); } catch (_) { @@ -64,63 +101,183 @@ class AuthenticationFirebaseDataSourceImpl } } + /// {@macro signin_anom} @override - - /// {@macro signup} - Future signUp({ - required String email, - required String password, - }) async { + Future signInAnonymously() async { try { - final userCredential = await _firebaseAuth.createUserWithEmailAndPassword( - email: email, - password: password, - ); - final user = userCredential.user; - if (user.isNotNull) { - return _mapper(user!); - } else { - throw Exception(); // Get caught just after. - } + final userCredential = await _firebaseAuth.signInAnonymously(); + + return _addToCredentialStream(userCredential); } on FirebaseAuthException catch (e) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode(e.code); + throw SignInAnonymouslyFailureFirebase.fromCode(e.code); } catch (_) { - throw SignUpWithEmailAndPasswordFailureFirebase(); + throw SignInAnonymouslyFailureFirebase(); } } + /// {@macro signin_google} + @override + Future signInWithGoogle() async { + try { + // Trigger the authentication flow + final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); + + // Obtain the auth details from the request + final GoogleSignInAuthentication? googleAuth = + await googleUser?.authentication; + + // Create a new credential + final credential = GoogleAuthProvider.credential( + accessToken: googleAuth?.accessToken, + idToken: googleAuth?.idToken, + ); + + final userCredential = + await _firebaseAuth.signInWithCredential(credential); + + return _addToCredentialStream(userCredential); + } on FirebaseAuthException catch (e) { + throw SignInWithGoogleFailureFirebase.fromCode(e.code); + } catch (_) { + throw SignInWithGoogleFailureFirebase(); + } + } + + /// {@macro signout} @override Future signOut() async { try { + _latestCredentials.add(null); await _firebaseAuth.signOut(); } catch (_) { throw SignOutFailureFirebase(); } } + // Account management methods =============================================== + + /// {@macro refresh} @override - Future getIdentityToken() async { + Future refresh() async { try { - final token = await _firebaseAuth.currentUser?.getIdToken(); - if (token.isNotNull) { - return token!; - } else { - throw Exception(); // Get caught just after. - } + final jwt = await _firebaseAuth.currentUser?.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); + + return account; } on FirebaseAuthException catch (e) { - throw GetIdTokenFailureFirebase.fromCode(e.code); + throw RefreshFailureFirebase.fromCode(e.code); } catch (_) { - throw GetIdTokenFailureFirebase(); + throw RefreshFailureFirebase(); } } + /// {@macro reauthenticate} @override - Stream streamAccount() => - _firebaseAuth.userChanges().map((user) { - final Account? account = (user.isNotNull) ? _mapper(user!) : null; - return account; - }); + Future reauthenticate() async { + final latestCreds = + await _latestCredentials.stream.asBroadcastStream().last; + try { + if (latestCreds?.credential != null) { + await _firebaseAuth.currentUser + ?.reauthenticateWithCredential(latestCreds!.credential!); + } else { + throw Exception(); // Get caught just after. + } + final jwt = await _firebaseAuth.currentUser?.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); + + return account; + } on FirebaseAuthException catch (e) { + throw ReauthenticateFailureFirebase.fromCode(e.code); + } catch (_) { + throw ReauthenticateFailureFirebase(); + } + } + + /// {@macro update_email} + @override + Future updateEmail({required String email}) async { + try { + await _firebaseAuth.currentUser!.updateEmail(email); + final jwt = await _firebaseAuth.currentUser!.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); + + return account; + } on FirebaseAuthException catch (e) { + throw UpdateEmailFailureFirebase.fromCode(e.code); + } catch (_) { + throw UpdateEmailFailureFirebase(); + } + } + + /// {@macro update_password} + @override + Future updatePassword({required String password}) async { + try { + await _firebaseAuth.currentUser!.updatePassword(password); + final jwt = await _firebaseAuth.currentUser!.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); + + return account; + } on FirebaseAuthException catch (e) { + throw UpdatePasswordFailureFirebase.fromCode(e.code); + } catch (_) { + throw UpdatePasswordFailureFirebase(); + } + } + + /// {@macro delete} + @override + Future delete() async { + try { + await _firebaseAuth.currentUser!.delete(); + } on FirebaseAuthException catch (e) { + throw DeleteAccountFailureFirebase.fromCode(e.code); + } catch (_) { + throw DeleteAccountFailureFirebase(); + } + } + + // Email related stuff ====================================================== + + /// {@macro send_email_verification} + @override + Future sendEmailVerification() async { + try { + await _firebaseAuth.currentUser!.sendEmailVerification(); + } on FirebaseAuthException catch (e) { + throw SendEmailVerificationFailureFirebase.fromCode(e.code); + } catch (_) { + throw SendEmailVerificationFailureFirebase(); + } + } + + /// {@macro send_password_reset_email} + @override + Future sendPasswordResetEmail({required String email}) async { + try { + await _firebaseAuth.sendPasswordResetEmail(email: email); + } on FirebaseAuthException catch (e) { + throw SendPasswordResetEmailFailureFirebase.fromCode(e.code); + } catch (_) { + throw SendPasswordResetEmailFailureFirebase(); + } + } + + /// {@macro confirm_password_reset} @override Future confirmPasswordReset({ required String code, @@ -138,45 +295,7 @@ class AuthenticationFirebaseDataSourceImpl } } - @override - Future sendEmailVerification() async { - try { - await _firebaseAuth.currentUser!.sendEmailVerification(); - } on FirebaseAuthException catch (e) { - throw SendEmailVerificationFailureFirebase.fromCode(e.code); - } catch (_) { - throw SendEmailVerificationFailureFirebase(); - } - } - - @override - Future sendPasswordResetEmail({required String email}) async { - try { - await _firebaseAuth.sendPasswordResetEmail(email: email); - } on FirebaseAuthException catch (e) { - throw SendPasswordResetEmailFailureFirebase.fromCode(e.code); - } catch (_) { - throw SendPasswordResetEmailFailureFirebase(); - } - } - - @override - Future signInAnonymously() async { - try { - final userCredential = await _firebaseAuth.signInAnonymously(); - final user = userCredential.user; - if (user.isNotNull) { - return _mapper(user!); - } else { - throw Exception(); // Get caught just after. - } - } on FirebaseAuthException catch (e) { - throw SignInAnonymouslyFailureFirebase.fromCode(e.code); - } catch (_) { - throw SignInAnonymouslyFailureFirebase(); - } - } - + /// {@macro verify_password_reset_code} @override Future verifyPasswordResetCode({required String code}) async { try { @@ -188,15 +307,4 @@ class AuthenticationFirebaseDataSourceImpl throw VerifyPasswordResetCodeFailureFirebase(); } } - - @override - Future refresh() async { - try { - await _firebaseAuth.currentUser!.reload(); - } on FirebaseAuthException catch (e) { - throw RefreshFailureFirebase.fromCode(e.code); - } catch (_) { - throw RefreshFailureFirebase(); - } - } } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart index 1a7fa1d5..ff876dd5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,26 +14,37 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'dart:async'; import 'dart:math'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource { - Pair? _connectedMock; - Pair? _registeredMock; - final StreamController _streamAccount = StreamController() - ..add(null); - - final List>? registeredAccounts; - final String idToken; - +/// {@template authentication_mock_data_source_impl} +/// Implementation of [AuthenticationRemoteDataSource] using Mocks. +/// {@endtemplate} +class AuthenticationMockDataSourceImpl + extends AuthenticationRemoteDataSource { + /// {@macro authentication_mock_data_source_impl} AuthenticationMockDataSourceImpl({ - this.idToken = 'fake-id-token', - this.registeredAccounts, + this.mockData = const { + 'test@test.fr': Pair('test12', '1'), + 'alice@test.fr': Pair('alice12', '2'), + 'bob@test.fr': Pair('bob1234', '3'), + }, + this.accessToken = 'mock_access_token', }); + /// Mock data. + /// Format: > + final Map> mockData; + + /// Current user. + Account? _currentUser; + + /// Access token. + final String accessToken; + + /// A random delay to simulate network latency. Future _randomDelay() async { await Future.delayed( Duration(milliseconds: Random().nextInt(400) + 200), @@ -41,167 +52,150 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource { return; } + // SignUp/SignIn methods ==================================================== + + /// {@macro signup_pwd} @override - Future confirmPasswordReset({ - required String code, - required String newPassword, + Future signUpWithEmailAndPassword({ + required String email, + required String password, }) async { await _randomDelay(); - } + mockData[email] = Pair(password, '4'); - @override - Future getIdentityToken() async { - await _randomDelay(); - return idToken; - } - - @override - Future refresh() async { - await _randomDelay(); - if (_connectedMock.isNull) { - throw RefreshFailureFirebase(); - } - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?) - ?.copyWith(lastSignInTime: refresh); - _connectedMock = _connectedMock?.copyWith(left: mock); - _streamAccount.add(mock); - } - - @override - Future sendEmailVerification() async { - await _randomDelay(); - if (_connectedMock.isNotNull) { - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?)?.copyWith( - emailVerified: false, - lastSignInTime: refresh, - ); - _streamAccount.add(mock); - _connectedMock = _connectedMock?.copyWith(left: mock); - return; - } - throw SendEmailVerificationFailureFirebase(); - } - - @override - Future sendPasswordResetEmail({required String email}) async { - await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - return; - } - } - if (_registeredMock.isNotNull) { - if (_registeredMock?.left?.email != email) { - throw SendPasswordResetEmailFailureFirebase(); - } - return; - } - throw SendPasswordResetEmailFailureFirebase(); - } - - @override - Future signInAnonymously() async { - await _randomDelay(); - final creation = DateTime.now(); - final mock = AccountModel( - uid: 'mock-id-anom', + return _currentUser = Account( + id: '4', + isAnonymous: false, emailVerified: false, - isAnonymous: true, - providerId: 'wyatt', - creationTime: creation, - lastSignInTime: creation, - isNewUser: creation == creation, + providerId: 'mock', + email: email, + accessToken: accessToken, ); - _streamAccount.add(mock); - _connectedMock = _connectedMock?.copyWith(left: mock); - return Future.value(mock); } + /// {@macro signin_pwd} @override Future signInWithEmailAndPassword({ required String email, required String password, }) async { await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - final account = accounts?.first; - if (account?.right != password) { - throw SignInWithCredentialFailureFirebase.fromCode('wrong-password'); - } - _streamAccount.add(account!.left); - _connectedMock = account.copyWith(); - return account.left!; - } + final pair = mockData[email]; + + if (pair == null || pair.left != password) { + throw SignInWithEmailAndPasswordFailureMock(); } - if (_registeredMock.isNotNull) { - if (_registeredMock?.left?.email != email) { - throw SignInWithCredentialFailureFirebase.fromCode('user-not-found'); - } - if (_registeredMock?.right != password) { - throw SignInWithCredentialFailureFirebase.fromCode('wrong-password'); - } - _streamAccount.add(_registeredMock!.left); - _connectedMock = _registeredMock!.copyWith(); - return _registeredMock!.left!; - } - throw SignInWithCredentialFailureFirebase(); + + return _currentUser = Account( + id: pair.right!, + isAnonymous: false, + emailVerified: true, + providerId: 'mock', + email: email, + accessToken: accessToken, + ); } + /// {@macro signin_anom} + @override + Future signInAnonymously() async { + await _randomDelay(); + return _currentUser = Account( + id: '5', + isAnonymous: true, + emailVerified: false, + providerId: 'mock', + accessToken: accessToken, + ); + } + + /// {@macro signin_google} + @override + Future signInWithGoogle() async { + await _randomDelay(); + return _currentUser = Account( + id: '6', + isAnonymous: false, + emailVerified: true, + providerId: 'google.com', + email: 'mock@gmail.com', + accessToken: accessToken, + ); + } + + /// {@macro signout} @override Future signOut() async { - _connectedMock = null; - _streamAccount.add(null); - } - - @override - Future signUp({ - required String email, - required String password, - }) async { await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode( - 'email-already-in-use', - ); - } - } - if (_registeredMock?.left?.email == email) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode( - 'email-already-in-use', - ); - } - final creation = DateTime.now(); - final mock = AccountModel( - uid: 'mock-id-email', - emailVerified: false, - isAnonymous: false, - providerId: 'wyatt', - email: email, - creationTime: creation, - lastSignInTime: creation, - isNewUser: creation == creation, - ); - _streamAccount.add(mock); - _registeredMock = Pair(mock, password); - return Future.value(mock); + _currentUser = null; } - @override - Stream streamAccount() => _streamAccount.stream.asBroadcastStream(); + // Account management methods =============================================== + /// {@macro refresh} + @override + Future refresh() async { + await _randomDelay(); + if (_currentUser == null) { + throw RefreshFailureMock(); + } + return _currentUser!; + } + + /// {@macro reauthenticate} + @override + Future reauthenticate() async { + await _randomDelay(); + if (_currentUser == null) { + throw ReauthenticateFailureMock(); + } + return _currentUser!; + } + + /// {@macro update_email} + @override + Future updateEmail({required String email}) async { + throw UnimplementedError(); + } + + /// {@macro update_password} + @override + Future updatePassword({required String password}) async { + throw UnimplementedError(); + } + + /// {@macro delete} + @override + Future delete() async { + throw UnimplementedError(); + } + + // Email related stuff ====================================================== + + /// {@macro send_email_verification} + @override + Future sendEmailVerification() async { + throw UnimplementedError(); + } + + /// {@macro send_password_reset_email} + @override + Future sendPasswordResetEmail({required String email}) async { + throw UnimplementedError(); + } + + /// {@macro confirm_password_reset} + @override + Future confirmPasswordReset({ + required String code, + required String newPassword, + }) async { + throw UnimplementedError(); + } + + /// {@macro verify_password_reset_code} @override Future verifyPasswordResetCode({required String code}) async { - await _randomDelay(); - return true; + throw UnimplementedError(); } } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart new file mode 100644 index 00000000..e76b675f --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart @@ -0,0 +1,19 @@ +// Copyright (C) 2023 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 'authentication_base_data_source.dart'; +export 'authentication_firebase_data_source_impl.dart'; +export 'authentication_mock_data_source_impl.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart index d886d329..683dd500 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart @@ -1,5 +1,4 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,73 +14,111 @@ // 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/core/exceptions/exceptions.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +/// {@template account_model} +/// Account Model to parse Firebase User data +/// {@endtemplate} class AccountModel extends Account { - @override - final String uid; + /// {@macro account_model} + factory AccountModel.fromFirebaseUserCredential( + UserCredential? userCredential, { + required String? accessToken, + }) { + final user = userCredential?.user; + if (user != null) { + final providerId = + (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; + return AccountModel._( + user: user, + id: user.uid, + emailVerified: user.emailVerified, + isAnonymous: user.isAnonymous, + providerId: providerId, + creationTime: user.metadata.creationTime, + lastSignInTime: user.metadata.lastSignInTime, + isNewUser: userCredential?.additionalUserInfo?.isNewUser, + email: user.email, + phoneNumber: user.phoneNumber, + photoURL: user.photoURL, + accessToken: accessToken, + ); + } else { + throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); + } + } - @override - final String? email; + /// {@macro account_model} + factory AccountModel.fromFirebaseUser( + User? user, { + required String? accessToken, + }) { + if (user != null) { + final providerId = + (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; + return AccountModel._( + user: user, + id: user.uid, + emailVerified: user.emailVerified, + isAnonymous: user.isAnonymous, + providerId: providerId, + creationTime: user.metadata.creationTime, + lastSignInTime: user.metadata.lastSignInTime, + isNewUser: false, + email: user.email, + phoneNumber: user.phoneNumber, + photoURL: user.photoURL, + accessToken: accessToken, + ); + } else { + throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); + } + } - @override - final DateTime? creationTime; + /// {@macro account_model} + factory AccountModel.fromSecureStorage({ + required String? id, + required String? email, + required String? accessToken, + }) { + if (id != null && email != null && accessToken != null) { + return AccountModel._( + user: null, + id: id, + emailVerified: false, + isAnonymous: false, + providerId: '', + email: email, + accessToken: accessToken, + ); + } else { + throw Exception( + 'null-id-email-access-token' + 'id, email, and accessToken cannot be null', + ); + } + } - @override - final bool emailVerified; - - @override - final bool isAnonymous; - - @override - final bool? isNewUser; - - @override - final DateTime? lastSignInTime; - - @override - final String? phoneNumber; - - @override - final String? photoURL; - - @override - final String providerId; - - AccountModel({ - required this.uid, - required this.emailVerified, - required this.isAnonymous, - required this.providerId, - this.lastSignInTime, - this.creationTime, - this.isNewUser, - this.email, - this.phoneNumber, - this.photoURL, + const AccountModel._({ + required this.user, + required super.id, + required super.emailVerified, + required super.isAnonymous, + required super.providerId, + super.lastSignInTime, + super.creationTime, + super.isNewUser, + super.email, + super.phoneNumber, + super.photoURL, + super.accessToken, }); - AccountModel copyWith({ - String? uid, - String? email, - DateTime? creationTime, - bool? emailVerified, - bool? isAnonymous, - bool? isNewUser, - DateTime? lastSignInTime, - String? phoneNumber, - String? photoURL, - String? providerId, - }) => AccountModel( - uid: uid ?? this.uid, - email: email ?? this.email, - creationTime: creationTime ?? this.creationTime, - emailVerified: emailVerified ?? this.emailVerified, - isAnonymous: isAnonymous ?? this.isAnonymous, - isNewUser: isNewUser ?? this.isNewUser, - lastSignInTime: lastSignInTime ?? this.lastSignInTime, - phoneNumber: phoneNumber ?? this.phoneNumber, - photoURL: photoURL ?? this.photoURL, - providerId: providerId ?? this.providerId, - ); + /// The Firebase User + final User? user; + + @override + String? get refreshToken => user?.refreshToken; } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart index 09cc76bf..3efbdbc0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart @@ -1,18 +1,17 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 'account_model.dart'; -export 'account_wrapper_model.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart index f5653592..9b8bc99a 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,102 +14,150 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'dart:async'; - -import 'package:rxdart/rxdart.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; -import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; -import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; -import 'package:wyatt_authentication_bloc/src/data/models/account_wrapper_model.dart'; -import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_cache_data_source.dart'; -import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; -import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/forms.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -typedef OnSignUpSuccess = FutureOrResult Function( - AuthenticationRepository repo, - Account? account, - WyattForm form, -); - -typedef OnAuthChange = FutureOrResult Function( - AuthenticationRepository repo, - Account? account, -); - -class AuthenticationRepositoryImpl - extends AuthenticationRepository { - final AuthenticationCacheDataSource _authenticationLocalDataSource; - final AuthenticationRemoteDataSource _authenticationRemoteDataSource; - - late FormRepository _formRepository; - - final OnSignUpSuccess? _onSignUpSuccess; - - final OnAuthChange? _onAccountChanges; - final StreamController>> _signUpStream = - StreamController(); - - bool _pause = false; // Semaphore - +/// {@template authentication_repository_impl} +/// The default implementation of [AuthenticationRepository]. +/// {@endtemplate} +class AuthenticationRepositoryImpl + extends AuthenticationRepository { + /// {@macro authentication_repository_impl} AuthenticationRepositoryImpl({ - required AuthenticationCacheDataSource authenticationCacheDataSource, - required AuthenticationRemoteDataSource authenticationRemoteDataSource, + required this.authenticationRemoteDataSource, + required this.authenticationCacheDataSource, + required this.authenticationSessionDataSource, FormRepository? formRepository, // ignore: strict_raw_type List? extraSignUpInputs, + // ignore: strict_raw_type + List? extraEditAccountInputs, FormInputValidator? customEmailValidator, FormInputValidator? customPasswordValidator, - OnSignUpSuccess? onSignUpSuccess, - OnAuthChange? onAuthChange, - }) : _authenticationLocalDataSource = authenticationCacheDataSource, - _authenticationRemoteDataSource = authenticationRemoteDataSource, - _onSignUpSuccess = onSignUpSuccess, - _onAccountChanges = onAuthChange { + }) { _formRepository = formRepository ?? FormRepositoryImpl(); + if (formRepository != null) { return; } _formRepository ..registerForm( - WyattFormImpl( - [ - FormInput( - AuthFormField.email, - customEmailValidator ?? const Email.pure(), - ), - FormInput( - AuthFormField.password, - customPasswordValidator ?? const Password.pure(), - ) - ], - name: AuthFormName.signInForm, + Forms.buildSignUpForm( + customEmailValidator, + customPasswordValidator, + extraSignUpInputs, ), ) ..registerForm( - WyattFormImpl( - [ - FormInput( - AuthFormField.email, - customEmailValidator ?? const Email.pure(), - ), - FormInput( - AuthFormField.password, - customPasswordValidator ?? const Password.pure(), - ), - ...extraSignUpInputs ?? [] - ], - name: AuthFormName.signUpForm, + Forms.buildSignInForm( + customEmailValidator, + customPasswordValidator, + ), + ) + ..registerForm( + Forms.buildPasswordResetForm(customEmailValidator), + ) + ..registerForm( + Forms.buildEditAccountForm( + customEmailValidator, + customPasswordValidator, + extraEditAccountInputs, ), ); } + /// The remote data source used to perform the authentication process. + final AuthenticationRemoteDataSource authenticationRemoteDataSource; + + /// The cache data source used to cache the current account. + final AuthenticationCacheDataSource authenticationCacheDataSource; + + /// The session data source used to manage the current session. + final AuthenticationSessionDataSource authenticationSessionDataSource; + + late FormRepository _formRepository; + + /// {@macro form_repo} @override FormRepository get formRepository => _formRepository; + // Cache related methods ==================================================== + + /// {@macro check_cache_account} + @override + Future checkForCachedAccount() async { + final cachedAccount = + await authenticationCacheDataSource.getCachedAccount(); + + if (cachedAccount == null) { + addSession( + const AuthenticationSession( + latestEvent: UnknownAuthenticationEvent(), + ), + ); + return; + } + + addSession( + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: cachedAccount), + ), + ); + return; + } + + // Session related methods =================================================== + + /// {@macro add_session} + @override + void addSession(AuthenticationSession session) => + authenticationSessionDataSource.addSession(session); + + /// {@macro session_stream} + @override + Stream> sessionStream() => + authenticationSessionDataSource.sessionStream(); + + /// {@macro current_session} + @override + FutureOrResult> currentSession() => + Result.tryCatchAsync, AppException, + AppException>( + () async { + final session = + await authenticationSessionDataSource.currentSession(); + + return session; + }, + (error) => error, + ); + + // SignUp/SignIn methods ==================================================== + + /// {@macro signup_pwd} + @override + FutureOrResult signUpWithEmailAndPassword({ + required String email, + required String password, + }) => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signUpWithEmailAndPassword( + email: email, + password: password, + ); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); + return account; + }, + (error) => error, + ); + + /// {@macro signin_pwd} @override FutureOrResult signInWithEmailAndPassword({ required String email, @@ -118,137 +166,149 @@ class AuthenticationRepositoryImpl Result.tryCatchAsync( () async { final account = - await _authenticationRemoteDataSource.signInWithEmailAndPassword( + await authenticationRemoteDataSource.signInWithEmailAndPassword( email: email, password: password, ); - await _authenticationLocalDataSource.storeAccount(account); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); return account; }, (error) => error, ); + /// {@macro signin_anom} + @override + FutureOrResult signInAnonymously() => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signInAnonymously(); + return account; + }, + (error) => error, + ); + + /// {@macro signin_google} + @override + FutureOrResult signInWithGoogle() => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signInWithGoogle(); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); + return account; + }, + (error) => error, + ); + + /// {@macro signout} @override FutureOrResult signOut() => Result.tryCatchAsync( () async { - await _authenticationRemoteDataSource.signOut(); - await _authenticationLocalDataSource.destroy(); + await authenticationRemoteDataSource.signOut(); + // Remove the cached account + await authenticationCacheDataSource.removeCachedAccount(); }, (error) => error, ); + // Account management methods =============================================== + + /// {@macro refresh} @override - FutureOrResult signUp({ - required String email, - required String password, - }) => + FutureOrResult refresh() => Result.tryCatchAsync( () async { - _pause = true; - final account = await _authenticationRemoteDataSource.signUp( - email: email, - password: password, - ); - await _authenticationLocalDataSource.storeAccount(account); - if (_onSignUpSuccess.isNotNull) { - final dataResult = await _onSignUpSuccess!.call( - this, - account, - _formRepository.accessForm(AuthFormName.signUpForm).clone(), - ); - await dataResult.foldAsync( - (data) async { - await _authenticationLocalDataSource.storeData(data); - _signUpStream - .add(Future.value(Ok(AccountWrapperModel(account, data)))); - }, - (error) async => error, - ); - } - _pause = false; + final account = await authenticationRemoteDataSource.refresh(); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); return account; }, - (error) { - _pause = false; - return error; - }, - ); - - @override - FutureOrResult destroyCache() => - Result.tryCatchAsync( - _authenticationLocalDataSource.destroy, (error) => error, ); + /// {@macro reauthenticate} @override - FutureOrResult> getCache() => - Result.tryCatchAsync, AppException, AppException>( - _authenticationLocalDataSource.load, - (error) => error, - ); - - @override - FutureOrResult getAccount() => + FutureOrResult reauthenticate() => Result.tryCatchAsync( - _authenticationLocalDataSource.loadAccount, - (error) => error, - ); - - @override - FutureOrResult setAccount( - Account account, - ) => - Result.tryCatchAsync( () async { - await _authenticationLocalDataSource.storeAccount(account); + final account = await authenticationRemoteDataSource.reauthenticate(); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); + return account; }, (error) => error, ); + /// {@macro update_email} @override - FutureOrResult getData() => - Result.tryCatchAsync( - _authenticationLocalDataSource.loadData, - (error) => error, - ); - - @override - FutureOrResult setData( - T? data, - ) => - Result.tryCatchAsync( + FutureOrResult updateEmail({required String email}) => + Result.tryCatchAsync( () async { - await _authenticationLocalDataSource.storeData(data); + final account = + await authenticationRemoteDataSource.updateEmail(email: email); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); + return account; }, (error) => error, ); + /// {@macro update_password} @override - FutureOrResult getIdentityToken() => - Result.tryCatchAsync( - _authenticationRemoteDataSource.getIdentityToken, - (error) => error, - ); - - @override - Stream>> streamAccount() => MergeStream([ - _signUpStream.stream.asBroadcastStream(), - _authenticationRemoteDataSource.streamAccount().map((account) async { - if (_onAccountChanges.isNotNull && !_pause) { - final dataResult = await _onAccountChanges!.call(this, account); - return dataResult.map((data) { - _authenticationLocalDataSource.storeData(data); - return AccountWrapperModel(account, data); - }); - } - return Ok, AppException>( - AccountWrapperModel(account, null), + FutureOrResult updatePassword({required String password}) => + Result.tryCatchAsync( + () async { + final account = await authenticationRemoteDataSource.updatePassword( + password: password, ); - }) - ]); + // Cache the account + await authenticationCacheDataSource.cacheAccount(account); + return account; + }, + (error) => error, + ); + /// {@macro delete} + @override + FutureOrResult delete() => + Result.tryCatchAsync( + () async { + await authenticationRemoteDataSource.delete(); + // Remove the cached account + await authenticationCacheDataSource.removeCachedAccount(); + }, + (error) => error, + ); + + // Email related stuff ====================================================== + + /// {@macro send_email_verification} + @override + FutureOrResult sendEmailVerification() => + Result.tryCatchAsync( + () async { + await authenticationRemoteDataSource.sendEmailVerification(); + }, + (error) => error, + ); + + /// {@macro send_password_reset_email} + @override + FutureOrResult sendPasswordResetEmail({required String email}) => + Result.tryCatchAsync( + () async { + await authenticationRemoteDataSource.sendPasswordResetEmail( + email: email, + ); + }, + (error) => error, + ); + + /// {@macro confirm_password_reset} @override FutureOrResult confirmPasswordReset({ required String code, @@ -256,7 +316,7 @@ class AuthenticationRepositoryImpl }) => Result.tryCatchAsync( () async { - await _authenticationRemoteDataSource.confirmPasswordReset( + await authenticationRemoteDataSource.confirmPasswordReset( code: code, newPassword: newPassword, ); @@ -264,54 +324,15 @@ class AuthenticationRepositoryImpl (error) => error, ); - @override - FutureOrResult sendEmailVerification() => - Result.tryCatchAsync( - () async { - await _authenticationRemoteDataSource.sendEmailVerification(); - }, - (error) => error, - ); - - @override - FutureOrResult sendPasswordResetEmail({required String email}) => - Result.tryCatchAsync( - () async { - await _authenticationRemoteDataSource.sendPasswordResetEmail( - email: email, - ); - }, - (error) => error, - ); - - @override - FutureOrResult signInAnonymously() => - Result.tryCatchAsync( - () async { - final account = - await _authenticationRemoteDataSource.signInAnonymously(); - return account; - }, - (error) => error, - ); - + /// {@macro verify_password_reset_code} @override FutureOrResult verifyPasswordResetCode({required String code}) => Result.tryCatchAsync( () async { - final response = await _authenticationRemoteDataSource + final response = await authenticationRemoteDataSource .verifyPasswordResetCode(code: code); return response; }, (error) => error, ); - - @override - FutureOrResult refresh() => - Result.tryCatchAsync( - () async { - await _authenticationRemoteDataSource.refresh(); - }, - (error) => error, - ); } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart index 7858c9e7..0081a38c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart index 11efe02d..843f681b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,5 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'local/authentication_cache_data_source.dart'; -export 'remote/authentication_remote_data_source.dart'; +export 'local/local.dart'; +export 'remote/remote.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart index c4d357e5..911ec217 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,14 +16,25 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; -abstract class AuthenticationCacheDataSource - extends BaseLocalDataSource { - Future storeAccount(Account? account); - Future storeData(T? data); - Future loadAccount(); - Future loadData(); - Future> load(); - Future destroy(); +/// {@template authentication_cache_data_source} +/// A data source that manages the cache strategy. +/// {@endtemplate} +abstract class AuthenticationCacheDataSource extends BaseLocalDataSource { + /// {@macro authentication_cache_data_source} + const AuthenticationCacheDataSource(); + + /// Returns the cached account if it exists. + Future getCachedAccount(); + + /// Adds the current account to the cache. + /// + /// If an account is already cached, it will be replaced. + Future cacheAccount(Account account); + + /// Removes the current account from the cache. + /// + /// The cache will be empty after this operation. + /// If no account is cached, nothing will happen. + Future removeCachedAccount(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart new file mode 100644 index 00000000..c24d859a --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart @@ -0,0 +1,36 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_session_data_source} +/// A data source that manages the current session. +/// {@endtemplate} +abstract class AuthenticationSessionDataSource + extends BaseLocalDataSource { + /// {@macro authentication_session_data_source} + const AuthenticationSessionDataSource(); + + /// Adds a new session to the data source. + void addSession(AuthenticationSession session); + + /// Returns a stream of sessions. + Stream> sessionStream(); + + /// Returns the current session. + Future> currentSession(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart new file mode 100644 index 00000000..739d4717 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart @@ -0,0 +1,18 @@ +// Copyright (C) 2023 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 'authentication_cache_data_source.dart'; +export 'authentication_session_data_source.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart index 755aa157..8d9afab5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,35 +17,70 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource { - Future signUp({ +/// {@template authentication_remote_data_source} +/// A remote data source for authentication. +/// It is responsible for all the external communication with the authentication +/// providers. +/// {@endtemplate} +abstract class AuthenticationRemoteDataSource + extends BaseRemoteDataSource { + /// {@macro authentication_remote_data_source} + const AuthenticationRemoteDataSource(); + + // SignUp/SignIn methods ==================================================== + + /// Sign up with email and password. + Future signUpWithEmailAndPassword({ required String email, required String password, }); + /// Sign in with email and password. Future signInWithEmailAndPassword({ required String email, required String password, }); + /// Sign in anonymously. + Future signInAnonymously(); + + /// Sign in with Google. + Future signInWithGoogle(); + + /// Sign out. Future signOut(); - Future refresh(); + // Account management methods =============================================== - Stream streamAccount(); + /// Refresh the current account. + Future refresh(); - Future getIdentityToken(); + /// Reauthenticate the current account. + Future reauthenticate(); + /// Update the current account's email. + Future updateEmail({required String email}); + + /// Update the current account's password. + Future updatePassword({required String password}); + + /// Delete the current account. + Future delete(); + + // Email related stuff ====================================================== + + /// Send an email verification. Future sendEmailVerification(); + /// Send a password reset email. Future sendPasswordResetEmail({required String email}); + /// Confirm password reset. Future confirmPasswordReset({ required String code, required String newPassword, }); + /// Verify password reset code. Future verifyPasswordResetCode({required String code}); - - Future signInAnonymously(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart new file mode 100644 index 00000000..7d684507 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart @@ -0,0 +1,17 @@ +// Copyright (C) 2023 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 'authentication_remote_data_source.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart b/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart index 7727f7ee..25af7843 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart index 5723d3a5..c0186496 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,67 +17,91 @@ import 'package:equatable/equatable.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; -abstract class Account extends Equatable implements Entity { +/// {@template account} +/// Represents a user [Account] in the +/// various identity provisioning systems. +/// {@endtemplate} +class Account extends Equatable implements Entity { + /// {@macro account} + const Account({ + required this.id, + required this.isAnonymous, + required this.emailVerified, + required this.providerId, + this.email, + this.phoneNumber, + this.photoURL, + this.creationTime, + this.lastSignInTime, + this.isNewUser, + this.accessToken, + this.refreshToken, + }); + /// The user's unique ID. - String get uid; + final String id; + + /// Returns whether the user is a anonymous. + final bool isAnonymous; /// The users email address. /// /// Will be `null` if signing in anonymously. - String? get email; + final String? email; /// Returns whether the users email address has been verified. /// /// To send a verification email, see `SendEmailVerification`. - bool get emailVerified; - - /// Returns whether the user is a anonymous. - bool get isAnonymous; - - /// Returns the users account creation time. - /// - /// When this account was created as dictated by the server clock. - DateTime? get creationTime; - - /// When the user last signed in as dictated by the server clock. - DateTime? get lastSignInTime; + final bool emailVerified; /// Returns the users phone number. /// /// This property will be `null` if the user has not signed in or been has /// their phone number linked. - String? get phoneNumber; + final String? phoneNumber; /// Returns a photo URL for the user. /// /// This property will be populated if the user has signed in or been linked /// with a 3rd party OAuth provider (such as Google). - String? get photoURL; + final String? photoURL; - /// The provider ID for the user. - String get providerId; + /// Returns the users account creation time. + /// + /// When this account was created as dictated by the server clock. + final DateTime? creationTime; + + /// When the user last signed in as dictated by the server clock. + final DateTime? lastSignInTime; /// Whether the user account has been recently created. - bool? get isNewUser; + final bool? isNewUser; + + /// The provider ID for the user. + final String providerId; + + /// The user access token + final String? accessToken; + + /// The user refresh token + final String? refreshToken; @override List get props => [ - uid, + id, + isAnonymous, email, emailVerified, - isAnonymous, - creationTime, - lastSignInTime, phoneNumber, photoURL, + creationTime, + lastSignInTime, providerId, isNewUser, + accessToken, + refreshToken, ]; @override - String toString() => 'AccountModel(uid: $uid, email: $email, ' - 'creationTime: $creationTime, emailVerified: $emailVerified, ' - 'isAnonymous: $isAnonymous, isNewUser: $isNewUser, lastSignInTime: ' - '$lastSignInTime, phoneNumber: $phoneNumber, photoURL: $photoURL, ' - 'providerId: $providerId)'; + bool get stringify => true; } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart new file mode 100644 index 00000000..bdcbff74 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart @@ -0,0 +1,69 @@ +// Copyright (C) 2023 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:equatable/equatable.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_session} +/// The [AuthenticationSession] object is used to transport and propagate +/// the last event issued by an authentication state change, a user account +/// if connected, and the associated data. +/// {@endtemplate} +class AuthenticationSession extends Equatable { + /// {@macro authentication_session} + const AuthenticationSession({ + required this.latestEvent, + this.account, + this.data, + }); + + /// Creates a new [AuthenticationSession] from an [AuthenticationChangeEvent]. + factory AuthenticationSession.fromEvent( + AuthenticationChangeEvent latestEvent, { + Data? data, + }) { + if (latestEvent is AuthenticatedChangeEvent) { + return AuthenticationSession( + latestEvent: latestEvent, + account: latestEvent.account, + data: data, + ); + } + return AuthenticationSession( + latestEvent: latestEvent, + data: data, + ); + } + + /// The last event issued by an authentication state change. + final AuthenticationChangeEvent latestEvent; + + /// The user account if connected. + final Account? account; + + /// The associated data. + final Data? data; + + @override + List get props => [ + latestEvent, + account, + data, + ]; + + @override + bool? get stringify => true; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account_wrapper.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart similarity index 59% rename from packages/wyatt_authentication_bloc/lib/src/domain/entities/account_wrapper.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart index 0788e03e..fb9487dd 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account_wrapper.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,17 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:equatable/equatable.dart'; -import 'package:wyatt_architecture/wyatt_architecture.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +part of 'authentication_change_event.dart'; -abstract class AccountWrapper extends Equatable implements Entity { - Account? get account; - T? get data; +/// {@template authenticated_change_event} +/// Represents every event where user is authenticated. +/// {@endtemplate} +abstract class AuthenticatedChangeEvent extends AuthenticationChangeEvent { + /// {@macro authenticated_change_event} + const AuthenticatedChangeEvent({required this.account}); + + /// The user's account. + final Account account; @override - List get props => [account, data]; - - @override - String toString() => 'AccountWrapper($account, data: $data)'; + List get props => [account]; } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart new file mode 100644 index 00000000..b32b68b4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart @@ -0,0 +1,45 @@ +// Copyright (C) 2023 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:equatable/equatable.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; + +part 'authenticated_change_event.dart'; +part 'deleted_event.dart'; +part 'reauthenticated_event.dart'; +part 'refreshed_event.dart'; +part 'signed_in_event.dart'; +part 'signed_in_from_cache_event.dart'; +part 'signed_out_event.dart'; +part 'signed_up_event.dart'; +part 'unknown_authentication_event.dart'; +part 'updated_event.dart'; + +/// {@template authentication_change_event} +/// Represents an event initiated by a change in +/// the user's authentication status. +/// {@endtemplate} +abstract class AuthenticationChangeEvent extends Equatable implements Entity { + /// {@macro authentication_change_event} + const AuthenticationChangeEvent(); + + @override + List get props => []; + + @override + bool get stringify => true; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart new file mode 100644 index 00000000..0ab52ae9 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template deleted_event} +/// When a user deleted his account. +/// {@endtemplate} +class DeletedEvent extends AuthenticationChangeEvent { + /// {@macro deleted_event} + const DeletedEvent(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart new file mode 100644 index 00000000..fa7e066a --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart @@ -0,0 +1,27 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template reauthenticated_event} +/// When a user re-authenticates (from the logged in state to the +/// logged in state with a different and fresh access +/// token and a different login time) +/// {@endtemplate} +class ReauthenticatedEvent extends AuthenticatedChangeEvent { + /// {@macro reauthenticated_event} + const ReauthenticatedEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart new file mode 100644 index 00000000..f765c3cc --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart @@ -0,0 +1,26 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template refreshed_event} +/// When a user access token is refreshed (from the logged in state to the +/// logged in state with a different access token) +/// {@endtemplate} +class RefreshedEvent extends AuthenticatedChangeEvent { + /// {@macro refreshed_event} + const RefreshedEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart new file mode 100644 index 00000000..17b2ae3e --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template signed_in_event} +/// When a user authenticates (from not logged in to logged in). +/// {@endtemplate} +class SignedInEvent extends AuthenticatedChangeEvent { + /// {@macro signed_in_event} + const SignedInEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart new file mode 100644 index 00000000..01bf868d --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template signed_in_from_cache_event} +/// When a user authenticates automatically (from not logged in to logged in). +/// {@endtemplate} +class SignedInFromCacheEvent extends AuthenticatedChangeEvent { + /// {@macro signed_in_from_cache_event} + const SignedInFromCacheEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart new file mode 100644 index 00000000..dc4ea4cd --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template signed_out_event} +/// When a user logs out. +/// {@endtemplate} +class SignedOutEvent extends AuthenticationChangeEvent { + /// {@macro signed_out_event} + const SignedOutEvent(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart new file mode 100644 index 00000000..f95f7e5e --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template signed_up_event} +/// When a user creates an account. +/// {@endtemplate} +class SignedUpEvent extends AuthenticatedChangeEvent { + /// {@macro signed_up_event} + const SignedUpEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart new file mode 100644 index 00000000..287b53a0 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template unknown_authentication_event} +/// When a user's login status is unknown. +/// {@endtemplate} +class UnknownAuthenticationEvent extends AuthenticationChangeEvent { + /// {@macro unknown_authentication_event} + const UnknownAuthenticationEvent(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart new file mode 100644 index 00000000..2178a56e --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 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 . + +part of 'authentication_change_event.dart'; + +/// {@template updated_event} +/// When the user's account has been updated. +/// {@endtemplate} +class UpdatedEvent extends AuthenticatedChangeEvent { + /// {@macro updated_event} + const UpdatedEvent({required super.account}); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart index 8ecf9215..a1afb54e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart @@ -1,18 +1,19 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 'account.dart'; -export 'account_wrapper.dart'; +export 'auth_session.dart'; +export 'authentication_change_event/authentication_change_event.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart index b88de024..a4f8769c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,13 +16,47 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -abstract class AuthenticationRepository extends BaseRepository { +/// {@template auth_repo} +/// Authentication repository interface. +/// {@endtemplate} +abstract class AuthenticationRepository extends BaseRepository { + /// {@template form_repo} + /// Form repository used in different authentication cubits/blocs + /// {@endtemplate} FormRepository get formRepository; - /// {@template signup} + // Cache related methods ==================================================== + + /// {@template check_cache_account} + /// Checks if there is a cached account. + /// And if there is, it will sign in the user automatically by + /// emitting an event. + /// {@endtemplate} + Future checkForCachedAccount(); + + // Session related methods =================================================== + + /// {@template add_session} + /// Add a new authentication event. + /// {@endtemplate} + void addSession(AuthenticationSession session); + + /// {@template session_stream} + /// Authentication state change event stream. + /// {@endtemplate} + Stream> sessionStream(); + + /// {@template current_session} + /// Latest session issued by the session stream. + /// {@endtemplate} + FutureOrResult> currentSession(); + + // SignUp/SignIn methods ==================================================== + + /// {@template signup_pwd} /// Creates a new user with the provided [email] and [password]. /// /// Returns the newly created user's unique identifier. @@ -30,11 +64,89 @@ abstract class AuthenticationRepository extends BaseRepository { /// Throws a SignUpWithEmailAndPasswordFailureInterface if /// an exception occurs. /// {@endtemplate} - FutureOrResult signUp({ + FutureOrResult signUpWithEmailAndPassword({ required String email, required String password, }); + /// {@template signin_pwd} + /// Signs in with the provided [email] and [password]. + /// + /// Throws a SignInWithEmailAndPasswordFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult signInWithEmailAndPassword({ + required String email, + required String password, + }); + + /// {@template signin_anom} + /// Sign in anonymously. + /// + /// Throws a SignInAnonymouslyFailureInterface if an exception occurs. + /// {@endtemplate} + FutureOrResult signInAnonymously(); + + /// {@template signin_google} + /// Starts the Sign In with Google Flow. + /// + /// Throws a SignInWithGoogleFailureInterface if an exception occurs. + /// {@endtemplate} + FutureOrResult signInWithGoogle(); + + /// {@template signout} + /// Signs out the current user. + /// It also clears the cache and the associated data. + /// {@endtemplate} + FutureOrResult signOut(); + + // Account management methods =============================================== + + /// {@template refresh} + /// Refreshes the current user, if signed in. + /// {@endtemplate} + FutureOrResult refresh(); + + /// {@template reauthenticate} + /// Some security-sensitive actions—such as deleting an account, + /// setting a primary email address, and changing a password—require that + /// the user has recently signed in. + /// + /// Throws a ReauthenticateFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult reauthenticate(); + + /// {@template update_email} + /// Update or add [email]. + /// + /// Throws a UpdateEmailFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult updateEmail({ + required String email, + }); + + /// {@template update_password} + /// Update or add [password]. + /// + /// Throws a UpdatePasswordFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult updatePassword({ + required String password, + }); + + /// {@template delete} + /// Delete account. + /// + /// Throws a DeleteAccountFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult delete(); + + // Email related stuff ====================================================== + /// {@template send_email_verification} /// Sends verification email to the account email. /// @@ -65,50 +177,4 @@ abstract class AuthenticationRepository extends BaseRepository { /// Throws a VerifyPasswordResetCodeFailureInterface if an exception occurs. /// {@endtemplate} FutureOrResult verifyPasswordResetCode({required String code}); - - /// {@template signin_anom} - /// Sign in anonymously. - /// - /// Throws a SignInAnonymouslyFailureInterface if an exception occurs. - /// {@endtemplate} - FutureOrResult signInAnonymously(); - - /// {@template signin_pwd} - /// Signs in with the provided [email] and [password]. - /// - /// Throws a SignInWithEmailAndPasswordFailureInterface if - /// an exception occurs. - /// {@endtemplate} - FutureOrResult signInWithEmailAndPassword({ - required String email, - required String password, - }); - - /// {@template signout} - /// Signs out the current user. - /// It also clears the cache and the associated data. - /// {@endtemplate} - FutureOrResult signOut(); - - FutureOrResult refresh(); - - /// {@template stream_account} - /// Stream of [AccountWrapper] which will emit the current account when - /// the authentication state changes. - /// - /// Emits [AccountWrapper] with null [Account] if the user is not - /// authenticated. - /// {@endtemplate} - Stream>> streamAccount(); - - FutureOrResult getIdentityToken(); - - FutureOrResult getAccount(); - FutureOrResult setAccount(Account account); - - FutureOrResult getData(); - FutureOrResult setData(T? data); - - FutureOrResult> getCache(); - FutureOrResult destroyCache(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart index 85f8ae88..8565338e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart index 95e85224..478b8ad0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart index 4a19e6a9..46eb0a57 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,10 +17,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; -class AuthenticationBuilder extends StatelessWidget { +/// {@template authentication_builder} +/// A widget that builds itself based on the current authentication state. +/// {@endtemplate} +class AuthenticationBuilder extends StatelessWidget { + /// {@macro authentication_builder} const AuthenticationBuilder({ required this.authenticated, required this.unauthenticated, @@ -28,20 +32,25 @@ class AuthenticationBuilder extends StatelessWidget { super.key, }); + /// Widget to show when the user is authenticated. final Widget Function( BuildContext context, - AccountWrapper accountWrapper, + AuthenticationSession session, ) authenticated; + + /// Widget to show when the user is unauthenticated. final Widget Function(BuildContext context) unauthenticated; + + /// Widget to show when the authentication status is unknown. final Widget Function(BuildContext context) unknown; @override Widget build(BuildContext context) => - BlocBuilder, AuthenticationState>( + BlocBuilder, AuthenticationState>( builder: (context, state) { if (state.status == AuthenticationStatus.authenticated) { - if (state.accountWrapper != null) { - return authenticated(context, state.accountWrapper!); + if (state.session != null) { + return authenticated(context, state.session!); } else { return unauthenticated(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 index cf648917..20b238c5 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,59 +18,176 @@ import 'dart:async'; import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart'; import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'authentication_state.dart'; -class AuthenticationCubit extends Cubit> { - final AuthenticationRepository _authenticationRepository; - +/// {@template authentication_cubit} +/// Abstract authentication cubit class needs to be implemented in application. +/// +/// This cubit is in charge of managing the global authentication state of +/// the application. +/// +/// Its here you can override every callbacks and add your custom logic. +/// {@endtemplate} +abstract class AuthenticationCubit + extends Cubit> { + /// {@macro authentication_cubit} AuthenticationCubit({ - required AuthenticationRepository authenticationRepository, - }) : _authenticationRepository = authenticationRepository, - super(const AuthenticationState.unknown()) { + required this.authenticationRepository, + this.checkForCachedAccountOnInitialization = true, + }) : super(const AuthenticationState.unknown()) { + _init(); + } + + /// The authentication repository. + final AuthenticationRepository authenticationRepository; + + /// Automatically check for cached account on initialization. + final bool checkForCachedAccountOnInitialization; + + /// The latest session. + AuthenticationSession? _latestSession; + + /// Method that is called when the cubit is initialized. + Future _init() async { + /// Setup listeners. _listenForAuthenticationChanges(); - } - void _listenForAuthenticationChanges() { - _authenticationRepository.streamAccount().listen((accountFutureResult) { - accountFutureResult.fold( - (value) { - if (value.account.isNotNull) { - emit(AuthenticationState.authenticated(value)); - return; - } - _authenticationRepository.destroyCache(); - emit(AuthenticationState.unauthenticated()); - return; - }, - (error) { - _authenticationRepository.destroyCache(); - emit(AuthenticationState.unauthenticated()); - return; - }, - ); - }); - } - - /// If authenticated, re-emits state with data freshly loaded from cache. - FutureOr reloadCache() async { - if (state.status == AuthenticationStatus.authenticated) { - final data = await _authenticationRepository.getCache(); - emit( - data.fold( - AuthenticationState.authenticated, - (error) => state, - ), - ); + /// Check if there is a cached account. + if (checkForCachedAccountOnInitialization) { + await checkForCachedAccount(); } } - FutureOr signOut() { - // TODO(hpcl): maybe force unauthenticated by emitting an event - _authenticationRepository.signOut(); + void _listenForAuthenticationChanges() { + authenticationRepository.sessionStream().asyncMap((session) async { + final event = session.latestEvent; + + /// If the session is signed in from cache. + if (event is SignedInFromCacheEvent) { + /// Call the custom routine. + final customRoutineResult = await onSignInFromCache(session); + + if (customRoutineResult.isOk) { + final account = event.account; + final sessionData = customRoutineResult.ok; + + final signedInSession = AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: sessionData, + ); + + return signedInSession; + } + } + return session; + }).listen((session) async { + /// Save the latest session. + _latestSession = session; + + /// If there is an account: emit authenticated state. + if (session.account != null) { + emit(AuthenticationState.authenticated(session)); + return; + } + + /// If there is no account: emit unauthenticated state. + emit(AuthenticationState.unauthenticated()); + + return; + }); } + + /// {@macro refresh} + FutureOr refresh() async => CustomRoutine( + routine: authenticationRepository.refresh, + attachedLogic: onRefresh, + onError: addError, + onSuccess: (result, data) => authenticationRepository.addSession( + AuthenticationSession.fromEvent( + RefreshedEvent(account: result), + data: data, + ), + ), + ).call(); + + /// {@macro reauthenticate} + FutureOr reauthenticate() async => CustomRoutine( + routine: authenticationRepository.reauthenticate, + attachedLogic: onReauthenticate, + onError: addError, + onSuccess: (result, data) => authenticationRepository.addSession( + AuthenticationSession.fromEvent( + ReauthenticatedEvent(account: result), + data: data, + ), + ), + ).call(); + + /// {@macro signout} + FutureOr signOut() async => CustomRoutine( + routine: authenticationRepository.signOut, + attachedLogic: (routineResult) => onSignOut(), + onError: addError, + onSuccess: (result, data) => authenticationRepository.addSession( + const AuthenticationSession( + latestEvent: SignedOutEvent(), + ), + ), + ).call(); + + /// {@macro delete} + FutureOr delete() async => CustomRoutine( + routine: authenticationRepository.delete, + attachedLogic: (routineResult) => onDelete(), + onError: addError, + onSuccess: (result, data) => authenticationRepository.addSession( + const AuthenticationSession( + latestEvent: DeletedEvent(), + ), + ), + ).call(); + + /// Checks for cached account. + FutureOr checkForCachedAccount() async => + authenticationRepository.checkForCachedAccount(); + + /// Returns latest session. + /// + /// Contains latest event and latest session data (account + extra data) + AuthenticationSession? currentSession() => _latestSession; + + /// This callback is triggered when the user is automaticcaly logged in from + /// the cache. + /// + /// For example: when the user is sign in from the Firebase cache. + FutureOrResult onSignInFromCache(AuthenticationSession session); + + /// This callback is triggered when the account is refreshed. + /// + /// For example: when the access token is refreshed. + FutureOrResult onRefresh(Result result); + + /// This callback is triggered when the account is re-authenticated + /// + /// For example: when the user is logged in and sign in + /// from an another provider + FutureOrResult onReauthenticate(Result result); + + /// This callback is triggered when the user is logged out. + /// + /// For example: when the user clicks on the logout button. + FutureOrResult onSignOut(); + + /// This callback is triggered when the current account is deleted from + /// the remote. + /// + /// For example: when the user wants to delete his account from Firebase + FutureOrResult onDelete(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart index bfd1e871..8a51d674 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,28 +16,37 @@ part of 'authentication_cubit.dart'; -class AuthenticationState extends Equatable { - final AuthenticationStatus status; - final AccountWrapper? accountWrapper; +/// {@template authentication_status} +/// The status of the authentication cubit. +/// {@endtemplate} +class AuthenticationState extends Equatable { + /// {@macro authentication_status} + const AuthenticationState._(this.status, this.session); - const AuthenticationState._({required this.status, this.accountWrapper}); + /// The user is not authenticated. + const AuthenticationState.unauthenticated() + : this._(AuthenticationStatus.unauthenticated, null); - const AuthenticationState.unknown() - : this._(status: AuthenticationStatus.unknown); - - const AuthenticationState.authenticated(AccountWrapper accountWrapper) + /// The user is authenticated. + const AuthenticationState.authenticated(AuthenticationSession session) : this._( - status: AuthenticationStatus.authenticated, - accountWrapper: accountWrapper, + AuthenticationStatus.authenticated, + session, ); - const AuthenticationState.unauthenticated() - : this._(status: AuthenticationStatus.unauthenticated); + /// The user's authentication status is unknown. + const AuthenticationState.unknown() + : this._(AuthenticationStatus.unknown, null); + + /// The status of the authentication cubit. + final AuthenticationStatus status; + + /// The session of the authentication cubit. + final AuthenticationSession? session; @override - List get props => [status, accountWrapper]; + List get props => [status, session]; @override - String toString() => - 'AuthenticationState(status: $status, accountWrapper: $accountWrapper)'; + bool? get stringify => true; } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart new file mode 100644 index 00000000..119e16fd --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart @@ -0,0 +1,105 @@ +// Copyright (C) 2023 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 . + +part of 'edit_account_cubit.dart'; + +/// {@template edit_account_cubit} +/// Abstract edit account cubit useful for implementing a cubit with fine +/// granularity by adding only the required mixins. +/// {@endtemplate} +abstract class BaseEditAccountCubit + extends FormDataCubit { + /// {@macro edit_account_cubit} + BaseEditAccountCubit({ + required this.authenticationRepository, + }) : super( + EditAccountState( + form: authenticationRepository.formRepository + .accessForm(AuthFormName.signInForm), + ), + ); + + /// The authentication repository. + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + + @override + String get formName => AuthFormName.signInForm; + + @override + FutureOr dataChanged( + String key, + FormInputValidator dirtyValue, + ) { + final form = formRepository.accessForm(formName).clone(); + + try { + form.updateValidator(key, dirtyValue); + formRepository.updateForm(form); + } catch (e) { + rethrow; + } + + emit( + EditAccountState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + EditAccountState(form: form, status: form.validate()), + ); + } + + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + EditAccountState(form: newForm, status: newForm.validate()), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + EditAccountState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseEditAccountCubit, ' + 'please use `updateEmail()` or `updatePassword()`.'; + emit( + EditAccountState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart new file mode 100644 index 00000000..abc378cc --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart @@ -0,0 +1,54 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/edit_account.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +part 'base_edit_account_cubit.dart'; +part 'edit_account_state.dart'; + +/// {@template edit_account_cubit} +/// Fully featured edit account cubit. +/// +/// Sufficient in most cases. (Where fine granularity is not required.) +/// {@endtemplate} +class EditAccountCubit extends BaseEditAccountCubit + with UpdateEmail, UpdatePassword { + /// {@macro edit_account_cubit} + EditAccountCubit({required super.authenticationRepository}); + + @override + FutureOrResult onEmailUpdated( + Result result, + WyattForm form, + ) => + const Ok(null); + + @override + FutureOrResult onPasswordUpdated( + Result result, + WyattForm form, + ) => + const Ok(null); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart new file mode 100644 index 00000000..d7dd5032 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart @@ -0,0 +1,55 @@ +// Copyright (C) 2023 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 . + +part of 'edit_account_cubit.dart'; + +/// {@template edit_account_state} +/// Edit account cubit state to manage the form. +/// {@endtemplate} +class EditAccountState extends FormDataState { + /// {@macro edit_account_state} + const EditAccountState({ + required super.form, + super.status = FormStatus.pure, + super.errorMessage, + }); + + /// Email validator of the form + FormInputValidator get email => + form.validatorOf(AuthFormField.email); + + /// Password validator of the form + FormInputValidator get password => + form.validatorOf(AuthFormField.password); + + EditAccountState copyWith({ + WyattForm? form, + FormStatus? status, + String? errorMessage, + }) => + EditAccountState( + form: form ?? this.form, + status: status ?? this.status, + errorMessage: errorMessage ?? this.errorMessage, + ); + + @override + List get props => [email, password, status]; + + @override + String toString() => 'EditAccountState(status: ${status.name} ' + '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)'; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart new file mode 100644 index 00000000..c755838f --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart @@ -0,0 +1,128 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Edit account mixin. +/// +/// Allows the user to edit his email +/// +/// Gives access to the `updateEmail` method and +/// `onEmailUpdated` callback. +mixin UpdateEmail on BaseEditAccountCubit { + /// This callback is triggered when user updates his email + FutureOrResult onEmailUpdated( + Result result, + WyattForm form, + ); + + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', + ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); + } + + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); + } + + /// {@macro update_email} + FutureOr updateEmail() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final email = form.valueOf(AuthFormField.email); + + if (email.isNullOrEmpty) { + emit( + EditAccountState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.updateEmail( + email: email!, + ), + attachedLogic: (routineResult) => onEmailUpdated( + routineResult, + form, + ), + onError: (error) { + emit( + EditAccountState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + UpdatedEvent(account: account), + data: data, + ), + ); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart new file mode 100644 index 00000000..31dcb20d --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart @@ -0,0 +1,127 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Edit account mixin. +/// +/// Allows the user to edit his password +/// +/// Gives access to the `updatePassword` method and +/// `onPasswordUpdated` callback. +mixin UpdatePassword on BaseEditAccountCubit { + /// This callback is triggered when a user edits his password. + FutureOrResult onPasswordUpdated( + Result result, + WyattForm form, + ); + + void passwordChanged(String value) { + final passwordValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.password) + .runtimeType; + assert( + passwordValidatorType == Password, + 'Use passwordCustomChanged(...) with validator $passwordValidatorType', + ); + final Password password = Password.dirty(value); + dataChanged(AuthFormField.password, password); + } + + /// Same as [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + /// {@macro update_password} + FutureOr updatePassword() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final password = form.valueOf(AuthFormField.password); + + if (password.isNullOrEmpty) { + emit( + EditAccountState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.updatePassword( + password: password!, + ), + attachedLogic: (routineResult) => onPasswordUpdated( + routineResult, + form, + ), + onError: (error) { + emit( + EditAccountState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + UpdatedEvent(account: account), + data: data, + ), + ); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart new file mode 100644 index 00000000..1040179f --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart @@ -0,0 +1,20 @@ +// Copyright (C) 2023 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 'cubit/edit_account_cubit.dart'; +export 'cubit/mixin/edit_email.dart'; +export 'cubit/mixin/edit_password.dart'; +export 'listener/edit_account_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart new file mode 100644 index 00000000..9adcb5ec --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart @@ -0,0 +1,82 @@ +// Copyright (C) 2023 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +/// {@template edit_account_listener} +/// Widget that listens and builds a child based on the state of +/// the edit account cubit +/// {@endtemplate} +class EditAccountListener extends StatelessWidget { + /// {@macro edit_account_listener} + const EditAccountListener({ + required this.child, + this.onProgress, + this.onSuccess, + this.onError, + this.customBuilder, + super.key, + }); + + /// Callback to show when the edit account is in progress + final void Function(BuildContext context)? onProgress; + + /// Callback to show when the edit account is successful + final void Function(BuildContext context)? onSuccess; + + /// Callback to show when the edit account is unsuccessful + final void Function( + BuildContext context, + FormStatus status, + String? errorMessage, + )? onError; + + /// Custom builder to show when the edit account is in progress, successful, + /// or unsuccessful + final void Function(BuildContext context, EditAccountState state)? + customBuilder; + + /// Child of the widget + final Widget child; + + @override + Widget build(BuildContext context) => + BlocListener, EditAccountState>( + listener: (context, state) { + if (customBuilder != null) { + return customBuilder!(context, state); + } + + if (onSuccess != null && + state.status == FormStatus.submissionSuccess) { + return onSuccess!(context); + } + if (onProgress != null && + state.status == FormStatus.submissionInProgress) { + return onProgress!(context); + } + if (onError != null && + (state.status == FormStatus.submissionCanceled || + state.status == FormStatus.submissionFailure)) { + return onError!(context, state.status, state.errorMessage); + } + }, + child: child, + ); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart index 2bb77e9c..c030260d 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,11 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/features/email_verification/cubit/email_verification_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +/// {@template email_verification_builder} +/// A widget that builds itself based on the latest [EmailVerificationState]. +/// {@endtemplate} class EmailVerificationBuilder extends StatelessWidget { + /// {@macro email_verification_builder} const EmailVerificationBuilder({ required this.verified, required this.notVerified, @@ -28,14 +32,21 @@ class EmailVerificationBuilder extends StatelessWidget { super.key, }); + /// Widget to show when the email is verified final Widget Function(BuildContext context) verified; + + /// Widget to show when the email is not verified final Widget Function(BuildContext context) notVerified; + + /// Widget to show when the email verification is unsuccessful final Widget Function( BuildContext context, FormStatus status, String? errorMessage, ) onError; + /// Custom builder to show when the email is verified, not verified, or + /// unsuccessful final Widget Function(BuildContext context, EmailVerificationState)? customBuilder; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart index ea829bb5..92227e52 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -23,21 +23,26 @@ import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; part 'email_verification_state.dart'; -class EmailVerificationCubit extends Cubit { - final AuthenticationRepository _authenticationRepository; - +/// {@template email_verification_cubit} +/// Cubit for sending email verification. +/// {@endtemplate} +class EmailVerificationCubit extends Cubit { + /// {@macro email_verification_cubit} EmailVerificationCubit({ - required AuthenticationRepository authenticationRepository, - }) : _authenticationRepository = authenticationRepository, - super(const EmailVerificationState()); + required this.authenticationRepository, + }) : super(const EmailVerificationState()); + + /// The [AuthenticationRepository] used to send email verification. + final AuthenticationRepository authenticationRepository; FutureOr sendEmailVerification() async { - emit(state.copyWith(status: FormStatus.submissionInProgress)); - final response = await _authenticationRepository.sendEmailVerification(); + emit(const EmailVerificationState(status: FormStatus.submissionInProgress)); + final response = await authenticationRepository.sendEmailVerification(); emit( response.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( + (value) => + const EmailVerificationState(status: FormStatus.submissionSuccess), + (error) => EmailVerificationState( errorMessage: error.message, status: FormStatus.submissionFailure, ), @@ -46,9 +51,9 @@ class EmailVerificationCubit extends Cubit { } FutureOr checkEmailVerification() async { - emit(state.copyWith(status: FormStatus.submissionInProgress)); + emit(const EmailVerificationState(status: FormStatus.submissionInProgress)); - final refresh = await _authenticationRepository.refresh(); + final refresh = await authenticationRepository.refresh(); if (refresh.isErr) { final refreshError = refresh.err!; emit( @@ -60,18 +65,20 @@ class EmailVerificationCubit extends Cubit { return; } - final currentAccount = await _authenticationRepository.getAccount(); - emit( - currentAccount.fold( - (value) => state.copyWith( - isVerified: value.emailVerified, + final session = await authenticationRepository.currentSession(); + final currentAccount = session.ok?.account; + if (currentAccount != null) { + emit( + EmailVerificationState( + isVerified: currentAccount.emailVerified, status: FormStatus.submissionSuccess, ), - (error) => EmailVerificationState( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); + ); + } else { + const EmailVerificationState( + errorMessage: 'No current session', + status: FormStatus.submissionFailure, + ); + } } } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart index 5f9382ac..22ac24c7 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart @@ -1,5 +1,4 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,17 +16,26 @@ part of 'email_verification_cubit.dart'; +/// {@template email_verification_state} +/// The state of the [EmailVerificationCubit]. +/// {@endtemplate} class EmailVerificationState extends Equatable { - final FormStatus status; - final bool isVerified; - final String? errorMessage; - + /// {@macro email_verification_state} const EmailVerificationState({ this.isVerified = false, this.status = FormStatus.pure, this.errorMessage, }); + /// The status of the form. + final FormStatus status; + + /// Whether the email is verified. + final bool isVerified; + + /// The error message if any. + final String? errorMessage; + EmailVerificationState copyWith({ FormStatus? status, bool? isVerified, diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart index 5624d94e..13ff15c5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/features.dart b/packages/wyatt_authentication_bloc/lib/src/features/features.dart index bd39a7f6..cbdaf015 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/features.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/features.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,6 +15,7 @@ // along with this program. If not, see . export 'authentication/authentication.dart'; +export 'edit_account/edit_account.dart'; export 'email_verification/email_verification.dart'; export 'password_reset/password_reset.dart'; export 'sign_in/sign_in.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart index 8b793973..969528e3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -24,39 +24,37 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'password_reset_state.dart'; +/// {@template password_reset_cubit} +/// Cubit that allows user to reset his password +/// {@endtemplate} class PasswordResetCubit extends FormDataCubit { - final AuthenticationRepository _authenticationRepository; - FormRepository get _formRepository => - _authenticationRepository.formRepository; - + /// {@macro password_reset_cubit} PasswordResetCubit({ - required AuthenticationRepository authenticationRepository, - }) : _authenticationRepository = authenticationRepository, - super( + required this.authenticationRepository, + }) : super( PasswordResetState( form: authenticationRepository.formRepository .accessForm(AuthFormName.passwordResetForm), ), ); + /// The repository that handles the authentication + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + @override String get formName => AuthFormName.passwordResetForm; - void emailChanged(String value) { - final Email email = Email.dirty(value); - dataChanged(AuthFormField.email, email); - } - @override FutureOr dataChanged( String key, FormInputValidator dirtyValue, ) { - final form = _formRepository.accessForm(formName).clone(); + final form = formRepository.accessForm(formName).clone(); try { form.updateValidator(key, dirtyValue); - _formRepository.updateForm(form); + formRepository.updateForm(form); } catch (e) { rethrow; } @@ -69,12 +67,39 @@ class PasswordResetCubit extends FormDataCubit { @override FutureOr reset() { final form = state.form.reset(); - _formRepository.updateForm(form); + formRepository.updateForm(form); emit( state.copyWith(form: form, status: form.validate()), ); } + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + state.copyWith( + form: newForm, + status: newForm.validate(), + ), + ); + } + + @override + FutureOr validate() { + emit( + state.copyWith( + status: formRepository.accessForm(formName).validate(), + ), + ); + } + + /// Sends a password reset email to the user @override FutureOr submit() async { if (!state.status.isValidated) { @@ -83,7 +108,7 @@ class PasswordResetCubit extends FormDataCubit { emit(state.copyWith(status: FormStatus.submissionInProgress)); - final form = _formRepository.accessForm(formName); + final form = formRepository.accessForm(formName); final email = form.valueOf(AuthFormField.email); if (email.isNullOrEmpty) { @@ -95,7 +120,7 @@ class PasswordResetCubit extends FormDataCubit { ); } - final response = await _authenticationRepository.sendPasswordResetEmail( + final response = await authenticationRepository.sendPasswordResetEmail( email: email!, ); @@ -110,29 +135,29 @@ class PasswordResetCubit extends FormDataCubit { ); } - @override - FutureOr update( - WyattForm form, { - SetOperation operation = SetOperation.replace, - }) { - final WyattForm current = _formRepository.accessForm(formName).clone(); - final WyattForm newForm = operation.operation.call(current, form); - _formRepository.updateForm(newForm); - - emit( - state.copyWith( - form: newForm, - status: newForm.validate(), - ), + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); } - @override - FutureOr validate() { - emit( - state.copyWith( - status: _formRepository.accessForm(formName).validate(), - ), - ); + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); } + + // TODO(wyatt): create base_password_reset_cubit and create mixins } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart index 8a11957d..eafbf6b6 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,15 +16,20 @@ part of 'password_reset_cubit.dart'; +/// {@template password_reset_state} +/// The state of the [PasswordResetCubit]. +/// {@endtemplate} class PasswordResetState extends FormDataState { - Email get email => form.validatorOf(AuthFormField.email); - + /// {@macro password_reset_state} const PasswordResetState({ required super.form, super.status = FormStatus.pure, super.errorMessage, }); + /// The email validator of the form. + Email get email => form.validatorOf(AuthFormField.email); + PasswordResetState copyWith({ WyattForm? form, FormStatus? status, diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart index 43919e02..f9039274 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart new file mode 100644 index 00000000..3d59bee5 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart @@ -0,0 +1,104 @@ +// Copyright (C) 2023 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 . + +part of 'sign_in_cubit.dart'; + +/// {@template sign_in_cubit} +/// Abstract sign in cubit useful for implementing a cubit with fine +/// granularity by adding only the required mixins. +/// {@endtemplate} +abstract class BaseSignInCubit extends FormDataCubit { + /// {@macro sign_in_cubit} + BaseSignInCubit({ + required this.authenticationRepository, + }) : super( + SignInState( + form: authenticationRepository.formRepository + .accessForm(AuthFormName.signInForm), + ), + ); + + /// The authentication repository. + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + + @override + String get formName => AuthFormName.signInForm; + + @override + FutureOr dataChanged( + String key, + FormInputValidator dirtyValue, + ) { + final form = formRepository.accessForm(formName).clone(); + + try { + form.updateValidator(key, dirtyValue); + formRepository.updateForm(form); + } catch (e) { + rethrow; + } + + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + SignInState(form: newForm, status: newForm.validate()), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseSignInCubit, ' + 'please use `signUpWithEmailAndPassword()`.'; + emit( + SignInState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart new file mode 100644 index 00000000..fde28872 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart @@ -0,0 +1,80 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Sign in mixin. +/// +/// Allows the user to sign in anonymously +/// +/// Gives access to the `signInAnonymously` method and +/// `onSignInAnonymously` callback. +mixin SignInAnonymously on BaseSignInCubit { + /// This callback is triggered when a user signs in anonymously. + FutureOrResult onSignInAnonymously( + Result result, + WyattForm form, + ); + + /// {@macro signin_anom} + FutureOr signInAnonymously() async { + if (state.status.isSubmissionInProgress) { + return; + } + + final form = formRepository.accessForm(formName); + emit(SignInState(form: form, status: FormStatus.submissionInProgress)); + + return CustomRoutine( + routine: authenticationRepository.signInAnonymously, + attachedLogic: (routineResult) => onSignInAnonymously( + routineResult, + form, + ), + onError: (error) { + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, + ), + ); + emit( + SignInState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart new file mode 100644 index 00000000..616cde9b --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart @@ -0,0 +1,153 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Sign in mixin. +/// +/// Allows the user to sign in with email and password +/// +/// Gives access to the `signInWithEmailAndPassword` method and +/// `onSignInWithEmailAndPassword` callback. +mixin SignInWithEmailPassword on BaseSignInCubit { + /// This callback is triggered when a user signs in with email and password. + FutureOrResult onSignInWithEmailAndPassword( + Result result, + WyattForm form, + ); + + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', + ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); + } + + void passwordChanged(String value) { + final passwordValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.password) + .runtimeType; + assert( + passwordValidatorType == Password, + 'Use passwordCustomChanged(...) with validator $passwordValidatorType', + ); + final Password password = Password.dirty(value); + dataChanged(AuthFormField.password, password); + } + + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); + } + + /// Same as [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + /// {@macro signin_pwd} + FutureOr signInWithEmailAndPassword() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + SignInState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final email = form.valueOf(AuthFormField.email); + final password = form.valueOf(AuthFormField.password); + + if (email.isNullOrEmpty || password.isNullOrEmpty) { + emit( + SignInState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.signInWithEmailAndPassword( + email: email!, + password: password!, + ), + attachedLogic: (routineResult) => onSignInWithEmailAndPassword( + routineResult, + form, + ), + onError: (error) { + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, + ), + ); + emit( + SignInState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart new file mode 100644 index 00000000..1d814d19 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart @@ -0,0 +1,79 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Sign in mixin. +/// +/// Allows the user to sign in with google +/// +/// Gives access to the `signInWithGoogle` method and +/// `onSignInWithGoogle` callback. +mixin SignInWithGoogle on BaseSignInCubit { + /// This callback is triggered when a user signs in with google. + FutureOrResult onSignInWithGoogle( + Result result, + WyattForm form, + ); + + /// {@macro signin_google} + FutureOr signInWithGoogle() async { + if (state.status.isSubmissionInProgress) { + return; + } + final form = formRepository.accessForm(formName); + emit(SignInState(form: form, status: FormStatus.submissionInProgress)); + + return CustomRoutine( + routine: authenticationRepository.signInWithGoogle, + attachedLogic: (routineResult) => onSignInWithGoogle( + routineResult, + form, + ), + onError: (error) { + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, + ), + ); + emit( + SignInState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart index 5db99b5f..fbde339c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,194 +16,51 @@ import 'dart:async'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_google.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +part 'base_sign_in_cubit.dart'; part 'sign_in_state.dart'; -class SignInCubit extends FormDataCubit { - final AuthenticationRepository _authenticationRepository; - FormRepository get _formRepository => - _authenticationRepository.formRepository; - - SignInCubit({ - required AuthenticationRepository authenticationRepository, - }) : _authenticationRepository = authenticationRepository, - super( - SignInState( - form: authenticationRepository.formRepository - .accessForm(AuthFormName.signInForm), - ), - ); +/// {@template sign_in_cubit} +/// Fully featured sign in cubit. +/// +/// Sufficient in most cases. (Where fine granularity is not required.) +/// {@endtemplate} +class SignInCubit extends BaseSignInCubit + with + SignInAnonymously, + SignInWithEmailPassword, + SignInWithGoogle { + /// {@macro sign_in_cubit} + SignInCubit({required super.authenticationRepository}); @override - String get formName => AuthFormName.signInForm; - - void emailChanged(String value) { - final emailValidatorType = _formRepository - .accessForm(formName) - .validatorOf(AuthFormField.email) - .runtimeType; - assert( - emailValidatorType == Email, - 'Use emailCustomChanged(...) with validator $emailValidatorType', - ); - - final Email email = Email.dirty(value); - dataChanged(AuthFormField.email, email); - } - - void passwordChanged(String value) { - final passwordValidatorType = _formRepository - .accessForm(formName) - .validatorOf(AuthFormField.password) - .runtimeType; - assert( - passwordValidatorType == Password, - 'Use passwordCustomChanged(...) with validator $passwordValidatorType', - ); - final Password password = Password.dirty(value); - dataChanged(AuthFormField.password, password); - } - - /// Same as [emailChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void emailCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.email, validator); - } - - /// Same as [passwordChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void passwordCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.password, validator); - } + FutureOrResult onSignInAnonymously( + Result result, + WyattForm form, + ) => + const Ok(null); @override - FutureOr dataChanged( - String key, - FormInputValidator dirtyValue, - ) { - final form = _formRepository.accessForm(formName).clone(); - - try { - form.updateValidator(key, dirtyValue); - _formRepository.updateForm(form); - } catch (e) { - rethrow; - } - - emit( - state.copyWith(form: form, status: form.validate()), - ); - } + FutureOrResult onSignInWithEmailAndPassword( + Result result, + WyattForm form, + ) => + const Ok(null); @override - FutureOr reset() { - final form = state.form.reset(); - _formRepository.updateForm(form); - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr submit() async { - throw UnimplementedError('`submit()` is not implemented for SignInCubit, ' - 'please use `signInWithEmailAndPassword()` or `signInAnonymously()`'); - } - - @override - FutureOr update( - WyattForm form, { - SetOperation operation = SetOperation.replace, - }) { - final WyattForm current = _formRepository.accessForm(formName).clone(); - final WyattForm newForm = operation.operation.call(current, form); - _formRepository.updateForm(newForm); - - emit( - state.copyWith( - form: newForm, - status: newForm.validate(), - ), - ); - } - - @override - FutureOr validate() { - emit( - state.copyWith( - status: _formRepository.accessForm(formName).validate(), - ), - ); - } - - FutureOr signInWithEmailAndPassword() async { - if (state.status.isSubmissionInProgress) { - return; - } - - if (!state.status.isValidated) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final form = _formRepository.accessForm(formName); - final email = form.valueOf(AuthFormField.email); - final password = form.valueOf(AuthFormField.password); - - if (email.isNullOrEmpty || password.isNullOrEmpty) { - emit( - state.copyWith( - errorMessage: 'An error occured while retrieving data from the form.', - status: FormStatus.submissionFailure, - ), - ); - } - - final uid = await _authenticationRepository.signInWithEmailAndPassword( - email: email!, - password: password!, - ); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } - - FutureOr signInAnonymously() async { - if (state.status.isSubmissionInProgress) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final uid = await _authenticationRepository.signInAnonymously(); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } + FutureOrResult onSignInWithGoogle( + Result result, + WyattForm form, + ) => + const Ok(null); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart index 8c65fe0f..39ed623f 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,18 +16,25 @@ part of 'sign_in_cubit.dart'; +/// {@template sign_in_state} +/// Sign in cubit state to manage the form. +/// {@endtemplate} class SignInState extends FormDataState { - FormInputValidator get email => - form.validatorOf(AuthFormField.email); - FormInputValidator get password => - form.validatorOf(AuthFormField.password); - + /// {@macro sign_in_state} const SignInState({ required super.form, super.status = FormStatus.pure, super.errorMessage, }); + /// Email validator of the form + FormInputValidator get email => + form.validatorOf(AuthFormField.email); + + /// Password validator of the form + FormInputValidator get password => + form.validatorOf(AuthFormField.password); + SignInState copyWith({ WyattForm? form, FormStatus? status, diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart index e51a1edd..2d55fe16 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/sign_in.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -class SignInListener extends StatelessWidget { +/// {@template sign_in_listener} +/// Widget that listens and builds a child based on the state of +/// the sign in cubit +/// {@endtemplate} +class SignInListener extends StatelessWidget { + /// {@macro sign_in_listener} const SignInListener({ required this.child, this.onProgress, @@ -29,19 +34,29 @@ class SignInListener extends StatelessWidget { super.key, }); + /// Callback to show when the sign in is in progress final void Function(BuildContext context)? onProgress; + + /// Callback to show when the sign in is successful final void Function(BuildContext context)? onSuccess; + + /// Callback to show when the sign in is unsuccessful final void Function( BuildContext context, FormStatus status, String? errorMessage, )? onError; + + /// Custom builder to show when the sign in is in progress, successful, or + /// unsuccessful final void Function(BuildContext context, SignInState state)? customBuilder; + + /// Child of the widget final Widget child; @override Widget build(BuildContext context) => - BlocListener, SignInState>( + BlocListener, SignInState>( listener: (context, state) { if (customBuilder != null) { return customBuilder!(context, state); diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart index 88fb9a39..37336de7 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +export 'cubit/mixin/sign_in_anonymously.dart'; +export 'cubit/mixin/sign_in_with_email_password.dart'; +export 'cubit/mixin/sign_in_with_google.dart'; export 'cubit/sign_in_cubit.dart'; export 'listener/sign_in_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart new file mode 100644 index 00000000..3691f4c5 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart @@ -0,0 +1,108 @@ +// Copyright (C) 2023 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 . + +part of 'sign_up_cubit.dart'; + +/// {@template base_sign_up_cubit} +/// Abstract sign up cubit useful for implementing a cubit with fine +/// granularity by adding only the required mixins. +/// {@endtemplate} +abstract class BaseSignUpCubit extends FormDataCubit { + /// {@macro base_sign_up_cubit} + BaseSignUpCubit({ + required this.authenticationRepository, + }) : super( + SignUpState( + form: authenticationRepository.formRepository + .accessForm(AuthFormName.signUpForm), + ), + ); + + /// The authentication repository. + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + + @override + String get formName => AuthFormName.signUpForm; + + @override + FutureOr dataChanged( + String key, + FormInputValidator dirtyValue, + ) { + final form = formRepository.accessForm(formName).clone(); + + try { + form.updateValidator(key, dirtyValue); + formRepository.updateForm(form); + } catch (e) { + rethrow; + } + + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + SignUpState( + form: newForm, + status: newForm.validate(), + ), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseSignUpCubit, ' + 'please use `signUpWithEmailAndPassword()`.'; + emit( + SignUpState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + throw UnimplementedError(error); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart new file mode 100644 index 00000000..80d56b7b --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart @@ -0,0 +1,143 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Sign up mixin. +/// +/// Allows the user to register with an email and a password. +/// +/// Gives access to the `signUpWithEmailPassword` method and +/// `onSignUpWithEmailAndPassword` callback. +mixin SignUpWithEmailPassword on BaseSignUpCubit { + /// This callback is triggered when a user creates an account. + /// + /// For example: when a user sign up in firebase. + FutureOrResult onSignUpWithEmailAndPassword( + Result result, + WyattForm form, + ); + + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', + ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); + } + + void passwordChanged(String value) { + final passwordValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.password) + .runtimeType; + assert( + passwordValidatorType == Password, + 'Use passwordCustomChanged(...) with validator $passwordValidatorType', + ); + final Password password = Password.dirty(value); + dataChanged(AuthFormField.password, password); + } + + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); + } + + /// Same as [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + /// {@macro signup_pwd} + FutureOr signUpWithEmailPassword() async { + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit(SignUpState(form: form, status: FormStatus.submissionInProgress)); + + final email = form.valueOf(AuthFormField.email); + final password = form.valueOf(AuthFormField.password); + + if (email.isNullOrEmpty || password.isNullOrEmpty) { + emit( + SignUpState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.signUpWithEmailAndPassword( + email: email!, + password: password!, + ), + attachedLogic: (routineResult) => onSignUpWithEmailAndPassword( + routineResult, + form, + ), + onError: (error) { + emit( + SignUpState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + AuthenticationSession.fromEvent( + SignedUpEvent(account: account), + data: data, + ), + ); + emit( + SignUpState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart index 38e719a1..09a76667 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,167 +16,32 @@ import 'dart:async'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +part 'base_sign_up_cubit.dart'; part 'sign_up_state.dart'; -class SignUpCubit extends FormDataCubit { - final AuthenticationRepository _authenticationRepository; - FormRepository get _formRepository => - _authenticationRepository.formRepository; - - SignUpCubit({ - required AuthenticationRepository authenticationRepository, - }) : _authenticationRepository = authenticationRepository, - super( - SignUpState( - form: authenticationRepository.formRepository - .accessForm(AuthFormName.signUpForm), - ), - ); +/// {@template sign_up_cubit} +/// Fully featured sign up cubit. +/// +/// Sufficient in most cases. (Where fine granularity is not required.) +/// {@endtemplate} +class SignUpCubit extends BaseSignUpCubit + with SignUpWithEmailPassword { + /// {@macro sign_up_cubit} + SignUpCubit({required super.authenticationRepository}); @override - String get formName => AuthFormName.signUpForm; - - void emailChanged(String value) { - final emailValidatorType = _formRepository - .accessForm(formName) - .validatorOf(AuthFormField.email) - .runtimeType; - assert( - emailValidatorType == Email, - 'Use emailCustomChanged(...) with validator $emailValidatorType', - ); - - final Email email = Email.dirty(value); - dataChanged(AuthFormField.email, email); - } - - void passwordChanged(String value) { - final passwordValidatorType = _formRepository - .accessForm(formName) - .validatorOf(AuthFormField.password) - .runtimeType; - assert( - passwordValidatorType == Password, - 'Use passwordCustomChanged(...) with validator $passwordValidatorType', - ); - final Password password = Password.dirty(value); - dataChanged(AuthFormField.password, password); - } - - /// Same as [emailChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void emailCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.email, validator); - } - - /// Same as [passwordChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void passwordCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.password, validator); - } - - @override - FutureOr dataChanged( - String key, - FormInputValidator dirtyValue, - ) { - final form = _formRepository.accessForm(formName).clone(); - - try { - form.updateValidator(key, dirtyValue); - _formRepository.updateForm(form); - } catch (e) { - rethrow; - } - - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr reset() { - final form = state.form.reset(); - _formRepository.updateForm(form); - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr submit() async { - if (!state.status.isValidated) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final form = _formRepository.accessForm(formName); - final email = form.valueOf(AuthFormField.email); - final password = form.valueOf(AuthFormField.password); - - if (email.isNullOrEmpty || password.isNullOrEmpty) { - emit( - state.copyWith( - errorMessage: 'An error occured while retrieving data from the form.', - status: FormStatus.submissionFailure, - ), - ); - } - - final uid = await _authenticationRepository.signUp( - email: email!, - password: password!, - ); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } - - @override - FutureOr update( - WyattForm form, { - SetOperation operation = SetOperation.replace, - }) { - final WyattForm current = _formRepository.accessForm(formName).clone(); - final WyattForm newForm = operation.operation.call(current, form); - _formRepository.updateForm(newForm); - - emit( - state.copyWith( - form: newForm, - status: newForm.validate(), - ), - ); - } - - @override - FutureOr validate() { - emit( - state.copyWith( - status: _formRepository.accessForm(formName).validate(), - ), - ); - } + FutureOrResult onSignUpWithEmailAndPassword( + Result result, + WyattForm form, + ) => + const Ok(null); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart index 8203c293..ac04efd5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,18 +16,25 @@ part of 'sign_up_cubit.dart'; +/// {@template sign_up_state} +/// Sign up cubit state to manage the form. +/// {@endtemplate} class SignUpState extends FormDataState { - FormInputValidator get email => - form.validatorOf(AuthFormField.email); - FormInputValidator get password => - form.validatorOf(AuthFormField.password); - + /// {@macro sign_up_state} const SignUpState({ required super.form, super.status = FormStatus.pure, super.errorMessage, }); + /// Email validator of the form + FormInputValidator get email => + form.validatorOf(AuthFormField.email); + + /// Password validator of the form + FormInputValidator get password => + form.validatorOf(AuthFormField.password); + SignUpState copyWith({ WyattForm? form, FormStatus? status, @@ -42,7 +49,6 @@ class SignUpState extends FormDataState { @override List get props => [email, password, status, form]; - @override @override String toString() => 'SignUpState(status: ${status.name} ' '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart index 925f0294..b4e5ad39 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -class SignUpListener extends StatelessWidget { +/// {@template sign_up_listener} +/// Widget that listens and builds a child based on the state of +/// the sign up cubit +/// {@endtemplate} +class SignUpListener extends StatelessWidget { + /// {@macro sign_up_listener} const SignUpListener({ required this.child, this.onProgress, @@ -29,19 +34,29 @@ class SignUpListener extends StatelessWidget { super.key, }); + /// Callback to show when the sign up is in progress final void Function(BuildContext context)? onProgress; + + /// Callback to show when the sign up is successful final void Function(BuildContext context)? onSuccess; + + /// Callback to show when the sign up is unsuccessful final void Function( BuildContext context, FormStatus status, String? errorMessage, )? onError; + + /// Custom builder to show when the sign up is in progress, successful, or + /// unsuccessful final void Function(BuildContext context, SignUpState state)? customBuilder; + + /// Child of the widget final Widget child; @override Widget build(BuildContext context) => - BlocListener, SignUpState>( + BlocListener, SignUpState>( listener: (context, state) { if (customBuilder != null) { return customBuilder!(context, state); diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart index 0eb01f0e..21c5895e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +export 'cubit/mixin/sign_up_with_email_password.dart'; export 'cubit/sign_up_cubit.dart'; export 'listener/sign_up_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/src.dart b/packages/wyatt_authentication_bloc/lib/src/src.dart index e5a07de0..18df157b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/src.dart +++ b/packages/wyatt_authentication_bloc/lib/src/src.dart @@ -1,16 +1,16 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . diff --git a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart index e40338b2..4ed48bd0 100644 --- a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart +++ b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/pubspec.yaml b/packages/wyatt_authentication_bloc/pubspec.yaml index 5b959149..f2ee8aeb 100644 --- a/packages/wyatt_authentication_bloc/pubspec.yaml +++ b/packages/wyatt_authentication_bloc/pubspec.yaml @@ -1,7 +1,7 @@ name: wyatt_authentication_bloc description: Authentication BLoC for Flutter repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_authentication_bloc -version: 0.4.0+3 +version: 0.5.0+1 publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub @@ -10,37 +10,33 @@ environment: flutter: ">=1.17.0" dependencies: - flutter: - sdk: flutter - + flutter: { sdk: flutter } crypto: ^3.0.2 flutter_bloc: ^8.1.1 equatable: ^2.0.5 - firebase_auth: ^4.1.1 - google_sign_in: ^5.3.0 - flutter_facebook_auth: ^4.3.0 - sign_in_with_apple: ^3.3.0 - twitter_login: ^4.2.3 + firebase_auth: ^4.2.0 + google_sign_in: ^5.4.2 rxdart: ^0.27.7 wyatt_form_bloc: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^0.2.0+2 + version: ^0.2.0+3 wyatt_architecture: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^0.1.0+1 + version: ^0.2.0 wyatt_type_utils: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^0.0.4 + version: ^0.0.5 + flutter_secure_storage: ^8.0.0 + http: ^0.13.5 dev_dependencies: - flutter_test: - sdk: flutter + flutter_test: { sdk: flutter } bloc_test: ^9.1.0 mocktail: ^0.3.0 wyatt_analysis: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 2.2.2 + version: ^2.5.0 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 e836bd4f..5469c51b 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -26,25 +26,55 @@ class MockAuthenticationRepository extends Mock class MockAccount extends Mock implements Account {} +class TestAuthenticationCubit extends AuthenticationCubit { + TestAuthenticationCubit({required super.authenticationRepository}); + + @override + FutureOrResult onDelete() async => const Ok(null); + + @override + FutureOrResult onReauthenticate( + Result result, + ) async => + const Ok(null); + + @override + FutureOrResult onRefresh(Result result) async => + const Ok(null); + + @override + FutureOrResult onSignInFromCache( + AuthenticationSession session, + ) async => + const Ok(null); + + @override + FutureOrResult onSignOut() async => const Ok(null); +} + void main() { group('AuthenticationCubit', () { final MockAccount account = MockAccount(); - final AccountWrapper wrapper = AccountWrapperModel(account, 10); + final AuthenticationSession session = AuthenticationSession( + latestEvent: const UnknownAuthenticationEvent(), + account: account, + data: 10, + ); late AuthenticationRepository authenticationRepository; setUp(() { authenticationRepository = MockAuthenticationRepository(); - when(() => authenticationRepository.streamAccount()).thenAnswer( + when(() => authenticationRepository.sessionStream()).thenAnswer( (_) => const Stream.empty(), ); - when( - () => authenticationRepository.getAccount(), - ).thenAnswer((_) async => Ok(account)); + when(() => authenticationRepository.checkForCachedAccount()).thenAnswer( + (_) => Future.value(), + ); }); test('initial auth state is `unknown`', () { expect( - AuthenticationCubit( + TestAuthenticationCubit( authenticationRepository: authenticationRepository, ).state, const AuthenticationState.unknown(), @@ -53,59 +83,29 @@ void main() { group('ListenForAuthenticationChanges', () { blocTest, AuthenticationState>( - 'emits authenticated when stream contains account', + 'emits authenticated when stream contains session', setUp: () { - when(() => authenticationRepository.streamAccount()).thenAnswer( - (_) => Stream.fromIterable([ - Future.value( - Ok(wrapper), - ) - ]), + when(() => authenticationRepository.sessionStream()).thenAnswer( + (_) => Stream.fromIterable([session]), ); }, - build: () => AuthenticationCubit( + build: () => TestAuthenticationCubit( authenticationRepository: authenticationRepository, ), seed: () => const AuthenticationState.unknown(), - expect: () => [AuthenticationState.authenticated(wrapper)], + expect: () => [AuthenticationState.authenticated(session)], ); blocTest, AuthenticationState>( 'emits unauthenticated when account stream is empty', setUp: () { - when( - () => authenticationRepository.destroyCache(), - ).thenAnswer((_) async => const Ok(null)); - when(() => authenticationRepository.streamAccount()).thenAnswer( - (_) => Stream.fromIterable([ - Future.value( - Ok(AccountWrapperModel(null, 1)), - ) - ]), + when(() => authenticationRepository.sessionStream()).thenAnswer( + (_) => Stream.fromIterable( + [const AuthenticationSession(latestEvent: SignedOutEvent())], + ), ); }, - build: () => AuthenticationCubit( - authenticationRepository: authenticationRepository, - ), - seed: () => const AuthenticationState.unknown(), - expect: () => [const AuthenticationState.unauthenticated()], - ); - - blocTest, AuthenticationState>( - 'emits unauthenticated when there is an error in stream', - setUp: () { - when( - () => authenticationRepository.destroyCache(), - ).thenAnswer((_) async => const Ok(null)); - when(() => authenticationRepository.streamAccount()).thenAnswer( - (_) => Stream.fromIterable([ - Future.value( - Err(ServerException()), - ) - ]), - ); - }, - build: () => AuthenticationCubit( + build: () => TestAuthenticationCubit( authenticationRepository: authenticationRepository, ), seed: () => const AuthenticationState.unknown(), @@ -121,7 +121,7 @@ void main() { () => authenticationRepository.signOut(), ).thenAnswer((_) async => const Ok(null)); }, - build: () => AuthenticationCubit( + build: () => TestAuthenticationCubit( authenticationRepository: authenticationRepository, ), act: (cubit) => cubit.signOut(), 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 a85c7998..9566f2f3 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ void main() { const AuthenticationState state = AuthenticationState.unauthenticated(); expect(state.status, AuthenticationStatus.unauthenticated); - expect(state.accountWrapper, null); + expect(state.session, null); }); }); @@ -36,10 +36,12 @@ void main() { final MockAccount account = MockAccount(); final AuthenticationState state = AuthenticationState.authenticated( - AccountWrapperModel(account, null), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + ), ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.accountWrapper?.account, account); + expect(state.session?.account, account); }); }); @@ -49,11 +51,14 @@ void main() { const String extra = 'AwesomeExtraData'; final AuthenticationState state = AuthenticationState.authenticated( - AccountWrapperModel(account, extra), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: extra, + ), ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.accountWrapper?.account, account); - expect(state.accountWrapper?.data, extra); + expect(state.session?.account, account); + expect(state.session?.data, extra); }); }); }); diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart index e07a4f2d..29e0c9b4 100644 --- a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -25,8 +25,8 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit { -} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} class MockAccount extends Mock implements Account {} @@ -39,15 +39,32 @@ void main() { setUp(() { authenticationRepository = MockAuthenticationRepository(); + account = MockAccount(); + + when(() => authenticationRepository.sessionStream()).thenAnswer( + (_) => Stream.fromIterable([ + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: 10, + ) + ]), + ); + when( - () => authenticationRepository.getAccount(), - ).thenAnswer((_) async => Ok(account)); + () => authenticationRepository.currentSession(), + ).thenAnswer( + (_) async => Ok( + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: 10, + ), + ), + ); when( () => authenticationRepository.refresh(), - ).thenAnswer((_) async => const Ok(null)); + ).thenAnswer((_) async => Ok(account)); - account = MockAccount(); when( () => account.emailVerified, ).thenAnswer((_) => true); @@ -104,7 +121,7 @@ void main() { 'emits failure', setUp: () { when(() => authenticationRepository.sendEmailVerification()) - .thenAnswer((_) async => Err(ServerException('erreur'))); + .thenAnswer((_) async => const Err(ServerException('erreur'))); }, build: () => EmailVerificationCubit( authenticationRepository: authenticationRepository, @@ -129,7 +146,7 @@ void main() { setUp: () { when( () => authenticationRepository.refresh(), - ).thenAnswer((_) async => const Ok(null)); + ).thenAnswer((_) async => Ok(account)); }, build: () => EmailVerificationCubit( authenticationRepository: authenticationRepository, @@ -145,7 +162,7 @@ void main() { setUp: () { when( () => authenticationRepository.refresh(), - ).thenAnswer((_) async => const Ok(null)); + ).thenAnswer((_) async => Ok(account)); when(() => account.emailVerified).thenAnswer((_) => false); }, build: () => EmailVerificationCubit( @@ -161,7 +178,7 @@ void main() { 'emits success with true if verified', setUp: () { when(() => authenticationRepository.refresh()) - .thenAnswer((_) async => const Ok(null)); + .thenAnswer((_) async => Ok(account)); }, build: () => EmailVerificationCubit( authenticationRepository: authenticationRepository, @@ -183,7 +200,7 @@ void main() { 'emits success with false if not verified', setUp: () { when(() => authenticationRepository.refresh()) - .thenAnswer((_) async => const Ok(null)); + .thenAnswer((_) async => Ok(account)); when(() => account.emailVerified).thenAnswer((_) => false); }, build: () => EmailVerificationCubit( @@ -205,29 +222,7 @@ void main() { 'emits failure on refresh error', setUp: () { when(() => authenticationRepository.refresh()) - .thenAnswer((_) async => Err(ServerException('erreur'))); - }, - build: () => EmailVerificationCubit( - authenticationRepository: authenticationRepository, - ), - seed: () => const EmailVerificationState(), - act: (cubit) => cubit.checkEmailVerification(), - expect: () => [ - const EmailVerificationState( - status: FormStatus.submissionInProgress, - ), - const EmailVerificationState( - errorMessage: 'erreur', - status: FormStatus.submissionFailure, - ) - ], - ); - - blocTest, EmailVerificationState>( - 'emits failure on get account error', - setUp: () { - when(() => authenticationRepository.getAccount()) - .thenAnswer((_) async => Err(ServerException('erreur'))); + .thenAnswer((_) async => const Err(ServerException('erreur'))); }, build: () => EmailVerificationCubit( authenticationRepository: authenticationRepository, diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart index 37e030b4..cf779daa 100644 --- a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart index e28ecb73..11c98b59 100644 --- a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -25,8 +25,8 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit { -} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} class MockAccount extends Mock implements Account {} @@ -272,7 +272,7 @@ void main() { () => authenticationRepository.sendPasswordResetEmail( email: any(named: 'email'), ), - ).thenAnswer((_) async => Err(ServerException())); + ).thenAnswer((_) async => const Err(ServerException())); when( () => formRepository.accessForm(AuthFormName.passwordResetForm), ).thenAnswer( diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart index 661ea241..518be2dc 100644 --- a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 d45316ff..bc517187 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -25,8 +25,8 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit { -} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} class MockAccount extends Mock implements Account {} @@ -435,7 +435,7 @@ void main() { email: any(named: 'email'), password: any(named: 'password'), ), - ).thenAnswer((_) async => Err(ServerException())); + ).thenAnswer((_) async => const Err(ServerException())); when( () => formRepository.accessForm(AuthFormName.signInForm), ).thenAnswer( @@ -579,11 +579,11 @@ void main() { [ FormInput( AuthFormField.email, - const Email.dirty(validEmailString), + const Email.pure(), ), FormInput( AuthFormField.password, - const Password.dirty(validPasswordString), + const Password.pure(), ) ], name: AuthFormName.signInForm, @@ -595,11 +595,11 @@ void main() { [ FormInput( AuthFormField.email, - const Email.dirty(validEmailString), + const Email.pure(), ), FormInput( AuthFormField.password, - const Password.dirty(validPasswordString), + const Password.pure(), ) ], name: AuthFormName.signInForm, @@ -615,7 +615,7 @@ void main() { setUp: () { when( () => authenticationRepository.signInAnonymously(), - ).thenAnswer((_) async => Err(ServerException())); + ).thenAnswer((_) async => const Err(ServerException())); }, build: () => SignInCubit( authenticationRepository: authenticationRepository, @@ -643,11 +643,11 @@ void main() { [ FormInput( AuthFormField.email, - const Email.dirty(validEmailString), + const Email.pure(), ), FormInput( AuthFormField.password, - const Password.dirty(validPasswordString), + const Password.pure(), ) ], name: AuthFormName.signInForm, @@ -659,11 +659,11 @@ void main() { [ FormInput( AuthFormField.email, - const Email.dirty(validEmailString), + const Email.pure(), ), FormInput( AuthFormField.password, - const Password.dirty(validPasswordString), + const Password.pure(), ) ], name: AuthFormName.signInForm, diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart index e55d92bd..30f40cb7 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 3d54a978..d437c339 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -25,8 +25,8 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock implements AuthenticationCubit { -} +class MockAuthenticationCubit extends Mock + implements AuthenticationCubit {} class MockAccount extends Mock implements Account {} @@ -59,7 +59,7 @@ void main() { formRepository = MockFormRepository(); when( - () => authenticationRepository.signUp( + () => authenticationRepository.signUpWithEmailAndPassword( email: any(named: 'email'), password: any(named: 'password'), ), @@ -258,13 +258,13 @@ void main() { ); }); - group('submit', () { + group('signUpWithEmailPassword', () { blocTest, SignUpState>( 'does nothing when status is not validated', build: () => SignUpCubit( authenticationRepository: authenticationRepository, ), - act: (cubit) => cubit.submit(), + act: (cubit) => cubit.signUpWithEmailPassword(), expect: () => const [], ); @@ -308,10 +308,10 @@ void main() { ), status: FormStatus.valid, ), - act: (cubit) => cubit.submit(), + act: (cubit) => cubit.signUpWithEmailPassword(), verify: (_) { verify( - () => authenticationRepository.signUp( + () => authenticationRepository.signUpWithEmailAndPassword( email: validEmailString, password: validPasswordString, ), @@ -360,7 +360,7 @@ void main() { ), status: FormStatus.valid, ), - act: (cubit) => cubit.submit(), + act: (cubit) => cubit.signUpWithEmailPassword(), expect: () => [ SignUpState( form: WyattFormImpl( @@ -402,11 +402,11 @@ void main() { 'when signUp fails', setUp: () { when( - () => authenticationRepository.signUp( + () => authenticationRepository.signUpWithEmailAndPassword( email: any(named: 'email'), password: any(named: 'password'), ), - ).thenAnswer((_) async => Err(ServerException())); + ).thenAnswer((_) async => const Err(ServerException())); when( () => formRepository.accessForm(AuthFormName.signUpForm), ).thenAnswer( @@ -444,7 +444,7 @@ void main() { ), status: FormStatus.valid, ), - act: (cubit) => cubit.submit(), + act: (cubit) => cubit.signUpWithEmailPassword(), expect: () => [ SignUpState( form: WyattFormImpl( diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart index 6e67399a..89380d66 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_bloc_helper/.gitignore b/packages/wyatt_bloc_helper/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_bloc_helper/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_bloc_helper/.gitignore b/packages/wyatt_bloc_helper/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_bloc_helper/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/.pubignore b/packages/wyatt_bloc_helper/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_bloc_helper/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/AUTHORS b/packages/wyatt_bloc_helper/AUTHORS deleted file mode 100644 index 2a0b50f7..00000000 --- a/packages/wyatt_bloc_helper/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Malo Léon -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/AUTHORS b/packages/wyatt_bloc_helper/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_bloc_helper/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/CHANGELOG.md b/packages/wyatt_bloc_helper/CHANGELOG.md index e0e380c8..492d3534 100644 --- a/packages/wyatt_bloc_helper/CHANGELOG.md +++ b/packages/wyatt_bloc_helper/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + + - **REFACTOR**: docs + nullable multiprovider attributes. + ## 2.0.0 > Note: This release has breaking changes. diff --git a/packages/wyatt_bloc_helper/LICENSE b/packages/wyatt_bloc_helper/LICENSE deleted file mode 100644 index e72bfdda..00000000 --- a/packages/wyatt_bloc_helper/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/LICENSE b/packages/wyatt_bloc_helper/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_bloc_helper/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/README.md b/packages/wyatt_bloc_helper/README.md index 5b055eb4..ea4ffd4f 100644 --- a/packages/wyatt_bloc_helper/README.md +++ b/packages/wyatt_bloc_helper/README.md @@ -7,7 +7,7 @@ * 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, + * 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. @@ -16,12 +16,10 @@ * along with this program. If not, see . --> -# Flutter - BloC Helper +# BloC Helper

- - Style: Wyatt Analysis - + Style: Wyatt Analysis SDK: Flutter

@@ -86,7 +84,7 @@ Widget buildChild(BuildContext context) { } ``` -> Note: here, you can use BlocBuilder, BlocListener,... and access Bloc and Repository instance with the mixin helper. +> Note: here, you can use BlocBuilder, BlocListener, ... and access Bloc and Repository instance with the mixin helper. ### Only BlocConsumer @@ -116,7 +114,7 @@ Widget onBuild(BuildContext context, CounterState state) { } ``` -If needed, you can wrap what depends on the state with the function `parent`. +If needed, you can wrap what depends on the state with the function `parent` . ```dart @override @@ -129,7 +127,7 @@ Widget parent(BuildContext context, Widget child) { ); ``` -> Note: you can override `onBuild`, but also `onListen`, `shouldBuildWhen` and `shouldListenWhen` methods. +> Note: you can override `onBuild` , but also `onListen` , `shouldBuildWhen` and `shouldListenWhen` methods. ### Both BlocProvider and BlocConsumer diff --git a/packages/wyatt_bloc_helper/analysis_options.yaml b/packages/wyatt_bloc_helper/analysis_options.yaml index b0c6aced..8c9daa4e 100644 --- a/packages/wyatt_bloc_helper/analysis_options.yaml +++ b/packages/wyatt_bloc_helper/analysis_options.yaml @@ -1,4 +1 @@ include: package:wyatt_analysis/analysis_options.flutter.yaml - -analyzer: - exclude: "!example/**" \ No newline at end of file diff --git a/packages/wyatt_bloc_helper/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_bloc_helper/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_bloc_helper/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_bloc_helper/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_bloc_helper/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_bloc_helper/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_bloc.dart b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_bloc.dart index 5bbd3d8e..7c807148 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_bloc.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_bloc.dart @@ -1,16 +1,16 @@ // 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 . @@ -25,7 +25,6 @@ class CounterBloc extends Bloc { final CounterRepository counterRepository; CounterBloc(this.counterRepository) : super(const CounterInitial()) { - on((event, emit) { emit(CounterModified(counterRepository.increment(state.count))); }); diff --git a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_event.dart b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_event.dart index c9d38554..53712a48 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_event.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_event.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_state.dart b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_state.dart index c0179e74..3a92be0f 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_state.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/bloc/counter_state.dart @@ -1,16 +1,16 @@ // 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 . @@ -32,4 +32,3 @@ class CounterInitial extends CounterState { class CounterModified extends CounterState { const CounterModified(super.count); } - diff --git a/packages/wyatt_bloc_helper/example/lib/counter/counter_bloc_page.dart b/packages/wyatt_bloc_helper/example/lib/counter/counter_bloc_page.dart index 2cb6f1d5..de9582da 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/counter_bloc_page.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/counter_bloc_page.dart @@ -24,14 +24,16 @@ class CounterBlocPage const CounterBlocPage({super.key}); @override - CounterBloc create(BuildContext context) => CounterBloc(repo(context)); + CounterBloc create(BuildContext context) => + CounterBloc(repo(context)); @override Widget onBuild(BuildContext context, CounterState state) { final textTheme = Theme.of(context).textTheme; return Scaffold( appBar: AppBar(title: const Text('Counter with Bloc')), - body: Center(child: Text('${state.count}', style: textTheme.headline2)), + body: + Center(child: Text('${state.count}', style: textTheme.displayMedium)), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, diff --git a/packages/wyatt_bloc_helper/example/lib/counter/counter_consumer_page.dart b/packages/wyatt_bloc_helper/example/lib/counter/counter_consumer_page.dart index 9a4a3005..76d426ad 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/counter_consumer_page.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/counter_consumer_page.dart @@ -28,7 +28,8 @@ class CounterConsumerPage final textTheme = Theme.of(context).textTheme; return Scaffold( appBar: AppBar(title: const Text('Counter with Consumer')), - body: Center(child: Text('${state.count}', style: textTheme.headline2)), + body: + Center(child: Text('${state.count}', style: textTheme.displayMedium)), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, diff --git a/packages/wyatt_bloc_helper/example/lib/counter/counter_cubit_page.dart b/packages/wyatt_bloc_helper/example/lib/counter/counter_cubit_page.dart index 5e04d72a..d906c30e 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/counter_cubit_page.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/counter_cubit_page.dart @@ -1,16 +1,16 @@ // 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 . @@ -19,19 +19,20 @@ import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; import 'package:flutter/material.dart'; import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; -class CounterCubitPage - extends CubitScreen { +class CounterCubitPage extends CubitScreen { const CounterCubitPage({super.key}); @override - CounterCubit create(BuildContext context) => CounterCubit(repo(context)); + CounterCubit create(BuildContext context) => + CounterCubit(repo(context)); @override Widget onBuild(BuildContext context, CounterState state) { final textTheme = Theme.of(context).textTheme; return Scaffold( appBar: AppBar(title: const Text('Counter with Cubit')), - body: Center(child: Text('${state.count}', style: textTheme.headline2)), + body: + Center(child: Text('${state.count}', style: textTheme.displayMedium)), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, @@ -53,4 +54,4 @@ class CounterCubitPage ), ); } -} \ No newline at end of file +} diff --git a/packages/wyatt_bloc_helper/example/lib/counter/counter_provider_page.dart b/packages/wyatt_bloc_helper/example/lib/counter/counter_provider_page.dart index 7a6c3d8c..4b81135a 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/counter_provider_page.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/counter_provider_page.dart @@ -35,7 +35,7 @@ class CounterProviderPage appBar: AppBar(title: const Text('Counter with Provider')), body: Center(child: BlocBuilder( builder: (context, state) { - return Text('${state.count}', style: textTheme.headline2); + return Text('${state.count}', style: textTheme.displayMedium); }, )), floatingActionButton: Column( diff --git a/packages/wyatt_bloc_helper/example/lib/counter/cubit/counter_state.dart b/packages/wyatt_bloc_helper/example/lib/counter/cubit/counter_state.dart index e1f39749..87e880b8 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter/cubit/counter_state.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter/cubit/counter_state.dart @@ -1,16 +1,16 @@ // 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 . @@ -32,4 +32,3 @@ class CounterInitial extends CounterState { class CounterModified extends CounterState { const CounterModified(super.count); } - diff --git a/packages/wyatt_bloc_helper/example/lib/counter_observer.dart b/packages/wyatt_bloc_helper/example/lib/counter_observer.dart index 8c75491b..26b1784c 100644 --- a/packages/wyatt_bloc_helper/example/lib/counter_observer.dart +++ b/packages/wyatt_bloc_helper/example/lib/counter_observer.dart @@ -1,16 +1,16 @@ // 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 . @@ -23,4 +23,4 @@ class CounterObserver extends BlocObserver { super.onChange(bloc, change); debugPrint('${bloc.runtimeType} $change'); } -} \ No newline at end of file +} diff --git a/packages/wyatt_bloc_helper/example/lib/main.dart b/packages/wyatt_bloc_helper/example/lib/main.dart index a707077c..3d825120 100644 --- a/packages/wyatt_bloc_helper/example/lib/main.dart +++ b/packages/wyatt_bloc_helper/example/lib/main.dart @@ -20,6 +20,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; void main() { - BlocOverrides.runZoned(() => runApp(const CounterRepositoryProviderPage()), - blocObserver: CounterObserver()); + Bloc.observer = CounterObserver(); + runApp(const CounterRepositoryProviderPage()); } diff --git a/packages/wyatt_bloc_helper/example/lib/main_page.dart b/packages/wyatt_bloc_helper/example/lib/main_page.dart index 2a82d039..b68383e3 100644 --- a/packages/wyatt_bloc_helper/example/lib/main_page.dart +++ b/packages/wyatt_bloc_helper/example/lib/main_page.dart @@ -56,7 +56,8 @@ class MainPage extends StatelessWidget { onPressed: () => Navigator.of(context) .push(MaterialPageRoute(builder: (context) { return BlocProvider( - create: (context) => CounterCubit(context.read()), + create: (context) => + CounterCubit(context.read()), child: const CounterConsumerPage(), ); })), diff --git a/packages/wyatt_bloc_helper/lib/src/mixins/bloc_base_provider_mixin.dart b/packages/wyatt_bloc_helper/lib/src/mixins/bloc_base_provider_mixin.dart index 6c2cf006..37b3c524 100644 --- a/packages/wyatt_bloc_helper/lib/src/mixins/bloc_base_provider_mixin.dart +++ b/packages/wyatt_bloc_helper/lib/src/mixins/bloc_base_provider_mixin.dart @@ -25,7 +25,7 @@ mixin BlocBaseProviderMixin> { /// Returns another [BlocBase] **not** used by this [BlocBaseProviderMixin]. /// Short hand for `context.read();` - /// + /// /// To get [BlocBase] used by by this [BlocBaseProviderMixin] see `bloc()` AnotherBloc anotherBloc(BuildContext context) => context.read(); diff --git a/packages/wyatt_bloc_helper/lib/src/mixins/bloc_provider_mixin.dart b/packages/wyatt_bloc_helper/lib/src/mixins/bloc_provider_mixin.dart index 0680a048..dae33c71 100644 --- a/packages/wyatt_bloc_helper/lib/src/mixins/bloc_provider_mixin.dart +++ b/packages/wyatt_bloc_helper/lib/src/mixins/bloc_provider_mixin.dart @@ -21,7 +21,7 @@ import 'package:flutter_bloc/flutter_bloc.dart' as blocbase; /// of helper methods for events. mixin BlocProviderMixin, Event> { /// Add an event to the [Bloc]. - /// + /// /// Short hand for `context.read().add(event)`. void add(BuildContext context, Event event) => context.read().add(event); diff --git a/packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart b/packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart index 046da441..9ac68ddb 100644 --- a/packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart +++ b/packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart @@ -17,7 +17,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +/// A utility class that provides a way to create a [BlocProvider] or +/// [RepositoryProvider] with a [Bloc] or Repository that is already +/// available in the widget tree. abstract class SmartProvider { + /// Creates a [BlocProvider] with a [Bloc] that is possibly already + /// available in the widget tree. static BlocProvider bloc, State extends Object>( BuildContext context, { @@ -45,6 +50,8 @@ abstract class SmartProvider { ); } + /// Creates a [RepositoryProvider] with a Repository that is possibly + /// already available in the widget tree. static RepositoryProvider repo( BuildContext context, { required Repository Function(BuildContext) create, diff --git a/packages/wyatt_bloc_helper/lib/src/widgets/multi_provider.dart b/packages/wyatt_bloc_helper/lib/src/widgets/multi_provider.dart index f6503928..4ddfbea0 100644 --- a/packages/wyatt_bloc_helper/lib/src/widgets/multi_provider.dart +++ b/packages/wyatt_bloc_helper/lib/src/widgets/multi_provider.dart @@ -18,14 +18,14 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; /// {@template multi_provider} -/// Merges [MultiRepositoryProvider] and [MultiBlocProvider] widgets into +/// Merges [MultiRepositoryProvider] and [MultiBlocProvider] widgets into /// one widget tree. /// /// [MultiProvider] improves the readability and eliminates the need /// to nest multiple providers. /// /// By using [MultiProvider] we can go from: -/// +/// /// ```dart /// MultiRepositoryProvider( /// providers: [ @@ -69,7 +69,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; /// ) /// ``` /// -/// [MultiProvider] converts the [RepositoryProvider] and [BlocProvider] lists +/// [MultiProvider] converts the [RepositoryProvider] and [BlocProvider] lists /// into a tree of nested provider widgets. /// As a result, the only advantage of using [MultiProvider] is /// improved readability due to the reduction in nesting and boilerplate. @@ -77,9 +77,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class MultiProvider extends StatelessWidget { /// {@macro multi_provider} const MultiProvider({ - required this.repositoryProviders, - required this.blocProviders, required this.child, + this.repositoryProviders = const >[], + this.blocProviders = const [], super.key, }); @@ -88,11 +88,31 @@ class MultiProvider extends StatelessWidget { final Widget child; @override - Widget build(BuildContext context) => MultiRepositoryProvider( - providers: repositoryProviders, - child: MultiBlocProvider( - providers: blocProviders, - child: child, - ), + Widget build(BuildContext context) { + if (repositoryProviders.isEmpty && blocProviders.isEmpty) { + return child; + } + + if (repositoryProviders.isEmpty) { + return MultiBlocProvider( + providers: blocProviders, + child: child, ); + } + + if (blocProviders.isEmpty) { + return MultiRepositoryProvider( + providers: repositoryProviders, + child: child, + ); + } + + return MultiRepositoryProvider( + providers: repositoryProviders, + child: MultiBlocProvider( + providers: blocProviders, + child: child, + ), + ); + } } diff --git a/packages/wyatt_bloc_helper/pubspec.yaml b/packages/wyatt_bloc_helper/pubspec.yaml index af6da51b..f9425b12 100644 --- a/packages/wyatt_bloc_helper/pubspec.yaml +++ b/packages/wyatt_bloc_helper/pubspec.yaml @@ -1,25 +1,23 @@ name: wyatt_bloc_helper description: Your best friend for blocs in Flutter repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_bloc_helper -version: 2.0.0 +version: 2.0.1 publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub environment: - sdk: '>=2.17.0 <3.0.0' + sdk: ">=2.17.0 <3.0.0" dependencies: - flutter: - sdk: flutter - + flutter: { sdk: flutter } + flutter_bloc: ^8.1.1 equatable: ^2.0.5 dev_dependencies: - flutter_test: - sdk: flutter + flutter_test: { sdk: flutter } bloc_test: ^9.1.0 - + wyatt_analysis: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub - version: ^2.2.2 \ No newline at end of file + version: ^2.5.0 diff --git a/packages/wyatt_bloc_layout/.gitignore b/packages/wyatt_bloc_layout/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_bloc_layout/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_bloc_layout/.pubignore b/packages/wyatt_bloc_layout/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_bloc_layout/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_cli_toolbox/.vscode/extensions.json b/packages/wyatt_bloc_layout/.vscode/extensions.json similarity index 100% rename from packages/wyatt_cli_toolbox/.vscode/extensions.json rename to packages/wyatt_bloc_layout/.vscode/extensions.json diff --git a/packages/wyatt_bloc_layout/.vscode/launch.json b/packages/wyatt_bloc_layout/.vscode/launch.json new file mode 100644 index 00000000..a5f4f148 --- /dev/null +++ b/packages/wyatt_bloc_layout/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // 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": "Launch Example", + "request": "launch", + "type": "dart", + "cwd": "example/", + "program": "lib/main.dart", + "flutterMode": "debug" + }, + ] +} \ No newline at end of file diff --git a/packages/wyatt_cli_toolbox/.vscode/settings.json b/packages/wyatt_bloc_layout/.vscode/settings.json similarity index 100% rename from packages/wyatt_cli_toolbox/.vscode/settings.json rename to packages/wyatt_bloc_layout/.vscode/settings.json diff --git a/packages/wyatt_bloc_layout/AUTHORS b/packages/wyatt_bloc_layout/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_bloc_layout/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_bloc_layout/CHANGELOG.md b/packages/wyatt_bloc_layout/CHANGELOG.md new file mode 100644 index 00000000..b9cf89a2 --- /dev/null +++ b/packages/wyatt_bloc_layout/CHANGELOG.md @@ -0,0 +1,35 @@ +## 0.1.0+1 + + - Update a dependency to the latest release. + +## 0.1.0 + +> Note: This release has breaking changes. + + - **BREAKING** **FEAT**(layout): update layout plugins with new components system. (e76857f1) + +## 0.0.2 + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: migrate bloc layouts using copywith component method (close #121). + - **REFACTOR**: update example (#92). + - **REFACTOR**: update package using nullable component data (#92). + - **REFACTOR**: update example with new app bar entity (#90). + - **FIX**: remove wyatt arch ios example. + - **FIX**: change example to be compatible with new AppTopBar and TextWrapper. + - **FIX**: fix textwrapper. + - **FIX**: update export file. + - **FIX**: rename file. + - **FEAT**: add attributs available for grid bloc layouts. + - **FEAT**: add grid content implementations. + - **FEAT**: rework on structure using new components and layouts. + - **FEAT**: make package compatible with crud cubit (close #111). + - **FEAT**: export layout_package & adapt imports. + - **FEAT**: export useful packages (close #88). + - **FEAT**: add all layout avalaible with crud bloc. + - **FEAT**: link error widget to error state. + - **FEAT**: add new package to combine bloc_helper, crud_bloc, ui_components, and ui_layout. + +# 0.0.1 + +- TODO: Describe initial release. diff --git a/packages/wyatt_bloc_layout/LICENSE b/packages/wyatt_bloc_layout/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_bloc_layout/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_bloc_layout/README.md b/packages/wyatt_bloc_layout/README.md new file mode 100644 index 00000000..39b4c134 --- /dev/null +++ b/packages/wyatt_bloc_layout/README.md @@ -0,0 +1,61 @@ + + +# Wyatt Bloc Layout + +

+ Style: Wyatt Analysis + SDK: Flutter +

+ +Bloc Layout for Flutter. + +Wyatt Bloc Layout is a Flutter package that is built on the Wyatt UI Layout package and the Wyatt Bloc Helper package. + +It provides a way to link multiple packages in order to create intelligent layouts that combine both layout and logic. The package allows developers to use the available layouts in the Wyatt UI Layout package along with the block state logic available in the Wyatt Bloc Helper package. + +It also uses the Wyatt Crud Bloc package to make it easier to implement CRUD logic. + +### Features + +* Allows developers to use available layouts from Wyatt UI Layout package. +* Links with the Wyatt Bloc Helper package to combine layout and block state logic. +* Uses the Wyatt Crud Bloc package to easily implement CRUD logic. + +#### Available bloc layouts + +* BottomNavigationBarGridLayoutCubitScreenCrudList +* BottomNavigationBarLayoutCubitScreen +* BottomNavigationBarLayoutCubitScreenCrud +* BottomNavigationBarLayoutCubitScreenCrudItem +* BottomNavigationBarLayoutCubitScreenCrudList +* FrameGridLayoutCubitScreenCrudList +* FrameLayoutCubitScreen +* FrameLayoutCubitScreenCrud +* FrameLayoutCubitScreenCrudItem +* FrameLayoutCubitScreenCrudList +* TopAppBarGridLayoutCubitScreenCrudList +* TopAppBarLayoutCubitScreen +* TopAppBarLayoutCubitScreenCrud +* TopAppBarLayoutCubitScreenCrudItem +* TopAppBarLayoutCubitScreenCrudList +* TopNavigationBarGridLayoutCubitScreenCrudList +* TopNavigationBarLayoutCubitScreen +* TopNavigationBarLayoutCubitScreenCrud +* TopNavigationBarLayoutCubitScreenCrudItem +* TopNavigationBarLayoutCubitScreenCrudList diff --git a/packages/wyatt_bloc_layout/analysis_options.yaml b/packages/wyatt_bloc_layout/analysis_options.yaml new file mode 100644 index 00000000..8c9daa4e --- /dev/null +++ b/packages/wyatt_bloc_layout/analysis_options.yaml @@ -0,0 +1 @@ +include: package:wyatt_analysis/analysis_options.flutter.yaml diff --git a/packages/wyatt_bloc_layout/example/lib/bloc/example_cubit.dart b/packages/wyatt_bloc_layout/example/lib/bloc/example_cubit.dart new file mode 100644 index 00000000..dd2275d4 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/bloc/example_cubit.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +class ExampleCubit extends Cubit { + ExampleCubit() : super(const CrudInitial()); + + FutureOr run() async { + while (true) { + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudLoading()); + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudError('Cubit Error')); + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudLoaded('DATA LOADED')); + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudInitial()); + } + } + + FutureOr runList() async { + while (true) { + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudLoading()); + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudError('Cubit Error')); + await Future.delayed(const Duration(seconds: 1)); + emit( + const CrudListLoaded([ + 'DATA LOADED 1', + 'DATA LOADED 2', + 'DATA LOADED 3', + 'DATA LOADED 4' + ]), + ); + await Future.delayed(const Duration(seconds: 1)); + emit(const CrudInitial()); + } + } +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.dart new file mode 100644 index 00000000..6e9c8c1c --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +part 'custom_app_bar.g.dart'; + +@ComponentCopyWithExtension() +class CustomAppBar extends TopAppBarComponent with $CustomAppBarCWMixin { + const CustomAppBar({super.key, super.title}); + @override + Widget build(BuildContext context) => AppBar( + title: Text(title?.data ?? 'Title'), + ); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.g.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.g.dart new file mode 100644 index 00000000..bbe73b13 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_app_bar.g.dart @@ -0,0 +1,99 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_app_bar.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy { + const $CustomAppBarCWProxyImpl(this._value); + final CustomAppBar _value; + @override + CustomAppBar title(TextWrapper? title) => this(title: title); + @override + CustomAppBar centerTitle(bool? centerTitle) => this(centerTitle: centerTitle); + @override + CustomAppBar shape(ShapeBorder? shape) => this(shape: shape); + @override + CustomAppBar systemOverlayStyle(SystemUiOverlayStyle? systemOverlayStyle) => + this(systemOverlayStyle: systemOverlayStyle); + @override + CustomAppBar automaticallyImplyLeading(bool? automaticallyImplyLeading) => + this(automaticallyImplyLeading: automaticallyImplyLeading); + @override + CustomAppBar flexibleSpace(Widget? flexibleSpace) => + this(flexibleSpace: flexibleSpace); + @override + CustomAppBar bottom(PreferredSizeWidget? bottom) => this(bottom: bottom); + @override + CustomAppBar elevation(double? elevation) => this(elevation: elevation); + @override + CustomAppBar scrolledUnderElevation(double? scrolledUnderElevation) => + this(scrolledUnderElevation: scrolledUnderElevation); + @override + CustomAppBar shadowColor(Color? shadowColor) => + this(shadowColor: shadowColor); + @override + CustomAppBar surfaceTintColor(Color? surfaceTintColor) => + this(surfaceTintColor: surfaceTintColor); + @override + CustomAppBar backgroundColor(MultiColor? backgroundColor) => + this(backgroundColor: backgroundColor); + @override + CustomAppBar iconTheme(IconThemeData? iconTheme) => + this(iconTheme: iconTheme); + @override + CustomAppBar primary(bool? primary) => this(primary: primary); + @override + CustomAppBar excludeHeaderSemantics(bool? excludeHeaderSemantics) => + this(excludeHeaderSemantics: excludeHeaderSemantics); + @override + CustomAppBar toolbarHeight(double? toolbarHeight) => + this(toolbarHeight: toolbarHeight); + @override + CustomAppBar leadingWidth(double? leadingWidth) => + this(leadingWidth: leadingWidth); + @override + CustomAppBar leading(Widget? leading) => this(leading: leading); + @override + CustomAppBar actions(List? actions) => this(actions: actions); + @override + CustomAppBar expandedWidget(List? expandedWidget) => + this(expandedWidget: expandedWidget); + @override + CustomAppBar key(Key? key) => this(key: key); + @override + CustomAppBar call({ + TextWrapper? title, + bool? centerTitle, + ShapeBorder? shape, + SystemUiOverlayStyle? systemOverlayStyle, + bool? automaticallyImplyLeading, + Widget? flexibleSpace, + PreferredSizeWidget? bottom, + double? elevation, + double? scrolledUnderElevation, + Color? shadowColor, + Color? surfaceTintColor, + MultiColor? backgroundColor, + IconThemeData? iconTheme, + bool? primary, + bool? excludeHeaderSemantics, + double? toolbarHeight, + double? leadingWidth, + Widget? leading, + List? actions, + List? expandedWidget, + Key? key, + }) => + CustomAppBar( + key: key ?? _value.key, + title: title ?? _value.title, + ); +} + +mixin $CustomAppBarCWMixin on Component { + $TopAppBarComponentCWProxy get copyWith => + $CustomAppBarCWProxyImpl(this as CustomAppBar); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.dart new file mode 100644 index 00000000..5a213cd8 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +part 'custom_bottom_bar.g.dart'; + +@ComponentCopyWithExtension() +class CustomBottomBar extends BottomNavigationBarComponent + with $CustomBottomBarCWMixin { + const CustomBottomBar({super.key}); + + @override + Widget build(BuildContext context) => BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + icon: Icon( + Icons.e_mobiledata, + ), + label: 'Icon 1', + ), + BottomNavigationBarItem( + icon: Icon( + Icons.do_not_disturb_off, + ), + label: 'Icon 2', + ), + ], + backgroundColor: Colors.blue, + ); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.g.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.g.dart new file mode 100644 index 00000000..463d310f --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_bottom_bar.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_bottom_bar.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $CustomBottomBarCWProxyImpl + implements $BottomNavigationBarComponentCWProxy { + const $CustomBottomBarCWProxyImpl(this._value); + final CustomBottomBar _value; + @override + CustomBottomBar onTap(void Function(BuildContext, int)? onTap) => + this(onTap: onTap); + @override + CustomBottomBar currentIndex(int? currentIndex) => + this(currentIndex: currentIndex); + @override + CustomBottomBar key(Key? key) => this(key: key); + @override + CustomBottomBar call({ + void Function(BuildContext, int)? onTap, + int? currentIndex, + Key? key, + }) => + CustomBottomBar( + key: key ?? _value.key, + ); +} + +mixin $CustomBottomBarCWMixin on Component { + $BottomNavigationBarComponentCWProxy get copyWith => + $CustomBottomBarCWProxyImpl(this as CustomBottomBar); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.dart new file mode 100644 index 00000000..40952513 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +part 'custom_error_widget.g.dart'; + +@ComponentCopyWithExtension() +class CustomErrorWidget extends ErrorComponent with $CustomErrorWidgetCWMixin { + const CustomErrorWidget({super.key, super.details}); + + @override + Widget build(BuildContext context) => ColoredBox( + color: Colors.red, + child: Center(child: Text(details?.data ?? 'Error')), + ); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.g.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.g.dart new file mode 100644 index 00000000..16a49808 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_error_widget.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_error_widget.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $CustomErrorWidgetCWProxyImpl implements $ErrorComponentCWProxy { + const $CustomErrorWidgetCWProxyImpl(this._value); + final CustomErrorWidget _value; + @override + CustomErrorWidget colors(MultiColor? colors) => this(colors: colors); + @override + CustomErrorWidget message(TextWrapper? message) => this(message: message); + @override + CustomErrorWidget details(TextWrapper? details) => this(details: details); + @override + CustomErrorWidget themeResolver( + ThemeResolver? themeResolver) => + this(themeResolver: themeResolver); + @override + CustomErrorWidget key(Key? key) => this(key: key); + @override + CustomErrorWidget call({ + MultiColor? colors, + TextWrapper? message, + TextWrapper? details, + ThemeResolver? themeResolver, + Key? key, + }) => + CustomErrorWidget( + key: key ?? _value.key, + details: details ?? _value.details, + ); +} + +mixin $CustomErrorWidgetCWMixin on Component { + $ErrorComponentCWProxy get copyWith => + $CustomErrorWidgetCWProxyImpl(this as CustomErrorWidget); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.dart new file mode 100644 index 00000000..c996a351 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +part 'custom_loading_widget.g.dart'; + +@ComponentCopyWithExtension() +class CustomLoadingWidget extends LoaderComponent + with $CustomLoadingWidgetCWMixin { + const CustomLoadingWidget({super.key, super.colors}); + + @override + Widget build(BuildContext context) => Center( + child: CircularProgressIndicator( + color: (colors?.isColor ?? false) ? colors!.color : Colors.blue, + ), + ); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.g.dart b/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.g.dart new file mode 100644 index 00000000..dfb8ace2 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/custom_loading_widget.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_loading_widget.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $CustomLoadingWidgetCWProxyImpl implements $LoaderComponentCWProxy { + const $CustomLoadingWidgetCWProxyImpl(this._value); + final CustomLoadingWidget _value; + @override + CustomLoadingWidget colors(MultiColor? colors) => this(colors: colors); + @override + CustomLoadingWidget radius(double? radius) => this(radius: radius); + @override + CustomLoadingWidget stroke(double? stroke) => this(stroke: stroke); + @override + CustomLoadingWidget duration(Duration? duration) => this(duration: duration); + @override + CustomLoadingWidget flip(bool? flip) => this(flip: flip); + @override + CustomLoadingWidget themeResolver( + ThemeResolver? themeResolver) => + this(themeResolver: themeResolver); + @override + CustomLoadingWidget key(Key? key) => this(key: key); + @override + CustomLoadingWidget call({ + MultiColor? colors, + double? radius, + double? stroke, + Duration? duration, + bool? flip, + ThemeResolver? themeResolver, + Key? key, + }) => + CustomLoadingWidget( + key: key ?? _value.key, + colors: colors ?? _value.colors, + ); +} + +mixin $CustomLoadingWidgetCWMixin on Component { + $LoaderComponentCWProxy get copyWith => + $CustomLoadingWidgetCWProxyImpl(this as CustomLoadingWidget); +} diff --git a/packages/wyatt_bloc_layout/example/lib/components/theme_components.dart b/packages/wyatt_bloc_layout/example/lib/components/theme_components.dart new file mode 100644 index 00000000..888522dd --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/components/theme_components.dart @@ -0,0 +1,14 @@ +import 'package:bloc_layout_example/components/custom_app_bar.dart'; +import 'package:bloc_layout_example/components/custom_bottom_bar.dart'; +import 'package:bloc_layout_example/components/custom_error_widget.dart'; +import 'package:bloc_layout_example/components/custom_loading_widget.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +abstract class AppThemeComponent { + static const ComponentThemeData components = ComponentThemeData.raw( + topAppBar: CustomAppBar(), + bottomNavigationBar: CustomBottomBar(), + loader: CustomLoadingWidget(), + error: CustomErrorWidget(), + ); +} diff --git a/packages/wyatt_bloc_layout/example/lib/main.dart b/packages/wyatt_bloc_layout/example/lib/main.dart new file mode 100644 index 00000000..ed7f9709 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/lib/main.dart @@ -0,0 +1,155 @@ +// 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:bloc_layout_example/bloc/example_cubit.dart'; +import 'package:bloc_layout_example/components/theme_components.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) => ComponentTheme( + data: AppThemeComponent.components, + child: MaterialApp( + title: 'Bloc Layout Example', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: Scaffold( + body: Column( + children: [ + Expanded( + child: Row( + children: [ + Expanded( + child: BlocProvider( + create: (_) => ExampleCubit()..run(), + child: const ExampleCrudStateManagement(), + ), + ), + Expanded( + child: BlocProvider( + create: (_) => ExampleCubit()..runList(), + child: const ExampleListCrudStateManagement(), + ), + ), + ], + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: BlocProvider( + create: (_) => ExampleCubit()..run(), + child: ExampleFrameLayoutCrudConsumer(), + ), + ), + Expanded( + child: BlocProvider( + create: (_) => ExampleCubit()..runList(), + child: ExampleFrameLayoutCrudListConsumer(), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); +} + +class ExampleCrudStateManagement + extends CubitScreenCrudItemBase { + const ExampleCrudStateManagement({super.key}); + + @override + Widget initialBuilder(BuildContext context, CrudInitial state) => + Container(color: Colors.yellow); + @override + Widget successBuilder(BuildContext context, CrudLoaded state) => + Center(child: Text(state.data ?? 'errors')); + + @override + ExampleCubit create(BuildContext context) => ExampleCubit()..run(); +} + +class ExampleListCrudStateManagement + extends CubitScreenCrudListBase { + const ExampleListCrudStateManagement({super.key}); + + @override + Widget initialBuilder(BuildContext context, CrudInitial state) => + Container(color: Colors.green); + @override + Widget successBuilder(BuildContext context, CrudListLoaded state) => + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: state.data.map((e) => Text(e ?? 'error')).toList(), + ); + + @override + ExampleCubit create(BuildContext context) => ExampleCubit()..run(); +} + +class ExampleFrameLayoutCrudConsumer + extends FrameLayoutCubitScreenCrudItem { + ExampleFrameLayoutCrudConsumer({super.key}) + : super( + customAppBar: (bar) => bar?.copyWith.title( + const TextWrapper('Example Title'), + ), + ); + + @override + Widget successBuilder(BuildContext context, CrudLoaded state) => + Center(child: Text(state.data ?? 'errors')); + + @override + ExampleCubit create(BuildContext context) => ExampleCubit()..run(); +} + +class ExampleFrameLayoutCrudListConsumer + extends FrameLayoutCubitScreenCrudList { + ExampleFrameLayoutCrudListConsumer({super.key}) + : super( + customAppBar: (bar) => bar?.copyWith.title( + const TextWrapper('Example Title'), + ), + ); + + @override + Widget successBuilder(BuildContext context, CrudListLoaded state) => + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: state.data.map((e) => Text(e ?? 'error')).toList(), + ); + + @override + ExampleCubit create(BuildContext context) => ExampleCubit()..run(); +} diff --git a/packages/wyatt_medium_feeds/example/pubspec.yaml b/packages/wyatt_bloc_layout/example/pubspec.yaml similarity index 74% rename from packages/wyatt_medium_feeds/example/pubspec.yaml rename to packages/wyatt_bloc_layout/example/pubspec.yaml index 8d11c3eb..97797a65 100644 --- a/packages/wyatt_medium_feeds/example/pubspec.yaml +++ b/packages/wyatt_bloc_layout/example/pubspec.yaml @@ -1,9 +1,9 @@ -name: medium_feeds_example +name: bloc_layout_example description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.16.2 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -27,35 +27,45 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: - flutter: - sdk: flutter + flutter: { sdk: flutter } - - wyatt_medium_feeds: - path: ../ + wyatt_bloc_layout: + path: "../" + flutter_bloc: ^8.1.2 - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + wyatt_bloc_helper: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 + wyatt_ui_layout: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.1.0+1 + wyatt_crud_bloc: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.1.1 + wyatt_ui_components: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.2.1 + wyatt_component_copy_with_extension: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 dev_dependencies: - flutter_test: - sdk: flutter + flutter_test: { sdk: flutter } + build_runner: ^2.3.3 - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 + wyatt_component_copy_with_gen: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/packages/wyatt_ui_components/example/test/widget_test.dart b/packages/wyatt_bloc_layout/example/test/widget_test.dart similarity index 98% rename from packages/wyatt_ui_components/example/test/widget_test.dart rename to packages/wyatt_bloc_layout/example/test/widget_test.dart index 52de7a27..1bb8b149 100644 --- a/packages/wyatt_ui_components/example/test/widget_test.dart +++ b/packages/wyatt_bloc_layout/example/test/widget_test.dart @@ -12,4 +12,4 @@ // 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 . \ No newline at end of file +// along with this program. If not, see . diff --git a/packages/wyatt_medium_feeds/example/web/favicon.png b/packages/wyatt_bloc_layout/example/web/favicon.png similarity index 100% rename from packages/wyatt_medium_feeds/example/web/favicon.png rename to packages/wyatt_bloc_layout/example/web/favicon.png diff --git a/packages/wyatt_medium_feeds/example/web/icons/Icon-192.png b/packages/wyatt_bloc_layout/example/web/icons/Icon-192.png similarity index 100% rename from packages/wyatt_medium_feeds/example/web/icons/Icon-192.png rename to packages/wyatt_bloc_layout/example/web/icons/Icon-192.png diff --git a/packages/wyatt_medium_feeds/example/web/icons/Icon-512.png b/packages/wyatt_bloc_layout/example/web/icons/Icon-512.png similarity index 100% rename from packages/wyatt_medium_feeds/example/web/icons/Icon-512.png rename to packages/wyatt_bloc_layout/example/web/icons/Icon-512.png diff --git a/packages/wyatt_medium_feeds/example/web/icons/Icon-maskable-192.png b/packages/wyatt_bloc_layout/example/web/icons/Icon-maskable-192.png similarity index 100% rename from packages/wyatt_medium_feeds/example/web/icons/Icon-maskable-192.png rename to packages/wyatt_bloc_layout/example/web/icons/Icon-maskable-192.png diff --git a/packages/wyatt_medium_feeds/example/web/icons/Icon-maskable-512.png b/packages/wyatt_bloc_layout/example/web/icons/Icon-maskable-512.png similarity index 100% rename from packages/wyatt_medium_feeds/example/web/icons/Icon-maskable-512.png rename to packages/wyatt_bloc_layout/example/web/icons/Icon-maskable-512.png diff --git a/packages/wyatt_bloc_layout/example/web/index.html b/packages/wyatt_bloc_layout/example/web/index.html new file mode 100644 index 00000000..41b3bc33 --- /dev/null +++ b/packages/wyatt_bloc_layout/example/web/index.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + + + diff --git a/packages/wyatt_medium_feeds/example/web/manifest.json b/packages/wyatt_bloc_layout/example/web/manifest.json similarity index 91% rename from packages/wyatt_medium_feeds/example/web/manifest.json rename to packages/wyatt_bloc_layout/example/web/manifest.json index 45dfbbec..096edf8f 100644 --- a/packages/wyatt_medium_feeds/example/web/manifest.json +++ b/packages/wyatt_bloc_layout/example/web/manifest.json @@ -1,6 +1,6 @@ { - "name": "medium_feeds_example", - "short_name": "medium_feeds_example", + "name": "example", + "short_name": "example", "start_url": ".", "display": "standalone", "background_color": "#0175C2", diff --git a/packages/wyatt_bloc_layout/lib/src/core/core.dart b/packages/wyatt_bloc_layout/lib/src/core/core.dart new file mode 100644 index 00000000..2916446f --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/core/core.dart @@ -0,0 +1,18 @@ +// 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 './crud_cubit_consumer_screen_mixin.dart'; +export './mixins/mixins.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/core/crud_cubit_consumer_screen_mixin.dart b/packages/wyatt_bloc_layout/lib/src/core/crud_cubit_consumer_screen_mixin.dart new file mode 100644 index 00000000..7a083f3c --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/core/crud_cubit_consumer_screen_mixin.dart @@ -0,0 +1,46 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; + +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +mixin CrudMixin, + SuccessState extends CrudSuccess> { + Widget errorBuilder(BuildContext context, CrudError state) => + context.components.errorComponent.call( + message: (state.message != null) ? TextWrapper(state.message!) : null, + ); + + Widget loadingBuilder(BuildContext context, CrudLoading state) => + context.components.loader ?? const SizedBox.shrink(); + + Widget initialBuilder(BuildContext context, CrudInitial state) => + const SizedBox.shrink(); + + Widget successBuilder(BuildContext context, SuccessState state); + + Widget crudBuilder(BuildContext context, CrudState state) => + CrudBuilder( + errorBuilder: errorBuilder, + loadingBuilder: loadingBuilder, + initialBuilder: initialBuilder, + state: state, + builder: successBuilder, + ); +} diff --git a/packages/wyatt_bloc_layout/lib/src/core/mixins/gird_view_mixin.dart b/packages/wyatt_bloc_layout/lib/src/core/mixins/gird_view_mixin.dart new file mode 100644 index 00000000..636048e2 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/core/mixins/gird_view_mixin.dart @@ -0,0 +1,36 @@ +// 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:flutter/material.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; +import 'package:wyatt_ui_layout/wyatt_ui_layout.dart'; + +mixin GridLayoutMixin { + Widget gridChild(BuildContext context, SuccessType? successType); + + double get verticalGap => 30; + double get horizontalGap => 30; + + Widget successBuilder( + BuildContext context, + CrudListLoaded state, + ) => + GridLayout( + verticalGap: verticalGap, + horizontalGap: horizontalGap, + children: state.data.map((e) => gridChild(context, e)).toList(), + ); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/utils.dart b/packages/wyatt_bloc_layout/lib/src/core/mixins/mixins.dart similarity index 94% rename from packages/wyatt_authentication_bloc/lib/src/core/utils/utils.dart rename to packages/wyatt_bloc_layout/lib/src/core/mixins/mixins.dart index 81005a25..d5b9315f 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/utils/utils.dart +++ b/packages/wyatt_bloc_layout/lib/src/core/mixins/mixins.dart @@ -1,17 +1,17 @@ // 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 'cryptography.dart'; +export './gird_view_mixin.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_bloc_layout.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_bloc_layout.dart new file mode 100644 index 00000000..24940e8a --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_bloc_layout.dart @@ -0,0 +1,22 @@ +// 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 './bottom_navigation_bar_bloc_layout.dart'; +export './bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart'; +export './bottom_navigation_bar_layout_cubit_screen.dart'; +export './bottom_navigation_bar_layout_cubit_screen_crud.dart'; +export './bottom_navigation_bar_layout_cubit_screen_crud_item.dart'; +export './bottom_navigation_bar_layout_cubit_screen_crud_list.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..952a2c81 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class BottomNavigationBarGridLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends BottomNavigationBarLayoutCubitScreenCrudList + with GridLayoutMixin { + const BottomNavigationBarGridLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen.dart new file mode 100644 index 00000000..0a02294f --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen.dart @@ -0,0 +1,43 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; + +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; +import 'package:wyatt_ui_layout/wyatt_ui_layout.dart'; + +abstract class BottomNavigationBarLayoutCubitScreen< + Cubit extends bloc_base.Cubit, + State extends Object> extends CubitScreenBase { + const BottomNavigationBarLayoutCubitScreen({ + this.custom, + this.height = 60, + super.key, + }); + + final double height; + final BottomNavigationBarComponent? Function(BottomNavigationBarComponent?)? + custom; + + @override + Widget parent(BuildContext context, Widget child) => + BottomNavigationBarLayout( + custom: custom, + body: child, + ); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud.dart new file mode 100644 index 00000000..c1cc938d --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud.dart @@ -0,0 +1,36 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class BottomNavigationBarLayoutCubitScreenCrud< + Cubit extends bloc_base.Cubit, + CrudSuccessState extends CrudSuccess> + extends BottomNavigationBarLayoutCubitScreen + with CrudMixin { + const BottomNavigationBarLayoutCubitScreenCrud({ + super.custom, + super.height, + super.key, + }); + + @override + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_item.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_item.dart new file mode 100644 index 00000000..69ff4371 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_item.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class BottomNavigationBarLayoutCubitScreenCrudItem< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends BottomNavigationBarLayoutCubitScreenCrud> { + const BottomNavigationBarLayoutCubitScreenCrudItem({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..7c6c5b21 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/bottom_navigation_bar_bloc_layout/bottom_navigation_bar_layout_cubit_screen_crud_list.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class BottomNavigationBarLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends BottomNavigationBarLayoutCubitScreenCrud> { + const BottomNavigationBarLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_base.dart new file mode 100644 index 00000000..5b01e789 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_base.dart @@ -0,0 +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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; + +abstract class CubitConsumerBase, + State extends Object> extends CubitConsumerScreen { + const CubitConsumerBase({super.key}); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_base.dart new file mode 100644 index 00000000..a9063d49 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_base.dart @@ -0,0 +1,31 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitConsumerCrudBase, + CrudSuccessState extends CrudSuccess> + extends CubitConsumerBase + with CrudMixin { + const CubitConsumerCrudBase({super.key}); + + @override + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_item_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_item_base.dart new file mode 100644 index 00000000..523ac073 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_item_base.dart @@ -0,0 +1,25 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitConsumerCrudItemBase< + Cubit extends bloc_base.Cubit, + T extends Object?> extends CubitConsumerCrudBase> { + const CubitConsumerCrudItemBase({super.key}); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_list_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_list_base.dart new file mode 100644 index 00000000..56c7eb36 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_consumer_crud_list_base.dart @@ -0,0 +1,25 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitConsumerCrudListBase< + Cubit extends bloc_base.Cubit, + T extends Object?> extends CubitConsumerCrudBase> { + const CubitConsumerCrudListBase({super.key}); +} diff --git a/packages/wyatt_cli_toolbox/lib/src/workflow/skip_exception.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_base.dart similarity index 71% rename from packages/wyatt_cli_toolbox/lib/src/workflow/skip_exception.dart rename to packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_base.dart index ecfed601..4dc4107a 100644 --- a/packages/wyatt_cli_toolbox/lib/src/workflow/skip_exception.dart +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_base.dart @@ -14,15 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -class SkipException implements Exception { - SkipException(this.message); +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; - final String? message; - - @override - String toString() { - final Object? message = this.message; - if (message == null) return 'Skipped'; - return '$message'; - } +abstract class CubitScreenBase, + State extends Object> extends CubitScreen { + const CubitScreenBase({super.key}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_base.dart similarity index 56% rename from packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart rename to packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_base.dart index e99b774e..ad9142f8 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_base.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -15,22 +14,18 @@ // 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/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitScreenCrudBase, + CrudSuccessState extends CrudSuccess> + extends CubitScreenBase + with CrudMixin { + const CubitScreenCrudBase({super.key}); -class AccountWrapperModel extends AccountWrapper { @override - final Account? account; - @override - final T? data; - - AccountWrapperModel(this.account, this.data); - - AccountWrapperModel copyWith({ - Account? account, - T? data, - }) => AccountWrapperModel( - account ?? this.account, - data ?? this.data, - ); + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); } diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_item_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_item_base.dart new file mode 100644 index 00000000..3fe2becb --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_item_base.dart @@ -0,0 +1,24 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitScreenCrudItemBase, + T extends Object?> extends CubitScreenCrudBase> { + const CubitScreenCrudItemBase({super.key}); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_list_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_list_base.dart new file mode 100644 index 00000000..f886138e --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/cubit_screen_crud_list_base.dart @@ -0,0 +1,24 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class CubitScreenCrudListBase, + T extends Object?> extends CubitScreenCrudBase> { + const CubitScreenCrudListBase({super.key}); +} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/framework.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_bloc_layout.dart similarity index 71% rename from packages/wyatt_cli_toolbox/lib/src/prompt/framework/framework.dart rename to packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_bloc_layout.dart index aac49fad..3233fe28 100644 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/framework.dart +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_bloc_layout.dart @@ -14,13 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -library prompt.framework; - -import 'dart:io'; -import 'package:meta/meta.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -part 'build_context.dart'; -part 'state.dart'; -part 'widget.dart'; +export './frame_bloc_layout.dart'; +export './frame_grid_layout_cubit_screen_crud_list.dart'; +export './frame_layout_cubit_screen.dart'; +export './frame_layout_cubit_screen_crud.dart'; +export './frame_layout_cubit_screen_crud_item.dart'; +export './frame_layout_cubit_screen_crud_list.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_grid_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_grid_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..044776d5 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_grid_layout_cubit_screen_crud_list.dart @@ -0,0 +1,32 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class FrameLayoutGridCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends FrameLayoutCubitScreenCrudList + with GridLayoutMixin { + const FrameLayoutGridCubitScreenCrudList({ + super.customAppBar, + super.customBottomNavBar, + super.height = 60, + super.scaffoldFieldsWrapper, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen.dart new file mode 100644 index 00000000..d5b6d415 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen.dart @@ -0,0 +1,48 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; + +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; +import 'package:wyatt_ui_layout/wyatt_ui_layout.dart'; + +abstract class FrameLayoutCubitScreen, + State extends Object> extends CubitScreenBase { + const FrameLayoutCubitScreen({ + this.customAppBar, + this.customBottomNavBar, + this.scaffoldFieldsWrapper, + this.height = 60, + super.key, + }); + + final TopAppBarComponent? Function(TopAppBarComponent?)? customAppBar; + final BottomNavigationBarComponent? Function(BottomNavigationBarComponent?)? + customBottomNavBar; + final double height; + final ScaffoldFieldsWrapper? scaffoldFieldsWrapper; + + @override + Widget parent(BuildContext context, Widget child) => FrameLayout( + customAppBar: customAppBar, + customBottomNavBar: customBottomNavBar, + height: height, + scaffoldFieldsWrapper: scaffoldFieldsWrapper, + body: child, + ); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud.dart new file mode 100644 index 00000000..0803c37e --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud.dart @@ -0,0 +1,38 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class FrameLayoutCubitScreenCrud< + Cubit extends bloc_base.Cubit, + CrudSuccessState extends CrudSuccess> + extends FrameLayoutCubitScreen + with CrudMixin { + const FrameLayoutCubitScreenCrud({ + super.customAppBar, + super.customBottomNavBar, + super.height, + super.key, + super.scaffoldFieldsWrapper, + }); + + @override + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); +} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/state.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_item.dart similarity index 56% rename from packages/wyatt_cli_toolbox/lib/src/prompt/framework/state.dart rename to packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_item.dart index ca6c1247..e3d9e965 100644 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/state.dart +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_item.dart @@ -14,37 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -part of prompt.framework; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; -abstract class State> { - W? _widget; - W get widget => _widget!; - - BuildContext? _context; - BuildContext get context => _context!; - - void build(); - - dynamic prompt(); - - @protected - @mustCallSuper - void dispose() { - _context = null; - } - - @protected - @mustCallSuper - void initState() { - _context ??= BuildContext(); - } - - @protected - @mustCallSuper - void setState(void Function() fn) { - fn(); - context.wipe(); - build(); - context.incrementBuildCount(); - } +abstract class FrameLayoutCubitScreenCrudItem< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends FrameLayoutCubitScreenCrud> { + const FrameLayoutCubitScreenCrudItem({ + super.customAppBar, + super.customBottomNavBar, + super.height = 60, + super.scaffoldFieldsWrapper, + super.key, + }); } diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..7ff1910b --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/frame_bloc_layout/frame_layout_cubit_screen_crud_list.dart @@ -0,0 +1,31 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class FrameLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends FrameLayoutCubitScreenCrud> { + const FrameLayoutCubitScreenCrudList({ + super.customAppBar, + super.customBottomNavBar, + super.height = 60, + super.scaffoldFieldsWrapper, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/grid_cubit_screen_crud_list_base.dart b/packages/wyatt_bloc_layout/lib/src/presentation/grid_cubit_screen_crud_list_base.dart new file mode 100644 index 00000000..c95cb338 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/grid_cubit_screen_crud_list_base.dart @@ -0,0 +1,25 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class GridCubitScreenCrudListBase< + Cubit extends bloc_base.Cubit, T extends Object?> + extends CubitScreenCrudListBase with GridLayoutMixin { + const GridCubitScreenCrudListBase({super.key}); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/presentation.dart b/packages/wyatt_bloc_layout/lib/src/presentation/presentation.dart new file mode 100644 index 00000000..7fbda27e --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/presentation.dart @@ -0,0 +1,28 @@ +// 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 './bottom_navigation_bar_bloc_layout/bottom_navigation_bar_bloc_layout.dart'; +export './cubit_consumer_base.dart'; +export './cubit_consumer_crud_base.dart'; +export './cubit_consumer_crud_item_base.dart'; +export './cubit_consumer_crud_list_base.dart'; +export './cubit_screen_base.dart'; +export './cubit_screen_crud_base.dart'; +export './cubit_screen_crud_item_base.dart'; +export './cubit_screen_crud_list_base.dart'; +export './frame_bloc_layout/frame_bloc_layout.dart'; +export './top_app_bar_bloc_layout/top_app_bar_bloc_layout.dart'; +export './top_navigation_bar_bloc_layout/top_navigation_bar_bloc_layout.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_bloc_layout.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_bloc_layout.dart new file mode 100644 index 00000000..6cc49ed5 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_bloc_layout.dart @@ -0,0 +1,22 @@ +// 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 './top_app_bar_bloc_layout.dart'; +export './top_app_bar_grid_layout_cubit_screen_crud_list.dart'; +export './top_app_bar_layout_cubit_screen.dart'; +export './top_app_bar_layout_cubit_screen_crud.dart'; +export './top_app_bar_layout_cubit_screen_crud_item.dart'; +export './top_app_bar_layout_cubit_screen_crud_list.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_grid_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_grid_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..e20a1842 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_grid_layout_cubit_screen_crud_list.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopAppBarGridLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopAppBarLayoutCubitScreenCrudList + with GridLayoutMixin { + const TopAppBarGridLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen.dart new file mode 100644 index 00000000..48fe0abe --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen.dart @@ -0,0 +1,41 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; + +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; +import 'package:wyatt_ui_layout/wyatt_ui_layout.dart'; + +abstract class TopAppBarLayoutCubitScreen, + State extends Object> extends CubitScreenBase { + const TopAppBarLayoutCubitScreen({ + this.custom, + this.height = 60, + super.key, + }); + + final double height; + final TopAppBarComponent? Function(TopAppBarComponent?)? custom; + + @override + Widget parent(BuildContext context, Widget child) => TopAppBarLayout( + height: height, + custom: custom, + body: child, + ); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud.dart new file mode 100644 index 00000000..efa82d3e --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud.dart @@ -0,0 +1,36 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopAppBarLayoutCubitScreenCrud< + Cubit extends bloc_base.Cubit, + CrudSuccessState extends CrudSuccess> + extends TopAppBarLayoutCubitScreen + with CrudMixin { + const TopAppBarLayoutCubitScreenCrud({ + super.custom, + super.height, + super.key, + }); + + @override + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); +} diff --git a/packages/wyatt_ui_layout/lib/src/presentation/layouts/app_bar_layout.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_item.dart similarity index 59% rename from packages/wyatt_ui_layout/lib/src/presentation/layouts/app_bar_layout.dart rename to packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_item.dart index 46d82bd8..dd7e2bb1 100644 --- a/packages/wyatt_ui_layout/lib/src/presentation/layouts/app_bar_layout.dart +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_item.dart @@ -14,22 +14,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:flutter/material.dart'; -import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; -import 'package:wyatt_ui_layout/src/presentation/layouts/layout.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; -class AppBarLayout extends Layout { - final String title; - final Widget body; - const AppBarLayout({ - required this.title, - required this.body, +abstract class TopAppBarLayoutCubitScreenCrudItem< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopAppBarLayoutCubitScreenCrud> { + const TopAppBarLayoutCubitScreenCrudItem({ + super.custom, + super.height = 60, super.key, }); - - @override - Widget build(BuildContext context) => Scaffold( - appBar: context.components.appBar.configure(title: title), - body: body, - ); } diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..902ce24c --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_app_bar_bloc_layout/top_app_bar_layout_cubit_screen_crud_list.dart @@ -0,0 +1,29 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopAppBarLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopAppBarLayoutCubitScreenCrud> { + const TopAppBarLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_bloc_layout.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_bloc_layout.dart new file mode 100644 index 00000000..7697dd49 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_bloc_layout.dart @@ -0,0 +1,22 @@ +// 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 './top_navigation_bar_bloc_layout.dart'; +export './top_navigation_bar_grid_layout_cubit_screen_crud_list.dart'; +export './top_navigation_bar_layout_cubit_screen.dart'; +export './top_navigation_bar_layout_cubit_screen_crud.dart'; +export './top_navigation_bar_layout_cubit_screen_crud_item.dart'; +export './top_navigation_bar_layout_cubit_screen_crud_list.dart'; diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_grid_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_grid_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..b57d29cf --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_grid_layout_cubit_screen_crud_list.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopNavigationBarGridLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopNavigationBarLayoutCubitScreenCrudList + with GridLayoutMixin { + const TopNavigationBarGridLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen.dart new file mode 100644 index 00000000..b1903cdc --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen.dart @@ -0,0 +1,42 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; + +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; +import 'package:wyatt_ui_layout/wyatt_ui_layout.dart'; + +abstract class TopNavigationBarLayoutCubitScreen< + Cubit extends bloc_base.Cubit, + State extends Object> extends CubitScreenBase { + const TopNavigationBarLayoutCubitScreen({ + this.custom, + this.height = 60, + super.key, + }); + + final double height; + final TopNavigationBarComponent? Function(TopNavigationBarComponent?)? custom; + + @override + Widget parent(BuildContext context, Widget child) => TopNavigationBarLayout( + height: height, + custom: custom, + body: child, + ); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud.dart new file mode 100644 index 00000000..76bd6beb --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud.dart @@ -0,0 +1,36 @@ +// 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:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopNavigationBarLayoutCubitScreenCrud< + Cubit extends bloc_base.Cubit, + CrudSuccessState extends CrudSuccess> + extends TopNavigationBarLayoutCubitScreen + with CrudMixin { + const TopNavigationBarLayoutCubitScreenCrud({ + super.custom, + super.height, + super.key, + }); + + @override + Widget onBuild(BuildContext context, CrudState state) => + crudBuilder(context, state); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_item.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_item.dart new file mode 100644 index 00000000..112b8844 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_item.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopNavigationBarLayoutCubitScreenCrudItem< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopNavigationBarLayoutCubitScreenCrud> { + const TopNavigationBarLayoutCubitScreenCrudItem({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_list.dart b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_list.dart new file mode 100644 index 00000000..0f17b282 --- /dev/null +++ b/packages/wyatt_bloc_layout/lib/src/presentation/top_navigation_bar_bloc_layout/top_navigation_bar_layout_cubit_screen_crud_list.dart @@ -0,0 +1,30 @@ +// 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:flutter_bloc/flutter_bloc.dart' as bloc_base; +import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; +import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; + +abstract class TopNavigationBarLayoutCubitScreenCrudList< + Cubit extends bloc_base.Cubit, SuccessType extends Object?> + extends TopNavigationBarLayoutCubitScreenCrud> { + const TopNavigationBarLayoutCubitScreenCrudList({ + super.custom, + super.height = 60, + super.key, + }); +} diff --git a/packages/wyatt_architecture/test/wyatt_architecture_test.dart b/packages/wyatt_bloc_layout/lib/src/src.dart similarity index 91% rename from packages/wyatt_architecture/test/wyatt_architecture_test.dart rename to packages/wyatt_bloc_layout/lib/src/src.dart index dc7ea003..d35a3ae0 100644 --- a/packages/wyatt_architecture/test/wyatt_architecture_test.dart +++ b/packages/wyatt_bloc_layout/lib/src/src.dart @@ -14,4 +14,5 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// Nothing to test as there is no logic in this package. +export 'core/core.dart'; +export 'presentation/presentation.dart'; diff --git a/packages/wyatt_ui_components/lib/wyatt_wyatt_ui_components.dart b/packages/wyatt_bloc_layout/lib/wyatt_bloc_layout.dart similarity index 93% rename from packages/wyatt_ui_components/lib/wyatt_wyatt_ui_components.dart rename to packages/wyatt_bloc_layout/lib/wyatt_bloc_layout.dart index 3d5154e2..34183618 100644 --- a/packages/wyatt_ui_components/lib/wyatt_wyatt_ui_components.dart +++ b/packages/wyatt_bloc_layout/lib/wyatt_bloc_layout.dart @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -/// Wyatt Ui Components -library wyatt_ui_components; +/// Bloc Layout +library wyatt_bloc_layout; export 'src/src.dart'; diff --git a/packages/wyatt_bloc_layout/models/class-models.puml b/packages/wyatt_bloc_layout/models/class-models.puml new file mode 100644 index 00000000..60bf99ae --- /dev/null +++ b/packages/wyatt_bloc_layout/models/class-models.puml @@ -0,0 +1,176 @@ +@startuml Class Model +set namespaceSeparator :: + +abstract class "wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" { + +Widget gridChild() + +Widget successBuilder() +} + +abstract class "wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" { + +Widget errorBuilder() + +Widget loadingBuilder() + +Widget initialBuilder() + +Widget successBuilder() + +Widget crudBuilder() +} + +abstract class "wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" { +} + +"wyatt_bloc_helper::src::cubit.dart::CubitScreen" <|-- "wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" + +abstract class "wyatt_bloc_layout::src::presentation::cubit_screen_crud_list_base.dart::CubitScreenCrudListBase" { +} + +"wyatt_bloc_layout::src::presentation::cubit_screen_crud_base.dart::CubitScreenCrudBase" <|-- "wyatt_bloc_layout::src::presentation::cubit_screen_crud_list_base.dart::CubitScreenCrudListBase" + +abstract class "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud.dart::FrameLayoutCubitScreenCrud" { + +Widget onBuild() +} + +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen.dart::FrameLayoutCubitScreen" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud.dart::FrameLayoutCubitScreenCrud" +"wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud.dart::FrameLayoutCubitScreenCrud" + +abstract class "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud_list.dart::FrameLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud.dart::FrameLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud_list.dart::FrameLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen.dart::FrameLayoutCubitScreen" { + +TopAppBarComponent? Function(TopAppBarComponent?)? customAppBar + +BottomNavigationBarComponent? Function(BottomNavigationBarComponent?)? customBottomNavBar + +double height + +Widget parent() +} + +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen.dart::FrameLayoutCubitScreen" o-- "null::TopAppBarComponent Function(TopAppBarComponent)" +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen.dart::FrameLayoutCubitScreen" o-- "null::BottomNavigationBarComponent Function(BottomNavigationBarComponent)" +"wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen.dart::FrameLayoutCubitScreen" + +abstract class "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_grid_layout_cubit_screen_crud_list.dart::FrameLayoutGridCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud_list.dart::FrameLayoutCubitScreenCrudList" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_grid_layout_cubit_screen_crud_list.dart::FrameLayoutGridCubitScreenCrudList" +"wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_grid_layout_cubit_screen_crud_list.dart::FrameLayoutGridCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud_item.dart::FrameLayoutCubitScreenCrudItem" { +} + +"wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud.dart::FrameLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::frame_bloc_layout::frame_layout_cubit_screen_crud_item.dart::FrameLayoutCubitScreenCrudItem" + +abstract class "wyatt_bloc_layout::src::presentation::cubit_screen_crud_item_base.dart::CubitScreenCrudItemBase" { +} + +"wyatt_bloc_layout::src::presentation::cubit_screen_crud_base.dart::CubitScreenCrudBase" <|-- "wyatt_bloc_layout::src::presentation::cubit_screen_crud_item_base.dart::CubitScreenCrudItemBase" + +abstract class "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud_list.dart::TopAppBarLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud.dart::TopAppBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud_list.dart::TopAppBarLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen.dart::TopAppBarLayoutCubitScreen" { + +double height + +TopAppBarComponent? Function(TopAppBarComponent?)? custom + +Widget parent() +} + +"wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen.dart::TopAppBarLayoutCubitScreen" o-- "null::TopAppBarComponent Function(TopAppBarComponent)" +"wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen.dart::TopAppBarLayoutCubitScreen" + +abstract class "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud.dart::TopAppBarLayoutCubitScreenCrud" { + +Widget onBuild() +} + +"wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen.dart::TopAppBarLayoutCubitScreen" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud.dart::TopAppBarLayoutCubitScreenCrud" +"wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud.dart::TopAppBarLayoutCubitScreenCrud" + +abstract class "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_grid_layout_cubit_screen_crud_list.dart::TopAppBarGridLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud_list.dart::TopAppBarLayoutCubitScreenCrudList" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_grid_layout_cubit_screen_crud_list.dart::TopAppBarGridLayoutCubitScreenCrudList" +"wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_grid_layout_cubit_screen_crud_list.dart::TopAppBarGridLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud_item.dart::TopAppBarLayoutCubitScreenCrudItem" { +} + +"wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud.dart::TopAppBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::top_app_bar_bloc_layout::top_app_bar_layout_cubit_screen_crud_item.dart::TopAppBarLayoutCubitScreenCrudItem" + +abstract class "wyatt_bloc_layout::src::presentation::grid_cubit_screen_crud_list_base.dart::GridCubitScreenCrudListBase" { +} + +"wyatt_bloc_layout::src::presentation::cubit_screen_crud_list_base.dart::CubitScreenCrudListBase" <|-- "wyatt_bloc_layout::src::presentation::grid_cubit_screen_crud_list_base.dart::GridCubitScreenCrudListBase" +"wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" <|-- "wyatt_bloc_layout::src::presentation::grid_cubit_screen_crud_list_base.dart::GridCubitScreenCrudListBase" + +abstract class "wyatt_bloc_layout::src::presentation::cubit_screen_crud_base.dart::CubitScreenCrudBase" { + +Widget onBuild() +} + +"wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" <|-- "wyatt_bloc_layout::src::presentation::cubit_screen_crud_base.dart::CubitScreenCrudBase" +"wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" <|-- "wyatt_bloc_layout::src::presentation::cubit_screen_crud_base.dart::CubitScreenCrudBase" + +abstract class "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen.dart::BottomNavigationBarLayoutCubitScreen" { + +double height + +BottomNavigationBarComponent? Function(BottomNavigationBarComponent?)? custom + +Widget parent() +} + +"wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen.dart::BottomNavigationBarLayoutCubitScreen" o-- "null::BottomNavigationBarComponent Function(BottomNavigationBarComponent)" +"wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen.dart::BottomNavigationBarLayoutCubitScreen" + +abstract class "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud_item.dart::BottomNavigationBarLayoutCubitScreenCrudItem" { +} + +"wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud.dart::BottomNavigationBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud_item.dart::BottomNavigationBarLayoutCubitScreenCrudItem" + +abstract class "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud.dart::BottomNavigationBarLayoutCubitScreenCrud" { + +Widget onBuild() +} + +"wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen.dart::BottomNavigationBarLayoutCubitScreen" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud.dart::BottomNavigationBarLayoutCubitScreenCrud" +"wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud.dart::BottomNavigationBarLayoutCubitScreenCrud" + +abstract class "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart::BottomNavigationBarGridLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud_list.dart::BottomNavigationBarLayoutCubitScreenCrudList" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart::BottomNavigationBarGridLayoutCubitScreenCrudList" +"wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_grid_layout_cubit_screen_crud_list.dart::BottomNavigationBarGridLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud_list.dart::BottomNavigationBarLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud.dart::BottomNavigationBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::bottom_navigation_bar_bloc_layout::bottom_navigation_bar_layout_cubit_screen_crud_list.dart::BottomNavigationBarLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud_list.dart::TopNavigationBarLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud.dart::TopNavigationBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud_list.dart::TopNavigationBarLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_grid_layout_cubit_screen_crud_list.dart::TopNavigationBarGridLayoutCubitScreenCrudList" { +} + +"wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud_list.dart::TopNavigationBarLayoutCubitScreenCrudList" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_grid_layout_cubit_screen_crud_list.dart::TopNavigationBarGridLayoutCubitScreenCrudList" +"wyatt_bloc_layout::src::core::mixins::gird_view_mixin.dart::GridLayoutMixin" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_grid_layout_cubit_screen_crud_list.dart::TopNavigationBarGridLayoutCubitScreenCrudList" + +abstract class "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen.dart::TopNavigationBarLayoutCubitScreen" { + +double height + +TopNavigationBarComponent? Function(TopNavigationBarComponent?)? custom + +Widget parent() +} + +"wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen.dart::TopNavigationBarLayoutCubitScreen" o-- "null::TopNavigationBarComponent Function(TopNavigationBarComponent)" +"wyatt_bloc_layout::src::presentation::cubit_screen_base.dart::CubitScreenBase" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen.dart::TopNavigationBarLayoutCubitScreen" + +abstract class "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud_item.dart::TopNavigationBarLayoutCubitScreenCrudItem" { +} + +"wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud.dart::TopNavigationBarLayoutCubitScreenCrud" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud_item.dart::TopNavigationBarLayoutCubitScreenCrudItem" + +abstract class "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud.dart::TopNavigationBarLayoutCubitScreenCrud" { + +Widget onBuild() +} + +"wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen.dart::TopNavigationBarLayoutCubitScreen" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud.dart::TopNavigationBarLayoutCubitScreenCrud" +"wyatt_bloc_layout::src::core::crud_cubit_consumer_screen_mixin.dart::CrudMixin" <|-- "wyatt_bloc_layout::src::presentation::top_navigation_bar_bloc_layout::top_navigation_bar_layout_cubit_screen_crud.dart::TopNavigationBarLayoutCubitScreenCrud" + + +@enduml \ No newline at end of file diff --git a/packages/wyatt_bloc_layout/pubspec.yaml b/packages/wyatt_bloc_layout/pubspec.yaml new file mode 100644 index 00000000..0e9e8dea --- /dev/null +++ b/packages/wyatt_bloc_layout/pubspec.yaml @@ -0,0 +1,37 @@ +name: wyatt_bloc_layout +description: Layouts based on bloc helper library +repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_bloc_layout +version: 0.1.0+1 + +publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + +environment: + sdk: ">=2.17.0 <3.0.0" + +dependencies: + flutter: { sdk: flutter } + + flutter_bloc: ^8.1.2 + + wyatt_bloc_helper: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 + + wyatt_ui_layout: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.1.0+1 + + wyatt_crud_bloc: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.1.1 + + wyatt_ui_components: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.2.1 + +dev_dependencies: + flutter_test: { sdk: flutter } + + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_cli_toolbox/.gitignore b/packages/wyatt_cli_toolbox/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_cli_toolbox/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_cli_toolbox/AUTHORS b/packages/wyatt_cli_toolbox/AUTHORS deleted file mode 100644 index b6d7d765..00000000 --- a/packages/wyatt_cli_toolbox/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_cli_toolbox/CHANGELOG.md b/packages/wyatt_cli_toolbox/CHANGELOG.md deleted file mode 100644 index effe43c8..00000000 --- a/packages/wyatt_cli_toolbox/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/packages/wyatt_cli_toolbox/LICENSE b/packages/wyatt_cli_toolbox/LICENSE deleted file mode 100644 index e72bfdda..00000000 --- a/packages/wyatt_cli_toolbox/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_cli_toolbox/README.md b/packages/wyatt_cli_toolbox/README.md deleted file mode 100644 index 99103fce..00000000 --- a/packages/wyatt_cli_toolbox/README.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# Dart - CLI Toolbox - -

- - Style: Wyatt Analysis - - SDK: Dart - WIP -

- - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/packages/wyatt_cli_toolbox/analysis_options.yaml b/packages/wyatt_cli_toolbox/analysis_options.yaml deleted file mode 100644 index 2f6092c4..00000000 --- a/packages/wyatt_cli_toolbox/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:wyatt_analysis/analysis_options.yaml \ No newline at end of file diff --git a/packages/wyatt_cli_toolbox/example/wyatt_cli_toolbox_example.dart b/packages/wyatt_cli_toolbox/example/wyatt_cli_toolbox_example.dart deleted file mode 100644 index 0bbdc468..00000000 --- a/packages/wyatt_cli_toolbox/example/wyatt_cli_toolbox_example.dart +++ /dev/null @@ -1,273 +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:io'; -import 'dart:math'; - -import 'package:wyatt_cli_toolbox/wyatt_cli_toolbox.dart'; - -void testStylish() { - print('my beautiful text in magenta'.magenta()); - print('you can combine multiple styles'.yellow().bgBlue().bold()); - - print('\x1B[36mstart style'); - print('style continues on this line'); - print('but not on this line'.reset()); - - print('\x1B[41mnot stripped\x1B[49m'); - print('\x1B[41mstripped\x1B[49m'.strip()); - - Stylish.config(enable: false); - print('you can disable extension'.fg(r: 20, g: 160, b: 80)); - Stylish.config(enable: true); - print('and reenable it on the fly'.fg(r: 20, g: 160, b: 80)); - print('custom bg color'.bg(r: 80, g: 110, b: 30)); -} - -void testSequences() { - Sequences.clearEntireScreen(); - print('Clear entire screen'); - - print('Hide cursor'); - Sequences.hideCursor(); - sleep(Duration(seconds: 1)); - print('Unhide cursor'); - Sequences.unhideCursor(); - sleep(Duration(seconds: 1)); - - print('Save cursor position'); - Sequences.savePosition(); - sleep(Duration(seconds: 1)); - - print('Move cursor'); - Sequences.moveCursor(6, 3); - sleep(Duration(seconds: 1)); - - Sequences.restorePosition(); - Sequences.moveDown(1); - sleep(Duration(seconds: 1)); - print('Restore cursor position'); -} - -Future testSpinners() async { - print('Starting computation 1...'); - await Spinner.start(SpinnerType.fistBump); - sleep(Duration(seconds: 2)); - Spinner.stop(); - - print('Starting computation 2...'); - await Spinner.start(SpinnerType.dots5, text: 'Loading...'); - sleep(Duration(seconds: 3)); - Spinner.stop(); - - print('Starting computation 3...'); - await Spinner.custom( - Indicator( - name: 'Eyes', - interval: 100, - frames: ['◡◡', '⊙⊙', '◠◠'] - .map((String e) => '\x1B[36m$e\x1B[39m') - .toList(), - label: 'Computing...', - ), - ); - await Future.delayed(Duration(seconds: 2)); - Spinner.stop(); - - print('Starting computation 4...'); - await Spinner.start(SpinnerType.pipe, text: 'Linking...'); - sleep(Duration(seconds: 3)); - Spinner.update( - SpinnerType.circle.indicator.copyWith(label: 'Compiling...'), - ); - sleep(Duration(seconds: 3)); - Spinner.stop(); -} - -void testPrompt() { - final Prompt pr = Prompt(); - final StringQuestion q1 = StringQuestion( - "What's your name ?", - identifier: 'name', - ); - final PasswordQuestion q8 = PasswordQuestion( - 'Password ?', - comment: 'Secret shhht.', - identifier: 'password', - ); - final NumberQuestion q7 = NumberQuestion( - 'How old are you?', - identifier: 'age', - ); - final BooleanQuestion q2 = BooleanQuestion( - 'Do you like Dart ?', - identifier: 'dart', - ); - final ListQuestion q3 = ListQuestion( - 'Which target ?', - ['android', 'ios', 'windows', 'macos'], - identifier: 'platform', - ); - final Message q4 = Message( - 'Oh oh !', - level: MessageLevel.warn, - identifier: 'warn', - ); - final Message q5 = Message( - 'Oh damn :(', - level: MessageLevel.fail, - identifier: 'error', - ); - final Message q6 = Message( - 'Thank you, bye! 🤙', - comment: 'Pretty comment nah?', - identifier: 'bye', - ); - - pr - ..addAll(>[q1, q8, q7, q2, q3, q4, q5, q6]) - ..ask(); -} - -Future testWorkflow() async { - final Task t1 = Task( - name: 'Analyzing', - id: 'analyze', - spinner: SpinnerType.circle, - task: () { - return waitFor( - Future.delayed(Duration(seconds: 3), () => 13), - ); - }, - onFinish: (Object? i) { - return '$i files analyzed'; - }, - ); - final Task t2 = Task( - name: 'Formatting', - id: 'format', - spinner: SpinnerType.circle, - task: () { - return waitFor( - Future.delayed(Duration(seconds: 4), () => 1287), - ); - }, - onFinish: (Object? i) { - return '$i files modified'; - }, - ); - final Task t3 = Task( - name: 'Building', - id: 'build', - task: () { - final List _tasks = [ - 'main.c', - 'crypto.c', - 'workflow.c', - 'wyatt.c', - 'logger.c', - 'task.c', - ]; - for (final String i in _tasks) { - Task.print(i); - sleep(Duration(seconds: Random().nextInt(4) + 1)); - } - }, - onFinish: (_) { - return 'Compilation success'; - }, - ); - final Task t4 = Task( - name: 'Testing', - id: 'test', - task: () { - final List _tasks = [ - 'wyatt.h', - 'crypto.h', - ]; - for (final String i in _tasks) { - Task.print(i); - sleep(Duration(seconds: Random().nextInt(3))); - } - throw Exception('An error occured during ${'test::crypto.h'.red()}'); - }, - onFinish: (_) { - return 'All tests passed'; - }, - onError: (Object e) { - return e.toString(); - }, - ); - final Task t5 = Task( - name: 'Bundling', - id: 'bundle', - task: () { - sleep(Duration(seconds: 3)); - throw SkipException('Bundle skipped.'); - }, - onFinish: (_) { - return 'Files generated in dist/'; - }, - onSkip: (SkipException e) { - return e.toString(); - }, - ); - - final Workflow w = await Workflow.create(>[t1, t2, t3, t4, t5]); - w.start(); - - print('\n${w.results.toString().dim()}'); -} - -void testNewPrompt() { - final name = Input(message: 'Your name').prompt(); - stdout.writeln(name); - - final email = Input( - message: 'Your email', - validator: (String x) { - if (x.contains('@')) { - return true; - } else { - throw ValidationError('Not a valid email'); - } - }, - ).prompt(); - stdout.writeln(email); - - final planet = Input( - message: 'Your planet', - defaultValue: 'Earth', - ).prompt(); - stdout.writeln(planet); - - final galaxy = Input( - message: 'Your galaxy', - initialValue: 'Andromeda', - ).prompt(); - stdout.writeln(galaxy); -} - -Future main() async { - // sleep(Duration(seconds: 2)); - // testPrompt(); - // await testWorkflow(); - // testStylish(); - // testSequences(); - // await testSpinners(); - // testPrompt(); - testNewPrompt(); -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/boolean_question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/boolean_question.dart deleted file mode 100644 index f817e3bd..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/boolean_question.dart +++ /dev/null @@ -1,60 +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:convert'; -import 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class BooleanQuestion extends Question { - BooleanQuestion( - String question, { - this.defaultTo = false, - String? comment, - required String identifier, - }) : super(QuestionType.booleanQuestion, identifier, question, comment); - - bool? answer; - final bool defaultTo; - - @override - String formatComment() => (super.formatComment().trim().isEmpty) - ? defaultTo - ? ' (Y/n) '.dim() - : ' (y/N) '.dim() - : super.formatComment(); - - @override - bool ask() { - stdout.write(formatQuestion()); - String input = ''; - input = stdin.readLineSync(encoding: utf8)!.trim(); - stdout.write(Sequences.escMoveUp(1) + formatQuestion()); - if (input.isEmpty) { - answer = defaultTo; - } else { - answer = input[0] == 'y' || input[0] == 'Y'; - } - String replaceStr = - '\r${formatQuestion()}${Sequences.escClearLineFromCursorToEnd()}'; - replaceStr += answer! ? 'Yes'.blue() : 'No'.blue(); - stdout.writeln(replaceStr); - - return answer!; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/control.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/control.dart deleted file mode 100644 index a90099b9..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/control.dart +++ /dev/null @@ -1,49 +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:io'; - -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -/// Abstract class providing XTerm escape sequences -abstract class Control { - /// Use Squences.escMoveUp, concatenate your string ([str]) - /// and then blank the remaining line. - static String replacePreviousLine(String str) => - Sequences.escMoveUp(1) + str + Sequences.escClearLineFromCursorToEnd(); - - /// Reset XTerm sequence. - /// This is always applied after using some other sequence. - static String reset = ''.reset(); - - /// See: https://codepoints.net/dingbats - static String questionIndicator() => '?'.green(); - - static String exclamationIndicator() => '!'.yellow(); - - static String infoIndicator() => - Platform.isWindows ? 'i'.cyan() : '\u2139'.cyan(); - - static String rightIndicator() => - Platform.isWindows ? '>'.blue() : '\u276F'.blue(); - - static String validIndicator() => - Platform.isWindows ? 'v'.green() : '\u2714'.green(); - - static String wrongIndicator() => - Platform.isWindows ? 'x'.red() : '\u2718'.red(); -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/build_context.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/framework/build_context.dart deleted file mode 100644 index 61586db9..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/build_context.dart +++ /dev/null @@ -1,95 +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 . - -part of prompt.framework; - -class BuildContext { - int _buildCount = 0; - int get buildCount => _buildCount; - void incrementBuildCount() => _buildCount++; - void resetBuildCount() => _buildCount = 0; - - int _lineCount = 0; - int get lineCount => _lineCount; - void incrementLineCount() => _lineCount++; - void resetLineCount() => _lineCount = 0; - - static void reset() { - Sequences.unhideCursor(); - Sequences.write(''.reset()); - } - - void hideCursor() { - Sequences.hideCursor(); - } - - void showCursor() { - Sequences.unhideCursor(); - } - - void write(String text) { - Sequences.write(text); - } - - void writeln(String text) { - incrementLineCount(); - Sequences.writeln(text); - } - - void erasePreviousLine([int n = 1]) { - for (int i = 0; i < n; i++) { - Sequences.moveUp(1); - Sequences.clearEntireLine(); - } - } - - void wipe() { - erasePreviousLine(lineCount); - resetLineCount(); - } - - int readKey() => stdin.readByteSync(); - - String readLine({ - String initialValue = '', - }) { - var buffer = initialValue; - var index = buffer.length; - - Sequences.savePosition(); - - if (buffer.isNotEmpty) { - write(buffer); - } - - while (true) { - final key = readKey(); - if (index == buffer.length) { - buffer += String.fromCharCode(key); - index++; - } else { - buffer = buffer.substring(0, index) + - String.fromCharCode(key) + - buffer.substring(index); - index++; - } - - Sequences.restorePosition(); - Sequences.clearLineFromCursorToEnd(); - write(buffer); - } - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/theme.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/framework/theme.dart deleted file mode 100644 index f6dde1a0..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/theme.dart +++ /dev/null @@ -1,150 +0,0 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// 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:io'; - -import 'package:wyatt_cli_toolbox/src/spinners/spinners.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -typedef StyleFunction = String Function(String); - -class Theme { - final String inputPrefix; - final String inputSuffix; - final String successPrefix; - final String successSuffix; - final String errorPrefix; - final String hiddenPrefix; - final StyleFunction messageStyle; - final StyleFunction errorStyle; - final StyleFunction hintStyle; - final StyleFunction valueStyle; - final StyleFunction defaultStyle; - - final String activeItemPrefix; - final String inactiveItemPrefix; - final StyleFunction activeItemStyle; - final StyleFunction inactiveItemStyle; - - final String checkedItemPrefix; - final String uncheckedItemPrefix; - - final String pickedItemPrefix; - final String unpickedItemPrefix; - - final bool showActiveCursor; - - final SpinnerType spinner; - - const Theme({ - required this.inputPrefix, - required this.inputSuffix, - required this.successPrefix, - required this.successSuffix, - required this.errorPrefix, - required this.hiddenPrefix, - required this.messageStyle, - required this.errorStyle, - required this.hintStyle, - required this.valueStyle, - required this.defaultStyle, - required this.activeItemPrefix, - required this.inactiveItemPrefix, - required this.activeItemStyle, - required this.inactiveItemStyle, - required this.checkedItemPrefix, - required this.uncheckedItemPrefix, - required this.pickedItemPrefix, - required this.unpickedItemPrefix, - required this.showActiveCursor, - required this.spinner, - }); - - Theme copyWith({ - String? inputPrefix, - String? inputSuffix, - String? successPrefix, - String? successSuffix, - String? errorPrefix, - String? hiddenPrefix, - StyleFunction? messageStyle, - StyleFunction? errorStyle, - StyleFunction? hintStyle, - StyleFunction? valueStyle, - StyleFunction? defaultStyle, - String? activeItemPrefix, - String? inactiveItemPrefix, - StyleFunction? activeItemStyle, - StyleFunction? inactiveItemStyle, - String? checkedItemPrefix, - String? uncheckedItemPrefix, - String? pickedItemPrefix, - String? unpickedItemPrefix, - bool? showActiveCursor, - SpinnerType? spinner, - }) { - return Theme( - inputPrefix: inputPrefix ?? this.inputPrefix, - inputSuffix: inputSuffix ?? this.inputSuffix, - successPrefix: successPrefix ?? this.successPrefix, - successSuffix: successSuffix ?? this.successSuffix, - errorPrefix: errorPrefix ?? this.errorPrefix, - hiddenPrefix: hiddenPrefix ?? this.hiddenPrefix, - messageStyle: messageStyle ?? this.messageStyle, - errorStyle: errorStyle ?? this.errorStyle, - hintStyle: hintStyle ?? this.hintStyle, - valueStyle: valueStyle ?? this.valueStyle, - defaultStyle: defaultStyle ?? this.defaultStyle, - activeItemPrefix: activeItemPrefix ?? this.activeItemPrefix, - inactiveItemPrefix: inactiveItemPrefix ?? this.inactiveItemPrefix, - activeItemStyle: activeItemStyle ?? this.activeItemStyle, - inactiveItemStyle: inactiveItemStyle ?? this.inactiveItemStyle, - checkedItemPrefix: checkedItemPrefix ?? this.checkedItemPrefix, - uncheckedItemPrefix: uncheckedItemPrefix ?? this.uncheckedItemPrefix, - pickedItemPrefix: pickedItemPrefix ?? this.pickedItemPrefix, - unpickedItemPrefix: unpickedItemPrefix ?? this.unpickedItemPrefix, - showActiveCursor: showActiveCursor ?? this.showActiveCursor, - spinner: spinner ?? this.spinner, - ); - } - - static Theme defaultTheme = colorfulTheme; - - static final colorfulTheme = Theme( - inputPrefix: '?'.padRight(2).green(), - inputSuffix: (Platform.isWindows ? '>' : '\u276F').padLeft(2).grey(), - successPrefix: (Platform.isWindows ? 'v' : '\u2714').padRight(2).green(), - successSuffix: '•'.padLeft(2).grey(), - errorPrefix: (Platform.isWindows ? 'x' : '\u2718').padRight(2).red(), - hiddenPrefix: '*****', - messageStyle: (String message) => message.bold(), - errorStyle: (String error) => error.red(), - hintStyle: (String hint) => '($hint)'.grey(), - valueStyle: (String value) => value.green(), - defaultStyle: (String value) => value.cyan(), - activeItemPrefix: (Platform.isWindows ? '>' : '\u276F').green(), - inactiveItemPrefix: ' ', - activeItemStyle: (String item) => item.cyan(), - inactiveItemStyle: (String item) => item, - checkedItemPrefix: (Platform.isWindows ? 'v' : '\u2714').green(), - uncheckedItemPrefix: ' ', - pickedItemPrefix: (Platform.isWindows ? '>' : '\u276F').green(), - unpickedItemPrefix: ' ', - showActiveCursor: false, - spinner: SpinnerType.arrow, - ); -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/widget.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/framework/widget.dart deleted file mode 100644 index 0b2fd301..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/framework/widget.dart +++ /dev/null @@ -1,46 +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 . - -part of prompt.framework; - -abstract class Widget { - int _initLineCount = 0; - - /// Creates the mutable state for this widget - @protected - @factory - State createState(); - - State pipeState(State state) => state; - - T prompt() { - final state = pipeState(createState()) - .._widget = this - ..initState(); - _initLineCount = state.context.lineCount; - state.context.resetLineCount(); - - state.build(); - state.context.incrementBuildCount(); - - final dynamic out = state.prompt(); - state.context.wipe(); - state.context.erasePreviousLine(_initLineCount); - state.dispose(); - - return out as T; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/keys.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/keys.dart deleted file mode 100644 index 73a4b37f..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/keys.dart +++ /dev/null @@ -1,56 +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 . - -// ignore_for_file: constant_identifier_names - -import 'dart:io'; - -const int ARROW_UP = 65; -const int ARROW_DOWN = 66; -const int ENTER = 10; -const int SPACE = 32; - -const int WIN_UP = 119; -const int WIN_DOWN = 115; -const int WIN_ENTER = 13; -const int WIN_SPACE = 20; - -/// Abstract class providing some key codes which can be statically accessed. -abstract class Keys { - /// Arrow down. Consists of three bytes. - /// For historical reasons, you can also use 's' - /// instead of arrow down on Windows. - /// - /// It is packed into a single element list in - /// order to not break the spread syntax. - static final List arrowDown = - Platform.isWindows ? [WIN_DOWN] : [27, 91, 66]; - - /// Arrows up. Consists of three bytes in Unix like systems (including MacOS). - /// For historical reasons, you can also use 'w' insted of arrow - /// up on Windows. - /// - /// It is packed into a single element list in - /// order to not break the spread syntax. - static final List arrowUp = - Platform.isWindows ? [WIN_UP] : [27, 91, 65]; - - /// Enter key. Single byte. - static final int enter = Platform.isWindows ? WIN_ENTER : ENTER; - - /// Space key. Single byte. - static final int space = Platform.isWindows ? WIN_SPACE : SPACE; -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/list_chooser.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/list_chooser.dart deleted file mode 100644 index e2ad2584..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/list_chooser.dart +++ /dev/null @@ -1,129 +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:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/control.dart'; -import 'package:wyatt_cli_toolbox/src/prompt/keys.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class ListChooser { - ListChooser(this.options) { - if (stdin.hasTerminal) { - // lineMode must be true to set echoMode in Windows - // see https://github.com/dart-lang/sdk/issues/28599 - stdin.echoMode = false; - stdin.lineMode = false; - } - } - - List options; - - String choose() { - int input; - int index = 0; - - _renderList(0, initial: true); - - while ((input = _userInput()) != ENTER) { - if (input == ARROW_UP) { - if (index > 0) { - index--; - } - } else if (input == ARROW_DOWN) { - if (index < options.length - 1) { - index++; - } - } - _renderList(index); - } - _resetStdin(); - return options[index]; - } - - void _deletePreviousList() { - for (int i = 0; i < options.length; i++) { - Sequences.write( - Sequences.escMoveUp(1) + Sequences.escClearLineFromCursorToEnd(), - ); - } - } - - void _renderList(int index, {bool initial = false}) { - if (!initial) { - _deletePreviousList(); - } - for (int i = 0; i < options.length; i++) { - if (i == index) { - stdout.writeln('${Control.rightIndicator()} ${options[i].blue()}'); - continue; - } - stdout.writeln(' ${options[i]}'); - } - } - - void _resetStdin() { - if (stdin.hasTerminal) { - // Order is important here - stdin.lineMode = true; - stdin.echoMode = true; - } - } - - // TODO(hpcl): improve keycode parsing for multiple bytes codes - int _userInput() { - final int navigationResult = stdin.readByteSync(); - if (navigationResult < 0) { - return navigationResult; - } - - if (Platform.isWindows) { - if (navigationResult == Keys.enter) { - return ENTER; - } - if (navigationResult == Keys.space) { - return SPACE; - } - if (navigationResult == Keys.arrowUp[0]) { - return ARROW_UP; - } - if (navigationResult == Keys.arrowDown[0]) { - return ARROW_DOWN; - } else { - return navigationResult; - } - } else { - if (navigationResult == ENTER) { - return ENTER; - } - if (navigationResult == SPACE) { - return SPACE; - } - - final int anotherByte = stdin.readByteSync(); - if (anotherByte == ENTER) { - return ENTER; - } - if (anotherByte == SPACE) { - return SPACE; - } - - final int input = stdin.readByteSync(); - return input; - } - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/list_question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/list_question.dart deleted file mode 100644 index c36ca38c..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/list_question.dart +++ /dev/null @@ -1,47 +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:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/list_chooser.dart'; -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class ListQuestion extends Question { - ListQuestion( - String question, - this.options, { - String? comment, - required String identifier, - }) : super(QuestionType.listQuestion, identifier, question, comment); - - List options; - String? answer; - - @override - String formatComment() => (super.formatComment().trim().isEmpty) - ? ' (User arrow keys) '.dim() - : super.formatComment(); - - @override - String ask() { - stdout.writeln(formatQuestion()); - final ListChooser chooser = ListChooser(options); - final String input = chooser.choose(); - answer = input; - return input; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/message.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/message.dart deleted file mode 100644 index 875d6abd..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/message.dart +++ /dev/null @@ -1,54 +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:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/control.dart'; -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; - -enum MessageLevel { debug, info, success, warn, fail } - -class Message extends Question { - Message( - String text, { - String? comment, - this.level = MessageLevel.info, - required String identifier, - }) : super(QuestionType.message, identifier, text, comment); - - MessageLevel level; - - @override - String get prefix { - switch (level) { - case MessageLevel.debug: - return ' '; - case MessageLevel.info: - return Control.infoIndicator(); - case MessageLevel.success: - return Control.validIndicator(); - case MessageLevel.warn: - return Control.exclamationIndicator(); - case MessageLevel.fail: - return Control.wrongIndicator(); - } - } - - @override - void ask() { - stdout.writeln(formatQuestion()); - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/number_question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/number_question.dart deleted file mode 100644 index 9fdfa186..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/number_question.dart +++ /dev/null @@ -1,57 +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:convert'; -import 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class NumberQuestion extends Question { - NumberQuestion(String question, {String? comment, required String identifier}) - : super(QuestionType.stringQuestion, identifier, question, comment); - - num? answer; - - @override - String formatComment() => (super.formatComment().trim().isEmpty) - ? ' Mandatory! '.dim() - : super.formatComment(); - - @override - num ask() { - stdout.write(formatQuestion()); - String input = ''; - bool valid = false; - num answer = 0; - while (!valid) { - input = stdin.readLineSync(encoding: utf8)!.trim(); - try { - valid = input.isNotEmpty; - answer = num.parse(input); - } catch (e) { - valid = false; - } - stdout.write(Sequences.escMoveUp(1) + formatQuestion()); - } - stdout.writeln( - // ignore: lines_longer_than_80_chars - '\r${formatQuestion()}${answer.toString().blue()}${Sequences.escClearLineFromCursorToEnd()}', - ); - return answer; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/password_question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/password_question.dart deleted file mode 100644 index 655c842a..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/password_question.dart +++ /dev/null @@ -1,66 +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:convert'; -import 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/keys.dart'; -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class PasswordQuestion extends Question { - PasswordQuestion( - String question, { - String? comment, - required String identifier, - }) : super(QuestionType.passwordQuestion, identifier, question, comment); - - String? answer; - - @override - String ask() { - if (stdin.hasTerminal) { - stdin.echoMode = false; - stdin.lineMode = false; - } - - stdout.write(formatQuestion()); - String input = ''; - final List bytes = []; - - int lastB = stdin.readByteSync(); - while (lastB != Keys.enter) { - stdout.write('*'); - bytes.add(lastB); - lastB = stdin.readByteSync(); - } - input = utf8.decode(bytes); - stdout.write(formatQuestion()); - answer = List.generate(input.length, (_) => '*') - .reduce((String value, String element) => '$value$element'); - stdout.writeln( - // ignore: lines_longer_than_80_chars - '\r${formatQuestion()}${answer!.blue()}${Sequences.escClearLineFromCursorToEnd()}', - ); - - if (stdin.hasTerminal) { - stdin.lineMode = true; - stdin.echoMode = true; - } - return input; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/prompt.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/prompt.dart deleted file mode 100644 index 962ea92e..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/prompt.dart +++ /dev/null @@ -1,66 +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 'package:wyatt_cli_toolbox/src/prompt/question.dart'; - -export 'boolean_question.dart'; -export 'framework/framework.dart'; -export 'framework/theme.dart'; -export 'list_question.dart'; -export 'message.dart'; -export 'number_question.dart'; -export 'password_question.dart'; -export 'question.dart'; -export 'string_question.dart'; -export 'widgets/input.dart'; - -class Prompt { - Prompt({this.questions}); - - Map answers = {}; - List>? questions; - - void add(Question question) { - if (questions != null) { - questions!.add(question); - } else { - questions = >[question]; - } - } - - void addAll(List> questions) { - if (this.questions != null) { - this.questions!.addAll(questions); - } else { - this.questions = questions; - } - } - - Map ask() { - if (questions != null) { - for (final Question question in questions!) { - if (!(question.type == QuestionType.message)) { - answers[question.identifier] = question.ask(); - } else { - question.ask(); - } - } - } else { - throw Exception('You must add questions before asking for prompt.'); - } - return answers; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/question.dart deleted file mode 100644 index 5e45a3d6..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/question.dart +++ /dev/null @@ -1,42 +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 'package:wyatt_cli_toolbox/src/prompt/control.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -enum QuestionType { - message, - stringQuestion, - booleanQuestion, - listQuestion, - passwordQuestion -} - -abstract class Question { - Question(this.type, this.identifier, this.question, this.comment); - - final QuestionType type; - final String identifier; - final String question; - final String? comment; - - String prefix = Control.questionIndicator(); - - String formatComment() => (comment != null) ? ' $comment '.dim() : ' '; - String formatQuestion() => '$prefix $question${formatComment()}'; - - T ask(); -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/string_question.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/string_question.dart deleted file mode 100644 index b1b81072..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/string_question.dart +++ /dev/null @@ -1,43 +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:convert'; -import 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/prompt/question.dart'; -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -class StringQuestion extends Question { - StringQuestion(String question, {String? comment, required String identifier}) - : super(QuestionType.stringQuestion, identifier, question, comment); - - String? answer; - - @override - String ask() { - stdout.write(formatQuestion()); - String input = ''; - input = stdin.readLineSync(encoding: utf8)!.trim(); - stdout.write(Sequences.escMoveUp(1) + formatQuestion()); - answer = input; - stdout.writeln( - // ignore: lines_longer_than_80_chars - '\r${formatQuestion()}${answer!.blue()}${Sequences.escClearLineFromCursorToEnd()}', - ); - return input; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/prompt/widgets/input.dart b/packages/wyatt_cli_toolbox/lib/src/prompt/widgets/input.dart deleted file mode 100644 index dddd374f..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/prompt/widgets/input.dart +++ /dev/null @@ -1,134 +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 'package:wyatt_cli_toolbox/src/prompt/framework/framework.dart'; -import 'package:wyatt_cli_toolbox/src/prompt/framework/theme.dart'; - -class Input extends Widget { - final String message; - final String initialValue; - final String? defaultValue; - final bool Function(String)? validator; - final Theme theme; - - Input({ - required this.message, - this.initialValue = '', - this.defaultValue, - this.validator, - }) : theme = Theme.defaultTheme; - - Input.withTheme({ - required this.message, - required this.theme, - this.initialValue = '', - this.defaultValue, - this.validator, - }); - - String promptInput({ - required String message, - String? hint, - }) { - final buffer = StringBuffer() - ..write(theme.inputPrefix) - ..write(theme.messageStyle(message)); - if (hint != null) { - buffer - ..write(' ') - ..write(theme.hintStyle(hint)); - } - buffer - ..write(theme.inputSuffix) - ..write(' '); - return buffer.toString(); - } - - String promptError({ - required String message, - }) { - final buffer = StringBuffer() - ..write(theme.errorPrefix) - ..write(theme.errorStyle(message)); - - return buffer.toString(); - } - - @override - State createState() => _InputState(); -} - -class _InputState extends State { - String? _value; - String? _error; - - @override - void initState() { - super.initState(); - _value = widget.initialValue; - } - - @override - void dispose() { - if (_value != null) { - // TODO(hpcl): print success - } - super.dispose(); - } - - @override - void build() { - if (_error != null) { - context.writeln(widget.promptError(message: _error!)); - } - } - - @override - String prompt() { - while (true) { - context.write( - widget.promptInput( - message: widget.message, - hint: widget.defaultValue, - ), - ); - final input = context.readLine(initialValue: widget.initialValue); - final line = input.isEmpty && widget.defaultValue != null - ? widget.defaultValue! - : input; - if (widget.validator != null) { - try { - widget.validator!(line); - } on ValidationError catch (e) { - setState(() { - _error = e.message; - }); - continue; - } - } - setState(() { - _value = line; - }); - return _value!; - } - } -} - -class ValidationError implements Exception { - final String message; - - ValidationError(this.message); -} diff --git a/packages/wyatt_cli_toolbox/lib/src/sequences/sequences.dart b/packages/wyatt_cli_toolbox/lib/src/sequences/sequences.dart deleted file mode 100644 index 2e96d89b..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/sequences/sequences.dart +++ /dev/null @@ -1,155 +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:io'; - -/// Abstract class providing some useful ANSI escape sequences -abstract class Sequences { - /// Clear screen (Raw Sequence) `\x1B[J` - static String escClearScreen() => '\x1B[J'; - - /// Clear screen from cursor to end (Raw Sequence) `\x1B[0J` - static String escClearScreenFromCursorToEnd() => '\x1B[0J'; - - /// Clear screen from cursor to start (Raw Sequence) `\x1B[1J` - static String escClearScreenFromCursorToStart() => '\x1B[1J'; - - /// Clear entire screen (Raw Sequence) `\x1B[2J` - static String escClearEntireScreen() => '\x1B[2J'; - - /// Clear line (Raw Sequence) `\x1B[K` - static String escClearLine() => '\x1B[K'; - - /// Clear line from cursor to end (Raw Sequence) `\x1B[0K` - static String escClearLineFromCursorToEnd() => '\x1B[0K'; - - /// Clear line from cursor to start (Raw Sequence) `\x1B[1K` - static String escClearLineFromCursorToStart() => '\x1B[1K'; - - /// Clear entire line (Raw Sequence) `\x1B[2K` - static String escClearEntireLine() => '\x1B[2K'; - - /// Move cursor up **#** lines (Raw Sequence) `\x1B[#A` - static String escMoveUp(int n) => '\x1B[${n}A'; - - /// Move cursor down **#** lines (Raw Sequence) `\x1B[#B` - static String escMoveDown(int n) => '\x1B[${n}B'; - - /// Move cursor right **#** columns (Raw Sequence) `\x1B[#C` - static String escMoveRight(int n) => '\x1B[${n}C'; - - /// Move cursor left **#** columns (Raw Sequence) `\x1B[#D` - static String escMoveLeft(int n) => '\x1B[${n}D'; - - /// Move cursor down **#** lines and place cursor at start (Raw Sequence) `\x1B[#E` - static String escMoveDownAtStart(int n) => '\x1B[${n}E'; - - /// Move cursor up **#** lines and place cursor at start (Raw Sequence) `\x1B[#F` - static String escMoveUpAtStart(int n) => '\x1B[${n}F'; - - /// Move cursor on x axis **#** columens (Raw Sequence) `\x1B[#G` - static String escMoveHorizontal(int n) => '\x1B[${n}G'; - - /// Move cursor on x,y axis (Raw Sequence) `\x1B[$line;${column}H` - static String escMoveCursor(int line, int column) => '\x1B[$line;${column}H'; - - /// Save cursor position (Raw Sequence) `\x1B7` - static String escSavePosition() => '\x1B7'; - - /// Restore cursor position (Raw Sequence) `\x1B8` - static String escRestorePosition() => '\x1B8'; - - /// Hide cursor (Raw Sequence) `\x1B[?25l` - static String escHideCursor() => '\x1B[?25l'; - - /// Unhide cursor (Raw Sequence) `\x1B[?25h` - static String escUnhideCursor() => '\x1B[?25h'; - - /// Clear screen `\x1B[J` - static void clearScreen() => write(escClearScreen()); - - /// Clear screen from cursor to end `\x1B[0J` - static void clearScreenFromCursorToEnd() => - write(escClearScreenFromCursorToEnd()); - - /// Clear screen from cursor to start `\x1B[1J` - static void clearScreenFromCursorToStart() => - write(escClearScreenFromCursorToStart()); - - /// Clear entire screen `\x1B[2J` - static void clearEntireScreen() => write(escClearEntireScreen()); - - /// Clear line `\x1B[K` - static void clearLine() => write(escClearLine()); - - /// Clear line from cursor to end `\x1B[0K` - static void clearLineFromCursorToEnd() => - write(escClearLineFromCursorToEnd()); - - /// Clear line from cursor to start `\x1B[1K` - static void clearLineFromCursorToStart() => - write(escClearLineFromCursorToStart()); - - /// Clear entire line `\x1B[2K` - static void clearEntireLine() => write(escClearEntireLine()); - - /// Move cursor up **#** lines `\x1B[#A` - static void moveUp(int n) => write(escMoveUp(n)); - - /// Move cursor down **#** lines `\x1B[#B` - static void moveDown(int n) => write(escMoveDown(n)); - - /// Move cursor right **#** columns `\x1B[#C` - static void moveRight(int n) => write(escMoveRight(n)); - - /// Move cursor left **#** columns `\x1B[#D` - static void moveLeft(int n) => write(escMoveLeft(n)); - - /// Move cursor down **#** lines and place cursor at start `\x1B[#E` - static void moveDownAtStart(int n) => write(escMoveDownAtStart(n)); - - /// Move cursor up **#** lines and place cursor at start `\x1B[#F` - static void moveUpAtStart(int n) => write(escMoveUpAtStart(n)); - - /// Move cursor on x axis **#** columens `\x1B[#G` - static void moveHorizontal(int n) => write(escMoveHorizontal(n)); - - /// Move cursor on x,y axis `\x1B[$line;${column}H` - static void moveCursor(int line, int column) => - write(escMoveCursor(line, column)); - - /// Save cursor position `\x1B7` - static void savePosition() => write(escSavePosition()); - - /// Restore cursor position `\x1B8` - static void restorePosition() => write(escRestorePosition()); - - /// Hide cursor `\x1B[?25l` - static void hideCursor() => write(escHideCursor()); - - /// Unhide cursor `\x1B[?25h` - static void unhideCursor() => write(escUnhideCursor()); - - /// Write string in standard output - static void write(String string) { - stdout.write(string); - } - - /// Write string on new line in standard output - static void writeln(String string) { - stdout.writeln(string); - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/spinners/indicator.dart b/packages/wyatt_cli_toolbox/lib/src/spinners/indicator.dart deleted file mode 100644 index 9b173cb0..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/spinners/indicator.dart +++ /dev/null @@ -1,99 +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 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; - -/// The [frames] field holds each individual frame of an animation, whilst the -/// [interval] represents the sleep time between each frame. -class Indicator { - - Indicator({ - required this.name, - required this.interval, - required this.frames, - this.label, - }); - - factory Indicator.fromMap(Map> map) { - final String name = map.keys.first; - return Indicator( - name: name, - // ignore: cast_nullable_to_non_nullable - interval: map[name]!['interval'] as int, - // ignore: cast_nullable_to_non_nullable - frames: List.from(map[name]!['frames'] as List), - ); - } - - final String name; - final int interval; - final List frames; - final String? label; - Timer? _timer; - - - Map> toMap() { - return >{ - name: { - 'interval': interval, - 'frames': frames, - }, - }; - } - - /// Animate the spinner. - void animate() { - stop(); - int frame = 0; - _timer = Timer.periodic(Duration(milliseconds: interval), (Timer t) { - Sequences.clearEntireLine(); - frame = (frame + 1) % frames.length; - if (label != null) { - stdout.write('${frames[frame]} $label'); - } else { - stdout.write(frames[frame]); - } - Sequences.moveHorizontal(1); - }); - } - - /// Stop the spinner (but don't kill isolate) - void stop() { - Sequences.clearEntireLine(); - _timer?.cancel(); - } - - Indicator copyWith({ - String? name, - int? interval, - List? frames, - String? label, - }) { - return Indicator( - name: name ?? this.name, - interval: interval ?? this.interval, - frames: frames ?? this.frames, - label: label ?? this.label, - ); - } - - @override - String toString() => - 'Indicator(name: $name, interval: $interval, frames: $frames)'; -} diff --git a/packages/wyatt_cli_toolbox/lib/src/spinners/spinner.dart b/packages/wyatt_cli_toolbox/lib/src/spinners/spinner.dart deleted file mode 100644 index 05010a8a..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/spinners/spinner.dart +++ /dev/null @@ -1,66 +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 'dart:isolate'; - -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/spinners/indicator.dart'; -import 'package:wyatt_cli_toolbox/src/spinners/spinner_type.dart'; - - -class Spinner { - /// Active isolate object. Is created when [start] is called. - static Isolate? _spinnerIsolate; - - /// Run the animation of active [_spinnerIsolate]. - static Future _animate(Indicator indicator) async { - indicator.animate(); - } - - /// Starts an animation on a new line. - static Future start(SpinnerType spinner, {String? text}) async { - return custom(spinner.indicator.copyWith(label: text)); - } - - /// Starts a custom animation on a new line. - static Future custom(Indicator indicator) async { - Sequences.hideCursor(); - return _spinnerIsolate ?? - (_spinnerIsolate = await Isolate.spawn( - _animate, - indicator, - )); - } - - /// Stops current spinner animation by killing the isolate instance, - /// and clears current line. - static void stop() { - if (_spinnerIsolate != null) { - _spinnerIsolate!.kill(priority: Isolate.immediate); - } - _spinnerIsolate = null; - Sequences.clearEntireLine(); - Sequences.moveHorizontal(1); - Sequences.unhideCursor(); - } - - /// Stop and restart a new indicator on same line. - static void update(Indicator indicator) { - stop(); - custom(indicator); - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/spinners/spinner_type.dart b/packages/wyatt_cli_toolbox/lib/src/spinners/spinner_type.dart deleted file mode 100644 index b7a86eee..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/spinners/spinner_type.dart +++ /dev/null @@ -1,113 +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 'package:wyatt_cli_toolbox/src/spinners/spinners.dart'; - -enum SpinnerType { - dots, - dots2, - dots3, - dots4, - dots5, - dots6, - dots7, - dots8, - dots9, - dots10, - dots11, - dots12, - dots8Bit, - line, - line2, - pipe, - simpleDots, - simpleDotsScrolling, - star, - star2, - flip, - hamburger, - growVertical, - growHorizontal, - balloon, - balloon2, - noise, - bounce, - boxBounce, - boxBounce2, - triangle, - arc, - circle, - squareCorners, - circleQuarters, - circleHalves, - squish, - toggle, - toggle2, - toggle3, - toggle4, - toggle5, - toggle6, - toggle7, - toggle8, - toggle9, - toggle10, - toggle11, - toggle12, - toggle13, - arrow, - arrow2, - arrow3, - bouncingBar, - bouncingBall, - smiley, - monkey, - hearts, - clock, - earth, - material, - moon, - runner, - pong, - shark, - dqpb, - weather, - christmas, - grenade, - point, - layer, - betaWave, - fingerDance, - fistBump, - soccerHeader, - mindblown, - speaker, - orangePulse, - bluePulse, - orangeBluePulse, - timeTravel, - aesthetic; - - String get name => toString().replaceAll(RegExp('SpinnerType.'), ''); - Indicator get indicator { - if (spinners.keys.contains(name)) { - return Indicator.fromMap( - >{name: spinners[name]!}, - ); - } else { - throw UnimplementedError(); - } - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/spinners/spinners.dart b/packages/wyatt_cli_toolbox/lib/src/spinners/spinners.dart deleted file mode 100644 index 6cfc9fbf..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/spinners/spinners.dart +++ /dev/null @@ -1,1111 +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 'indicator.dart'; -export 'spinner.dart'; -export 'spinner_type.dart'; - -// From https://raw.githubusercontent.com/sindresorhus/cli-spinners/master/spinners.json -const Map> spinners = >{ - 'dots': { - 'interval': 80, - 'frames': ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] - }, - 'dots2': { - 'interval': 80, - 'frames': ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] - }, - 'dots3': { - 'interval': 80, - 'frames': ['⠋', '⠙', '⠚', '⠞', '⠖', '⠦', '⠴', '⠲', '⠳', '⠓'] - }, - 'dots4': { - 'interval': 80, - 'frames': [ - '⠄', - '⠆', - '⠇', - '⠋', - '⠙', - '⠸', - '⠰', - '⠠', - '⠰', - '⠸', - '⠙', - '⠋', - '⠇', - '⠆' - ] - }, - 'dots5': { - 'interval': 80, - 'frames': [ - '⠋', - '⠙', - '⠚', - '⠒', - '⠂', - '⠂', - '⠒', - '⠲', - '⠴', - '⠦', - '⠖', - '⠒', - '⠐', - '⠐', - '⠒', - '⠓', - '⠋' - ] - }, - 'dots6': { - 'interval': 80, - 'frames': [ - '⠁', - '⠉', - '⠙', - '⠚', - '⠒', - '⠂', - '⠂', - '⠒', - '⠲', - '⠴', - '⠤', - '⠄', - '⠄', - '⠤', - '⠴', - '⠲', - '⠒', - '⠂', - '⠂', - '⠒', - '⠚', - '⠙', - '⠉', - '⠁' - ] - }, - 'dots7': { - 'interval': 80, - 'frames': [ - '⠈', - '⠉', - '⠋', - '⠓', - '⠒', - '⠐', - '⠐', - '⠒', - '⠖', - '⠦', - '⠤', - '⠠', - '⠠', - '⠤', - '⠦', - '⠖', - '⠒', - '⠐', - '⠐', - '⠒', - '⠓', - '⠋', - '⠉', - '⠈' - ] - }, - 'dots8': { - 'interval': 80, - 'frames': [ - '⠁', - '⠁', - '⠉', - '⠙', - '⠚', - '⠒', - '⠂', - '⠂', - '⠒', - '⠲', - '⠴', - '⠤', - '⠄', - '⠄', - '⠤', - '⠠', - '⠠', - '⠤', - '⠦', - '⠖', - '⠒', - '⠐', - '⠐', - '⠒', - '⠓', - '⠋', - '⠉', - '⠈', - '⠈' - ] - }, - 'dots9': { - 'interval': 80, - 'frames': ['⢹', '⢺', '⢼', '⣸', '⣇', '⡧', '⡗', '⡏'] - }, - 'dots10': { - 'interval': 80, - 'frames': ['⢄', '⢂', '⢁', '⡁', '⡈', '⡐', '⡠'] - }, - 'dots11': { - 'interval': 100, - 'frames': ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'] - }, - 'dots12': { - 'interval': 80, - 'frames': [ - '⢀⠀', - '⡀⠀', - '⠄⠀', - '⢂⠀', - '⡂⠀', - '⠅⠀', - '⢃⠀', - '⡃⠀', - '⠍⠀', - '⢋⠀', - '⡋⠀', - '⠍⠁', - '⢋⠁', - '⡋⠁', - '⠍⠉', - '⠋⠉', - '⠋⠉', - '⠉⠙', - '⠉⠙', - '⠉⠩', - '⠈⢙', - '⠈⡙', - '⢈⠩', - '⡀⢙', - '⠄⡙', - '⢂⠩', - '⡂⢘', - '⠅⡘', - '⢃⠨', - '⡃⢐', - '⠍⡐', - '⢋⠠', - '⡋⢀', - '⠍⡁', - '⢋⠁', - '⡋⠁', - '⠍⠉', - '⠋⠉', - '⠋⠉', - '⠉⠙', - '⠉⠙', - '⠉⠩', - '⠈⢙', - '⠈⡙', - '⠈⠩', - '⠀⢙', - '⠀⡙', - '⠀⠩', - '⠀⢘', - '⠀⡘', - '⠀⠨', - '⠀⢐', - '⠀⡐', - '⠀⠠', - '⠀⢀', - '⠀⡀' - ] - }, - 'dots8Bit': { - 'interval': 80, - 'frames': [ - '⠀', - '⠁', - '⠂', - '⠃', - '⠄', - '⠅', - '⠆', - '⠇', - '⡀', - '⡁', - '⡂', - '⡃', - '⡄', - '⡅', - '⡆', - '⡇', - '⠈', - '⠉', - '⠊', - '⠋', - '⠌', - '⠍', - '⠎', - '⠏', - '⡈', - '⡉', - '⡊', - '⡋', - '⡌', - '⡍', - '⡎', - '⡏', - '⠐', - '⠑', - '⠒', - '⠓', - '⠔', - '⠕', - '⠖', - '⠗', - '⡐', - '⡑', - '⡒', - '⡓', - '⡔', - '⡕', - '⡖', - '⡗', - '⠘', - '⠙', - '⠚', - '⠛', - '⠜', - '⠝', - '⠞', - '⠟', - '⡘', - '⡙', - '⡚', - '⡛', - '⡜', - '⡝', - '⡞', - '⡟', - '⠠', - '⠡', - '⠢', - '⠣', - '⠤', - '⠥', - '⠦', - '⠧', - '⡠', - '⡡', - '⡢', - '⡣', - '⡤', - '⡥', - '⡦', - '⡧', - '⠨', - '⠩', - '⠪', - '⠫', - '⠬', - '⠭', - '⠮', - '⠯', - '⡨', - '⡩', - '⡪', - '⡫', - '⡬', - '⡭', - '⡮', - '⡯', - '⠰', - '⠱', - '⠲', - '⠳', - '⠴', - '⠵', - '⠶', - '⠷', - '⡰', - '⡱', - '⡲', - '⡳', - '⡴', - '⡵', - '⡶', - '⡷', - '⠸', - '⠹', - '⠺', - '⠻', - '⠼', - '⠽', - '⠾', - '⠿', - '⡸', - '⡹', - '⡺', - '⡻', - '⡼', - '⡽', - '⡾', - '⡿', - '⢀', - '⢁', - '⢂', - '⢃', - '⢄', - '⢅', - '⢆', - '⢇', - '⣀', - '⣁', - '⣂', - '⣃', - '⣄', - '⣅', - '⣆', - '⣇', - '⢈', - '⢉', - '⢊', - '⢋', - '⢌', - '⢍', - '⢎', - '⢏', - '⣈', - '⣉', - '⣊', - '⣋', - '⣌', - '⣍', - '⣎', - '⣏', - '⢐', - '⢑', - '⢒', - '⢓', - '⢔', - '⢕', - '⢖', - '⢗', - '⣐', - '⣑', - '⣒', - '⣓', - '⣔', - '⣕', - '⣖', - '⣗', - '⢘', - '⢙', - '⢚', - '⢛', - '⢜', - '⢝', - '⢞', - '⢟', - '⣘', - '⣙', - '⣚', - '⣛', - '⣜', - '⣝', - '⣞', - '⣟', - '⢠', - '⢡', - '⢢', - '⢣', - '⢤', - '⢥', - '⢦', - '⢧', - '⣠', - '⣡', - '⣢', - '⣣', - '⣤', - '⣥', - '⣦', - '⣧', - '⢨', - '⢩', - '⢪', - '⢫', - '⢬', - '⢭', - '⢮', - '⢯', - '⣨', - '⣩', - '⣪', - '⣫', - '⣬', - '⣭', - '⣮', - '⣯', - '⢰', - '⢱', - '⢲', - '⢳', - '⢴', - '⢵', - '⢶', - '⢷', - '⣰', - '⣱', - '⣲', - '⣳', - '⣴', - '⣵', - '⣶', - '⣷', - '⢸', - '⢹', - '⢺', - '⢻', - '⢼', - '⢽', - '⢾', - '⢿', - '⣸', - '⣹', - '⣺', - '⣻', - '⣼', - '⣽', - '⣾', - '⣿' - ] - }, - 'line': { - 'interval': 130, - 'frames': ['-', r'\', '|', '/'] - }, - 'line2': { - 'interval': 100, - 'frames': ['⠂', '-', '–', '—', '–', '-'] - }, - 'pipe': { - 'interval': 100, - 'frames': ['┤', '┘', '┴', '└', '├', '┌', '┬', '┐'] - }, - 'simpleDots': { - 'interval': 400, - 'frames': ['. ', '.. ', '...', ' '] - }, - 'simpleDotsScrolling': { - 'interval': 200, - 'frames': ['. ', '.. ', '...', ' ..', ' .', ' '] - }, - 'star': { - 'interval': 70, - 'frames': ['✶', '✸', '✹', '✺', '✹', '✷'] - }, - 'star2': { - 'interval': 80, - 'frames': ['+', 'x', '*'] - }, - 'flip': { - 'interval': 70, - 'frames': [ - '_', - '_', - '_', - '-', - '`', - '`', - "'", - '´', - '-', - '_', - '_', - '_', - ] - }, - 'hamburger': { - 'interval': 100, - 'frames': ['☱', '☲', '☴'] - }, - 'growVertical': { - 'interval': 120, - 'frames': ['▁', '▃', '▄', '▅', '▆', '▇', '▆', '▅', '▄', '▃'] - }, - 'growHorizontal': { - 'interval': 120, - 'frames': [ - '▏', - '▎', - '▍', - '▌', - '▋', - '▊', - '▉', - '▊', - '▋', - '▌', - '▍', - '▎' - ] - }, - 'balloon': { - 'interval': 140, - 'frames': [' ', '.', 'o', 'O', '@', '*', ' '] - }, - 'balloon2': { - 'interval': 120, - 'frames': ['.', 'o', 'O', '°', 'O', 'o', '.'] - }, - 'noise': { - 'interval': 100, - 'frames': ['▓', '▒', '░'] - }, - 'bounce': { - 'interval': 120, - 'frames': ['⠁', '⠂', '⠄', '⠂'] - }, - 'boxBounce': { - 'interval': 120, - 'frames': ['▖', '▘', '▝', '▗'] - }, - 'boxBounce2': { - 'interval': 100, - 'frames': ['▌', '▀', '▐', '▄'] - }, - 'triangle': { - 'interval': 50, - 'frames': ['◢', '◣', '◤', '◥'] - }, - 'arc': { - 'interval': 100, - 'frames': ['◜', '◠', '◝', '◞', '◡', '◟'] - }, - 'circle': { - 'interval': 120, - 'frames': ['◡', '⊙', '◠'] - }, - 'squareCorners': { - 'interval': 180, - 'frames': ['◰', '◳', '◲', '◱'] - }, - 'circleQuarters': { - 'interval': 120, - 'frames': ['◴', '◷', '◶', '◵'] - }, - 'circleHalves': { - 'interval': 50, - 'frames': ['◐', '◓', '◑', '◒'] - }, - 'squish': { - 'interval': 100, - 'frames': ['╫', '╪'] - }, - 'toggle': { - 'interval': 250, - 'frames': ['⊶', '⊷'] - }, - 'toggle2': { - 'interval': 80, - 'frames': ['▫', '▪'] - }, - 'toggle3': { - 'interval': 120, - 'frames': ['□', '■'] - }, - 'toggle4': { - 'interval': 100, - 'frames': ['■', '□', '▪', '▫'] - }, - 'toggle5': { - 'interval': 100, - 'frames': ['▮', '▯'] - }, - 'toggle6': { - 'interval': 300, - 'frames': ['ဝ', '၀'] - }, - 'toggle7': { - 'interval': 80, - 'frames': ['⦾', '⦿'] - }, - 'toggle8': { - 'interval': 100, - 'frames': ['◍', '◌'] - }, - 'toggle9': { - 'interval': 100, - 'frames': ['◉', '◎'] - }, - 'toggle10': { - 'interval': 100, - 'frames': ['㊂', '㊀', '㊁'] - }, - 'toggle11': { - 'interval': 50, - 'frames': ['⧇', '⧆'] - }, - 'toggle12': { - 'interval': 120, - 'frames': ['☗', '☖'] - }, - 'toggle13': { - 'interval': 80, - 'frames': ['=', '*', '-'] - }, - 'arrow': { - 'interval': 100, - 'frames': ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'] - }, - 'arrow2': { - 'interval': 80, - 'frames': ['⬆️ ', '↗️ ', '➡️ ', '↘️ ', '⬇️ ', '↙️ ', '⬅️ ', '↖️ '] - }, - 'arrow3': { - 'interval': 120, - 'frames': ['▹▹▹▹▹', '▸▹▹▹▹', '▹▸▹▹▹', '▹▹▸▹▹', '▹▹▹▸▹', '▹▹▹▹▸'] - }, - 'bouncingBar': { - 'interval': 80, - 'frames': [ - '[ ]', - '[= ]', - '[== ]', - '[=== ]', - '[ ===]', - '[ ==]', - '[ =]', - '[ ]', - '[ =]', - '[ ==]', - '[ ===]', - '[====]', - '[=== ]', - '[== ]', - '[= ]' - ] - }, - 'bouncingBall': { - 'interval': 80, - 'frames': [ - '( ● )', - '( ● )', - '( ● )', - '( ● )', - '( ●)', - '( ● )', - '( ● )', - '( ● )', - '( ● )', - '(● )' - ] - }, - 'smiley': { - 'interval': 200, - 'frames': ['😄 ', '😝 '] - }, - 'monkey': { - 'interval': 300, - 'frames': ['🙈 ', '🙈 ', '🙉 ', '🙊 '] - }, - 'hearts': { - 'interval': 100, - 'frames': ['💛 ', '💙 ', '💜 ', '💚 ', '❤️ '] - }, - 'clock': { - 'interval': 100, - 'frames': [ - '🕛 ', - '🕐 ', - '🕑 ', - '🕒 ', - '🕓 ', - '🕔 ', - '🕕 ', - '🕖 ', - '🕗 ', - '🕘 ', - '🕙 ', - '🕚 ' - ] - }, - 'earth': { - 'interval': 180, - 'frames': ['🌍 ', '🌎 ', '🌏 '] - }, - 'material': { - 'interval': 17, - 'frames': [ - '█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '███████▁▁▁▁▁▁▁▁▁▁▁▁▁', - '████████▁▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '██████████▁▁▁▁▁▁▁▁▁▁', - '███████████▁▁▁▁▁▁▁▁▁', - '█████████████▁▁▁▁▁▁▁', - '██████████████▁▁▁▁▁▁', - '██████████████▁▁▁▁▁▁', - '▁██████████████▁▁▁▁▁', - '▁██████████████▁▁▁▁▁', - '▁██████████████▁▁▁▁▁', - '▁▁██████████████▁▁▁▁', - '▁▁▁██████████████▁▁▁', - '▁▁▁▁█████████████▁▁▁', - '▁▁▁▁██████████████▁▁', - '▁▁▁▁██████████████▁▁', - '▁▁▁▁▁██████████████▁', - '▁▁▁▁▁██████████████▁', - '▁▁▁▁▁██████████████▁', - '▁▁▁▁▁▁██████████████', - '▁▁▁▁▁▁██████████████', - '▁▁▁▁▁▁▁█████████████', - '▁▁▁▁▁▁▁█████████████', - '▁▁▁▁▁▁▁▁████████████', - '▁▁▁▁▁▁▁▁████████████', - '▁▁▁▁▁▁▁▁▁███████████', - '▁▁▁▁▁▁▁▁▁███████████', - '▁▁▁▁▁▁▁▁▁▁██████████', - '▁▁▁▁▁▁▁▁▁▁██████████', - '▁▁▁▁▁▁▁▁▁▁▁▁████████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁███████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████', - '█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████', - '██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███', - '██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███', - '███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███', - '████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██', - '█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '██████▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '████████▁▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '█████████▁▁▁▁▁▁▁▁▁▁▁', - '███████████▁▁▁▁▁▁▁▁▁', - '████████████▁▁▁▁▁▁▁▁', - '████████████▁▁▁▁▁▁▁▁', - '██████████████▁▁▁▁▁▁', - '██████████████▁▁▁▁▁▁', - '▁██████████████▁▁▁▁▁', - '▁██████████████▁▁▁▁▁', - '▁▁▁█████████████▁▁▁▁', - '▁▁▁▁▁████████████▁▁▁', - '▁▁▁▁▁████████████▁▁▁', - '▁▁▁▁▁▁███████████▁▁▁', - '▁▁▁▁▁▁▁▁█████████▁▁▁', - '▁▁▁▁▁▁▁▁█████████▁▁▁', - '▁▁▁▁▁▁▁▁▁█████████▁▁', - '▁▁▁▁▁▁▁▁▁█████████▁▁', - '▁▁▁▁▁▁▁▁▁▁█████████▁', - '▁▁▁▁▁▁▁▁▁▁▁████████▁', - '▁▁▁▁▁▁▁▁▁▁▁████████▁', - '▁▁▁▁▁▁▁▁▁▁▁▁███████▁', - '▁▁▁▁▁▁▁▁▁▁▁▁███████▁', - '▁▁▁▁▁▁▁▁▁▁▁▁▁███████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁███████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁', - '▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁' - ] - }, - 'moon': { - 'interval': 80, - 'frames': ['🌑 ', '🌒 ', '🌓 ', '🌔 ', '🌕 ', '🌖 ', '🌗 ', '🌘 '] - }, - 'runner': { - 'interval': 140, - 'frames': ['🚶 ', '🏃 '] - }, - 'pong': { - 'interval': 80, - 'frames': [ - '▐⠂ ▌', - '▐⠈ ▌', - '▐ ⠂ ▌', - '▐ ⠠ ▌', - '▐ ⡀ ▌', - '▐ ⠠ ▌', - '▐ ⠂ ▌', - '▐ ⠈ ▌', - '▐ ⠂ ▌', - '▐ ⠠ ▌', - '▐ ⡀ ▌', - '▐ ⠠ ▌', - '▐ ⠂ ▌', - '▐ ⠈ ▌', - '▐ ⠂▌', - '▐ ⠠▌', - '▐ ⡀▌', - '▐ ⠠ ▌', - '▐ ⠂ ▌', - '▐ ⠈ ▌', - '▐ ⠂ ▌', - '▐ ⠠ ▌', - '▐ ⡀ ▌', - '▐ ⠠ ▌', - '▐ ⠂ ▌', - '▐ ⠈ ▌', - '▐ ⠂ ▌', - '▐ ⠠ ▌', - '▐ ⡀ ▌', - '▐⠠ ▌' - ] - }, - 'shark': { - 'interval': 120, - 'frames': [ - r'▐|\____________▌', - r'▐_|\___________▌', - r'▐__|\__________▌', - r'▐___|\_________▌', - r'▐____|\________▌', - r'▐_____|\_______▌', - r'▐______|\______▌', - r'▐_______|\_____▌', - r'▐________|\____▌', - r'▐_________|\___▌', - r'▐__________|\__▌', - r'▐___________|\_▌', - r'▐____________|\▌', - '▐____________/|▌', - '▐___________/|_▌', - '▐__________/|__▌', - '▐_________/|___▌', - '▐________/|____▌', - '▐_______/|_____▌', - '▐______/|______▌', - '▐_____/|_______▌', - '▐____/|________▌', - '▐___/|_________▌', - '▐__/|__________▌', - '▐_/|___________▌', - '▐/|____________▌' - ] - }, - 'dqpb': { - 'interval': 100, - 'frames': ['d', 'q', 'p', 'b'] - }, - 'weather': { - 'interval': 100, - 'frames': [ - '☀️ ', - '☀️ ', - '☀️ ', - '🌤 ', - '⛅️ ', - '🌥 ', - '☁️ ', - '🌧 ', - '🌨 ', - '🌧 ', - '🌨 ', - '🌧 ', - '🌨 ', - '⛈ ', - '🌨 ', - '🌧 ', - '🌨 ', - '☁️ ', - '🌥 ', - '⛅️ ', - '🌤 ', - '☀️ ', - '☀️ ' - ] - }, - 'christmas': { - 'interval': 400, - 'frames': ['🌲', '🎄'] - }, - 'grenade': { - 'interval': 80, - 'frames': [ - '، ', - '′ ', - ' ´ ', - ' ‾ ', - ' ⸌', - ' ⸊', - ' |', - ' ⁎', - ' ⁕', - ' ෴ ', - ' ⁓', - ' ', - ' ', - ' ' - ] - }, - 'point': { - 'interval': 125, - 'frames': ['∙∙∙', '●∙∙', '∙●∙', '∙∙●', '∙∙∙'] - }, - 'layer': { - 'interval': 150, - 'frames': ['-', '=', '≡'] - }, - 'betaWave': { - 'interval': 80, - 'frames': [ - 'ρββββββ', - 'βρβββββ', - 'ββρββββ', - 'βββρβββ', - 'ββββρββ', - 'βββββρβ', - 'ββββββρ' - ] - }, - 'fingerDance': { - 'interval': 160, - 'frames': ['🤘 ', '🤟 ', '🖖 ', '✋ ', '🤚 ', '👆 '] - }, - 'fistBump': { - 'interval': 80, - 'frames': [ - '🤜\u3000\u3000\u3000\u3000🤛 ', - '🤜\u3000\u3000\u3000\u3000🤛 ', - '🤜\u3000\u3000\u3000\u3000🤛 ', - '\u3000🤜\u3000\u3000🤛\u3000 ', - '\u3000\u3000🤜🤛\u3000\u3000 ', - '\u3000🤜✨🤛\u3000\u3000 ', - '🤜\u3000✨\u3000🤛\u3000 ' - ] - }, - 'soccerHeader': { - 'interval': 80, - 'frames': [ - ' 🧑⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ', - '🧑 ⚽️ 🧑 ' - ] - }, - 'mindblown': { - 'interval': 160, - 'frames': [ - '😐 ', - '😐 ', - '😮 ', - '😮 ', - '😦 ', - '😦 ', - '😧 ', - '😧 ', - '🤯 ', - '💥 ', - '✨ ', - '\u3000 ', - '\u3000 ', - '\u3000 ' - ] - }, - 'speaker': { - 'interval': 160, - 'frames': ['🔈 ', '🔉 ', '🔊 ', '🔉 '] - }, - 'orangePulse': { - 'interval': 100, - 'frames': ['🔸 ', '🔶 ', '🟠 ', '🟠 ', '🔶 '] - }, - 'bluePulse': { - 'interval': 100, - 'frames': ['🔹 ', '🔷 ', '🔵 ', '🔵 ', '🔷 '] - }, - 'orangeBluePulse': { - 'interval': 100, - 'frames': [ - '🔸 ', - '🔶 ', - '🟠 ', - '🟠 ', - '🔶 ', - '🔹 ', - '🔷 ', - '🔵 ', - '🔵 ', - '🔷 ' - ] - }, - 'timeTravel': { - 'interval': 100, - 'frames': [ - '🕛 ', - '🕚 ', - '🕙 ', - '🕘 ', - '🕗 ', - '🕖 ', - '🕕 ', - '🕔 ', - '🕓 ', - '🕒 ', - '🕑 ', - '🕐 ' - ] - }, - 'aesthetic': { - 'interval': 80, - 'frames': [ - '▰▱▱▱▱▱▱', - '▰▰▱▱▱▱▱', - '▰▰▰▱▱▱▱', - '▰▰▰▰▱▱▱', - '▰▰▰▰▰▱▱', - '▰▰▰▰▰▰▱', - '▰▰▰▰▰▰▰', - '▰▱▱▱▱▱▱' - ] - } -}; diff --git a/packages/wyatt_cli_toolbox/lib/src/stylish/stylish.dart b/packages/wyatt_cli_toolbox/lib/src/stylish/stylish.dart deleted file mode 100644 index 7a3bc878..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/stylish/stylish.dart +++ /dev/null @@ -1,210 +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 'package:wyatt_cli_toolbox/src/stylish/utils.dart'; - -extension Stylish on String { - /// Status of the extension - static bool enabled = true; - - /// Formats a string if ansi escape sequences are supported. - static bool forced = false; - - /// Enable or disable styling - static void config({bool? enable}) { - Stylish.enabled = enable ?? Stylish.enabled; - } - - // Foreground Colors - /// Format this string with ANSI to be colored black. - String black() => format(30, 39)(this); - - /// Format this string with ANSI to be colored red. - String red() => format(31, 39)(this); - - /// Format this string with ANSI to be colored green. - String green() => format(32, 39)(this); - - /// Format this string with ANSI to be colored yellow. - String yellow() => format(33, 39)(this); - - /// Format this string with ANSI to be colored blue. - String blue() => format(34, 39)(this); - - /// Format this string with ANSI to be colored magenta. - String magenta() => format(35, 39)(this); - - /// Format this string with ANSI to be colored cyan. - String cyan() => format(36, 39)(this); - - /// Format this string with ANSI to be colored white. - String white() => format(37, 39)(this); - - /// Format this string with ANSI to be colored bright black or gray or grey. - String brightBlack() => format(90, 39)(this); - - /// Format this string with ANSI to be colored bright red. - String brightRed() => format(91, 39)(this); - - /// Format this string with ANSI to be colored bright green. - String brightGreen() => format(92, 39)(this); - - /// Format this string with ANSI to be colored bright yellow. - String brightYellow() => format(93, 39)(this); - - /// Format this string with ANSI to be colored bright blue. - String brightBlue() => format(94, 39)(this); - - /// Format this string with ANSI to be colored bright magenta. - String brightMagenta() => format(95, 39)(this); - - /// Format this string with ANSI to be colored bright cyan. - String brightCyan() => format(96, 39)(this); - - /// Format this string with ANSI to be colored bright white. - String brightWhite() => format(97, 39)(this); - - // Background Colors - /// Format this string with ANSI adding a black background color. - String bgBlack() => format(40, 49)(this); - - /// Format this string with ANSI adding a red background color. - String bgRed() => format(41, 49)(this); - - /// Format this string with ANSI adding a green background color. - String bgGreen() => format(42, 49)(this); - - /// Format this string with ANSI adding a yellow background color. - String bgYellow() => format(43, 49)(this); - - /// Format this string with ANSI adding a blue background color. - String bgBlue() => format(44, 49)(this); - - /// Format this string with ANSI adding a magenta background color. - String bgMagenta() => format(45, 49)(this); - - /// Format this string with ANSI adding a cyan background color. - String bgCyan() => format(46, 49)(this); - - /// Format this string with ANSI adding a white background color. - String bgWhite() => format(47, 49)(this); - - /// Format this string with ANSI adding a bright black - /// or gray or grey background color. - String bgBrightBlack() => format(100, 49)(this); - - /// Format this string with ANSI adding a bright red - /// background color. - String bgBrightRed() => format(101, 49)(this); - - /// Format this string with ANSI adding a bright green - /// background color. - String bgBrightGreen() => format(102, 49)(this); - - /// Format this string with ANSI adding a bright yellow - /// background color. - String bgBrightYellow() => format(103, 49)(this); - - /// Format this string with ANSI adding a bright blue - /// background color. - String bgBrightBlue() => format(104, 49)(this); - - /// Format this string with ANSI adding a bright magenta - /// background color. - String bgBrightMagenta() => format(105, 49)(this); - - /// Format this string with ANSI adding a bright cyan - /// background color. - String bgBrightCyan() => format(106, 49)(this); - - /// Format this string with ANSI adding a bright white - /// background color. - String bgBrightWhite() => format(107, 49)(this); - - /// Format this string with ANSI to be colored bright black or gray or grey. - String gray() => brightBlack(); - - /// Format this string with ANSI to be colored bright black or gray or grey. - String grey() => brightBlack(); - - /// Format this string with ANSI adding a bright black - /// or gray or grey background color. - String bgGray() => bgBrightBlack(); - - /// Format this string with ANSI adding a bright black - /// or gray or grey background color. - String bgGrey() => bgBrightBlack(); - - /// Format this string with ANSI to be styled as a bold text. - String bold() => format(1, 22)(this); - - /// Format this string with ANSI to make it appear as a dimmed text. - String dim() => format(2, 22)(this); - - /// Format this string with ANSI to make it appear italic. - String italic() => format(3, 23)(this); - - /// Format this string with ANSI adding an underline. - String underline() => format(4, 24)(this); - - /// Format this string with ANSI making it appear blinking slowly. - String blink() => format(5, 25)(this); - - /// Format this string with ANSI making it appear blinking rapidly. - String strobe() => format(6, 25)(this); - - /// Format this string with ANSI inverting the style. - String inverse() => format(7, 27)(this); - - /// Format this string with ANSI making it invisible. - String hidden() => format(8, 28)(this); - - /// Format this string with ANSI adding a strike through the text. - String strikethrough() => format(9, 29)(this); - - /// Format this string with ANSI adding a frame. - String frame() => format(51, 54)(this); - - /// Format this string with ANSI adding a circle. - String encircle() => format(52, 54)(this); - - /// Format this string with ANSI adding an overline. - String overline() => format(53, 55)(this); - - /// Format this string with ANSI resetting the previous color chains. - String reset() => format(0, 0)(this); - - /// If exists, all ANSI sequences will be removed from this string. - String strip() { - return replaceAll(ansiPattern, ''); - } - - /// Format this string with ANSI setting it's foreground color the - /// value defined as RGB parameters. - /// - /// [r]/[g]/[b] parameters can be an [int] in the range of `0` to `255`. - String fg({int r = 255, int g = 255, int b = 255}) { - return format('38;5;${rgbToAnsiCode(r, g, b)}', 0)(this); - } - - /// Format this string with ANSI setting it's background color the value - /// defined as RGB parameters. - /// - /// [r]/[g]/[b] parameters can be an [int] in the range of `0` to `255`. - String bg({int r = 255, int g = 255, int b = 255}) { - return format('48;5;${rgbToAnsiCode(r, g, b)}', 0)(this); - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi.dart b/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi.dart deleted file mode 100644 index 2a417b41..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi.dart +++ /dev/null @@ -1,17 +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 . - -bool get supportsAnsiColor => false; diff --git a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_io.dart b/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_io.dart deleted file mode 100644 index 51cea779..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_io.dart +++ /dev/null @@ -1,19 +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:io'; - -bool get supportsAnsiColor => stdout.supportsAnsiEscapes; diff --git a/packages/wyatt_cli_toolbox/lib/src/stylish/utils.dart b/packages/wyatt_cli_toolbox/lib/src/stylish/utils.dart deleted file mode 100644 index 2ef62a36..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/stylish/utils.dart +++ /dev/null @@ -1,45 +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 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; - -/// Converts an rgb value of given [r], [g] and [b] int values -/// to an ANSI usable color. -int rgbToAnsiCode(int r, int g, int b) => - (((r.clamp(0, 255) / 255) * 5).toInt() * 36 + - ((g.clamp(0, 255) / 255) * 5).toInt() * 6 + - ((b.clamp(0, 255) / 255) * 5).toInt() + - 16) - .clamp(0, 256); - -/// Regular Expression pattern for all possible types of ANSI escape -/// sequences in a [String]. -final RegExp ansiPattern = RegExp( - [ - r'[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)', - r'(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-ntqry=><~]))' - ].join('|'), -); - -/// Formats a string if ansi escape sequences are supported. -String Function(String) format(dynamic start, dynamic end) => (String x) { - // if ((supportsAnsiColor || Stylish.forced) && Stylish.enabled) { - if (Stylish.enabled) { - return '\x1B[${start}m$x\x1B[${end}m'; - } else { - return x; - } - }; diff --git a/packages/wyatt_cli_toolbox/lib/src/workflow/task.dart b/packages/wyatt_cli_toolbox/lib/src/workflow/task.dart deleted file mode 100644 index d9e5e166..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/workflow/task.dart +++ /dev/null @@ -1,148 +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 'dart:io'; - -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/spinners/spinners.dart'; -import 'package:wyatt_cli_toolbox/src/stylish/stylish.dart'; -import 'package:wyatt_cli_toolbox/src/workflow/skip_exception.dart'; - -enum ExitStatus { nil, success, fail, skip } - -class Task { - Task({ - required this.name, - String? id, - SpinnerType? spinner, - this.timer = true, - this.task, - this.onFinish, - this.onError, - this.onSkip, - }) { - if (id != null) { - identifier = id; - } else { - identifier = name; - } - _isolateTask = IsolateTask( - name: name, - spinner: spinner ?? SpinnerType.dots, - timer: timer, - ); - } - - String name; - late String identifier; - bool timer; - - /// **Synchronous** function. Use experimental `waitFor()` - /// if you have async calls.** - T Function()? task; - T? result; - - String Function(Object? o)? onFinish; - String Function(Object e)? onError; - String Function(SkipException e)? onSkip; - - late IsolateTask _isolateTask; - static String lastPrint = ''; - - IsolateTask get animation => _isolateTask; - - T? invoke() { - final T Function()? t = task; - if (t != null) { - return t(); - } - } - - static void print(String message) { - //waitFor(Future.delayed(Duration(milliseconds: 1))); - lastPrint = message; - stdout.write('\n'); - Sequences.moveDownAtStart(1); - Sequences.clearEntireLine(); - stdout.write(' > $message'.dim()); - Sequences.moveUpAtStart(1); - } - - static void clearPrint() { - Sequences.moveDownAtStart(1); - Sequences.clearEntireLine(); - Sequences.moveUpAtStart(1); - } -} - -class IsolateTask { - IsolateTask({ - required this.name, - required SpinnerType spinner, - required this.timer, - }) { - _indicator = spinner.indicator; - } - - final Stopwatch _stopwatch = Stopwatch(); - Timer? _timer; - int _frame = 0; - late Indicator _indicator; - - String name; - bool timer; - - void run() { - if (timer) { - _stopwatch - ..reset() - ..start(); - _timer?.cancel(); - } - - _timer = Timer.periodic( - Duration(milliseconds: _indicator.interval), - (Timer t) { - Sequences.clearEntireLine(); - _frame = (_frame + 1) % _indicator.frames.length; - stdout.write('${_indicator.frames[_frame].green()} $name...'); - Sequences.moveHorizontal(1); - }, - ); - } - - void stop(ExitStatus status, {String? reason}) { - _stopwatch.stop(); - final String time = - (_stopwatch.elapsed.inMilliseconds / 1000.0).toStringAsFixed(1); - Sequences.clearEntireLine(); - String prefix = ''; - String message = ''; - if (status == ExitStatus.success) { - prefix = '✓'.green(); - message = reason ?? 'Finished'; - } else if (status == ExitStatus.fail) { - prefix = 'x'.red(); - message = reason ?? 'Failed'; - } else if (status == ExitStatus.skip) { - prefix = '◊'.yellow(); - message = reason ?? 'Skipped'; - } - stdout.write('$prefix $message ${timer ? '(${time}s)' : ''}\n'); - _timer?.cancel(); - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/workflow/utils.dart b/packages/wyatt_cli_toolbox/lib/src/workflow/utils.dart deleted file mode 100644 index a07d9388..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/workflow/utils.dart +++ /dev/null @@ -1,64 +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'; - -// From dart-cli -T waitFor(Future future, {Duration? timeout}) { - late T result; - bool futureCompleted = false; - Object? error; - StackTrace? stacktrace; - - future.then( - (T r) { - futureCompleted = true; - result = r; - }, - onError: (Object? e, StackTrace? st) { - error = e; - stacktrace = st; - }, - ); - - late Stopwatch s; - if (timeout != null) { - s = Stopwatch()..start(); - } - - Timer.run(() {}); - - while (!futureCompleted && (error == null)) { - Duration? remaining; - if (timeout != null) { - if (s.elapsed >= timeout) { - throw TimeoutException('waitFor() timed out', timeout); - } - remaining = timeout - s.elapsed; - } - } - if (timeout != null) { - s.stop(); - } - - Timer.run(() {}); - - if (error != null) { - throw AsyncError(error!, stacktrace); - } - - return result; -} diff --git a/packages/wyatt_cli_toolbox/lib/src/workflow/workflow.dart b/packages/wyatt_cli_toolbox/lib/src/workflow/workflow.dart deleted file mode 100644 index 669825b4..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/workflow/workflow.dart +++ /dev/null @@ -1,164 +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 'dart:isolate'; - -import 'package:wyatt_cli_toolbox/src/sequences/sequences.dart'; -import 'package:wyatt_cli_toolbox/src/workflow/skip_exception.dart'; -import 'package:wyatt_cli_toolbox/src/workflow/task.dart'; - -export 'skip_exception.dart'; -export 'task.dart'; -export 'utils.dart'; - -enum WorkflowControl { start, next, stop } - -class Workflow { - Workflow._(this._workflowIsolate, this._tasks, this._toIsolate); - - Isolate? _workflowIsolate; - final SendPort _toIsolate; - final List> _tasks; - final Map _results = {}; - - Map get results => _results; - - static Future _initIsolate(List> tasks) async { - final List animations = []; - for (final Task t in tasks) { - animations.add(t.animation); - } - - Isolate? workflowIsolate; - - final Completer completer = Completer(); - final ReceivePort isolateToMainStream = ReceivePort() - // Retrieve send port sent by isolate - ..listen((dynamic data) { - if (data is SendPort) { - completer.complete(Workflow._(workflowIsolate, tasks, data)); - } - }); - - workflowIsolate = await Isolate.spawn( - _start, - [isolateToMainStream.sendPort, animations], - ); - return completer.future; - } - - static void _start(List args) { - // ignore: cast_nullable_to_non_nullable - final SendPort isolateToMainStream = args[0] as SendPort; - // ignore: cast_nullable_to_non_nullable - final List tasks = args[1] as List; - final ReceivePort mainToIsolateStream = ReceivePort(); - - isolateToMainStream.send(mainToIsolateStream.sendPort); - - mainToIsolateStream.listen((dynamic data) { - final List args = data as List; - // ignore: cast_nullable_to_non_nullable - final WorkflowControl control = args[0] as WorkflowControl; - // ignore: cast_nullable_to_non_nullable - final int taskId = args[1] as int; - final ExitStatus? exit = args[2] as ExitStatus?; - final String? reason = args[3] as String?; - - if (control == WorkflowControl.start) { - tasks[taskId].run(); - } else if (control == WorkflowControl.next) { - if (exit != null) { - tasks[taskId - 1].stop(exit, reason: reason); - } - tasks[taskId].run(); - } else if (control == WorkflowControl.stop) { - tasks[taskId].stop(exit!, reason: reason); - } - }); - } - - static Future create(List> tasks) async { - final Workflow w = await _initIsolate(tasks); - return w; - } - - void _animation( - WorkflowControl control, - int taskId, { - ExitStatus? status, - String? reason, - }) { - _toIsolate.send([control, taskId, status, reason]); - } - - Map start() { - Sequences.hideCursor(); - int _index = 0; - - for (final Task _ in _tasks) { - _call(_index); - _index++; - } - - if (_workflowIsolate != null) { - _workflowIsolate!.kill(priority: Isolate.immediate); - } - _workflowIsolate = null; - Sequences.unhideCursor(); - return _results; - } - - ExitStatus _call(int taskId) { - ExitStatus status = ExitStatus.nil; - String message = 'nil'; - final Task t = _tasks[taskId]; - - if (t.task != null) { - _animation(WorkflowControl.start, taskId); - try { - // Call task function - final dynamic res = t.invoke(); - _results[t.identifier] = res; - - message = 'Finished'; - if (t.onFinish != null) { - message = t.onFinish!(res); - } - status = ExitStatus.success; - } catch (e) { - if (e is SkipException) { - message = e.toString(); - if (t.onSkip != null) { - message = t.onSkip!(e); - } - - status = ExitStatus.skip; - } else { - message = e.toString(); - if (t.onError != null) { - message = t.onError!(e); - } - - status = ExitStatus.fail; - } - } - _animation(WorkflowControl.stop, taskId, status: status, reason: message); - } - return status; - } -} diff --git a/packages/wyatt_cli_toolbox/lib/src/wyatt_cli_toolbox_base.dart b/packages/wyatt_cli_toolbox/lib/src/wyatt_cli_toolbox_base.dart deleted file mode 100644 index e8a6f159..00000000 --- a/packages/wyatt_cli_toolbox/lib/src/wyatt_cli_toolbox_base.dart +++ /dev/null @@ -1,6 +0,0 @@ -// TODO: Put public facing types in this file. - -/// Checks if you are awesome. Spoiler: you are. -class Awesome { - bool get isAwesome => true; -} diff --git a/packages/wyatt_cli_toolbox/pubspec.yaml b/packages/wyatt_cli_toolbox/pubspec.yaml deleted file mode 100644 index ae49532a..00000000 --- a/packages/wyatt_cli_toolbox/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: wyatt_cli_toolbox -description: A toolbox for Dart CLI projects. -repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_cli_toolbox -version: 1.0.0 - -environment: - sdk: '>=2.17.0 <3.0.0' - -dev_dependencies: - wyatt_analysis: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_analysis-v2.2.2 - path: packages/wyatt_analysis -dependencies: {meta: ^1.8.0} diff --git a/packages/wyatt_component_copy_with_extension/.gitignore b/packages/wyatt_component_copy_with_extension/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_extension/.pubignore b/packages/wyatt_component_copy_with_extension/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_medium_feeds/.vscode/extensions.json b/packages/wyatt_component_copy_with_extension/.vscode/extensions.json similarity index 100% rename from packages/wyatt_medium_feeds/.vscode/extensions.json rename to packages/wyatt_component_copy_with_extension/.vscode/extensions.json diff --git a/packages/wyatt_component_copy_with_extension/.vscode/launch.json b/packages/wyatt_component_copy_with_extension/.vscode/launch.json new file mode 100644 index 00000000..653eabc8 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/.vscode/launch.json @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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 . + */ + +{ + // 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": "Launch Example", + "request": "launch", + "type": "dart", + "cwd": "example/", + "program": "lib/main.dart", + "flutterMode": "debug" + }, + ] +} \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_extension/.vscode/settings.json b/packages/wyatt_component_copy_with_extension/.vscode/settings.json new file mode 100644 index 00000000..a729c46c --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "dart.runPubGetOnPubspecChanges": "never", + "bloc.newCubitTemplate.type": "equatable", + "psi-header.changes-tracking": { + "isActive": true + }, + "psi-header.config": { + "blankLinesAfter": 1, + "forceToTop": true + }, + "psi-header.lang-config": [ + { + "beforeHeader": [ + "# -*- coding:utf-8 -*-", + "#!/usr/bin/env python3" + ], + "begin": "###", + "end": "###", + "language": "python", + "prefix": "# " + }, + { + "beforeHeader": [ + "#!/usr/bin/env sh", + "" + ], + "language": "shellscript", + "begin": "", + "end": "", + "prefix": "# " + }, + { + "begin": "", + "end": "", + "language": "dart", + "prefix": "// " + }, + { + "begin": "", + "end": "", + "language": "yaml", + "prefix": "# " + }, + { + "begin": "", + "language": "markdown", + }, + ], + "psi-header.templates": [ + { + "language": "*", + "template": [ + "Copyright (C) <> 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 ." + ], + } + ], +} \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_extension/AUTHORS b/packages/wyatt_component_copy_with_extension/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_extension/CHANGELOG.md b/packages/wyatt_component_copy_with_extension/CHANGELOG.md new file mode 100644 index 00000000..218133df --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/CHANGELOG.md @@ -0,0 +1,16 @@ +## 2.0.1 + + - **FIX**(gen): rename builder correctly. (cef73aa6) + +## 2.0.0 + +> Note: This release has breaking changes. + + - **FIX**: remove wyatt arch ios example. + - **FEAT**: add class annotation for component code generators. + - **DOCS**: add some documentation. + - **BREAKING** **REFACTOR**: rename file. + +## 1.0.0 + +- Initial version. diff --git a/packages/wyatt_component_copy_with_extension/LICENSE b/packages/wyatt_component_copy_with_extension/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_extension/README.md b/packages/wyatt_component_copy_with_extension/README.md new file mode 100644 index 00000000..4dd5beaf --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/README.md @@ -0,0 +1,82 @@ + + +# Component Copy With Extension + +

+ Style: Wyatt Analysis + SDK: Dart & Flutter +

+ +This package provides annotations for generating code and simplifying the use of an UI kit within a Flutter application. **The package contains only the annotation classes**. + +> This package does not contain Flutter specific code, but there is no sense in using it without Flutter. + +## Summary + +* `ComponentProxyExtension` - Annotation class for generating a proxy of a component of an UI kit. +* `ComponentCopyWithExtension` - Annotation class for generating the copyWith method of a component implementation. + +For example, let's say we have a component of an UI kit that we want to use in our application. + +1) We create the component in the `wyatt_ui_components` , add the `ComponentProxyExtension` annotation and generate the code. This component does not have any specific implementation, and only have a set of properties. +2) Now we implement the component in our ui kit, `wyatt_ui_kit` , add the `ComponentCopyWithExtension` annotation and generate the code. This component has a specific implementation and can be used in the application. +3) But we can implement multiple ui kits, and each of them can have their own implementation of the same component. And at the top of the application tree we can use the `wyatt_ui_components` package, which contains only the proxy of the component. + +> In that way, the **application is UI kit agnostic**, and we can easily change the UI kit without changing the code of the application. + +We will use the `LoaderComponent` component as an example in this documentation. + +## Annotation Classes + +#### `ComponentProxyExtension` + +This annotation class is used to annotate a new component of an UI kit in the `wyatt_ui_components` package. It generates the abstract proxy of the component and allows access to all its properties in different packages and throughout the application. + +```dart +part 'loader_component.g.dart'; + +@ComponentProxyExtension() +abstract class LoaderComponent extends Component + with CopyWithMixin<$LoaderComponentCWProxy> { + + const LoaderComponent({ + ... + }); +} +``` + +#### `ComponentCopyWithExtension` + +This annotation class is used to annotate the implementation of components directly in the application. It generates the implementation of the proxy and the mixin to ensure that the component meets the specifications defined in the `wyatt_ui_components package` . + +```dart +part 'loader.g.dart'; + +@ComponentCopyWithExtension() +class Loader extends LoaderComponent with $LoaderCWMixin { + + const Loader({ + ... + }); +} +``` + +## Additional features + +The skipFields field allows you to directly and specifically change a field. This makes it easier to use. You can disable it through annotation. diff --git a/packages/wyatt_component_copy_with_extension/analysis_options.yaml b/packages/wyatt_component_copy_with_extension/analysis_options.yaml new file mode 100644 index 00000000..1c320a71 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/analysis_options.yaml @@ -0,0 +1,7 @@ + +include: package:wyatt_analysis/analysis_options.yaml + + + + + diff --git a/packages/wyatt_component_copy_with_extension/example/.gitignore b/packages/wyatt_component_copy_with_extension/example/.gitignore new file mode 100644 index 00000000..24476c5d --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/example/.gitignore @@ -0,0 +1,44 @@ +# 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/ + +# 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_component_copy_with_extension/example/.metadata b/packages/wyatt_component_copy_with_extension/example/.metadata new file mode 100644 index 00000000..30e0d3ce --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/example/.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: b06b8b2710955028a6b562f5aa6fe62941d6febf + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + - platform: web + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + + # 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_medium_feeds/example/README.md b/packages/wyatt_component_copy_with_extension/example/README.md similarity index 50% rename from packages/wyatt_medium_feeds/example/README.md rename to packages/wyatt_component_copy_with_extension/example/README.md index f3e776e7..2b3fce4c 100644 --- a/packages/wyatt_medium_feeds/example/README.md +++ b/packages/wyatt_component_copy_with_extension/example/README.md @@ -1,4 +1,4 @@ -# medium_feeds_example +# example A new Flutter project. @@ -8,9 +8,9 @@ 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://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +- [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, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, +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_component_copy_with_extension/example/analysis_options.yaml b/packages/wyatt_component_copy_with_extension/example/analysis_options.yaml new file mode 100644 index 00000000..0939257e --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/example/analysis_options.yaml @@ -0,0 +1,7 @@ + +include: package:wyatt_analysis/analysis_options.flutter.yaml + + + + + diff --git a/packages/wyatt_component_copy_with_extension/example/lib/main.dart b/packages/wyatt_component_copy_with_extension/example/lib/main.dart new file mode 100644 index 00000000..25f5fbc8 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/example/lib/main.dart @@ -0,0 +1,29 @@ +// Copyright (C) 2023 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:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; + +@ComponentProxyExtension() +class BasicComponentAnnotationExemple {} + +@ComponentProxyExtension(skipFields: true) +class ComponentAnnotationExempleWithSkipFields {} + +@ComponentCopyWithExtension() +class BasicCustomComponent {} + +@ComponentCopyWithExtension(skipFields: false) +class CustomComponentAnnotationExempleWithSkipFields {} diff --git a/packages/wyatt_component_copy_with_extension/example/pubspec.yaml b/packages/wyatt_component_copy_with_extension/example/pubspec.yaml new file mode 100644 index 00000000..d636921c --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/example/pubspec.yaml @@ -0,0 +1,27 @@ +name: component_copy_with_extension_example +description: A new Flutter project. +version: 1.0.0 + +publish_to: "none" + +environment: + sdk: ">=2.19.0 <3.0.0" + flutter: ">=3.0.0" + +dependencies: + flutter: + sdk: flutter + wyatt_component_copy_with_extension: + path: "../" + +dev_dependencies: + flutter_test: + sdk: flutter + + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 + +# The following section is specific to Flutter. +flutter: + uses-material-design: true diff --git a/packages/wyatt_component_copy_with_extension/lib/src/component_copy_with_extension.dart b/packages/wyatt_component_copy_with_extension/lib/src/component_copy_with_extension.dart new file mode 100644 index 00000000..ec55aa5f --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/lib/src/component_copy_with_extension.dart @@ -0,0 +1,45 @@ +// Copyright (C) 2023 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:meta/meta_meta.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; + +/// {@template component_copy_with_extension} +/// This annotation class is used to annotate the implementation of components +/// directly in the application. It generates the implementation of the proxy +/// and the mixin to ensure that the component meets the specifications +/// defined in the UI Kit. +/// +/// Basically it indicate that the `copyWith` extension +/// should be generated for the component. +/// +/// ```dart +/// part 'loader.g.dart'; +/// +/// @ComponentCopyWithExtension() +/// class Loader extends LoaderComponent with $LoaderCWMixin { +/// +/// const Loader({ +/// ... +/// }); +/// } +/// ``` +/// {@endtemplate} +@Target({TargetKind.classType}) +class ComponentCopyWithExtension extends ComponentAnnotation { + /// {@macro component_copy_with_extension} + const ComponentCopyWithExtension({super.skipFields}); +} diff --git a/packages/wyatt_component_copy_with_extension/lib/src/component_proxy_extension.dart b/packages/wyatt_component_copy_with_extension/lib/src/component_proxy_extension.dart new file mode 100644 index 00000000..d34ac82c --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/lib/src/component_proxy_extension.dart @@ -0,0 +1,45 @@ +// 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:meta/meta_meta.dart'; +import 'package:wyatt_component_copy_with_extension/src/domain/component_annotation.dart'; + +/// {@template component_proxy_extension} +/// This annotation class is used to annotate a new component of an UI kit. +/// It generates the abstract proxy of the component and allows access to +/// all its properties in different packages and throughout the application. +/// +/// ```dart +/// part 'loader_component.g.dart'; +/// +/// @ComponentProxyExtension() +/// abstract class LoaderComponent extends Component +/// with CopyWithMixin<$LoaderComponentCWProxy> { +/// +/// const LoaderComponent({ +/// ... +/// }); +/// } +/// ``` +/// +/// The [skipFields] option allows you to directly and specifically change +/// a field. This makes it easier to use. +/// +/// {@endtemplate} +@Target({TargetKind.classType}) +class ComponentProxyExtension extends ComponentAnnotation { + /// {@macro component_proxy_extension} + const ComponentProxyExtension({super.skipFields}); +} diff --git a/packages/wyatt_component_copy_with_extension/lib/src/domain/component_annotation.dart b/packages/wyatt_component_copy_with_extension/lib/src/domain/component_annotation.dart new file mode 100644 index 00000000..4408aa19 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/lib/src/domain/component_annotation.dart @@ -0,0 +1,28 @@ +// Copyright (C) 2023 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 . + +/// {@template component_annotation} +/// Abstract class that is used as a base for all annotations +/// {@endtemplate} +abstract class ComponentAnnotation { + /// {@macro component_annotation} + const ComponentAnnotation({this.skipFields = true}); + + /// Prevent the library from generating `copyWith` functions for individual + /// fields e.g. `instance.copyWith.id("123")`. If you want to use only + /// copyWith(...) function. Default is `true`. + final bool? skipFields; +} diff --git a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_html.dart b/packages/wyatt_component_copy_with_extension/lib/src/domain/domain.dart similarity index 89% rename from packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_html.dart rename to packages/wyatt_component_copy_with_extension/lib/src/domain/domain.dart index 74e1eece..c06b052c 100644 --- a/packages/wyatt_cli_toolbox/lib/src/stylish/support/supports_ansi_html.dart +++ b/packages/wyatt_component_copy_with_extension/lib/src/domain/domain.dart @@ -1,17 +1,17 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 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 . -bool get supportsAnsiColor => true; +export './component_annotation.dart'; diff --git a/packages/wyatt_component_copy_with_extension/lib/wyatt_component_copy_with_extension.dart b/packages/wyatt_component_copy_with_extension/lib/wyatt_component_copy_with_extension.dart new file mode 100644 index 00000000..ba920e68 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/lib/wyatt_component_copy_with_extension.dart @@ -0,0 +1,22 @@ +// Copyright (C) 2023 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 . + +/// Extension for component copy with feature +library wyatt_component_copy_with_extension; + +export './src/domain/domain.dart'; +export 'src/component_copy_with_extension.dart'; +export 'src/component_proxy_extension.dart'; diff --git a/packages/wyatt_component_copy_with_extension/pubspec.yaml b/packages/wyatt_component_copy_with_extension/pubspec.yaml new file mode 100644 index 00000000..dd7b1db9 --- /dev/null +++ b/packages/wyatt_component_copy_with_extension/pubspec.yaml @@ -0,0 +1,17 @@ +name: wyatt_component_copy_with_extension +description: Extension for component copy with feature. +repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/component_copy_with_extension +version: 2.0.1 + +publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + +environment: + sdk: ">=2.19.0 <3.0.0" + +dependencies: + meta: ^1.8.0 + +dev_dependencies: + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_component_copy_with_gen/.gitignore b/packages/wyatt_component_copy_with_gen/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/.pubignore b/packages/wyatt_component_copy_with_gen/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/.vscode/extensions.json b/packages/wyatt_component_copy_with_gen/.vscode/extensions.json new file mode 100644 index 00000000..30cd2233 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/.vscode/extensions.json @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +{ + "recommendations": [ + "psioniq.psi-header", + "blaugold.melos-code" + ] +} \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/.vscode/launch.json b/packages/wyatt_component_copy_with_gen/.vscode/launch.json new file mode 100644 index 00000000..653eabc8 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/.vscode/launch.json @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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 . + */ + +{ + // 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": "Launch Example", + "request": "launch", + "type": "dart", + "cwd": "example/", + "program": "lib/main.dart", + "flutterMode": "debug" + }, + ] +} \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/.vscode/settings.json b/packages/wyatt_component_copy_with_gen/.vscode/settings.json new file mode 100644 index 00000000..a729c46c --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "dart.runPubGetOnPubspecChanges": "never", + "bloc.newCubitTemplate.type": "equatable", + "psi-header.changes-tracking": { + "isActive": true + }, + "psi-header.config": { + "blankLinesAfter": 1, + "forceToTop": true + }, + "psi-header.lang-config": [ + { + "beforeHeader": [ + "# -*- coding:utf-8 -*-", + "#!/usr/bin/env python3" + ], + "begin": "###", + "end": "###", + "language": "python", + "prefix": "# " + }, + { + "beforeHeader": [ + "#!/usr/bin/env sh", + "" + ], + "language": "shellscript", + "begin": "", + "end": "", + "prefix": "# " + }, + { + "begin": "", + "end": "", + "language": "dart", + "prefix": "// " + }, + { + "begin": "", + "end": "", + "language": "yaml", + "prefix": "# " + }, + { + "begin": "", + "language": "markdown", + }, + ], + "psi-header.templates": [ + { + "language": "*", + "template": [ + "Copyright (C) <> 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 ." + ], + } + ], +} \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/AUTHORS b/packages/wyatt_component_copy_with_gen/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/CHANGELOG.md b/packages/wyatt_component_copy_with_gen/CHANGELOG.md new file mode 100644 index 00000000..590150c8 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/CHANGELOG.md @@ -0,0 +1,21 @@ +## 2.0.1 + + - **FIX**(gen): rename builder correctly. (cef73aa6) + +## 2.0.0 + +> Note: This release has breaking changes. + + - **REFACTOR**: migrate components using code generator packages (#115). + - **FIX**: remove wyatt arch ios example. + - **FIX**: change example to be compatible with new AppTopBar and TextWrapper. + - **FIX**: fix textwrapper. + - **FIX**: update example (#118). + - **FIX**: copywith method takes non nullable fields too (#118). + - **FEAT**: add generators for components proxy and mixins to enable copywith methods. + - **DOCS**: add some documentation. + - **BREAKING** **REFACTOR**: rename file. + +## 1.0.0 + +- Initial version. diff --git a/packages/wyatt_component_copy_with_gen/LICENSE b/packages/wyatt_component_copy_with_gen/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_component_copy_with_gen/README.md b/packages/wyatt_component_copy_with_gen/README.md new file mode 100644 index 00000000..64e5e799 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/README.md @@ -0,0 +1,59 @@ + + +# Component Copy With Gen + +

+ Style: Wyatt Analysis + SDK: Dart & Flutter +

+ +A Dart package for generating code from annotations to ease the use of a UIKit in Flutter applications. The generated code is based on the annotation classes present in the [ `wyatt_component_copy_with_extension` package](https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_component_copy_with_extension) + +> This package does not contain Flutter specific code, but there is no sense in using it without Flutter. + +## Features + +* Supports the generation of abstract proxies in the `wyatt_ui_components` package. +* Supports direct use in Flutter applications. + +## Usage + +### In the 'wyatt_ui_components' package + +* Add the appropriate annotation when adding a new component. +* Run the build runner command to generate the proxy. + +### In Flutter applications (or UI Kit implementations) + +* Add the following dependencies to your pubspec.yaml: + +```yaml +dependencies: + ... + wyatt_component_copy_with_extension: ^0.0.1 +dev_dependencies: + ... + wyatt_component_copy_with_gen: ^0.0.1 + build_runner: ^2.3.3 +``` + +* In your UIKit, extend the desired component class and add the appropriate annotation. +* Run the code generation command via the build runner. + +For further details and additional features on class annotation, see the 'wyatt_component_copy_with_extension' package's README. diff --git a/packages/wyatt_component_copy_with_gen/analysis_options.yaml b/packages/wyatt_component_copy_with_gen/analysis_options.yaml new file mode 100644 index 00000000..e1caf220 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/analysis_options.yaml @@ -0,0 +1 @@ +include: package:wyatt_analysis/analysis_options.yaml diff --git a/packages/wyatt_component_copy_with_gen/build.yaml b/packages/wyatt_component_copy_with_gen/build.yaml new file mode 100644 index 00000000..ec4b846d --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/build.yaml @@ -0,0 +1,21 @@ +targets: + $default: + builders: + wyatt_component_copy_with_gen: + enabled: true + generate_for: + exclude: + - test + - example + include: + - test/gen_* + +builders: + wyatt_component_copy_with_gen: + target: ":wyatt_component_copy_with_gen" + import: "package:wyatt_component_copy_with_gen/wyatt_component_copy_with_gen.dart" + builder_factories: ["componentCopyWithReporter"] + build_extensions: { ".dart": ["copy_with_extension_gen.g.part"] } + auto_apply: dependents + build_to: cache + applies_builders: ["source_gen|combining_builder"] diff --git a/packages/wyatt_component_copy_with_gen/example/.gitignore b/packages/wyatt_component_copy_with_gen/example/.gitignore new file mode 100644 index 00000000..24476c5d --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/.gitignore @@ -0,0 +1,44 @@ +# 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/ + +# 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_component_copy_with_gen/example/.metadata b/packages/wyatt_component_copy_with_gen/example/.metadata new file mode 100644 index 00000000..30e0d3ce --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/.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: b06b8b2710955028a6b562f5aa6fe62941d6febf + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + - platform: web + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + + # 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_component_copy_with_gen/example/README.md b/packages/wyatt_component_copy_with_gen/example/README.md new file mode 100644 index 00000000..2b3fce4c --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/README.md @@ -0,0 +1,16 @@ +# example + +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_component_copy_with_gen/example/analysis_options.yaml b/packages/wyatt_component_copy_with_gen/example/analysis_options.yaml new file mode 100644 index 00000000..50ed209d --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/analysis_options.yaml @@ -0,0 +1,7 @@ + + + +include: package:wyatt_analysis/analysis_options.yaml + + + diff --git a/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.dart b/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.dart new file mode 100644 index 00000000..b9404eab --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.dart @@ -0,0 +1,33 @@ +// Copyright (C) 2023 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:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_ui_components.dart'; + +part 'custom_top_bar_example.g.dart'; + +@ComponentCopyWithExtension() +class CustomTopAppBarExample extends TopAppBarComponent + with $CustomTopAppBarExampleCWMixin { + const CustomTopAppBarExample({super.title, super.key}); + + @override + Widget build(BuildContext context) => AppBar( + title: Text(super.title?.data ?? ''), + ); +} diff --git a/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.g.dart b/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.g.dart new file mode 100644 index 00000000..ac4e015b --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/lib/custom_top_bar_example.g.dart @@ -0,0 +1,106 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_top_bar_example.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $CustomTopAppBarExampleCWProxyImpl implements $TopAppBarComponentCWProxy { + const $CustomTopAppBarExampleCWProxyImpl(this._value); + final CustomTopAppBarExample _value; + @override + CustomTopAppBarExample title(TextWrapper? title) => this(title: title); + @override + CustomTopAppBarExample centerTitle(bool? centerTitle) => + this(centerTitle: centerTitle); + @override + CustomTopAppBarExample shape(ShapeBorder? shape) => this(shape: shape); + @override + CustomTopAppBarExample systemOverlayStyle( + SystemUiOverlayStyle? systemOverlayStyle) => + this(systemOverlayStyle: systemOverlayStyle); + @override + CustomTopAppBarExample automaticallyImplyLeading( + bool? automaticallyImplyLeading) => + this(automaticallyImplyLeading: automaticallyImplyLeading); + @override + CustomTopAppBarExample flexibleSpace(Widget? flexibleSpace) => + this(flexibleSpace: flexibleSpace); + @override + CustomTopAppBarExample bottom(PreferredSizeWidget? bottom) => + this(bottom: bottom); + @override + CustomTopAppBarExample elevation(double? elevation) => + this(elevation: elevation); + @override + CustomTopAppBarExample scrolledUnderElevation( + double? scrolledUnderElevation) => + this(scrolledUnderElevation: scrolledUnderElevation); + @override + CustomTopAppBarExample shadowColor(Color? shadowColor) => + this(shadowColor: shadowColor); + @override + CustomTopAppBarExample surfaceTintColor(Color? surfaceTintColor) => + this(surfaceTintColor: surfaceTintColor); + @override + CustomTopAppBarExample backgroundColor(MultiColor? backgroundColor) => + this(backgroundColor: backgroundColor); + @override + CustomTopAppBarExample iconTheme(IconThemeData? iconTheme) => + this(iconTheme: iconTheme); + @override + CustomTopAppBarExample primary(bool? primary) => this(primary: primary); + @override + CustomTopAppBarExample excludeHeaderSemantics(bool? excludeHeaderSemantics) => + this(excludeHeaderSemantics: excludeHeaderSemantics); + @override + CustomTopAppBarExample toolbarHeight(double? toolbarHeight) => + this(toolbarHeight: toolbarHeight); + @override + CustomTopAppBarExample leadingWidth(double? leadingWidth) => + this(leadingWidth: leadingWidth); + @override + CustomTopAppBarExample leading(Widget? leading) => this(leading: leading); + @override + CustomTopAppBarExample actions(List? actions) => + this(actions: actions); + @override + CustomTopAppBarExample expandedWidget(List? expandedWidget) => + this(expandedWidget: expandedWidget); + @override + CustomTopAppBarExample key(Key? key) => this(key: key); + @override + CustomTopAppBarExample call({ + TextWrapper? title, + bool? centerTitle, + ShapeBorder? shape, + SystemUiOverlayStyle? systemOverlayStyle, + bool? automaticallyImplyLeading, + Widget? flexibleSpace, + PreferredSizeWidget? bottom, + double? elevation, + double? scrolledUnderElevation, + Color? shadowColor, + Color? surfaceTintColor, + MultiColor? backgroundColor, + IconThemeData? iconTheme, + bool? primary, + bool? excludeHeaderSemantics, + double? toolbarHeight, + double? leadingWidth, + Widget? leading, + List? actions, + List? expandedWidget, + Key? key, + }) => + CustomTopAppBarExample( + title: title ?? _value.title, + key: key ?? _value.key, + ); +} + +mixin $CustomTopAppBarExampleCWMixin on Component { + $TopAppBarComponentCWProxy get copyWith => + $CustomTopAppBarExampleCWProxyImpl(this as CustomTopAppBarExample); +} diff --git a/packages/wyatt_component_copy_with_gen/example/pubspec.yaml b/packages/wyatt_component_copy_with_gen/example/pubspec.yaml new file mode 100644 index 00000000..8ced47f8 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/example/pubspec.yaml @@ -0,0 +1,29 @@ +name: component_copy_with_gen_example +description: A new Flutter project. +version: 1.0.0 + +publish_to: "none" + +environment: + sdk: ">=2.19.0 <3.0.0" + +dependencies: + flutter: { sdk: flutter } + + wyatt_component_copy_with_extension: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 + + wyatt_ui_components: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^0.2.1 + +dev_dependencies: + build_runner: ^2.3.3 + + wyatt_component_copy_with_gen: + path: "../" + + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_component_copy_with_gen/lib/src/builder.dart b/packages/wyatt_component_copy_with_gen/lib/src/builder.dart new file mode 100644 index 00000000..c82cd976 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/lib/src/builder.dart @@ -0,0 +1,28 @@ +// Copyright (C) 2023 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:build/build.dart'; +import 'package:source_gen/source_gen.dart'; +import 'package:wyatt_component_copy_with_gen/src/generators/component_copy_with_generator.dart'; +import 'package:wyatt_component_copy_with_gen/src/generators/component_proxy_generator.dart'; + +Builder componentCopyWithReporter(BuilderOptions options) => SharedPartBuilder( + [ + ComponentProxyGenerator(), + ComponentCopyWithGenerator(), + ], + 'component_copy_with', + ); diff --git a/packages/wyatt_component_copy_with_gen/lib/src/generators/component_copy_with_generator.dart b/packages/wyatt_component_copy_with_gen/lib/src/generators/component_copy_with_generator.dart new file mode 100644 index 00000000..d64b2b25 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/lib/src/generators/component_copy_with_generator.dart @@ -0,0 +1,97 @@ +// Copyright (C) 2023 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:analyzer/dart/element/element.dart'; +import 'package:build/build.dart'; +import 'package:source_gen/source_gen.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; + +class ComponentCopyWithGenerator + extends GeneratorForAnnotation { + @override + FutureOr generateForAnnotatedElement( + Element element, + ConstantReader annotation, + BuildStep buildStep, + ) { + /// Check element type + if (element is! ClassElement) { + throw InvalidGenerationSourceError( + 'Only classes can be annotated with "CopyWith". "$element" is ' + 'not a ClassElement.', + element: element, + ); + } + + final classAnnotation = ComponentCopyWithExtension( + skipFields: annotation.peek('skipFields')?.boolValue ?? true, + ); + + final generatedCode = StringBuffer() + + // Generate CopyWith Proxy implementation. + ..write('class \$${element.displayName}CWProxyImpl implements ' + '\$${element.supertype?.getDisplayString( + withNullability: false, + )}CWProxy { ' + 'const \$${element.displayName}CWProxyImpl ' + '(this._value); ' + 'final ${element.displayName} _value;'); + + if (classAnnotation.skipFields ?? true) { + for (final superField + in element.supertype!.element.constructors.first.parameters) { + final superFieldDisplayName = superField.displayName; + generatedCode.write('@override ${element.displayName} ' + '$superFieldDisplayName(${superField.type.getDisplayString( + withNullability: false, + )}? ' + ' $superFieldDisplayName)' + ' => this($superFieldDisplayName : $superFieldDisplayName); '); + } + } + + generatedCode.write('@override ${element.displayName} call ({'); + + for (final superField + in element.supertype!.element.constructors.first.parameters) { + final superFieldDisplayName = superField.displayName; + generatedCode.write('${superField.type.getDisplayString( + withNullability: false, + )}? $superFieldDisplayName,'); + } + + generatedCode.write('})=>${element.displayName}('); + + for (final superField in element.constructors.first.parameters) { + final superFieldDisplayName = superField.displayName; + generatedCode.write('$superFieldDisplayName:$superFieldDisplayName?? ' + '_value.$superFieldDisplayName,'); + } + + generatedCode + ..write(');}') + ..write( + 'mixin \$${element.displayName}CWMixin on Component { ' + '\$${element.supertype?.element.displayName}CWProxy get copyWith => ' + '\$${element.displayName}CWProxyImpl(this as ${element.displayName});}', + ); + + return generatedCode.toString(); + } +} diff --git a/packages/wyatt_component_copy_with_gen/lib/src/generators/component_proxy_generator.dart b/packages/wyatt_component_copy_with_gen/lib/src/generators/component_proxy_generator.dart new file mode 100644 index 00000000..3dd4f79a --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/lib/src/generators/component_proxy_generator.dart @@ -0,0 +1,72 @@ +// Copyright (C) 2023 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:analyzer/dart/element/element.dart'; +import 'package:build/build.dart'; +import 'package:source_gen/source_gen.dart'; +import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; + +class ComponentProxyGenerator + extends GeneratorForAnnotation { + @override + FutureOr generateForAnnotatedElement( + Element element, + ConstantReader annotation, + BuildStep buildStep, + ) { + /// Check element type + if (element is! ClassElement) { + throw InvalidGenerationSourceError( + 'Only classes can be annotated with "CopyWith". "$element" is ' + 'not a ClassElement.', + element: element, + ); + } + + final classAnnotation = ComponentProxyExtension( + skipFields: annotation.peek('skipFields')?.boolValue ?? true, + ); + + final generatedCode = StringBuffer() + ..write('abstract class \$${element.displayName}CWProxy {'); + + if (classAnnotation.skipFields ?? true) { + for (final field in element.constructors.first.parameters) { + generatedCode.write( + '${element.displayName} ' + '${field.displayName}(${field.type.getDisplayString( + withNullability: false, + )}? ' + '${field.displayName});', + ); + } + } + + generatedCode.write('${element.displayName} call({'); + + for (final field in element.constructors.first.parameters) { + generatedCode.write('${field.type.getDisplayString( + withNullability: false, + )}? ${field.displayName}, '); + } + + generatedCode.write('});}'); + + return generatedCode.toString(); + } +} diff --git a/packages/wyatt_component_copy_with_gen/lib/wyatt_component_copy_with_gen.dart b/packages/wyatt_component_copy_with_gen/lib/wyatt_component_copy_with_gen.dart new file mode 100644 index 00000000..3ae2761e --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/lib/wyatt_component_copy_with_gen.dart @@ -0,0 +1,21 @@ +// Copyright (C) 2023 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 . + +/// Generator for copywith method for components +library wyatt_component_copy_with_gen; + +export 'src/builder.dart'; +export 'src/generators/component_copy_with_generator.dart'; diff --git a/packages/wyatt_component_copy_with_gen/pubspec.yaml b/packages/wyatt_component_copy_with_gen/pubspec.yaml new file mode 100644 index 00000000..e7e40745 --- /dev/null +++ b/packages/wyatt_component_copy_with_gen/pubspec.yaml @@ -0,0 +1,25 @@ +name: wyatt_component_copy_with_gen +description: Generator for copywith method for components. +repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/component_copy_with_gen +version: 2.0.1 + +publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + +environment: + sdk: ">=2.19.0 <3.0.0" + +dependencies: + build: ^2.3.1 + source_gen: ^1.2.7 + analyzer: ^5.4.0 + + wyatt_component_copy_with_extension: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.0.1 + +dev_dependencies: + test: ^1.21.0 + + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_crud_bloc/.gitignore b/packages/wyatt_crud_bloc/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_crud_bloc/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_crud_bloc/.gitignore b/packages/wyatt_crud_bloc/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_crud_bloc/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_crud_bloc/.pubignore b/packages/wyatt_crud_bloc/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_crud_bloc/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_crud_bloc/AUTHORS b/packages/wyatt_crud_bloc/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_crud_bloc/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_crud_bloc/CHANGELOG.md b/packages/wyatt_crud_bloc/CHANGELOG.md index 8690ac22..8aabadb5 100644 --- a/packages/wyatt_crud_bloc/CHANGELOG.md +++ b/packages/wyatt_crud_bloc/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.1.1 + + - **REFACTOR**: remove cross package export. + - **REFACTOR**: update package using new architecture usecase execute method (close #77). + - **FEAT**: change responsibility of blocs (closes #45, closes #44). + ## 0.1.0+2 - Update a dependency to the latest release. diff --git a/packages/wyatt_crud_bloc/LICENSE b/packages/wyatt_crud_bloc/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_crud_bloc/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_crud_bloc/README.md b/packages/wyatt_crud_bloc/README.md index 8b55e735..4f483186 100644 --- a/packages/wyatt_crud_bloc/README.md +++ b/packages/wyatt_crud_bloc/README.md @@ -1,39 +1,167 @@ - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. +# CRUD BloC -## Features +

+ Style: Wyatt Analysis + SDK: Flutter +

-TODO: List what your package can do. Maybe include images, gifs, or videos. +CRUD Bloc Pattern utilities for Flutter. -## Getting started +This package defines a set of classes that can be used to implement the CRUD Bloc Pattern. -TODO: List prerequisites and provide or point to information on how to -start using the package. +* Model +* Data Source + + In Memory + + Firestore +* Repository +* Use Case + + Create + + Get + + Get All + + Update + + Update All + + Delete + + Delete All + + Query +* Bloc + + Standard (C R U D), you have to choose the responsiblity of the bloc for each use case. For example, you can have a cubit that only handles the creation of an entity, and another cubit that only handles the deletion of an entity. Each cubit can only have one operation responsibility of each type, for example you can't have a cubit that handles get and get all. + + Advanced, you can set every use case to be handled by the bloc. This is useful if you want to have a single bloc that handles all the operations of an entity. ## Usage -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. +Create a model class that extends the `ObjectModel` class. ```dart -const like = 'sample'; +class User extends ObjectModel { + @override + final String? id; + + final String? name; + + const User({ + required this.name, + this.id, + }); + + Map toMap() { + return { + 'name': name ?? '', + }; + } + + @override + String toString() => 'User(id: $id, name: $name)'; +} ``` -## Additional information +You have to implement a bloc. -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. +```dart +/// A [CrudCubit] for [User]. +class UserCubit extends CrudCubit { + final CrudRepository _crudRepository; + + UserCubit(this._crudRepository); + + @override + CreateOperation? get createOperation => + Create(_crudRepository); + + @override + DeleteOperation? get deleteOperation => + Delete(_crudRepository); + + @override + ReadOperation? get readOperation => + GetAll(_crudRepository); + + @override + UpdateOperation? get updateOperation => + Update(_crudRepository); +} +``` + +> You can also use the `CrudAdvancedCubit` class to implement a bloc that handles all the use cases. + +Then you can use the bloc in your widget with a data source and a repository. + +```dart +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + final CrudDataSource userLocalDataSource = + CrudInMemoryDataSourceImpl(toMap: (user) => user.toMap()); + + final CrudRepository userRepository = + CrudRepositoryImpl(crudDataSource: userLocalDataSource); + + return RepositoryProvider>.value( + value: userRepository, + child: BlocProvider( + create: (context) => UserCubit(userRepository)..read(), + child: MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(), + ), + ), + ); + } +} +``` + +And anywhere in your widget tree you can use the BlocBuilder to build your widget. + +```dart +... +BlocBuilder( + builder: (context, state) { + return CrudBuilder.typed>( + state: state, + builder: ((context, state) { + return ListView.builder( + shrinkWrap: true, + itemCount: state.data.length, + itemBuilder: (context, index) { + final user = state.data.elementAt(index); + return ListTile( + title: Text(user?.name ?? 'Error'), + subtitle: Text(user?.id ?? 'Error'), + onTap: () { + context.read().delete(id: (user?.id)!); + }, + ); + }, + ); + }), + initialBuilder: (context, state) => const Text("Loading..."), + loadingBuilder: (context, state) => const Text("Loading..."), + errorBuilder: (context, state) => Text("Error: $state"), + ); + }, +), +... +``` diff --git a/packages/wyatt_crud_bloc/analysis_options.yaml b/packages/wyatt_crud_bloc/analysis_options.yaml index f09fbccc..8c9daa4e 100644 --- a/packages/wyatt_crud_bloc/analysis_options.yaml +++ b/packages/wyatt_crud_bloc/analysis_options.yaml @@ -1,4 +1 @@ include: package:wyatt_analysis/analysis_options.flutter.yaml - -analyzer: - exclude: "!example/**" diff --git a/packages/wyatt_crud_bloc/example/android/app/google-services.json b/packages/wyatt_crud_bloc/example/android/app/google-services.json deleted file mode 100644 index 448a816f..00000000 --- a/packages/wyatt_crud_bloc/example/android/app/google-services.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "project_info": { - "project_number": "136771801992", - "firebase_url": "https://tchat-beta.firebaseio.com", - "project_id": "tchat-beta", - "storage_bucket": "tchat-beta.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:136771801992:android:4ff419f07afdad6097203d", - "android_client_info": { - "package_name": "com.example.authentication_bloc_example" - } - }, - "oauth_client": [ - { - "client_id": "136771801992-nps7ic22shstvgdv0c2ojvbkj3dkntum.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.example.authentication_bloc_example", - "certificate_hash": "5d8790309e13b68c35e5d4d8437c35c6d15e6131" - } - }, - { - "client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "136771801992-e585bm1n9b3lv89t4phrl9u0glsg52ua.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.example.example" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:136771801992:android:8482c9b90bc29de697203d", - "android_client_info": { - "package_name": "com.example.crud_bloc_example" - } - }, - "oauth_client": [ - { - "client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "136771801992-e585bm1n9b3lv89t4phrl9u0glsg52ua.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.example.example" - } - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/packages/wyatt_crud_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_crud_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_crud_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_crud_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_crud_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_crud_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_crud_bloc/example/lib/app.dart b/packages/wyatt_crud_bloc/example/lib/app.dart index 7f5e9357..d5339343 100644 --- a/packages/wyatt_crud_bloc/example/lib/app.dart +++ b/packages/wyatt_crud_bloc/example/lib/app.dart @@ -36,8 +36,12 @@ class MyApp extends StatelessWidget { return RepositoryProvider>.value( value: userRepository, - child: BlocProvider( - create: (context) => UserCubit(userRepository)..getAll(), + child: MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => UserCubit(userRepository)..read(), + ), + ], child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( @@ -78,9 +82,7 @@ class MyHomePage extends StatelessWidget { title: Text(user?.name ?? 'Error'), subtitle: Text(user?.id ?? 'Error'), onTap: () { - context.read().delete( - (user?.id)!, - ); + context.read().delete(id: (user?.id)!); }, ); }, @@ -92,7 +94,6 @@ class MyHomePage extends StatelessWidget { ); }, ), - const SizedBox(height: 20), ElevatedButton( onPressed: () { @@ -109,24 +110,10 @@ class MyHomePage extends StatelessWidget { ), ElevatedButton( onPressed: () { - context.read().deleteAll(); - }, - child: const Text("DeleteAll"), - ), - ElevatedButton( - onPressed: () { - context.read().getAll(); + context.read().read(); }, child: const Text("GetAll"), ), - ElevatedButton( - onPressed: () { - context - .read() - .query([LimitQuery(2)]); - }, - child: const Text("Query"), - ), const SizedBox(height: 20), ], ), diff --git a/packages/wyatt_crud_bloc/example/lib/app_bloc_observer.dart b/packages/wyatt_crud_bloc/example/lib/app_bloc_observer.dart index 3bbf28e5..630d240d 100644 --- a/packages/wyatt_crud_bloc/example/lib/app_bloc_observer.dart +++ b/packages/wyatt_crud_bloc/example/lib/app_bloc_observer.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/example/lib/models.dart b/packages/wyatt_crud_bloc/example/lib/models.dart index b4ccfebf..e9ed1c7f 100644 --- a/packages/wyatt_crud_bloc/example/lib/models.dart +++ b/packages/wyatt_crud_bloc/example/lib/models.dart @@ -18,37 +18,18 @@ import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; class User extends ObjectModel { @override - String? id; + final String? id; - String? name; - String? email; - String? phone; + final String? name; + final String? email; + final String? phone; - User({ + const User({ required this.name, required this.email, required this.phone, this.id, }); - // User._(); - - // factory User.parser() { - // return User._(); - // } - - // @override - // User? from(DocumentSnapshot? object) { - // if (object == null) return null; - // if (object.exists) { - // return User( - // id: object.id, - // name: (object.data() as Map?)!['name'] as String, - // email: (object.data() as Map?)!['email'] as String, - // phone: (object.data() as Map?)!['phone'] as String, - // ); - // } - // return null; - // } Map toMap() { return { diff --git a/packages/wyatt_crud_bloc/example/lib/user_cubit.dart b/packages/wyatt_crud_bloc/example/lib/user_cubit.dart index 703d6686..cc34df6c 100644 --- a/packages/wyatt_crud_bloc/example/lib/user_cubit.dart +++ b/packages/wyatt_crud_bloc/example/lib/user_cubit.dart @@ -17,32 +17,25 @@ import 'package:crud_bloc_example/models.dart'; import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; +/// A [CrudCubit] for [User]. class UserCubit extends CrudCubit { final CrudRepository _crudRepository; UserCubit(this._crudRepository); @override - Create? get crudCreate => Create(_crudRepository); + CreateOperation? get createOperation => + Create(_crudRepository); @override - Delete? get crudDelete => Delete(_crudRepository); + DeleteOperation? get deleteOperation => + Delete(_crudRepository); @override - DeleteAll? get crudDeleteAll => DeleteAll(_crudRepository); + ReadOperation? get readOperation => + GetAll(_crudRepository); @override - Get? get crudGet => Get(_crudRepository); - - @override - GetAll? get crudGetAll => GetAll(_crudRepository); - - @override - Query? get crudQuery => Query(_crudRepository); - - @override - Update? get crudUpdate => Update(_crudRepository); - - @override - UpdateAll? get crudUpdateAll => UpdateAll(_crudRepository); + UpdateOperation? get updateOperation => + Update(_crudRepository); } diff --git a/packages/wyatt_crud_bloc/example/test/widget_test.dart b/packages/wyatt_crud_bloc/example/test/widget_test.dart index e69de29b..8b137891 100644 --- a/packages/wyatt_crud_bloc/example/test/widget_test.dart +++ b/packages/wyatt_crud_bloc/example/test/widget_test.dart @@ -0,0 +1 @@ + diff --git a/packages/wyatt_crud_bloc/lib/src/core/core.dart b/packages/wyatt_crud_bloc/lib/src/core/core.dart index 1d218692..12ebcadf 100644 --- a/packages/wyatt_crud_bloc/lib/src/core/core.dart +++ b/packages/wyatt_crud_bloc/lib/src/core/core.dart @@ -15,3 +15,4 @@ // along with this program. If not, see . export 'enums/where_query_type.dart'; +export 'mixins/operation.dart'; diff --git a/packages/wyatt_crud_bloc/lib/src/core/enums/where_query_type.dart b/packages/wyatt_crud_bloc/lib/src/core/enums/where_query_type.dart index f20879e7..6a7c9bfe 100644 --- a/packages/wyatt_crud_bloc/lib/src/core/enums/where_query_type.dart +++ b/packages/wyatt_crud_bloc/lib/src/core/enums/where_query_type.dart @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Defines different query types for WhereQuery. enum WhereQueryType { isEqualTo, isNotEqualTo, diff --git a/packages/wyatt_crud_bloc/lib/src/core/mixins/operation.dart b/packages/wyatt_crud_bloc/lib/src/core/mixins/operation.dart new file mode 100644 index 00000000..dbfc08ff --- /dev/null +++ b/packages/wyatt_crud_bloc/lib/src/core/mixins/operation.dart @@ -0,0 +1,34 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; + +/// Defines every write operation in CRUD. +mixin CreateOperation + on AsyncUseCase {} + +/// Defines every read operation in CRUD. +mixin ReadOperation + on AsyncUseCase {} + +/// Defines every update operation in CRUD. +mixin UpdateOperation + on AsyncUseCase {} + +/// Defines every delete operation in CRUD. +mixin DeleteOperation + on AsyncUseCase {} diff --git a/packages/wyatt_crud_bloc/lib/src/data/data.dart b/packages/wyatt_crud_bloc/lib/src/data/data.dart index ad1ef342..2fbca202 100644 --- a/packages/wyatt_crud_bloc/lib/src/data/data.dart +++ b/packages/wyatt_crud_bloc/lib/src/data/data.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/data/data_sources/local/crud_in_memory_data_source_impl.dart b/packages/wyatt_crud_bloc/lib/src/data/data_sources/local/crud_in_memory_data_source_impl.dart index 63fe3de4..7c2f706b 100644 --- a/packages/wyatt_crud_bloc/lib/src/data/data_sources/local/crud_in_memory_data_source_impl.dart +++ b/packages/wyatt_crud_bloc/lib/src/data/data_sources/local/crud_in_memory_data_source_impl.dart @@ -17,21 +17,24 @@ import 'dart:async'; import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; -import 'package:wyatt_crud_bloc/src/core/extensions/num_extension.dart'; -import 'package:wyatt_crud_bloc/src/domain/data_sources/crud_data_source.dart'; +import 'package:wyatt_crud_bloc/src/domain/data_sources/data_sources.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +/// {@template crud_in_memory_data_source_impl} +/// A [CrudDataSource] that stores data in memory. +/// {@endtemplate} class CrudInMemoryDataSourceImpl extends CrudDataSource { + /// {@macro crud_in_memory_data_source_impl} + CrudInMemoryDataSourceImpl({required this.toMap, Map? data}) + : _data = data ?? {}; final Map _data; final StreamController> _streamData = StreamController(); final Map Function(Model) toMap; - CrudInMemoryDataSourceImpl({required this.toMap, Map? data}) - : _data = data ?? {}; - @override Future create(Model object, {String? id}) async { _data[id ?? object.id ?? ''] = object; diff --git a/packages/wyatt_crud_bloc/lib/src/data/data_sources/remote/crud_firestore_data_source_impl.dart b/packages/wyatt_crud_bloc/lib/src/data/data_sources/remote/crud_firestore_data_source_impl.dart index 2b8fd504..2915f2e6 100644 --- a/packages/wyatt_crud_bloc/lib/src/data/data_sources/remote/crud_firestore_data_source_impl.dart +++ b/packages/wyatt_crud_bloc/lib/src/data/data_sources/remote/crud_firestore_data_source_impl.dart @@ -20,20 +20,23 @@ import 'package:wyatt_crud_bloc/src/domain/data_sources/crud_data_source.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +/// {@template crud_firestore_data_source_impl} +/// A concrete implementation of [CrudDataSource] that uses +/// [FirebaseFirestore] as the data source. +/// {@endtemplate} class CrudFirestoreDataSourceImpl extends CrudDataSource { - final FirebaseFirestore _firestore; - - final Map Function(Model, SetOptions?) _toFirestore; - late CollectionReference _collectionReference; - + /// {@macro crud_firestore_data_source_impl} CrudFirestoreDataSourceImpl( String collection, { + /// The function that converts a [DocumentSnapshot] to a [Model]. required Model Function( DocumentSnapshot>, SnapshotOptions?, ) fromFirestore, + + /// The function that converts a [Model] to a [Map]. required Map Function(Model, SetOptions?) toFirestore, FirebaseFirestore? firestore, }) : _firestore = firestore ?? FirebaseFirestore.instance, @@ -44,6 +47,10 @@ class CrudFirestoreDataSourceImpl toFirestore: toFirestore, ); } + final FirebaseFirestore _firestore; + + final Map Function(Model, SetOptions?) _toFirestore; + late CollectionReference _collectionReference; @override Future create(Model object, {String? id}) { diff --git a/packages/wyatt_crud_bloc/lib/src/data/repositories/crud_repository_impl.dart b/packages/wyatt_crud_bloc/lib/src/data/repositories/crud_repository_impl.dart index 1a62f179..7f068be2 100644 --- a/packages/wyatt_crud_bloc/lib/src/data/repositories/crud_repository_impl.dart +++ b/packages/wyatt_crud_bloc/lib/src/data/repositories/crud_repository_impl.dart @@ -21,13 +21,16 @@ import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +/// {@template crud_repository_impl} +/// A repository that implements the [CrudRepository] interface. +/// {@endtemplate} class CrudRepositoryImpl extends CrudRepository { - final CrudDataSource _crudDataSource; - - CrudRepositoryImpl({ + /// {@macro crud_repository_impl} + const CrudRepositoryImpl({ required CrudDataSource crudDataSource, }) : _crudDataSource = crudDataSource; + final CrudDataSource _crudDataSource; @override FutureOrResult create(Model object, {String? id}) => @@ -100,6 +103,6 @@ class CrudRepositoryImpl if (lst.isNotNull) { return Ok, AppException>(lst); } - return Err, AppException>(ServerException()); + return Err, AppException>(const ServerException()); }); } diff --git a/packages/wyatt_crud_bloc/lib/src/data/repositories/repositories.dart b/packages/wyatt_crud_bloc/lib/src/data/repositories/repositories.dart index bf40c523..f31c2358 100644 --- a/packages/wyatt_crud_bloc/lib/src/data/repositories/repositories.dart +++ b/packages/wyatt_crud_bloc/lib/src/data/repositories/repositories.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/data_sources/crud_data_source.dart b/packages/wyatt_crud_bloc/lib/src/domain/data_sources/crud_data_source.dart index 95defb4c..b6d0ba30 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/data_sources/crud_data_source.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/data_sources/crud_data_source.dart @@ -17,27 +17,42 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +/// {@template crud_data_source} +/// A [BaseDataSource] that provides SCRUD operations. +/// {@endtemplate} abstract class CrudDataSource extends BaseDataSource { + /// {@macro crud_data_source} + const CrudDataSource(); + + /// Creates a new [Model] object. Future create(Model object, {String? id}); + /// Gets a [Model] object by its [id]. Future get(String id); + /// Gets all [Model] objects. Future> getAll(); + /// Updates a [Model] object by its [id]. Future update( String id, { Model? object, Map? raw, }); + /// Updates all [Model] objects. Future updateAll(Map? data); + /// Deletes a [Model] object by its [id]. Future delete(String id); + /// Deletes all [Model] objects. Future deleteAll(); + /// Queries [Model] objects by [conditions]. Future> query(List conditions); + /// Streams [Model] objects by [conditions]. Stream> stream({ String? id, List? conditions, diff --git a/packages/wyatt_crud_bloc/lib/src/domain/data_sources/data_sources.dart b/packages/wyatt_crud_bloc/lib/src/domain/data_sources/data_sources.dart index 8495ee03..925fd22f 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/data_sources/data_sources.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/data_sources/data_sources.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/domain.dart b/packages/wyatt_crud_bloc/lib/src/domain/domain.dart index a02a23f3..35c41307 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/domain.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/domain.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/entities/entities.dart b/packages/wyatt_crud_bloc/lib/src/domain/entities/entities.dart index bd9cb1f9..bb2a29f7 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/entities/entities.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/entities/object_model.dart b/packages/wyatt_crud_bloc/lib/src/domain/entities/object_model.dart index 2b419e41..10dc5a25 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/entities/object_model.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/entities/object_model.dart @@ -16,6 +16,13 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; +/// {@template object_model} +/// An abstract class that represents an object model. +/// {@endtemplate} abstract class ObjectModel extends Entity { + /// {@macro object_model} + const ObjectModel(); + + /// The id of the object model. String? get id; } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/entities/query.dart b/packages/wyatt_crud_bloc/lib/src/domain/entities/query.dart index c95d1cda..5fe8908f 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/entities/query.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/entities/query.dart @@ -17,30 +17,59 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; -// ignore: one_member_abstracts -abstract class QueryParser { - Q parser(QueryInterface condition, Q query); +// // ignore: one_member_abstracts +// abstract class QueryParser { +// Q parser(QueryInterface condition, Q query); +// } + +typedef QueryParser = Q Function(QueryInterface condition, Q query); + +/// {@template query} +/// An abstract class that represents a query. +/// {@endtemplate} +abstract class QueryInterface extends Entity { + /// {@macro query} + const QueryInterface(); } -abstract class QueryInterface extends Entity {} - +/// {@template where_query} +/// Represents a where query. +/// {@endtemplate} class WhereQuery extends QueryInterface { + /// {@macro where_query} + const WhereQuery(this.type, this.field, this.value); + + /// The type of the where query. final WhereQueryType type; + + /// The field of the where query. final String field; + + /// The value of the where query. final Value value; - - WhereQuery(this.type, this.field, this.value); } +/// {@template limit_query} +/// Represents a limit query. +/// {@endtemplate} class LimitQuery extends QueryInterface { + /// {@macro limit_query} + const LimitQuery(this.limit); + + /// The limit of the limit query. final int limit; - - LimitQuery(this.limit); } +/// {@template offset_query} +/// Represents an offset query. +/// {@endtemplate} class OrderByQuery extends QueryInterface { - final String field; - final bool ascending; + /// {@macro offset_query} + const OrderByQuery(this.field, {this.ascending = true}); - OrderByQuery(this.field, {this.ascending = true}); + /// The field of the order by query. + final String field; + + /// The ascending of the order by query. + final bool ascending; } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/repositories/crud_repository.dart b/packages/wyatt_crud_bloc/lib/src/domain/repositories/crud_repository.dart index f0313c44..95b52190 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/repositories/crud_repository.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/repositories/crud_repository.dart @@ -18,20 +18,43 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +/// {@template crud_repository} +/// An abstract class that represents a SCRUD repository. +/// {@endtemplate} abstract class CrudRepository extends BaseRepository { + /// {@macro crud_repository} + const CrudRepository(); + + /// Creates a new object. FutureOrResult create(Model object, {String? id}); + + /// Gets an object by its [id]. FutureOrResult get(String id); + + /// Gets all objects. FutureOrResult> getAll(); + + /// Updates an object by its [id]. FutureOrResult update( String id, { Model? object, Map? raw, }); + + /// Updates all objects. FutureOrResult updateAll(Map raw); + + /// Deletes an object by its [id]. FutureOrResult delete(String id); + + /// Deletes all objects. FutureOrResult deleteAll(); + + /// Queries objects by [conditions]. FutureOrResult> query(List conditions); + + /// Streams objects by [conditions]. StreamResult> stream({ String? id, List? conditions, diff --git a/packages/wyatt_crud_bloc/lib/src/domain/repositories/repositories.dart b/packages/wyatt_crud_bloc/lib/src/domain/repositories/repositories.dart index decedffe..fb45fc62 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/repositories/repositories.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/repositories/repositories.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/create.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/create.dart index 4ddf5710..ff88a046 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/create.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/create.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -18,21 +17,28 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; -class Create extends AsyncUseCase { - final CrudRepository _crudRepository; +/// {@template create} +/// A use case that creates an object model. +/// {@endtemplate} +class Create extends AsyncUseCase + with CreateOperation { + /// {@macro create} + const Create(this._crudRepository); - Create(this._crudRepository); + final CrudRepository _crudRepository; @override FutureOr onStart(Model? params) { - if(params == null){ + if (params == null) { throw ClientException('$Model cannot be null.'); } } - + @override - FutureOrResult call(Model? params) => _crudRepository.create(params!); + FutureOrResult execute(Model? params) => + _crudRepository.create(params!); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete.dart index 3bd2e867..d8ffb17d 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete.dart @@ -17,21 +17,28 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; -class Delete extends AsyncUseCase { - final CrudRepository _crudRepository; +/// {@template delete} +/// A use case that deletes an object model. +/// {@endtemplate} +class Delete extends AsyncUseCase + with DeleteOperation { + /// {@macro delete} + const Delete(this._crudRepository); - Delete(this._crudRepository); + final CrudRepository _crudRepository; @override FutureOr onStart(String? params) { - if(params == null){ - throw ClientException('Id cannot be null.'); + if (params == null) { + throw const ClientException('Id cannot be null.'); } } @override - FutureOrResult call(String? params) => _crudRepository.delete(params!); + FutureOrResult execute(String? params) => + _crudRepository.delete(params!); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete_all.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete_all.dart index d3caf9d1..ae1935d7 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete_all.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/delete_all.dart @@ -15,14 +15,20 @@ // along with this program. If not, see . import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; -class DeleteAll extends AsyncUseCase { +/// {@template delete_all} +/// A use case that deletes all the object models. +/// {@endtemplate} +class DeleteAll extends AsyncUseCase + with DeleteOperation { + /// {@macro delete_all} + const DeleteAll(this._crudRepository); + final CrudRepository _crudRepository; - DeleteAll(this._crudRepository); - @override - FutureOrResult call(void params) => _crudRepository.deleteAll(); + FutureOrResult execute(void params) => _crudRepository.deleteAll(); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/get.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/get.dart index 947deeca..08850936 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/get.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/get.dart @@ -17,21 +17,28 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; -class Get extends AsyncUseCase { - final CrudRepository _crudRepository; - +/// {@template get} +/// A use case that gets an object model. +/// {@endtemplate} +class Get extends AsyncUseCase + with ReadOperation { + /// {@macro get} Get(this._crudRepository); + final CrudRepository _crudRepository; + @override FutureOr onStart(String? params) { - if(params == null){ - throw ClientException('Id cannot be null.'); + if (params == null) { + throw const ClientException('Id cannot be null.'); } } @override - FutureOrResult call(String? params) => _crudRepository.get(params!); + FutureOrResult execute(String? params) => + _crudRepository.get(params!); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/get_all.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/get_all.dart index 6088193b..63379212 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/get_all.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/get_all.dart @@ -15,15 +15,20 @@ // along with this program. If not, see . import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; -class GetAll - extends AsyncUseCase> { +/// {@template get_all} +/// A use case that gets all the object models. +/// {@endtemplate} +class GetAll extends AsyncUseCase> + with ReadOperation> { + /// {@macro get_all} + const GetAll(this._crudRepository); + final CrudRepository _crudRepository; - GetAll(this._crudRepository); - @override - FutureOrResult> call(void params) => _crudRepository.getAll(); + FutureOrResult> execute(void params) => _crudRepository.getAll(); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/params.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/params.dart index 3b67e551..3b8bf1ee 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/params.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/params.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/stream_parameters.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/stream_parameters.dart index 6a3cfa0e..0b2d178b 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/stream_parameters.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/stream_parameters.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -17,12 +16,19 @@ import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +/// {@template stream_parameters} +/// Represents the parameters for a query stream +/// {@endtemplate} class StreamParameters { - final String? id; - final List? conditions; - - StreamParameters({ + /// {@macro stream_parameters} + const StreamParameters({ this.id, this.conditions, }); + + /// The id of the object model. + final String? id; + + /// The conditions of the query. + final List? conditions; } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/update_parameters.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/update_parameters.dart index b23744bd..c44ab784 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/update_parameters.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/params/update_parameters.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -15,14 +14,23 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// {@template update_parameters} +/// Represents the parameters for an update use case +/// {@endtemplate} class UpdateParameters { - final String id; - final Model? object; - final Map? raw; - - UpdateParameters({ + /// {@macro update_parameters} + const UpdateParameters({ required this.id, this.object, this.raw, }); + + /// The id of the object model. + final String id; + + /// The object model. + final Model? object; + + /// The raw data. + final Map? raw; } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/query.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/query.dart index f9b43531..4869fa0d 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/query.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/query.dart @@ -17,24 +17,30 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; +/// {@template query} +/// A use case that queries the object models. +/// {@endtemplate} class Query - extends AsyncUseCase, List> { - final CrudRepository _crudRepository; + extends AsyncUseCase, List> + with ReadOperation, List> { + /// {@macro query} + const Query(this._crudRepository); - Query(this._crudRepository); + final CrudRepository _crudRepository; @override FutureOr onStart(List? params) { - if(params == null){ - throw ClientException('List of conditions cannot be null.'); + if (params == null) { + throw const ClientException('List of conditions cannot be null.'); } } @override - FutureOrResult> call(List? params) => + FutureOrResult> execute(List? params) => _crudRepository.query(params!); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/stream_query.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/stream_query.dart deleted file mode 100644 index 2b2c80e5..00000000 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/stream_query.dart +++ /dev/null @@ -1,44 +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 . - - - -// class Stream extends UseCase> { -// final CrudRepository _crudRepository; - -// Stream(this._crudRepository); - -// @override -// StreamResult> call(StreamParameters params) => -// _crudRepository.stream(id: params.id, conditions: params.conditions); -// } - -// class StreamQuery -// extends StreamUseCase> { -// final CrudRepository _crudRepository; - -// StreamQuery(this._crudRepository); - -// @override -// FutureOr onStart(StreamParameters? params) { -// if(params == null){ -// throw ClientException('Stream parameters cannot be null.'); -// } -// } - -// @override -// FutureOrResult>> call(StreamParameters? params) => _crudRepository.stream(); -// } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/update.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/update.dart index 982045c7..237e3e9d 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/update.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/update.dart @@ -17,25 +17,31 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; +/// {@template update} +/// A use case that updates an object model. +/// {@endtemplate} class Update - extends AsyncUseCase, void> { - final CrudRepository _crudRepository; + extends AsyncUseCase, void> + with UpdateOperation> { + /// {@macro update} + const Update(this._crudRepository); - Update(this._crudRepository); + final CrudRepository _crudRepository; @override FutureOr onStart(UpdateParameters? params) { - if(params == null){ - throw ClientException('Update parameters cannot be null.'); + if (params == null) { + throw const ClientException('Update parameters cannot be null.'); } } @override - FutureOrResult call(UpdateParameters? params) => + FutureOrResult execute(UpdateParameters? params) => _crudRepository.update( params!.id, object: params.object, diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/update_all.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/update_all.dart index 35779703..22c32181 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/update_all.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/update_all.dart @@ -17,23 +17,29 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; +/// {@template update_all} +/// A use case that updates all the object models. +/// {@endtemplate} class UpdateAll - extends AsyncUseCase, void> { - final CrudRepository _crudRepository; + extends AsyncUseCase, void> + with UpdateOperation> { + /// {@macro update_all} + const UpdateAll(this._crudRepository); - UpdateAll(this._crudRepository); + final CrudRepository _crudRepository; @override FutureOr onStart(Map? params) { - if(params == null){ - throw ClientException('Data cannot be null.'); + if (params == null) { + throw const ClientException('Data cannot be null.'); } } @override - FutureOrResult call(Map? params) => + FutureOrResult execute(Map? params) => _crudRepository.updateAll(params!); } diff --git a/packages/wyatt_crud_bloc/lib/src/domain/usecases/usecases.dart b/packages/wyatt_crud_bloc/lib/src/domain/usecases/usecases.dart index 984bbb28..4a8d8467 100644 --- a/packages/wyatt_crud_bloc/lib/src/domain/usecases/usecases.dart +++ b/packages/wyatt_crud_bloc/lib/src/domain/usecases/usecases.dart @@ -1,16 +1,16 @@ // 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 . @@ -21,6 +21,5 @@ export 'get.dart'; export 'get_all.dart'; export 'params/params.dart'; export 'query.dart'; -export 'stream_query.dart'; export 'update.dart'; export 'update_all.dart'; diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_advanced_cubit.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_advanced_cubit.dart new file mode 100644 index 00000000..d41e35d9 --- /dev/null +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_advanced_cubit.dart @@ -0,0 +1,305 @@ +// Copyright (C) 2023 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:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; +import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; +import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; +import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; + +/// {@template crud_cubit_advanced} +/// Cubit that handles CRUD operations with more granularity. +/// {@endtemplate} +abstract class CrudAdvancedCubit + extends CrudBaseCubit { + /// {@macro crud_cubit} + CrudAdvancedCubit() : super(); + + Create? get crudCreate; + DeleteAll? get crudDeleteAll; + Delete? get crudDelete; + GetAll? get crudGetAll; + Get? get crudGet; + Query? get crudQuery; + UpdateAll? get crudUpdateAll; + Update? get crudUpdate; + + FutureOr create(Model model) async { + final crud = crudCreate; + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(model); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + if (stateCopy.data == null) { + return CrudLoaded(model); + } + if (stateCopy.data!.id == model.id) { + return CrudLoaded(model); + } + + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + if (stateCopy.data.isEmpty) { + return CrudListLoaded([model]); + } + final List lst = stateCopy.data.toList()..add(model); + + return CrudListLoaded(lst); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr delete(String id) async { + final crud = crudDelete; + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(id); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + if (stateCopy.data?.id == id) { + return CrudLoaded(null); + } + + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + return CrudListLoaded( + stateCopy.data.where((element) => element?.id != id).toList(), + ); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr deleteAll() async { + final crud = crudDeleteAll; + if (crud == null) { + return; + } + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(null); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + return CrudLoaded(null); + } + if (stateCopy is CrudListLoaded) { + return CrudListLoaded(const []); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr get(String id) async { + final crud = crudGet; + if (crud == null) { + return; + } + emit(const CrudLoading()); + final result = await crud.call(id); + emit( + result.fold( + CrudLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr getAll() async { + final crud = crudGetAll; + if (crud == null) { + return; + } + emit(const CrudLoading()); + final result = await crud.call(null); + emit( + result.fold( + CrudListLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr query(List conditions) async { + final crud = crudQuery; + if (crud == null) { + return; + } + + emit(const CrudLoading()); + final result = await crud.call(conditions); + emit( + result.fold( + CrudListLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr update(UpdateParameters param) async { + final crud = crudUpdate; + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(param); + emit( + await result.foldAsync( + (_) async { + if (stateCopy is CrudLoaded) { + if (stateCopy.data?.id == param.id) { + // Same object, need to update actual stateCopy + final crudGet = this.crudGet; + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final newVersion = await crudGet.call(param.id); + if (newVersion.isOk) { + return CrudLoaded(newVersion.ok); + } + } + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + final bool listContains = + stateCopy.data.any((element) => element?.id == param.id); + if (listContains) { + // Loaded objects contains the modified object. + + final crudGet = this.crudGet; + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final newVersion = await crudGet.call(param.id); + if (newVersion.isOk) { + final newList = stateCopy.data + .where( + (element) => element?.id != param.id, + ) + .toList(); + return CrudListLoaded(newList + [newVersion.ok]); + } + } + return stateCopy; + } + return const CrudOkReturn(); + }, + (error) async => CrudError(error.toString()), + ), + ); + } + + FutureOr updateAll(Map param) async { + final crud = crudUpdateAll; + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(param); + emit( + await result.foldAsync( + (_) async { + if (stateCopy is CrudLoaded) { + // Same object, need to update actual stateCopy + final crudGet = this.crudGet; + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final actualId = stateCopy.data?.id; + final newVersion = await crudGet.call(actualId ?? ''); + if (newVersion.isOk) { + return CrudLoaded(newVersion.ok); + } + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + final crudQuery = this.crudQuery; + if (crudQuery == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + // Load all id to retrieve exactly same object + // (not all because previous stateCopy can be a query result) + final List ids = stateCopy.data + .map( + (e) => e?.id, + ) + .toList(); + final result = await crudQuery.call([ + WhereQuery( + WhereQueryType.whereIn, + 'id', + ids, + ) + ]); + if (result.isOk) { + return CrudListLoaded(result.ok ?? []); + } + return stateCopy; + } + return const CrudOkReturn(); + }, + (error) async => CrudError(error.toString()), + ), + ); + } +} diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart new file mode 100644 index 00000000..c694b880 --- /dev/null +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart @@ -0,0 +1,28 @@ +// 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:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'crud_state.dart'; + +/// {@template crud_base_cubit} +/// A base [Cubit] that handles SCRUD operations. +/// {@endtemplate} +abstract class CrudBaseCubit extends Cubit { + /// {@macro crud_base_cubit} + CrudBaseCubit() : super(const CrudInitial()); +} diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_state.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_state.dart similarity index 58% rename from packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_state.dart rename to packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_state.dart index 2506b7bb..64f2479a 100644 --- a/packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_state.dart +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_base_cubit/crud_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -part of 'crud_cubit.dart'; +part of 'crud_base_cubit.dart'; abstract class CrudState extends Equatable { const CrudState(); @@ -23,40 +23,57 @@ abstract class CrudState extends Equatable { List get props => []; } -class CrudInitial extends CrudState {} - -class CrudLoading extends CrudState {} - -abstract class CrudSuccess extends CrudState { - const CrudSuccess(); +/// Initial state of the CrudBaseCubit. +class CrudInitial extends CrudState { + const CrudInitial(); } -class CrudOkReturn extends CrudState { - const CrudOkReturn(); +/// Loading state of the CrudBaseCubit. +class CrudLoading extends CrudState { + const CrudLoading(); } +/// Error state of the CrudBaseCubit. class CrudError extends CrudState { - final String? message; - const CrudError(this.message); + final String? message; @override List get props => [message]; } -class CrudLoaded extends CrudSuccess { - final T? data; +/// Success state of the CrudBaseCubit. +/// This state is used to indicate that the operation was successful. +/// Can be one or list of objects. +abstract class CrudSuccess extends CrudState { + const CrudSuccess(); +} +/// Success state of the CrudBaseCubit. +/// This state is used to indicate that the operation was successful. +/// Contains no objects. +/// Used for create, update, delete operations. +class CrudOkReturn extends CrudSuccess { + const CrudOkReturn(); +} + +/// Loaded state of the CrudBaseCubit. +/// This state is used to indicate that the operation was successful. +/// Contains one object. +class CrudLoaded extends CrudSuccess { const CrudLoaded(this.data); + final T? data; @override List get props => [data]; } +/// Loaded state of the CrudBaseCubit. +/// This state is used to indicate that the operation was successful. +/// Contains list of objects. class CrudListLoaded extends CrudSuccess { - final List data; - const CrudListLoaded(this.data); + final List data; @override List get props => [data]; diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_cubit.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_cubit.dart new file mode 100644 index 00000000..5d18975f --- /dev/null +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/blocs/crud_cubit.dart @@ -0,0 +1,369 @@ +// Copyright (C) 2023 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:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; +import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; +import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; +import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; +import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; +import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; + +/// {@template crud_cubit} +/// Cubit that handles CRUD operations. +/// {@endtemplate} +abstract class CrudCubit extends CrudBaseCubit { + /// {@macro crud_cubit} + CrudCubit() : super(); + + /// Create operation. + /// Can be create. + CreateOperation? get createOperation; + + /// Read operation. + /// Can be get, getAll, query. + ReadOperation? get readOperation; + + /// Update operation. + /// Can be update, updateAll. + UpdateOperation? get updateOperation; + + /// Delete operation. + /// Can be delete or deleteAll. + DeleteOperation? get deleteOperation; + + Expected? _checkOperation(dynamic operation) { + if (operation == null) { + return null; + } + if (operation is! Expected) { + return null; + } + return operation; + } + + FutureOr create(Model model) async { + if (_checkOperation>(createOperation) != null) { + return _create(model); + } + } + + FutureOr read({String? id, List? conditions}) async { + if (_checkOperation>(readOperation) != null && id != null) { + return _get(id); + } + if (_checkOperation>(readOperation) != null) { + return _getAll(); + } + if (_checkOperation>(readOperation) != null && + conditions != null) { + return _query(conditions); + } + if (_checkOperation>(readOperation) != null && + conditions == null) { + return _getAll(); + } + } + + FutureOr update( + UpdateParameters? single, + Map? all, + ) async { + if (_checkOperation>(updateOperation) != null && + single != null) { + return _update(single); + } + + if (_checkOperation>(updateOperation) != null && + all != null) { + return _updateAll(all); + } + } + + FutureOr delete({String? id}) async { + if (_checkOperation>(deleteOperation) != null && id != null) { + return _delete(id); + } + if (_checkOperation>(deleteOperation) != null) { + return _deleteAll(); + } + } + + FutureOr _create(Model model) async { + final crud = _checkOperation>(createOperation); + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(model); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + if (stateCopy.data == null) { + return CrudLoaded(model); + } + if (stateCopy.data!.id == model.id) { + return CrudLoaded(model); + } + + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + if (stateCopy.data.isEmpty) { + return CrudListLoaded([model]); + } + final List lst = stateCopy.data.toList()..add(model); + + return CrudListLoaded(lst); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _delete(String id) async { + final crud = _checkOperation>(deleteOperation); + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(id); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + if (stateCopy.data?.id == id) { + return CrudLoaded(null); + } + + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + return CrudListLoaded( + stateCopy.data.where((element) => element?.id != id).toList(), + ); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _deleteAll() async { + final crud = _checkOperation>(deleteOperation); + if (crud == null) { + return; + } + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(null); + emit( + result.fold( + (_) { + if (stateCopy is CrudLoaded) { + return CrudLoaded(null); + } + if (stateCopy is CrudListLoaded) { + return CrudListLoaded(const []); + } + + return const CrudOkReturn(); + }, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _get(String id) async { + final crud = _checkOperation>(readOperation); + if (crud == null) { + return; + } + emit(const CrudLoading()); + final result = await crud.call(id); + emit( + result.fold( + CrudLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _getAll() async { + final crud = _checkOperation>(readOperation); + if (crud == null) { + return; + } + emit(const CrudLoading()); + final result = await crud.call(null); + emit( + result.fold( + CrudListLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _query(List conditions) async { + final crud = _checkOperation>(readOperation); + if (crud == null) { + return; + } + + emit(const CrudLoading()); + final result = await crud.call(conditions); + emit( + result.fold( + CrudListLoaded.new, + (error) => CrudError(error.toString()), + ), + ); + } + + FutureOr _update(UpdateParameters param) async { + final crud = _checkOperation>(updateOperation); + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(param); + emit( + await result.foldAsync( + (_) async { + if (stateCopy is CrudLoaded) { + if (stateCopy.data?.id == param.id) { + // Same object, need to update actual stateCopy + final crudGet = _checkOperation>(readOperation); + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final newVersion = await crudGet.call(param.id); + if (newVersion.isOk) { + return CrudLoaded(newVersion.ok); + } + } + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + final bool listContains = + stateCopy.data.any((element) => element?.id == param.id); + if (listContains) { + // Loaded objects contains the modified object. + + final crudGet = _checkOperation>(readOperation); + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final newVersion = await crudGet.call(param.id); + if (newVersion.isOk) { + final newList = stateCopy.data + .where( + (element) => element?.id != param.id, + ) + .toList(); + return CrudListLoaded(newList + [newVersion.ok]); + } + } + return stateCopy; + } + return const CrudOkReturn(); + }, + (error) async => CrudError(error.toString()), + ), + ); + } + + FutureOr _updateAll(Map param) async { + final crud = _checkOperation>(updateOperation); + if (crud == null) { + return; + } + + final stateCopy = state; + emit(const CrudLoading()); + final result = await crud.call(param); + emit( + await result.foldAsync( + (_) async { + if (stateCopy is CrudLoaded) { + // Same object, need to update actual stateCopy + final crudGet = _checkOperation>(readOperation); + if (crudGet == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + final actualId = stateCopy.data?.id; + final newVersion = await crudGet.call(actualId ?? ''); + if (newVersion.isOk) { + return CrudLoaded(newVersion.ok); + } + return stateCopy; + } + if (stateCopy is CrudListLoaded) { + final crudQuery = _checkOperation>(readOperation); + if (crudQuery == null) { + // No read operation, can't update stateCopy. + return stateCopy; + } + // Load all id to retrieve exactly same object + // (not all because previous stateCopy can be a query result) + final List ids = stateCopy.data + .map( + (e) => e?.id, + ) + .toList(); + final result = await crudQuery.call([ + WhereQuery( + WhereQueryType.whereIn, + 'id', + ids, + ) + ]); + if (result.isOk) { + return CrudListLoaded(result.ok ?? []); + } + return stateCopy; + } + return const CrudOkReturn(); + }, + (error) async => CrudError(error.toString()), + ), + ); + } +} diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/builder/builder.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/builder/builder.dart index 0184a4a5..52cf109d 100644 --- a/packages/wyatt_crud_bloc/lib/src/features/crud/builder/builder.dart +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/builder/builder.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/builder/crud_builder.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/builder/crud_builder.dart index 62f1faaa..d864ce7a 100644 --- a/packages/wyatt_crud_bloc/lib/src/features/crud/builder/crud_builder.dart +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/builder/crud_builder.dart @@ -15,15 +15,19 @@ // along with this program. If not, see . import 'package:flutter/material.dart'; -import 'package:wyatt_crud_bloc/src/features/crud/cubit/crud_cubit.dart'; +import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; +/// {@template crud_builder} +/// A widget that builds itself based on the latest snapshot of interaction +/// with a [CrudBaseCubit]. +/// +/// * I = Initial State +/// * L = Loading State +/// * S = Success State +/// * E = Error State +/// {@endtemplate} class CrudBuilder extends StatelessWidget { - /// `` - /// - /// - I: the Initial State - /// - L: the Loading State - /// - S: the Success State - /// - E: the Error State + /// {@macro crud_builder} const CrudBuilder({ required this.state, required this.builder, @@ -34,11 +38,11 @@ class CrudBuilder extends StatelessWidget { super.key, }); - /// `` + /// {@macro crud_builder} /// - /// - S: the Success State - /// - /// For CrudStates only. + /// This factory constructor is used to create a [CrudBuilder] with + /// [CrudState]s. `S` is the Success State, and it must be a subtype of + /// [CrudSuccess]. It the only type that you have to specify. static CrudBuilder typed({ required CrudState state, diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/crud.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/crud.dart index cb18407c..16113197 100644 --- a/packages/wyatt_crud_bloc/lib/src/features/crud/crud.dart +++ b/packages/wyatt_crud_bloc/lib/src/features/crud/crud.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 'blocs/crud_advanced_cubit.dart'; +export 'blocs/crud_base_cubit/crud_base_cubit.dart'; +export 'blocs/crud_cubit.dart'; export 'builder/builder.dart'; -export 'cubit/crud_cubit.dart'; diff --git a/packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_cubit.dart b/packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_cubit.dart deleted file mode 100644 index 67f43c1b..00000000 --- a/packages/wyatt_crud_bloc/lib/src/features/crud/cubit/crud_cubit.dart +++ /dev/null @@ -1,267 +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:equatable/equatable.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wyatt_architecture/wyatt_architecture.dart'; -import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; -import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart'; -import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; -import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; - -part 'crud_state.dart'; - -abstract class CrudCubit extends Cubit { - Create? get crudCreate; - DeleteAll? get crudDeleteAll; - Delete? get crudDelete; - GetAll? get crudGetAll; - Get? get crudGet; - Query? get crudQuery; - UpdateAll? get crudUpdateAll; - Update? get crudUpdate; - - CrudCubit() : super(CrudInitial()); - - FutureOr create(Model model) async { - if (crudCreate != null) { - final stateCopy = state; - emit(CrudLoading()); - final result = await crudCreate!.call(model); - emit( - result.fold( - (_) { - if (stateCopy is CrudLoaded) { - return stateCopy; - } - if (stateCopy is CrudListLoaded) { - if (stateCopy.data.isEmpty) { - return CrudListLoaded([model]); - } - final List lst = stateCopy.data.toList()..add(model); - return CrudListLoaded(lst); - } - return const CrudOkReturn(); - }, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr delete(String id) async { - if (crudDelete != null) { - final stateCopy = state; - emit(CrudLoading()); - final result = await crudDelete!.call(id); - emit( - result.fold( - (_) { - if (stateCopy is CrudLoaded) { - return stateCopy; - } - if (stateCopy is CrudListLoaded) { - return CrudListLoaded( - stateCopy.data.where((element) => element?.id != id).toList(), - ); - } - return const CrudOkReturn(); - }, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr deleteAll() async { - if (crudDeleteAll != null) { - final stateCopy = state; - emit(CrudLoading()); - final result = await crudDeleteAll!.call(null); - emit( - result.fold( - (_) { - if (stateCopy is CrudLoaded) { - return CrudLoaded(null); - } - if (stateCopy is CrudListLoaded) { - return CrudListLoaded(const []); - } - return const CrudOkReturn(); - }, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr get(String id) async { - if (crudGet != null) { - emit(CrudLoading()); - final result = await crudGet!.call(id); - emit( - result.fold( - CrudLoaded.new, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr getAll() async { - if (crudGetAll != null) { - emit(CrudLoading()); - final result = await crudGetAll!.call(null); - emit( - result.fold( - CrudListLoaded.new, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr query(List conditions) async { - if (crudQuery != null) { - emit(CrudLoading()); - final result = await crudQuery!.call(conditions); - emit( - result.fold( - CrudListLoaded.new, - (error) => CrudError(error.toString()), - ), - ); - } - } - - FutureOr update(UpdateParameters param) async { - if (crudUpdate != null) { - final stateCopy = state; - emit(CrudLoading()); - final result = await crudUpdate!.call(param); - emit( - await result.foldAsync( - (_) async { - if (stateCopy is CrudLoaded) { - if (stateCopy.data?.id == param.id) { - // Same object, need to update actual stateCopy - if (crudGet == null) { - throw ClientException( - 'Need to init Get usecase to use update.', - ); - } - final newVersion = await crudGet!.call(param.id); - if (newVersion.isOk) { - return CrudLoaded(newVersion.ok); - } - } - return stateCopy; - } - if (stateCopy is CrudListLoaded) { - final bool listContains = - stateCopy.data.any((element) => element?.id == param.id); - if (listContains) { - // Loaded objects contains the modified object. - if (crudGet == null) { - throw ClientException( - 'Need to init Get usecase to use update.', - ); - } - final newVersion = await crudGet!.call(param.id); - if (newVersion.isOk) { - final newList = stateCopy.data - .where( - (element) => element?.id != param.id, - ) - .toList(); - return CrudListLoaded(newList + [newVersion.ok]); - } - } - return stateCopy; - } - return const CrudOkReturn(); - }, - (error) async => CrudError(error.toString()), - ), - ); - } - } - - FutureOr updateAll(Map param) async { - if (crudUpdateAll != null) { - final stateCopy = state; - emit(CrudLoading()); - final result = await crudUpdateAll!.call(param); - emit( - await result.foldAsync( - (_) async { - if (stateCopy is CrudLoaded) { - // Same object, need to update actual stateCopy - if (crudGet == null) { - throw ClientException( - 'Need to init Get usecase to use updateAll.', - ); - } - final actualId = stateCopy.data?.id; - final newVersion = await crudGet!.call(actualId ?? ''); - if (newVersion.isOk) { - return CrudLoaded(newVersion.ok); - } - return stateCopy; - } - if (stateCopy is CrudListLoaded) { - if (crudQuery == null) { - throw ClientException( - 'Need to init Query usecase to use updateAll.', - ); - } - // Load all id to retrieve exactly same object - // (not all because previous stateCopy can be a query result) - final List ids = stateCopy.data - .map( - (e) => e?.id, - ) - .toList(); - final result = await crudQuery!.call([ - WhereQuery( - WhereQueryType.whereIn, - 'id', - ids, - ) - ]); - if (result.isOk) { - return CrudListLoaded(result.ok ?? []); - } - return stateCopy; - } - return const CrudOkReturn(); - }, - (error) async => CrudError(error.toString()), - ), - ); - } - } -} diff --git a/packages/wyatt_crud_bloc/lib/src/features/features.dart b/packages/wyatt_crud_bloc/lib/src/features/features.dart index 996ab833..f91fc8cf 100644 --- a/packages/wyatt_crud_bloc/lib/src/features/features.dart +++ b/packages/wyatt_crud_bloc/lib/src/features/features.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_crud_bloc/pubspec.yaml b/packages/wyatt_crud_bloc/pubspec.yaml index b237deb2..ebec6c8a 100644 --- a/packages/wyatt_crud_bloc/pubspec.yaml +++ b/packages/wyatt_crud_bloc/pubspec.yaml @@ -1,7 +1,7 @@ name: wyatt_crud_bloc description: Create/Read/Update/Delete BLoC for Flutter repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_crud_bloc -version: 0.1.0+2 +version: 0.1.1 publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub @@ -10,8 +10,7 @@ environment: flutter: ">=1.17.0" dependencies: - flutter: - sdk: flutter + flutter: { sdk: flutter } flutter_bloc: ^8.1.1 equatable: ^2.0.5 @@ -19,16 +18,15 @@ dependencies: wyatt_architecture: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 0.1.0+1 + version: ^0.2.0 wyatt_type_utils: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 0.0.4 + version: ^0.0.5 dev_dependencies: - flutter_test: - sdk: flutter + flutter_test: { sdk: flutter } bloc_test: ^9.1.0 wyatt_analysis: - hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: 2.2.2 + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_crud_bloc/test/wyatt_crud_bloc_test.dart b/packages/wyatt_crud_bloc/test/wyatt_crud_bloc_test.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/wyatt_deferred_widget_annotation/.gitignore b/packages/wyatt_deferred_widget_annotation/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_deferred_widget_annotation/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_annotation/.pubignore b/packages/wyatt_deferred_widget_annotation/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_deferred_widget_annotation/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_annotation/AUTHORS b/packages/wyatt_deferred_widget_annotation/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_deferred_widget_annotation/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_annotation/LICENSE b/packages/wyatt_deferred_widget_annotation/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_deferred_widget_annotation/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_gen/.gitignore b/packages/wyatt_deferred_widget_gen/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_deferred_widget_gen/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_gen/.pubignore b/packages/wyatt_deferred_widget_gen/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_deferred_widget_gen/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_gen/AUTHORS b/packages/wyatt_deferred_widget_gen/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_deferred_widget_gen/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_deferred_widget_gen/LICENSE b/packages/wyatt_deferred_widget_gen/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_deferred_widget_gen/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_form_bloc/.gitignore b/packages/wyatt_form_bloc/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_form_bloc/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_form_bloc/.gitignore b/packages/wyatt_form_bloc/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_form_bloc/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_form_bloc/.pubignore b/packages/wyatt_form_bloc/.pubignore deleted file mode 100644 index 11610c5a..00000000 --- a/packages/wyatt_form_bloc/.pubignore +++ /dev/null @@ -1,2 +0,0 @@ -firebase_options.dart -.vscode \ No newline at end of file diff --git a/packages/wyatt_form_bloc/.pubignore b/packages/wyatt_form_bloc/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_form_bloc/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_form_bloc/AUTHORS b/packages/wyatt_form_bloc/AUTHORS deleted file mode 100644 index b6d7d765..00000000 --- a/packages/wyatt_form_bloc/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_form_bloc/AUTHORS b/packages/wyatt_form_bloc/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_form_bloc/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_form_bloc/CHANGELOG.md b/packages/wyatt_form_bloc/CHANGELOG.md index 3c1cfc37..64c2926f 100644 --- a/packages/wyatt_form_bloc/CHANGELOG.md +++ b/packages/wyatt_form_bloc/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.0+3 + + - **REFACTOR**: remove cross package export. + - **FIX**: fix textController rebuild. + ## 0.2.0+2 - Update a dependency to the latest release. diff --git a/packages/wyatt_form_bloc/LICENSE b/packages/wyatt_form_bloc/LICENSE deleted file mode 100644 index 3b2646b3..00000000 --- a/packages/wyatt_form_bloc/LICENSE +++ /dev/null @@ -1,692 +0,0 @@ - - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_form_bloc/LICENSE b/packages/wyatt_form_bloc/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_form_bloc/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_form_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_form_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_form_bloc/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_form_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wyatt_form_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/wyatt_form_bloc/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/wyatt_form_bloc/example/lib/app/app.dart b/packages/wyatt_form_bloc/example/lib/app/app.dart index 63c35292..d69e3a30 100644 --- a/packages/wyatt_form_bloc/example/lib/app/app.dart +++ b/packages/wyatt_form_bloc/example/lib/app/app.dart @@ -35,7 +35,9 @@ class App extends StatelessWidget { FormInput(formFieldEmail, const Email.pure(), metadata: const FormInputMetadata(extra: blue)), FormInput( - formFieldList, const ListOption.pure(choices: ['c1', 'c2', 'c3'],defaultValue: 'c3')), + formFieldList, + const ListOption.pure( + choices: ['c1', 'c2', 'c3'], defaultValue: 'c3')), FormInput(formFieldRadio, const TextString.pure()), FormInput(formFieldPro, const Boolean.pure(), metadata: const FormInputMetadata(name: 'business')), @@ -65,7 +67,7 @@ class App extends StatelessWidget { Widget build(BuildContext context) { FormRepository formRepository = FormRepositoryImpl() ..registerForm(getNormalFormData()); - + // FormRepository formRepository = FormRepositoryImpl() // ..registerForm(WyattFormImpl([ // FormInput(formFieldName, const Name.pure('Test'), diff --git a/packages/wyatt_form_bloc/example/lib/app/metadata.dart b/packages/wyatt_form_bloc/example/lib/app/metadata.dart index 6d66f961..138da48b 100644 --- a/packages/wyatt_form_bloc/example/lib/app/metadata.dart +++ b/packages/wyatt_form_bloc/example/lib/app/metadata.dart @@ -15,10 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -enum Category { - perso, - business -} +enum Category { perso, business } class Metadata { final Category category; diff --git a/packages/wyatt_form_bloc/example/lib/constants.dart b/packages/wyatt_form_bloc/example/lib/constants.dart index a52efc92..f8c7dca6 100644 --- a/packages/wyatt_form_bloc/example/lib/constants.dart +++ b/packages/wyatt_form_bloc/example/lib/constants.dart @@ -1,16 +1,16 @@ // 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 . @@ -23,4 +23,4 @@ const String formFieldList = 'list'; const String formFieldRadio = 'radio'; const String formFieldHidden = 'hidden'; -const String formFieldPro = 'isPro'; \ No newline at end of file +const String formFieldPro = 'isPro'; diff --git a/packages/wyatt_form_bloc/example/lib/main.dart b/packages/wyatt_form_bloc/example/lib/main.dart index 42275ce9..28a8f3d9 100644 --- a/packages/wyatt_form_bloc/example/lib/main.dart +++ b/packages/wyatt_form_bloc/example/lib/main.dart @@ -21,10 +21,6 @@ import 'package:form_bloc_example/app/bloc_observer.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - BlocOverrides.runZoned( - () => runApp( - const App(), - ), - blocObserver: AppBlocObserver(), - ); + Bloc.observer = AppBlocObserver(); + runApp(const App()); } diff --git a/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart b/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart index fd87bc2d..3d71e18f 100644 --- a/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart +++ b/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart @@ -38,8 +38,7 @@ class _NameInput extends StatelessWidget { Widget build(BuildContext context) { return InputBuilderTextController( field: formFieldName, - builder: - (context, cubit, state, field, input, controller, metadata) { + builder: (context, cubit, state, field, input, controller, metadata) { final meta = state.form.metadataOf(field).extra; final color = computeColor(meta); return Row( diff --git a/packages/wyatt_form_bloc/example/test/widget_test.dart b/packages/wyatt_form_bloc/example/test/widget_test.dart index e69de29b..8b137891 100644 --- a/packages/wyatt_form_bloc/example/test/widget_test.dart +++ b/packages/wyatt_form_bloc/example/test/widget_test.dart @@ -0,0 +1 @@ + diff --git a/packages/wyatt_form_bloc/lib/src/core/enums/set_operations.dart b/packages/wyatt_form_bloc/lib/src/core/enums/set_operations.dart index 3e27f437..6395940d 100644 --- a/packages/wyatt_form_bloc/lib/src/core/enums/set_operations.dart +++ b/packages/wyatt_form_bloc/lib/src/core/enums/set_operations.dart @@ -33,7 +33,7 @@ enum SetOperation { /// Add new elements to set. union(FormUnion()); - final FormOperation operation; - const SetOperation(this.operation); + + final FormOperation operation; } diff --git a/packages/wyatt_form_bloc/lib/src/core/enums/validation_error.dart b/packages/wyatt_form_bloc/lib/src/core/enums/validation_error.dart index 4966b6b8..cb9b2526 100644 --- a/packages/wyatt_form_bloc/lib/src/core/enums/validation_error.dart +++ b/packages/wyatt_form_bloc/lib/src/core/enums/validation_error.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart b/packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart index e6a08758..6e3b9912 100644 --- a/packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart +++ b/packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart @@ -26,6 +26,14 @@ import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator // ignore: must_be_immutable class WyattFormImpl extends WyattForm { + WyattFormImpl( + this._inputs, { + required String name, + FormValidator validationStrategy = const EveryInputValidator(), + }) : _name = name, + _validator = validationStrategy { + _inputsInitial = _inputs.map((input) => input.clone()).toList(); + } final List< FormInput, dynamic>> _inputs; @@ -36,15 +44,6 @@ class WyattFormImpl extends WyattForm { FormInput, dynamic>> _inputsInitial; - WyattFormImpl( - this._inputs, { - required String name, - FormValidator validationStrategy = const EveryInputValidator(), - }) : _name = name, - _validator = validationStrategy { - _inputsInitial = _inputs.map((input) => input.clone()).toList(); - } - @override List< FormInput, @@ -149,7 +148,7 @@ class WyattFormImpl extends WyattForm { @override bool isValidInput(String key) => inputOf(key).validator.valid; - + @override bool isInvalidInput(String key) => inputOf(key).validator.invalid; diff --git a/packages/wyatt_form_bloc/lib/src/data/input_validators/boolean.dart b/packages/wyatt_form_bloc/lib/src/data/input_validators/boolean.dart index dba84780..4cbb9722 100644 --- a/packages/wyatt_form_bloc/lib/src/data/input_validators/boolean.dart +++ b/packages/wyatt_form_bloc/lib/src/data/input_validators/boolean.dart @@ -22,17 +22,15 @@ import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator /// {@endtemplate} class Boolean extends NullableValidator { /// {@macro boolean} - const Boolean.pure({bool defaultValue = false}) - : super.pure(defaultValue); + const Boolean.pure({bool defaultValue = false}) : super.pure(defaultValue); /// {@macro boolean} const Boolean.dirty({bool? value}) : super.dirty(value); - + @override ValidationStandardError get onNull => ValidationStandardError.invalid; @override ValidationStandardError? validator(bool? value) => value != null ? null : onNull; - } diff --git a/packages/wyatt_form_bloc/lib/src/data/input_validators/enum_option.dart b/packages/wyatt_form_bloc/lib/src/data/input_validators/enum_option.dart index 8a939fba..b4e1eaa8 100644 --- a/packages/wyatt_form_bloc/lib/src/data/input_validators/enum_option.dart +++ b/packages/wyatt_form_bloc/lib/src/data/input_validators/enum_option.dart @@ -21,8 +21,7 @@ class EnumOption extends AnyValidator, ValidationError> { const EnumOption.pure({this.enums = const [], T? defaultValue}) : super.pure(defaultValue); - const EnumOption.dirty({required this.enums, T? value}) - : super.dirty(value); + const EnumOption.dirty({required this.enums, T? value}) : super.dirty(value); final List enums; diff --git a/packages/wyatt_form_bloc/lib/src/domain/entities/form_input.dart b/packages/wyatt_form_bloc/lib/src/domain/entities/form_input.dart index 741b3ac2..39bdd7e2 100644 --- a/packages/wyatt_form_bloc/lib/src/domain/entities/form_input.dart +++ b/packages/wyatt_form_bloc/lib/src/domain/entities/form_input.dart @@ -61,6 +61,5 @@ class FormInput< List get props => [key, validator, metadata]; @override - String toString() => - 'FormInput(name: $name, $validator)'; + String toString() => 'FormInput(name: $name, $validator)'; } diff --git a/packages/wyatt_form_bloc/lib/src/presentation/features/form_data/form_data_state.dart b/packages/wyatt_form_bloc/lib/src/presentation/features/form_data/form_data_state.dart index 57ab4c95..05caf251 100644 --- a/packages/wyatt_form_bloc/lib/src/presentation/features/form_data/form_data_state.dart +++ b/packages/wyatt_form_bloc/lib/src/presentation/features/form_data/form_data_state.dart @@ -17,6 +17,12 @@ part of 'form_data_cubit.dart'; abstract class FormDataState extends Equatable { + const FormDataState({ + required this.form, + this.status = FormStatus.pure, + this.errorMessage, + }); + /// Global status of a form. final FormStatus status; @@ -26,12 +32,6 @@ abstract class FormDataState extends Equatable { /// Optional error message. final String? errorMessage; - const FormDataState({ - required this.form, - this.status = FormStatus.pure, - this.errorMessage, - }); - @override List get props => [status, form, errorMessage]; } diff --git a/packages/wyatt_form_bloc/lib/src/presentation/features/form_data_impl/form_data_cubit_impl.dart b/packages/wyatt_form_bloc/lib/src/presentation/features/form_data_impl/form_data_cubit_impl.dart index 2eb50aa7..7721ff36 100644 --- a/packages/wyatt_form_bloc/lib/src/presentation/features/form_data_impl/form_data_cubit_impl.dart +++ b/packages/wyatt_form_bloc/lib/src/presentation/features/form_data_impl/form_data_cubit_impl.dart @@ -27,11 +27,10 @@ import 'package:wyatt_form_bloc/src/presentation/features/form_data/form_data_cu part 'form_data_state_impl.dart'; abstract class FormDataCubitImpl extends FormDataCubit { - final FormRepository _formRepository; - final String _formName; - FormDataCubitImpl(this._formRepository, this._formName) : super(FormDataStateImpl(form: _formRepository.accessForm(_formName))); + final FormRepository _formRepository; + final String _formName; @override String get formName => _formName; diff --git a/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart b/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart index 999c9104..a571ce69 100644 --- a/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart +++ b/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart @@ -48,7 +48,7 @@ class InputBuilderTextController().formName; + final formName = context.read().formName; final value = context.read().accessForm(formName).valueOf(field); _controller diff --git a/packages/wyatt_form_bloc/pubspec.yaml b/packages/wyatt_form_bloc/pubspec.yaml index a292249a..da3c4645 100644 --- a/packages/wyatt_form_bloc/pubspec.yaml +++ b/packages/wyatt_form_bloc/pubspec.yaml @@ -1,7 +1,7 @@ name: wyatt_form_bloc description: Manage forms in Dart & Flutter with Bloc repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_form_bloc -version: 0.2.0+2 +version: 0.2.0+3 publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub @@ -17,11 +17,11 @@ dependencies: wyatt_architecture: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^0.1.0+1 + version: ^0.2.0 wyatt_type_utils: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^0.0.4 + version: ^0.0.5 dev_dependencies: @@ -30,4 +30,4 @@ dev_dependencies: wyatt_analysis: hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ - version: ^2.2.2 + version: ^2.5.0 diff --git a/packages/wyatt_http_client/.gitignore b/packages/wyatt_http_client/.gitignore deleted file mode 100644 index 65c34dc8..00000000 --- a/packages/wyatt_http_client/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/wyatt_http_client/.gitignore b/packages/wyatt_http_client/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_http_client/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_http_client/.pubignore b/packages/wyatt_http_client/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_http_client/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_http_client/AUTHORS b/packages/wyatt_http_client/AUTHORS deleted file mode 100644 index b6d7d765..00000000 --- a/packages/wyatt_http_client/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to this project. Names should be added to the list like so: -# -# Name/Organization - -Wyatt Group S.A.S -Hugo Pointcheval \ No newline at end of file diff --git a/packages/wyatt_http_client/AUTHORS b/packages/wyatt_http_client/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_http_client/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_http_client/CHANGELOG.md b/packages/wyatt_http_client/CHANGELOG.md index f597ef73..d8a9e94b 100644 --- a/packages/wyatt_http_client/CHANGELOG.md +++ b/packages/wyatt_http_client/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.0.0 + +> Note: This release has breaking changes. + + - **DOCS**: add simple example. + - **BREAKING** **REFACTOR**: fix cascade dart good practices + docs. + ## 1.2.0 - **FEAT**: add new middleware feature. diff --git a/packages/wyatt_http_client/LICENSE b/packages/wyatt_http_client/LICENSE deleted file mode 100644 index e72bfdda..00000000 --- a/packages/wyatt_http_client/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - (at your option) 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/packages/wyatt_http_client/LICENSE b/packages/wyatt_http_client/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_http_client/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_http_client/README.md b/packages/wyatt_http_client/README.md index ee2b78d5..aee439ed 100644 --- a/packages/wyatt_http_client/README.md +++ b/packages/wyatt_http_client/README.md @@ -16,12 +16,10 @@ * along with this program. If not, see . --> -# Dart - HTTP Client +# HTTP Client

- - Style: Wyatt Analysis - + Style: Wyatt Analysis SDK: Dart & Flutter

@@ -52,13 +50,13 @@ For example, if you want to log every request, and simplify an url you can use p ```dart // Create the Pipeline final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( + ..addMiddleware( + const UriPrefixMiddleware( protocol: Protocols.http, authority: 'localhost:80', ), ) - .addMiddleware(SimpleLoggerMiddleware()); + ..addMiddleware(const SimpleLoggerMiddleware()); ``` Then if you print the pipeline, @@ -94,20 +92,20 @@ Let's start by creating the Pipeline: ```dart final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( + ..addMiddleware( + const UriPrefixMiddleware( protocol: Protocols.http, authority: 'localhost:80', ), ) - .addMiddleware(BodyToJsonMiddleware()) - .addMiddleware( - UnsafeAuthMiddleware( + ..addMiddleware(const BodyToJsonMiddleware()) + ..addMiddleware( + const UnsafeAuthMiddleware( username: 'wyatt', password: 'motdepasse', ), ) - .addMiddleware(SimpleLoggerMiddleware()); + ..addMiddleware(SimpleLoggerMiddleware()); ``` Then simply create a client and make a call. @@ -128,14 +126,14 @@ So now we want a real authentication. ```dart final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( + ..addMiddleware( + const UriPrefixMiddleware( protocol: Protocols.http, authority: 'localhost:80', ), ) - .addMiddleware(BodyToJsonMiddleware()) - .addMiddleware( + ..addMiddleware(const BodyToJsonMiddleware()) + ..addMiddleware( RefreshTokenAuthMiddleware( authorizationEndpoint: '/auth/sign-in', tokenEndpoint: '/auth/refresh', @@ -144,7 +142,7 @@ final Pipeline pipeline = Pipeline() unauthorized: HttpStatus.forbidden, ), ) - .addMiddleware(SimpleLoggerMiddleware()); + ..addMiddleware(const SimpleLoggerMiddleware()); ``` > Here we just change `UnsafeAuthMiddleware` by `RefreshTokenAuthMiddleware` and the whole app while adapt to a new authentication system. @@ -157,6 +155,8 @@ You can create your own middleware by implementing `Middleware` class, and use m class SimpleLoggerMiddleware with OnRequestMiddleware, OnResponseMiddleware implements Middleware { + + const SimpleLoggerMiddleware(); @override String getName() => 'SimpleLogger'; diff --git a/packages/wyatt_http_client/example/example.dart b/packages/wyatt_http_client/example/example.dart new file mode 100644 index 00000000..a5c529ea --- /dev/null +++ b/packages/wyatt_http_client/example/example.dart @@ -0,0 +1,78 @@ +// Copyright (C) 2023 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:wyatt_http_client/wyatt_http_client.dart'; + +Future testSimpleGet() async { + print('testSimpleGet'); + final pipeline = Pipeline() + ..addMiddleware(const BodyToJsonMiddleware()) + ..addMiddleware(const SimpleLoggerMiddleware()); + + final client = MiddlewareClient(pipeline: pipeline); + + final response = await client + .get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1')); + print(response.body); +} + +Future testUriPrefix() async { + print('testUriPrefix'); + final pipeline = Pipeline() + ..addMiddleware( + const UriPrefixMiddleware( + protocol: Protocols.https, + authority: 'jsonplaceholder.typicode.com', + ), + ) + ..addMiddleware(const BodyToJsonMiddleware()) + ..addMiddleware(const SimpleLoggerMiddleware()); + + final client = MiddlewareClient(pipeline: pipeline); + + final response = await client.get(Uri.parse('/todos/1')); + print(response.body); +} + +Future testBasicAuth() async { + print('testBasicAuth'); + final pipeline = Pipeline() + ..addMiddleware( + const BasicAuthMiddleware( + username: 'guest', + password: 'guest', + ), + ) + ..addMiddleware(const BodyToJsonMiddleware()) + ..addMiddleware(const SimpleLoggerMiddleware()); + + final client = MiddlewareClient(pipeline: pipeline); + + final response = + await client.get(Uri.parse('https://jigsaw.w3.org/HTTP/Basic/')); + + if (HttpStatus.from(response.statusCode).isSuccess()) { + print("🎉 You're in!"); + } else { + print("⭕️ Nope, you're not in."); + } +} + +void main(List args) { + testSimpleGet(); + testUriPrefix(); + testBasicAuth(); +} diff --git a/packages/wyatt_http_client/example/http_client_example.dart b/packages/wyatt_http_client/example/http_client_example.dart deleted file mode 100644 index 57b16bee..00000000 --- a/packages/wyatt_http_client/example/http_client_example.dart +++ /dev/null @@ -1,294 +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 'dart:io'; - -import 'package:wyatt_http_client/wyatt_http_client.dart'; - -String lastToken = ''; -int token = 0; - -void printAuth(HttpRequest req) { - print( - 'Authorization => ' - "${req.headers.value('Authorization') ?? 'no authorization header'}", - ); -} - -Future handleBasic(HttpRequest req) async { - printAuth(req); -} - -Future handleBasicNegotiate(HttpRequest req) async { - if (req.headers.value('Authorization') == null) { - req.response.statusCode = HttpStatus.unauthorized.statusCode; - req.response.headers.set(HeaderKeys.wwwAuthenticate, 'Basic realm="Wyatt"'); - print(req.response.headers.value('WWW-Authenticate')); - return req.response.close(); - } - printAuth(req); -} - -Future handleBearer(HttpRequest req) async { - printAuth(req); -} - -Future handleDigest(HttpRequest req) async { - if (req.headers.value('Authorization') == null) { - req.response.statusCode = HttpStatus.unauthorized.statusCode; - req.response.headers.set( - 'WWW-Authenticate', - 'Digest realm="Wyatt", ' - 'qop="auth,auth-int", ' - 'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", ' - 'opaque="5ccc069c403ebaf9f0171e9517f40e41"', - ); - print(req.response.headers.value('WWW-Authenticate')); - return req.response.close(); - } - printAuth(req); -} - -Future handleUnsafe(HttpRequest req) async { - print( - 'Query parameters => ' - '${req.uri.queryParameters.toString()}', - ); -} - -Future handleOauth2RefreshToken(HttpRequest req) async { - final action = req.uri.queryParameters['action']; - if (action == null) { - printAuth(req); - } - - switch (action) { - case 'login': - if (req.method == 'POST') { - token++; - req.response.write( - '{"accessToken": "access-token-awesome$token", ' - '"refreshToken": "refresh-token-awesome$token"}', - ); - } - break; - case 'refresh': - printAuth(req); - if (req.method == 'GET') { - token++; - req.response.write('{"accessToken": "access-token-refreshed$token"}'); - } - break; - case 'access-denied': - final String receivedToken = req.headers.value('Authorization') ?? ''; - if (receivedToken != '' && - lastToken != '' && - receivedToken != lastToken) { - lastToken = receivedToken; - printAuth(req); - return req.response.close(); - } else { - lastToken = receivedToken; - req.response.statusCode = HttpStatus.unauthorized.statusCode; - return req.response.close(); - } - default: - break; - } -} - -Future server() async { - final server = await HttpServer.bind(InternetAddress.anyIPv6, 8080); - var error = 0; - var token = 0; - await server.forEach((HttpRequest request) { - print('[${request.method}] ${request.uri}'); - switch (request.uri.path) { - case '/test/basic-test': - handleBasic(request); - break; - case '/test/basic-test-with-negotiate': - handleBasicNegotiate(request); - break; - case '/test/digest-test': - handleDigest(request); - break; - case '/test/apikey-test': - handleBearer(request); - break; - case '/test/bearer-test': - handleBearer(request); - break; - case '/test/unsafe-test': - handleUnsafe(request); - break; - case '/test/oauth2-test': - handleOauth2RefreshToken(request); - break; - - case '/test/bearer-login': - if (request.method == 'POST') { - request.response.write('{"token": "access-token-test"}'); - } - break; - - case '/test/oauth2-test-error': - error++; - print('Error $error'); - if (error >= 3) { - print('Authorized'); - error = 0; - } else { - request.response.statusCode = HttpStatus.unauthorized.statusCode; - } - break; - case '/test/oauth2-test-timeout': - error++; - print('Error $error'); - request.response.statusCode = HttpStatus.unauthorized.statusCode; - break; - case '/test/oauth2-login': - if (request.method == 'POST') { - token++; - request.response.write( - '{"accessToken": "access-token-awesome$token", ' - '"refreshToken": "refresh-token-awesome$token"}', - ); - } - break; - case '/test/oauth2-refresh': - print( - 'Authorization => ' - "${request.headers.value('Authorization') ?? 'no refresh token'}", - ); - if (request.method == 'GET') { - token++; - request.response - .write('{"accessToken": "access-token-refreshed$token"}'); - } - break; - case '/test/oauth2-refresh-error': - request.response.statusCode = HttpStatus.unauthorized.statusCode; - break; - - default: - print(' => Unknown path or method'); - request.response.statusCode = HttpStatus.notFound.statusCode; - } - request.response.close(); - print('===================='); - }); -} - -Future main() async { - unawaited(server()); - final base = 'localhost:8080'; - final uriPrefix = UriPrefixMiddleware( - protocol: Protocols.http, - authority: base, - ); - final jsonEncoder = BodyToJsonMiddleware(); - final logger = SimpleLoggerMiddleware(); - - // Basic - final basicAuth = BasicAuthMiddleware( - username: 'username', - password: 'password', - ); - final basic = MiddlewareClient( - pipeline: Pipeline.fromIterable([ - uriPrefix, - basicAuth, - logger, - ]), - ); - await basic.get(Uri.parse('/test/basic-test')); - - // Digest - final digestAuth = DigestAuthMiddleware( - username: 'Mufasa', - password: 'Circle Of Life', - ); - final digest = MiddlewareClient( - pipeline: Pipeline.fromIterable([ - uriPrefix, - digestAuth, - logger, - ]), - ); - await digest.get(Uri.parse('/test/digest-test')); - - // // Bearer - // final bearer = BearerAuthenticationClient( - // token: 'access-token-test', - // inner: restClient, - // ); - // await bearer.get(Uri.parse('/test/bearer-test')); - - // // API Key - // final apiKey = BearerAuthenticationClient( - // token: 'awesome-api-key', - // authenticationMethod: 'ApiKey', - // inner: restClient, - // ); - // await apiKey.get(Uri.parse('/test/apikey-test')); - - // Unsafe URL - final unsafeAuth = UnsafeAuthMiddleware( - username: 'Mufasa', - password: 'Circle Of Life', - ); - final unsafe = MiddlewareClient( - pipeline: Pipeline.fromIterable([ - uriPrefix, - unsafeAuth, - logger, - ]), - ); - await unsafe.get(Uri.parse('/test/unsafe-test')); - - // OAuth2 - final refreshTokenAuth = RefreshTokenAuthMiddleware( - authorizationEndpoint: '/test/oauth2-test?action=login', - tokenEndpoint: '/test/oauth2-test?action=refresh', - accessTokenParser: (body) => body['accessToken']! as String, - refreshTokenParser: (body) => body['refreshToken']! as String, - ); - final refreshToken = MiddlewareClient( - pipeline: Pipeline.fromIterable([ - uriPrefix, - jsonEncoder, - refreshTokenAuth, - logger, - ]), - ); - await refreshToken.get(Uri.parse('/test/oauth2-test')); - // Login - await refreshToken.post( - Uri.parse('/test/oauth2-test'), - body: { - 'username': 'username', - 'password': 'password', - }, - ); - await refreshToken.get(Uri.parse('/test/oauth2-test')); - // await refreshToken.refresh(); - // await refreshToken.get(Uri.parse('/test/oauth2-test')); - // await refreshToken.get(Uri.parse('/test/oauth2-test?action=access-denied')); - - exit(0); -} diff --git a/packages/wyatt_http_client/example/http_client_fastapi_example.dart b/packages/wyatt_http_client/example/http_client_fastapi_example.dart deleted file mode 100644 index 5393611c..00000000 --- a/packages/wyatt_http_client/example/http_client_fastapi_example.dart +++ /dev/null @@ -1,398 +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 . - -// ignore_for_file: public_member_api_docs, sort_constructors_first -import 'dart:convert'; - -import 'package:wyatt_http_client/src/middleware_client.dart'; -import 'package:wyatt_http_client/src/middlewares/body_to_json_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/refresh_token_auth_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/simple_logger_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/uri_prefix_middleware.dart'; -import 'package:wyatt_http_client/src/pipeline.dart'; -import 'package:wyatt_http_client/src/utils/http_status.dart'; -import 'package:wyatt_http_client/src/utils/protocols.dart'; - -enum EmailVerificationAction { - signUp, - resetPassword, - changeEmail; - - String toSnakeCase() { - return name.splitMapJoin( - RegExp('[A-Z]'), - onMatch: (m) => '_${m[0]?.toLowerCase()}', - onNonMatch: (n) => n, - ); - } - - factory EmailVerificationAction.fromString(String str) { - return EmailVerificationAction.values.firstWhere( - (EmailVerificationAction element) => element.toSnakeCase() == str, - ); - } -} - -class VerifyCode { - final String email; - final String verificationCode; - final EmailVerificationAction action; - VerifyCode({ - required this.email, - required this.verificationCode, - required this.action, - }); - - VerifyCode copyWith({ - String? email, - String? verificationCode, - EmailVerificationAction? action, - }) { - return VerifyCode( - email: email ?? this.email, - verificationCode: verificationCode ?? this.verificationCode, - action: action ?? this.action, - ); - } - - Map toMap() { - return { - 'email': email, - 'verification_code': verificationCode, - 'action': action.toSnakeCase(), - }; - } - - factory VerifyCode.fromMap(Map map) { - return VerifyCode( - email: map['email'] as String, - verificationCode: map['verification_code'] as String, - action: EmailVerificationAction.fromString(map['action'] as String), - ); - } - - String toJson() => json.encode(toMap()); - - factory VerifyCode.fromJson(String source) => - VerifyCode.fromMap(json.decode(source) as Map); - - @override - String toString() => - 'VerifyCode(email: $email, verificationCode: $verificationCode, action: $action)'; -} - -class Account { - final String email; - final String? sessionId; - Account({ - required this.email, - this.sessionId, - }); - - Account copyWith({ - String? email, - String? sessionId, - }) { - return Account( - email: email ?? this.email, - sessionId: sessionId ?? this.sessionId, - ); - } - - Map toMap() { - return { - 'email': email, - 'session_id': sessionId, - }; - } - - factory Account.fromMap(Map map) { - return Account( - email: map['email'] as String, - sessionId: map['session_id'] != null ? map['session_id'] as String : null, - ); - } - - String toJson() => json.encode(toMap()); - - factory Account.fromJson(String source) => - Account.fromMap(json.decode(source) as Map); - - @override - String toString() => 'Account(email: $email, sessionId: $sessionId)'; -} - -class SignUp { - final String sessionId; - final String password; - SignUp({ - required this.sessionId, - required this.password, - }); - - SignUp copyWith({ - String? sessionId, - String? password, - }) { - return SignUp( - sessionId: sessionId ?? this.sessionId, - password: password ?? this.password, - ); - } - - Map toMap() { - return { - 'session_id': sessionId, - 'password': password, - }; - } - - factory SignUp.fromMap(Map map) { - return SignUp( - sessionId: map['session_id'] as String, - password: map['password'] as String, - ); - } - - String toJson() => json.encode(toMap()); - - factory SignUp.fromJson(String source) => - SignUp.fromMap(json.decode(source) as Map); - - @override - String toString() => 'SignUp(sessionId: $sessionId, password: $password)'; -} - -class TokenSuccess { - final String accessToken; - final String refreshToken; - final Account account; - TokenSuccess({ - required this.accessToken, - required this.refreshToken, - required this.account, - }); - - TokenSuccess copyWith({ - String? accessToken, - String? refreshToken, - Account? account, - }) { - return TokenSuccess( - accessToken: accessToken ?? this.accessToken, - refreshToken: refreshToken ?? this.refreshToken, - account: account ?? this.account, - ); - } - - Map toMap() { - return { - 'access_token': accessToken, - 'refresh_token': refreshToken, - 'account': account.toMap(), - }; - } - - factory TokenSuccess.fromMap(Map map) { - return TokenSuccess( - accessToken: map['access_token'] as String, - refreshToken: map['refresh_token'] as String, - account: Account.fromMap(map['account'] as Map), - ); - } - - String toJson() => json.encode(toMap()); - - factory TokenSuccess.fromJson(String source) => - TokenSuccess.fromMap(json.decode(source) as Map); - - @override - String toString() => - 'TokenSuccess(accessToken: $accessToken, refreshToken: $refreshToken, account: $account)'; -} - -class Login { - final String email; - final String password; - Login({ - required this.email, - required this.password, - }); - - Login copyWith({ - String? email, - String? password, - }) { - return Login( - email: email ?? this.email, - password: password ?? this.password, - ); - } - - Map toMap() { - return { - 'email': email, - 'password': password, - }; - } - - factory Login.fromMap(Map map) { - return Login( - email: map['email'] as String, - password: map['password'] as String, - ); - } - - String toJson() => json.encode(toMap()); - - factory Login.fromJson(String source) => - Login.fromMap(json.decode(source) as Map); - - @override - String toString() => 'Login(email: $email, password: $password)'; -} - -class FastAPI { - final String baseUrl; - final MiddlewareClient client; - final int apiVersion; - - FastAPI({ - this.baseUrl = 'localhost:80', - MiddlewareClient? client, - this.apiVersion = 1, - }) : client = client ?? MiddlewareClient(); - - String get apiPath => '/api/v$apiVersion'; - - Future sendSignUpCode(String email) async { - final r = await client.post( - Uri.parse('$apiPath/auth/send-sign-up-code'), - body: { - 'email': email, - }, - ); - if (r.statusCode != 201) { - throw Exception('Invalid reponse: ${r.statusCode}'); - } - } - - Future verifyCode(VerifyCode verifyCode) async { - final r = await client.post( - Uri.parse('$apiPath/auth/verify-code'), - body: verifyCode.toMap(), - ); - if (r.statusCode != 202) { - throw Exception('Invalid reponse: ${r.statusCode}'); - } else { - return Account.fromMap( - (jsonDecode(r.body) as Map)['account'] - as Map, - ); - } - } - - Future signUp(SignUp signUp) async { - final r = await client.post( - Uri.parse('$apiPath/auth/sign-up'), - body: signUp.toMap(), - ); - if (r.statusCode != 201) { - throw Exception('Invalid reponse: ${r.statusCode}'); - } else { - return Account.fromJson(r.body); - } - } - - Future signInWithPassword(Login login) async { - final r = await client.post( - Uri.parse('$apiPath/auth/sign-in-with-password'), - body: login.toMap(), - ); - if (r.statusCode != 200) { - throw Exception('Invalid reponse: ${r.statusCode}'); - } else { - return TokenSuccess.fromJson(r.body); - } - } - - // Future refresh() async { - // final r = await client.refresh(); - // return TokenSuccess.fromJson(r?.body ?? ''); - // } - - Future> getAccountList() async { - final r = await client.get( - Uri.parse('$apiPath/account'), - ); - if (r.statusCode != 200) { - throw Exception('Invalid reponse: ${r.statusCode}'); - } else { - final list = (jsonDecode(r.body) as Map)['founds'] - as List>; - final result = []; - for (final element in list) { - result.add(Account.fromMap(element)); - } - return result; - } - } -} - -void main(List args) async { - final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( - protocol: Protocols.http, - authority: 'localhost:80', - ), - ) - .addMiddleware(BodyToJsonMiddleware()) - .addMiddleware( - RefreshTokenAuthMiddleware( - authorizationEndpoint: '/api/v1/auth/sign-in-with-password', - tokenEndpoint: '/api/v1/auth/refresh', - accessTokenParser: (body) => body['access_token']! as String, - refreshTokenParser: (body) => body['refresh_token']! as String, - unauthorized: HttpStatus.forbidden, - ), - ) - .addMiddleware(SimpleLoggerMiddleware()); - - print(pipeline); - final client = MiddlewareClient(pipeline: pipeline); - - final api = FastAPI( - client: client, - ); - - await api.sendSignUpCode('git@pcl.ovh'); - final verifiedAccount = await api.verifyCode( - VerifyCode( - email: 'git@pcl.ovh', - verificationCode: '000000000', - action: EmailVerificationAction.signUp, - ), - ); - final registeredAccount = await api.signUp( - SignUp(sessionId: verifiedAccount.sessionId ?? '', password: 'password'), - ); - final signedInAccount = await api.signInWithPassword( - Login(email: 'git@pcl.ovh', password: 'password'), - ); - final accountList = await api.getAccountList(); - print(accountList); -} diff --git a/packages/wyatt_http_client/example/pipeline.dart b/packages/wyatt_http_client/example/pipeline.dart deleted file mode 100644 index 334fc509..00000000 --- a/packages/wyatt_http_client/example/pipeline.dart +++ /dev/null @@ -1,162 +0,0 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// 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:wyatt_http_client/src/middleware_client.dart'; -import 'package:wyatt_http_client/src/middlewares/body_to_json_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/simple_logger_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/unsafe_auth_middleware.dart'; -import 'package:wyatt_http_client/src/middlewares/uri_prefix_middleware.dart'; -import 'package:wyatt_http_client/src/pipeline.dart'; -import 'package:wyatt_http_client/src/utils/protocols.dart'; - -// class RequestMutatorMiddleware implements Middleware { -// @override -// Middleware? parent; - -// @override -// Middleware? child; - -// RequestMutatorMiddleware({ -// this.parent, -// this.child, -// }); - -// @override -// BaseRequest onRequest(BaseRequest request) { -// print('RequestMutator::OnRequest: ${request.method} -> ${request.url}'); -// return child?.onRequest(request) ?? request; -// } - -// @override -// BaseResponse onResponse(BaseResponse response) { -// final res = child?.onResponse(response) ?? response; -// print( -// 'RequestMutator::OnResponse: ${res.statusCode} -> ${res.contentLength} bytes', -// ); -// return res; -// } -// } - -// typedef Middleware = Handler Function(Handler innerHandler); - -// Middleware createMiddleware({ -// FutureOr Function(Request)? requestHandler, -// FutureOr Function(Response)? responseHandler, -// FutureOr Function(Object error, StackTrace)? errorHandler, -// }) { -// requestHandler ??= (request) => null; -// responseHandler ??= (response) => response; - -// FutureOr Function(Object, StackTrace)? onError; -// if (errorHandler != null) { -// onError = (error, stackTrace) { -// if (error is Exception) throw error; -// return errorHandler(error, stackTrace); -// }; -// } - -// return (Handler innerHandler) { -// return (request) { -// return Future.sync(() => requestHandler!(request)).then((response) { -// if (response != null) return response; - -// return Future.sync(() => innerHandler(request)) -// .then((response) => responseHandler!(response), onError: onError); -// }); -// }; -// }; -// } - -// extension MiddlewareX on Middleware { -// Middleware addMiddleware(Middleware other) => -// (Handler handler) => this(other(handler)); -// Handler addHandler(Handler handler) => this(handler); -// } - -// typedef Handler = FutureOr Function(Request request); - -// final headerMutator = createMiddleware( -// responseHandler: (response) { -// print(response.headers); -// return response; -// },); - -// class Pipeline { -// const Pipeline(); - -// Pipeline addMiddleware(Middleware middleware) => -// _Pipeline(middleware, addHandler); - -// Handler addHandler(Handler handler) => handler; - -// Middleware get middleware => addHandler; -// } - -// class _Pipeline extends Pipeline { -// final Middleware _middleware; -// final Middleware _parent; - -// _Pipeline(this._middleware, this._parent); - -// @override -// Handler addHandler(Handler handler) => _parent(_middleware(handler)); -// } - -Future main(List args) async { - final UnsafeAuthMiddleware auth = UnsafeAuthMiddleware(); - final Pipeline pipeline = Pipeline() - .addMiddleware( - UriPrefixMiddleware( - protocol: Protocols.http, - authority: 'localhost:80', - ), - ) - .addMiddleware(BodyToJsonMiddleware()) - .addMiddleware( - UnsafeAuthMiddleware( - username: 'wyatt', - password: 'motdepasse', - ), - ) - .addMiddleware(SimpleLoggerMiddleware()); - // .addMiddleware( - // RefreshTokenMiddleware( - // authorizationEndpoint: '/api/v1/account/test?action=authorize', - // tokenEndpoint: '/api/v1/account/test?action=refresh', - // accessTokenParser: (body) => body['access_token']! as String, - // refreshTokenParser: (body) => body['refresh_token']! as String, - // ), - // ); - - print(pipeline); - final client = MiddlewareClient(pipeline: pipeline); - await client.post( - Uri.parse('/api/v1/account/test'), - body: { - 'email': 'test@test.fr', - }, - ); - auth - ..username = 'username' - ..password = 'password'; - await client.post( - Uri.parse('/api/v1/account/test'), - body: { - 'email': 'test@test.fr', - }, - ); -} diff --git a/packages/wyatt_http_client/lib/src/middleware.dart b/packages/wyatt_http_client/lib/src/middleware.dart index 07cf6323..9f0c9d67 100644 --- a/packages/wyatt_http_client/lib/src/middleware.dart +++ b/packages/wyatt_http_client/lib/src/middleware.dart @@ -18,12 +18,21 @@ import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/models/middleware_response.dart'; +/// {@template middleware} +/// A middleware is a class that can intercept requests and responses +/// and modify them before they are sent to the server or before they +/// are returned to the client. +/// {@endtemplate} abstract class Middleware { - Middleware(); + /// {@macro middleware} + const Middleware(); + + /// The name of the middleware. String getName(); } mixin OnRequestMiddleware { + /// Performs an action before the request is sent to the server. Future onRequest( MiddlewareContext context, MiddlewareRequest request, @@ -31,6 +40,7 @@ mixin OnRequestMiddleware { } mixin OnResponseMiddleware { + /// Performs an action before the response is returned to the client. Future onResponse( MiddlewareContext context, MiddlewareResponse response, diff --git a/packages/wyatt_http_client/lib/src/middleware_client.dart b/packages/wyatt_http_client/lib/src/middleware_client.dart index 0f646f70..23c1f064 100644 --- a/packages/wyatt_http_client/lib/src/middleware_client.dart +++ b/packages/wyatt_http_client/lib/src/middleware_client.dart @@ -24,17 +24,24 @@ import 'package:wyatt_http_client/src/models/unfreezed_request.dart'; import 'package:wyatt_http_client/src/pipeline.dart'; import 'package:wyatt_http_client/src/utils/http_methods.dart'; +/// {@template middleware_client} +/// A custom [Client] implementation that allows you to intercept requests +/// and responses and modify them before they are sent to the server or +/// before they are returned to the client. +/// {@endtemplate} class MiddlewareClient extends BaseClient { - final Client inner; - final Pipeline pipeline; - + /// {@macro middleware_client} MiddlewareClient({ Pipeline? pipeline, Client? inner, }) : pipeline = pipeline ?? Pipeline(), - inner = inner ?? Client() { - print('Using Pipeline:\n$pipeline'); - } + inner = inner ?? Client(); + + /// The [Client] that will be used to send requests. + final Client inner; + + /// The [Pipeline] that will be used to intercept requests and responses. + final Pipeline pipeline; @override Future head(Uri url, {Map? headers}) => @@ -81,9 +88,7 @@ class MiddlewareClient extends BaseClient { _sendUnstreamed(HttpMethods.delete.method, url, headers, body, encoding); @override - Future send(BaseRequest request) { - return inner.send(request); - } + Future send(BaseRequest request) => inner.send(request); Future _sendUnstreamed( String method, diff --git a/packages/wyatt_http_client/lib/src/middlewares/basic_auth_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/basic_auth_middleware.dart index 027ad964..37bf033a 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/basic_auth_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/basic_auth_middleware.dart @@ -22,17 +22,26 @@ import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/utils/authentication_methods.dart'; import 'package:wyatt_http_client/src/utils/header_keys.dart'; +/// {@template basic_auth_middleware} +/// A middleware that adds basic authentication to the request. +/// {@endtemplate} class BasicAuthMiddleware with OnRequestMiddleware implements Middleware { - String? username; - String? password; - final String authenticationHeader; - - BasicAuthMiddleware({ + /// {@macro basic_auth_middleware} + const BasicAuthMiddleware({ this.username, this.password, this.authenticationHeader = HeaderKeys.authorization, }); + /// The username to use for authentication. + final String? username; + + /// The password to use for authentication. + final String? password; + + /// The header to use for authentication. + final String authenticationHeader; + @override String getName() => 'BasicAuth'; @@ -44,10 +53,7 @@ class BasicAuthMiddleware with OnRequestMiddleware implements Middleware { if (username == null || password == null) { return request; } - print( - '${getName()}::OnRequest\n' - '>> Basic: ${base64Encode(utf8.encode('$username:$password'))}', - ); + final mutation = { authenticationHeader: '${AuthenticationMethods.basic} ' '${base64Encode(utf8.encode('$username:$password'))}', diff --git a/packages/wyatt_http_client/lib/src/middlewares/body_to_json_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/body_to_json_middleware.dart index a77048d8..e9aaaba7 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/body_to_json_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/body_to_json_middleware.dart @@ -20,7 +20,13 @@ import 'package:wyatt_http_client/src/middleware.dart'; import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; +/// {@template body_to_json_middleware} +/// A middleware that transforms the body in json if it's a [Map]. +/// {@endtemplate} class BodyToJsonMiddleware with OnRequestMiddleware implements Middleware { + /// {@macro body_to_json_middleware} + const BodyToJsonMiddleware(); + @override String getName() => 'BodyToJson'; @@ -29,11 +35,6 @@ class BodyToJsonMiddleware with OnRequestMiddleware implements Middleware { MiddlewareContext context, MiddlewareRequest request, ) async { - print( - '${getName()}::OnRequest\n' - '>> Transforms body in json if Map then update ' - 'headers with right content-type', - ); final mutation = { 'content-type': 'application/json; charset=utf-8', }; diff --git a/packages/wyatt_http_client/lib/src/middlewares/default_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/default_middleware.dart index 65b766ca..456a07b5 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/default_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/default_middleware.dart @@ -16,7 +16,13 @@ import 'package:wyatt_http_client/src/middleware.dart'; +/// {@template default_middleware} +/// A default middleware that does nothing. +/// {@endtemplate} class DefaultMiddleware implements Middleware { + /// {@macro default_middleware} + const DefaultMiddleware(); + @override String getName() => 'DefaultMiddleware'; } diff --git a/packages/wyatt_http_client/lib/src/middlewares/digest_auth_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/digest_auth_middleware.dart index 538f6eb2..55c17030 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/digest_auth_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/digest_auth_middleware.dart @@ -22,16 +22,13 @@ import 'package:wyatt_http_client/src/utils/digest_auth.dart'; import 'package:wyatt_http_client/src/utils/header_keys.dart'; import 'package:wyatt_http_client/src/utils/http_status.dart'; +/// {@template digest_auth_middleware} +/// A middleware that handles digest authentication. +/// {@endtemplate} class DigestAuthMiddleware with OnRequestMiddleware, OnResponseMiddleware implements Middleware { - final String username; - final String password; - final DigestAuth _digestAuth; - final String authenticationHeader; - final String wwwAuthenticateHeader; - final HttpStatus unauthorized; - + /// {@macro digest_auth_middleware} DigestAuthMiddleware({ required this.username, required this.password, @@ -39,6 +36,12 @@ class DigestAuthMiddleware this.wwwAuthenticateHeader = HeaderKeys.wwwAuthenticate, this.unauthorized = HttpStatus.unauthorized, }) : _digestAuth = DigestAuth(username, password); + final String username; + final String password; + final DigestAuth _digestAuth; + final String authenticationHeader; + final String wwwAuthenticateHeader; + final HttpStatus unauthorized; @override String getName() => 'DigestAuth'; @@ -48,10 +51,6 @@ class DigestAuthMiddleware MiddlewareContext context, MiddlewareRequest request, ) async { - print( - '${getName()}::OnRequest\n' - '>> Digest ready: ${_digestAuth.isReady()}', - ); if (_digestAuth.isReady()) { final mutation = { authenticationHeader: _digestAuth.getAuthString( @@ -83,10 +82,6 @@ class DigestAuthMiddleware return MiddlewareResponse(httpResponse: newResponse); } } - print( - '${getName()}::OnResponse\n' - '>> Digest ready: ${_digestAuth.isReady()}', - ); return response; } } diff --git a/packages/wyatt_http_client/lib/src/middlewares/middlewares.dart b/packages/wyatt_http_client/lib/src/middlewares/middlewares.dart index 724b3ac9..29bbf147 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/middlewares.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/middlewares.dart @@ -1,20 +1,21 @@ // 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 'access_token_auth_middleware.dart'; +// All built-in middlewares + export 'basic_auth_middleware.dart'; export 'body_to_json_middleware.dart'; export 'default_middleware.dart'; diff --git a/packages/wyatt_http_client/lib/src/middlewares/refresh_token_auth_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/refresh_token_auth_middleware.dart index f470699a..50f5005d 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/refresh_token_auth_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/refresh_token_auth_middleware.dart @@ -28,9 +28,24 @@ import 'package:wyatt_http_client/src/utils/http_status.dart'; typedef TokenParser = String Function(Map); +/// {@template refresh_token_auth_middleware} +/// A middleware that refreshes the access token when it expires. +/// This middleware is useful for OAuth2. +/// {@endtemplate} class RefreshTokenAuthMiddleware with OnRequestMiddleware, OnResponseMiddleware implements Middleware { + /// {@macro refresh_token_auth_middleware} + RefreshTokenAuthMiddleware({ + required this.authorizationEndpoint, + required this.tokenEndpoint, + required this.accessTokenParser, + required this.refreshTokenParser, + this.authenticationHeader = HeaderKeys.authorization, + this.authenticationMethod = AuthenticationMethods.bearer, + this.unauthorized = HttpStatus.unauthorized, + this.maxAttempts = 8, + }); final String authorizationEndpoint; final String tokenEndpoint; @@ -44,17 +59,6 @@ class RefreshTokenAuthMiddleware final HttpStatus unauthorized; final int maxAttempts; - RefreshTokenAuthMiddleware({ - required this.authorizationEndpoint, - required this.tokenEndpoint, - required this.accessTokenParser, - required this.refreshTokenParser, - this.authenticationHeader = HeaderKeys.authorization, - this.authenticationMethod = AuthenticationMethods.bearer, - this.unauthorized = HttpStatus.unauthorized, - this.maxAttempts = 8, - }); - @override String getName() => 'RefreshToken'; @@ -114,11 +118,6 @@ class RefreshTokenAuthMiddleware MiddlewareContext context, MiddlewareRequest request, ) async { - print( - '${getName()}::OnRequest\n' - '>> accessToken: $accessToken\n' - '>> refreshToken: $refreshToken', - ); // Check if it is authorization if (context.originalRequest?.url == Uri.parse(authorizationEndpoint)) { return request; @@ -169,12 +168,6 @@ class RefreshTokenAuthMiddleware } } - print( - '${getName()}::OnResponse\n' - '>> accessToken: $accessToken\n' - '>> refreshToken: $refreshToken', - ); - if (response.status == unauthorized) { // Refresh MiddlewareRequest? newRequest = await refresh(context); diff --git a/packages/wyatt_http_client/lib/src/middlewares/simple_logger_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/simple_logger_middleware.dart index 8e2d2637..31492b8f 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/simple_logger_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/simple_logger_middleware.dart @@ -19,9 +19,15 @@ import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/models/middleware_response.dart'; +/// {@template simple_logger_middleware} +/// A simple logger middleware that logs the request and response. +/// {@endtemplate} class SimpleLoggerMiddleware with OnRequestMiddleware, OnResponseMiddleware implements Middleware { + /// {@macro simple_logger_middleware} + const SimpleLoggerMiddleware(); + @override String getName() => 'SimpleLogger'; @@ -30,11 +36,22 @@ class SimpleLoggerMiddleware MiddlewareContext context, MiddlewareRequest request, ) async { - print( - '${getName()}::OnRequest\n' - '>> ${request.method} ${request.url}\n' - '>> Headers: ${request.headers}\n>> Body: ${request.encodedBody}', - ); + final log = StringBuffer() + ..writeln('${getName()}::OnRequest') + ..writeln('>> ${request.method} ${request.url}'); + if (request.headers.isNotEmpty) { + log.writeln('>> Headers:'); + request.headers.forEach((key, value) { + log.writeln('>> $key: $value'); + }); + } + if (request.encodedBody.isNotEmpty) { + log + ..writeln('>> Body:') + ..writeln(request.encodedBody); + } + print(log); + return request; } @@ -43,12 +60,13 @@ class SimpleLoggerMiddleware MiddlewareContext context, MiddlewareResponse response, ) async { - print( - '${getName()}::OnResponse\n' - '>> Status: ${response.status.name.toUpperCase()}\n' - '>> Length: ${response.contentLength ?? '0'} bytes', - // '>> Body: ${response.body}', - ); + final log = StringBuffer() + ..writeln('${getName()}::OnResponse') + ..writeln('>> Status: ${response.status.name.toUpperCase()}') + ..writeln('>> Length: ${response.contentLength ?? '0'} bytes'); + + print(log); + return response; } } diff --git a/packages/wyatt_http_client/lib/src/middlewares/unsafe_auth_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/unsafe_auth_middleware.dart index f929f623..f4481877 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/unsafe_auth_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/unsafe_auth_middleware.dart @@ -19,19 +19,23 @@ import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/utils/convert.dart'; +/// {@template unsafe_auth_middleware} +/// A middleware that appends the username and password to the URL. +/// +/// This is not recommended to use in production. +/// {@endtemplate} class UnsafeAuthMiddleware with OnRequestMiddleware implements Middleware { - String? username; - String? password; - - final String usernameField; - final String passwordField; - - UnsafeAuthMiddleware({ + const UnsafeAuthMiddleware({ this.username, this.password, this.usernameField = 'username', this.passwordField = 'password', }); + final String? username; + final String? password; + + final String usernameField; + final String passwordField; @override String getName() => 'UnsafeAuth'; @@ -46,10 +50,6 @@ class UnsafeAuthMiddleware with OnRequestMiddleware implements Middleware { } final Uri uri = request.url + '?$usernameField=$username&$passwordField=$password'; - print( - '${getName()}::OnRequest\n' - '>> Append: ?$usernameField=$username&$passwordField=$password', - ); request.modifyRequest(request.unfreezedRequest.copyWith(url: uri)); return request; } diff --git a/packages/wyatt_http_client/lib/src/middlewares/uri_prefix_middleware.dart b/packages/wyatt_http_client/lib/src/middlewares/uri_prefix_middleware.dart index c52f3fdf..f02cff99 100644 --- a/packages/wyatt_http_client/lib/src/middlewares/uri_prefix_middleware.dart +++ b/packages/wyatt_http_client/lib/src/middlewares/uri_prefix_middleware.dart @@ -19,15 +19,22 @@ import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/utils/protocols.dart'; +/// {@template uri_prefix_middleware} +/// A middleware that adds a prefix to the request's URI. +/// {@endtemplate} class UriPrefixMiddleware with OnRequestMiddleware implements Middleware { - final Protocols protocol; - final String? authority; - - UriPrefixMiddleware({ + /// {@macro uri_prefix_middleware} + const UriPrefixMiddleware({ required this.protocol, required this.authority, }); + /// The protocol of the prefix. + final Protocols protocol; + + /// The authority of the prefix. + final String? authority; + @override String getName() => 'UriPrefix'; @@ -37,11 +44,6 @@ class UriPrefixMiddleware with OnRequestMiddleware implements Middleware { MiddlewareRequest request, ) async { final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); - print( - '${getName()}::OnRequest\n' - '>> From: ${request.url}\n' - '>> To: $uri', - ); request.modifyRequest(request.unfreezedRequest.copyWith(url: uri)); return request; } diff --git a/packages/wyatt_http_client/lib/src/models/middleware_context.dart b/packages/wyatt_http_client/lib/src/models/middleware_context.dart index 19877109..5071b39e 100644 --- a/packages/wyatt_http_client/lib/src/models/middleware_context.dart +++ b/packages/wyatt_http_client/lib/src/models/middleware_context.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -20,15 +19,12 @@ import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/models/middleware_response.dart'; import 'package:wyatt_http_client/src/pipeline.dart'; +/// {@template middleware_context} +/// A class that contains the context of the middleware. +/// {@endtemplate} class MiddlewareContext { - Pipeline pipeline; - MiddlewareClient client; - MiddlewareRequest? originalRequest; - MiddlewareRequest? lastRequest; - MiddlewareResponse? originalResponse; - MiddlewareResponse? lastResponse; - - MiddlewareContext({ + /// {@macro middleware_context} + const MiddlewareContext({ required this.pipeline, required this.client, this.originalRequest, @@ -37,6 +33,26 @@ class MiddlewareContext { this.lastResponse, }); + /// The pipeline that the middleware is in. + final Pipeline pipeline; + + /// The client that the middleware is in. + final MiddlewareClient client; + + /// The original request that the middleware is in. + final MiddlewareRequest? originalRequest; + + /// The last request that the middleware is in. + final MiddlewareRequest? lastRequest; + + /// The original response that the middleware is in. + final MiddlewareResponse? originalResponse; + + /// The last response that the middleware is in. + final MiddlewareResponse? lastResponse; + + /// Create a copy of this [MiddlewareContext] with the given fields replaced + /// with the new values. MiddlewareContext copyWith({ Pipeline? pipeline, MiddlewareClient? client, @@ -44,19 +60,19 @@ class MiddlewareContext { MiddlewareRequest? lastRequest, MiddlewareResponse? originalResponse, MiddlewareResponse? lastResponse, - }) { - return MiddlewareContext( - pipeline: pipeline ?? this.pipeline, - client: client ?? this.client, - originalRequest: originalRequest ?? this.originalRequest, - lastRequest: lastRequest ?? this.lastRequest, - originalResponse: originalResponse ?? this.originalResponse, - lastResponse: lastResponse ?? this.lastResponse, - ); - } + }) => + MiddlewareContext( + pipeline: pipeline ?? this.pipeline, + client: client ?? this.client, + originalRequest: originalRequest ?? this.originalRequest, + lastRequest: lastRequest ?? this.lastRequest, + originalResponse: originalResponse ?? this.originalResponse, + lastResponse: lastResponse ?? this.lastResponse, + ); @override - String toString() { - return 'MiddlewareContext(pipeline: $pipeline, client: $client, originalRequest: $originalRequest, lastRequest: $lastRequest, originalResponse: $originalResponse, lastResponse: $lastResponse)'; - } + String toString() => + 'MiddlewareContext(pipeline: $pipeline, client: $client, ' + 'originalRequest: $originalRequest, lastRequest: $lastRequest, ' + 'originalResponse: $originalResponse, lastResponse: $lastResponse)'; } diff --git a/packages/wyatt_http_client/lib/src/models/middleware_request.dart b/packages/wyatt_http_client/lib/src/models/middleware_request.dart index 42c9ac34..e7c93703 100644 --- a/packages/wyatt_http_client/lib/src/models/middleware_request.dart +++ b/packages/wyatt_http_client/lib/src/models/middleware_request.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -22,42 +21,61 @@ import 'package:wyatt_http_client/src/models/unfreezed_request.dart'; import 'package:wyatt_http_client/src/utils/convert.dart'; import 'package:wyatt_http_client/src/utils/request_utils.dart'; +/// {@template middleware_request} +/// A class that represents a middleware request. +/// {@endtemplate} class MiddlewareRequest { - UnfreezedRequest unfreezedRequest; - Request _httpRequest; - - Request get request => _httpRequest; - - // Proxy - String get method => _httpRequest.method; - Uri get url => _httpRequest.url; - Map get headers => _httpRequest.headers; - Encoding get encoding => _httpRequest.encoding; - String get encodedBody => _httpRequest.body; - Object? get body => unfreezedRequest.body; - + /// {@macro middleware_request} MiddlewareRequest({ required this.unfreezedRequest, }) : _httpRequest = Request(unfreezedRequest.method, unfreezedRequest.url); + /// The unfreezed request. + UnfreezedRequest unfreezedRequest; + + Request _httpRequest; + + /// The http request. (Read-only) + Request get request => _httpRequest; + + /// The request method (proxy, read-only). + String get method => _httpRequest.method; + + /// The request url (proxy, read-only). + Uri get url => _httpRequest.url; + + /// The request headers (proxy, read-only). + Map get headers => _httpRequest.headers; + + /// The request body (proxy, read-only). + Encoding get encoding => _httpRequest.encoding; + + /// The request body (proxy, read-only). + String get encodedBody => _httpRequest.body; + + /// The request body (proxy, read-only). + Object? get body => unfreezedRequest.body; + + /// Copies this request and returns a new request with the given + /// [unfreezedRequest]. MiddlewareRequest copyWith({ UnfreezedRequest? unfreezedRequest, - }) { - return MiddlewareRequest( - unfreezedRequest: unfreezedRequest ?? this.unfreezedRequest, - ); - } + }) => + MiddlewareRequest( + unfreezedRequest: unfreezedRequest ?? this.unfreezedRequest, + ); + /// Modifies the request with the given [unfreezedRequest]. void modifyRequest(UnfreezedRequest unfreezedRequest) { - String? _body; + String? body; if (unfreezedRequest.body != null) { - final body = unfreezedRequest.body; + var body = unfreezedRequest.body; if (body is String) { - _body = body; + body = body; } else if (body is List) { - _body = String.fromCharCodes(body.cast()); + body = String.fromCharCodes(body.cast()); } else if (body is Map) { - _body = Convert.mapToQuery(body.cast()); + body = Convert.mapToQuery(body.cast()); } } _httpRequest = RequestUtils.copyRequestWith( @@ -65,7 +83,7 @@ class MiddlewareRequest { method: unfreezedRequest.method, url: unfreezedRequest.url, headers: unfreezedRequest.headers, - body: _body, + body: body, ) as Request; if (unfreezedRequest.encoding != null) { _httpRequest.encoding = unfreezedRequest.encoding!; @@ -73,6 +91,8 @@ class MiddlewareRequest { this.unfreezedRequest = unfreezedRequest; } + /// Applies the changes made to the request by modifying it with the + /// [unfreezedRequest]. void apply() { modifyRequest(unfreezedRequest); } diff --git a/packages/wyatt_http_client/lib/src/models/middleware_response.dart b/packages/wyatt_http_client/lib/src/models/middleware_response.dart index 9404fa3a..19781901 100644 --- a/packages/wyatt_http_client/lib/src/models/middleware_response.dart +++ b/packages/wyatt_http_client/lib/src/models/middleware_response.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -18,12 +17,25 @@ import 'package:http/http.dart'; import 'package:wyatt_http_client/src/utils/http_status.dart'; +/// {@template middleware_response} +/// A class that represents a middleware response. +/// {@endtemplate} class MiddlewareResponse { - BaseResponse httpResponse; + /// {@macro middleware_response} + const MiddlewareResponse({ + required this.httpResponse, + }); - // Proxy + /// {@macro middleware_response} + final BaseResponse httpResponse; + + /// The status code of the response. (proxy) int get statusCode => httpResponse.statusCode; + + /// The status of the response. (proxy) HttpStatus get status => HttpStatus.from(statusCode); + + /// The body of the response. (proxy or empty string) String get body { if (httpResponse is Response) { return (httpResponse as Response).body; @@ -31,22 +43,21 @@ class MiddlewareResponse { return ''; } } + + /// The content length of the response. (proxy) int? get contentLength => httpResponse.contentLength; + + /// The headers of the response. (proxy) Map get headers => httpResponse.headers; - MiddlewareResponse({ - required this.httpResponse, - }); - + /// Returns a copy of this response with the given [httpResponse]. MiddlewareResponse copyWith({ BaseResponse? httpResponse, - }) { - return MiddlewareResponse( - httpResponse: httpResponse ?? this.httpResponse, - ); - } + }) => + MiddlewareResponse( + httpResponse: httpResponse ?? this.httpResponse, + ); @override - String toString() => - 'MiddlewareResponse(httpResponse: $httpResponse)'; + String toString() => 'MiddlewareResponse(httpResponse: $httpResponse)'; } diff --git a/packages/wyatt_http_client/lib/src/models/models.dart b/packages/wyatt_http_client/lib/src/models/models.dart index 4170d54b..95b3b377 100644 --- a/packages/wyatt_http_client/lib/src/models/models.dart +++ b/packages/wyatt_http_client/lib/src/models/models.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_http_client/lib/src/models/unfreezed_request.dart b/packages/wyatt_http_client/lib/src/models/unfreezed_request.dart index 9aa9790f..6779a5b6 100644 --- a/packages/wyatt_http_client/lib/src/models/unfreezed_request.dart +++ b/packages/wyatt_http_client/lib/src/models/unfreezed_request.dart @@ -16,14 +16,14 @@ import 'dart:convert'; +/// {@template unfreezed_request} +/// A class that represents an unfreezed request. +/// It is used to unfreeze a Request object, and allows you to +/// modify the request before sending it. +/// {@endtemplate} class UnfreezedRequest { - final String method; - final Uri url; - final Map? headers; - final Object? body; - final Encoding? encoding; - - UnfreezedRequest({ + /// {@macro unfreezed_request} + const UnfreezedRequest({ required this.method, required this.url, this.headers, @@ -31,25 +31,39 @@ class UnfreezedRequest { this.encoding, }); + /// The request method. + final String method; + + /// The request url. + final Uri url; + + /// The request headers. + final Map? headers; + + /// The request body. + final Object? body; + + /// The request encoding. + final Encoding? encoding; + + /// Copies this request and returns a new request with the given [method], + /// [url], [headers], [body] and [encoding]. UnfreezedRequest copyWith({ String? method, Uri? url, Map? headers, Object? body, Encoding? encoding, - }) { - return UnfreezedRequest( - method: method ?? this.method, - url: url ?? this.url, - headers: headers ?? this.headers, - body: body ?? this.body, - encoding: encoding ?? this.encoding, - ); - } + }) => + UnfreezedRequest( + method: method ?? this.method, + url: url ?? this.url, + headers: headers ?? this.headers, + body: body ?? this.body, + encoding: encoding ?? this.encoding, + ); @override - String toString() { - return 'UnfreezedRequest(method: $method, url: $url, headers: ' - '$headers, body: $body, encoding: $encoding)'; - } + String toString() => 'UnfreezedRequest(method: $method, url: $url, headers: ' + '$headers, body: $body, encoding: $encoding)'; } diff --git a/packages/wyatt_http_client/lib/src/pipeline.dart b/packages/wyatt_http_client/lib/src/pipeline.dart index aa0b8a1b..d68e7e39 100644 --- a/packages/wyatt_http_client/lib/src/pipeline.dart +++ b/packages/wyatt_http_client/lib/src/pipeline.dart @@ -19,19 +19,27 @@ import 'package:wyatt_http_client/src/models/middleware_context.dart'; import 'package:wyatt_http_client/src/models/middleware_request.dart'; import 'package:wyatt_http_client/src/models/middleware_response.dart'; +/// {@template pipeline} +/// A [Pipeline] is a list of [Middleware]s that are executed in order. +/// {@endtemplate} class Pipeline { - final List _middlewares; - - int get length => _middlewares.length; - + /// {@macro pipeline} Pipeline() : _middlewares = []; + + /// {@macro pipeline} Pipeline.fromIterable(Iterable middlewares) : _middlewares = middlewares.toList(); + final List _middlewares; + + /// The length of the [Pipeline]. + /// + /// This is the number of [Middleware]s in the [Pipeline]. + int get length => _middlewares.length; + /// Add a [Middleware] to this [Pipeline] - Pipeline addMiddleware(Middleware middleware) { + void addMiddleware(Middleware middleware) { _middlewares.add(middleware); - return this; } /// Create new [Pipeline] from the start or end to a specified [Middleware]. @@ -56,28 +64,35 @@ class Pipeline { return Pipeline.fromIterable(fromEnd ? nodes.reversed : nodes); } + /// Call the [onRequest] method of all [OnRequestMiddleware]s in the + /// [Pipeline]. + /// + /// The [MiddlewareRequest] returned by the last [OnRequestMiddleware] is + /// returned. Future onRequest( MiddlewareContext context, MiddlewareRequest request, ) async { - print('\n\nNEW REQUEST\n'); MiddlewareRequest req = request..apply(); MiddlewareContext ctx = context.copyWith(lastRequest: req); for (final middleware in _middlewares) { if (middleware is OnRequestMiddleware) { - req = await (middleware as OnRequestMiddleware) - .onRequest(ctx, request); + req = await (middleware as OnRequestMiddleware).onRequest(ctx, request); ctx = context.copyWith(lastRequest: req); } } return req; } + /// Call the [onResponse] method of all [OnResponseMiddleware]s in the + /// [Pipeline]. + /// + /// The [MiddlewareResponse] returned by the last [OnResponseMiddleware] is + /// returned. Future onResponse( MiddlewareContext context, MiddlewareResponse response, ) async { - print('\n\nNEW RESPONSE\n'); MiddlewareResponse res = response; MiddlewareContext ctx = context.copyWith(lastResponse: res); for (final middleware in _middlewares.reversed) { diff --git a/packages/wyatt_http_client/lib/src/utils/authentication_methods.dart b/packages/wyatt_http_client/lib/src/utils/authentication_methods.dart index ef73c15f..d8f028c2 100644 --- a/packages/wyatt_http_client/lib/src/utils/authentication_methods.dart +++ b/packages/wyatt_http_client/lib/src/utils/authentication_methods.dart @@ -14,8 +14,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Defines some authentication methods abstract class AuthenticationMethods { + /// The `Basic` authentication method. static const String basic = 'Basic'; + + /// The `Bearer` authentication method. static const String bearer = 'Bearer'; + + /// The `Digest` authentication method. static const String digest = 'Digest'; } diff --git a/packages/wyatt_http_client/lib/src/utils/convert.dart b/packages/wyatt_http_client/lib/src/utils/convert.dart index 96746448..93c86d59 100644 --- a/packages/wyatt_http_client/lib/src/utils/convert.dart +++ b/packages/wyatt_http_client/lib/src/utils/convert.dart @@ -16,12 +16,16 @@ import 'dart:convert'; -class Convert { +/// Defines some convert functions. +abstract class Convert { + /// Converts a list of bytes to a hex string. + /// + /// If [upperCase] is `true`, the hex string will be in uppercase. static String toHex(List bytes, {bool upperCase = false}) { final buffer = StringBuffer(); for (final int part in bytes) { if (part & 0xff != part) { - throw FormatException('Non-byte integer detected'); + throw const FormatException('Non-byte integer detected'); } buffer.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}'); } @@ -32,17 +36,25 @@ class Convert { } } + /// Converts a map to a query string. + /// + /// If [encoding] is `null`, the default encoding is `utf8`. + /// + /// For example, the map `{a: 1, b: 2}` will be converted to `a=1&b=2`. static String mapToQuery(Map map, {Encoding? encoding}) { final pairs = >[]; - map.forEach((key, value) => pairs.add([ - Uri.encodeQueryComponent(key, encoding: encoding ?? utf8), - Uri.encodeQueryComponent(value, encoding: encoding ?? utf8) - ]),); + map.forEach( + (key, value) => pairs.add([ + Uri.encodeQueryComponent(key, encoding: encoding ?? utf8), + Uri.encodeQueryComponent(value, encoding: encoding ?? utf8) + ]), + ); return pairs.map((pair) => '${pair[0]}=${pair[1]}').join('&'); } } extension UriX on Uri { + /// Returns a new [Uri] by appending the given [path] to this [Uri]. Uri operator +(String path) { final thisPath = toString(); return Uri.parse(thisPath + path); diff --git a/packages/wyatt_http_client/lib/src/utils/crypto.dart b/packages/wyatt_http_client/lib/src/utils/crypto.dart index 319b9299..bf7fa5a6 100644 --- a/packages/wyatt_http_client/lib/src/utils/crypto.dart +++ b/packages/wyatt_http_client/lib/src/utils/crypto.dart @@ -18,11 +18,12 @@ import 'dart:convert'; import 'package:crypto/crypto.dart'; -class Crypto { +/// Defines some crypto functions. +abstract class Crypto { /// Hash a string using MD5 static String md5Hash(String data) { - final content = Utf8Encoder().convert(data); - final md5Crypto = md5; + final content = const Utf8Encoder().convert(data); + const md5Crypto = md5; final digest = md5Crypto.convert(content).toString(); return digest; } diff --git a/packages/wyatt_http_client/lib/src/utils/delay.dart b/packages/wyatt_http_client/lib/src/utils/delay.dart index af89f3ac..cc9d4193 100644 --- a/packages/wyatt_http_client/lib/src/utils/delay.dart +++ b/packages/wyatt_http_client/lib/src/utils/delay.dart @@ -17,16 +17,18 @@ import 'dart:core'; import 'dart:math'; +/// Defines some delay functions. abstract class Delay { + /// Returns a delay based on the [attempt]. static Duration getRetryDelay(int attempt) { assert(attempt >= 0, 'attempt cannot be negative'); if (attempt <= 0) { return Duration.zero; } final rand = Random(); - final Duration delayFactor = const Duration(milliseconds: 200); - final double randomizationFactor = 0.25; - final Duration maxDelay = const Duration(seconds: 30); + const Duration delayFactor = Duration(milliseconds: 200); + const double randomizationFactor = 0.25; + const Duration maxDelay = Duration(seconds: 30); final rf = randomizationFactor * (rand.nextDouble() * 2 - 1) + 1; final exp = min(attempt, 31); // prevent overflows. diff --git a/packages/wyatt_http_client/lib/src/utils/digest_auth.dart b/packages/wyatt_http_client/lib/src/utils/digest_auth.dart index 41581dfb..065eeef0 100644 --- a/packages/wyatt_http_client/lib/src/utils/digest_auth.dart +++ b/packages/wyatt_http_client/lib/src/utils/digest_auth.dart @@ -19,9 +19,13 @@ import 'dart:math'; import 'package:wyatt_http_client/src/utils/convert.dart'; import 'package:wyatt_http_client/src/utils/crypto.dart'; +/// A class for digest authentication. class DigestAuth { - String username; - String password; + // request counter + + DigestAuth(this.username, this.password); + final String username; + final String password; // must get from first response String? _algorithm; @@ -30,9 +34,7 @@ class DigestAuth { String? _nonce; String? _opaque; - int _nc = 0; // request counter - - DigestAuth(this.username, this.password); + int _nc = 0; /// Splits WWW-Authenticate header into a map. Map? splitWWWAuthenticateHeader(String header) { @@ -61,9 +63,7 @@ class DigestAuth { return Convert.toHex(values); } - String _formatNonceCount(int nc) { - return nc.toRadixString(16).padLeft(8, '0'); - } + String _formatNonceCount(int nc) => nc.toRadixString(16).padLeft(8, '0'); String _computeHA1( String realm, @@ -148,7 +148,7 @@ class DigestAuth { } String getAuthString(String method, Uri url) { - final _cnonce = _computeNonce(); + final cnonce = _computeNonce(); _nc += 1; // if url has query parameters, append query to path final path = url.hasQuery ? '${url.path}?${url.query}' : url.path; @@ -162,7 +162,7 @@ class DigestAuth { _qop, _opaque, _realm!, - _cnonce, + cnonce, _nonce, _nc, username, @@ -192,7 +192,5 @@ class DigestAuth { } } - bool isReady() { - return _nonce != null && (_nc == 0 || _qop != null); - } + bool isReady() => _nonce != null && (_nc == 0 || _qop != null); } diff --git a/packages/wyatt_http_client/lib/src/utils/header_keys.dart b/packages/wyatt_http_client/lib/src/utils/header_keys.dart index 9fe72ce8..c1c9e986 100644 --- a/packages/wyatt_http_client/lib/src/utils/header_keys.dart +++ b/packages/wyatt_http_client/lib/src/utils/header_keys.dart @@ -14,8 +14,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Defines some header keys. abstract class HeaderKeys { + /// The `Authorization` header key. static const String authorization = 'Authorization'; + + /// The `WWW-Authenticate` header key. static const String wwwAuthenticate = 'WWW-Authenticate'; + + /// The `Content-Type` header key. static const String contentType = 'Content-Type'; } diff --git a/packages/wyatt_http_client/lib/src/utils/http_methods.dart b/packages/wyatt_http_client/lib/src/utils/http_methods.dart index 49087965..efef38c4 100644 --- a/packages/wyatt_http_client/lib/src/utils/http_methods.dart +++ b/packages/wyatt_http_client/lib/src/utils/http_methods.dart @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Defines http verb methods. enum HttpMethods { head('HEAD'), get('GET'), @@ -22,7 +23,10 @@ enum HttpMethods { patch('PATCH'), delete('DELETE'); - final String method; - const HttpMethods(this.method); + + /// Returns the method of the http verb. + /// + /// For example, the method of [HttpMethods.get] is `GET`. + final String method; } diff --git a/packages/wyatt_http_client/lib/src/utils/http_status.dart b/packages/wyatt_http_client/lib/src/utils/http_status.dart index c5715c70..f5a5c488 100644 --- a/packages/wyatt_http_client/lib/src/utils/http_status.dart +++ b/packages/wyatt_http_client/lib/src/utils/http_status.dart @@ -81,10 +81,14 @@ enum HttpStatus { // Client generated status code. networkConnectTimeoutError(599); - final int statusCode; - const HttpStatus(this.statusCode); + /// Returns the [HttpStatus] with the given [statusCode]. + factory HttpStatus.from(int status) => + HttpStatus.values.firstWhere((element) => element.statusCode == status); + + final int statusCode; + bool equals(Object other) { if (other is HttpStatus) { return statusCode == other.statusCode; @@ -95,29 +99,18 @@ enum HttpStatus { return false; } - bool isInfo() { - return statusCode >= 100 && statusCode < 200; - } + /// Checks if the status code is in the range of 100-199. + bool isInfo() => statusCode >= 100 && statusCode < 200; - bool isSuccess() { - return statusCode >= 200 && statusCode < 300; - } + /// Checks if the status code is in the range of 200-299. + bool isSuccess() => statusCode >= 200 && statusCode < 300; - bool isRedirection() { - return statusCode >= 300 && statusCode < 400; - } + /// Checks if the status code is in the range of 300-399. + bool isRedirection() => statusCode >= 300 && statusCode < 400; - bool isClientError() { - return statusCode >= 400 && statusCode < 500; - } - - bool isServerError() { - return statusCode >= 500 && statusCode < 600; - } - - factory HttpStatus.from(int status) { - return HttpStatus.values - .firstWhere((element) => element.statusCode == status); - } + /// Checks if the status code is in the range of 400-499. + bool isClientError() => statusCode >= 400 && statusCode < 500; + /// Checks if the status code is in the range of 500-599. + bool isServerError() => statusCode >= 500 && statusCode < 600; } diff --git a/packages/wyatt_http_client/lib/src/utils/protocols.dart b/packages/wyatt_http_client/lib/src/utils/protocols.dart index 97b9d5f3..bf41a5d6 100644 --- a/packages/wyatt_http_client/lib/src/utils/protocols.dart +++ b/packages/wyatt_http_client/lib/src/utils/protocols.dart @@ -14,9 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Defines few protocols enum Protocols { http, https; + /// Returns the scheme of the protocol. + /// + /// For example, the scheme of [Protocols.http] is `http://`. String get scheme => '$name://'; } diff --git a/packages/wyatt_http_client/lib/src/utils/request_utils.dart b/packages/wyatt_http_client/lib/src/utils/request_utils.dart index b50c0063..01794757 100644 --- a/packages/wyatt_http_client/lib/src/utils/request_utils.dart +++ b/packages/wyatt_http_client/lib/src/utils/request_utils.dart @@ -16,6 +16,7 @@ import 'package:http/http.dart'; +/// Defines some request utils. abstract class RequestUtils { static Request _copyNormalRequestWith( Request original, { @@ -38,6 +39,9 @@ abstract class RequestUtils { return request; } + /// Copies the given [original] request and returns a new request with the + /// given [method], [url], [headers], [maxRedirects], [followRedirects], + /// [persistentConnection] and [body]. static BaseRequest copyRequestWith( BaseRequest original, { String? method, @@ -77,6 +81,8 @@ abstract class RequestUtils { return request; } + /// Copies the given [original] request and returns a new request. + /// This method is useful when you want to modify the request static BaseRequest copyRequest(BaseRequest original) { if (original is Request) { return _copyNormalRequest(original); diff --git a/packages/wyatt_http_client/lib/src/utils/utils.dart b/packages/wyatt_http_client/lib/src/utils/utils.dart index 5dfc082c..91d8efc1 100644 --- a/packages/wyatt_http_client/lib/src/utils/utils.dart +++ b/packages/wyatt_http_client/lib/src/utils/utils.dart @@ -1,16 +1,16 @@ // 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 . diff --git a/packages/wyatt_http_client/pubspec.yaml b/packages/wyatt_http_client/pubspec.yaml index 127a612b..7e287156 100644 --- a/packages/wyatt_http_client/pubspec.yaml +++ b/packages/wyatt_http_client/pubspec.yaml @@ -1,7 +1,9 @@ name: wyatt_http_client description: A Dart client for RESTful APIs with authentication. repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_http_client -version: 1.2.0 +version: 2.0.0 + +publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub environment: sdk: '>=2.17.0 <3.0.0' @@ -12,7 +14,5 @@ dependencies: dev_dependencies: wyatt_analysis: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_analysis-v2.2.2 - path: packages/wyatt_analysis + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 diff --git a/packages/wyatt_http_client/test/wyatt_http_client_test.dart b/packages/wyatt_http_client/test/wyatt_http_client_test.dart deleted file mode 100644 index fad5335c..00000000 --- a/packages/wyatt_http_client/test/wyatt_http_client_test.dart +++ /dev/null @@ -1 +0,0 @@ -// TODO(hpcl): Add tests. diff --git a/packages/wyatt_i18n/.gitignore b/packages/wyatt_i18n/.gitignore new file mode 120000 index 00000000..6ef08f9d --- /dev/null +++ b/packages/wyatt_i18n/.gitignore @@ -0,0 +1 @@ +../../.gitignore \ No newline at end of file diff --git a/packages/wyatt_i18n/.pubignore b/packages/wyatt_i18n/.pubignore new file mode 120000 index 00000000..52b2f28d --- /dev/null +++ b/packages/wyatt_i18n/.pubignore @@ -0,0 +1 @@ +../../.pubignore \ No newline at end of file diff --git a/packages/wyatt_i18n/.vscode/extensions.json b/packages/wyatt_i18n/.vscode/extensions.json new file mode 100644 index 00000000..30cd2233 --- /dev/null +++ b/packages/wyatt_i18n/.vscode/extensions.json @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +{ + "recommendations": [ + "psioniq.psi-header", + "blaugold.melos-code" + ] +} \ No newline at end of file diff --git a/packages/wyatt_i18n/.vscode/launch.json b/packages/wyatt_i18n/.vscode/launch.json new file mode 100644 index 00000000..653eabc8 --- /dev/null +++ b/packages/wyatt_i18n/.vscode/launch.json @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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 . + */ + +{ + // 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": "Launch Example", + "request": "launch", + "type": "dart", + "cwd": "example/", + "program": "lib/main.dart", + "flutterMode": "debug" + }, + ] +} \ No newline at end of file diff --git a/packages/wyatt_i18n/.vscode/settings.json b/packages/wyatt_i18n/.vscode/settings.json new file mode 100644 index 00000000..a729c46c --- /dev/null +++ b/packages/wyatt_i18n/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "dart.runPubGetOnPubspecChanges": "never", + "bloc.newCubitTemplate.type": "equatable", + "psi-header.changes-tracking": { + "isActive": true + }, + "psi-header.config": { + "blankLinesAfter": 1, + "forceToTop": true + }, + "psi-header.lang-config": [ + { + "beforeHeader": [ + "# -*- coding:utf-8 -*-", + "#!/usr/bin/env python3" + ], + "begin": "###", + "end": "###", + "language": "python", + "prefix": "# " + }, + { + "beforeHeader": [ + "#!/usr/bin/env sh", + "" + ], + "language": "shellscript", + "begin": "", + "end": "", + "prefix": "# " + }, + { + "begin": "", + "end": "", + "language": "dart", + "prefix": "// " + }, + { + "begin": "", + "end": "", + "language": "yaml", + "prefix": "# " + }, + { + "begin": "", + "language": "markdown", + }, + ], + "psi-header.templates": [ + { + "language": "*", + "template": [ + "Copyright (C) <> 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 ." + ], + } + ], +} \ No newline at end of file diff --git a/packages/wyatt_i18n/AUTHORS b/packages/wyatt_i18n/AUTHORS new file mode 120000 index 00000000..f04b7e8a --- /dev/null +++ b/packages/wyatt_i18n/AUTHORS @@ -0,0 +1 @@ +../../AUTHORS \ No newline at end of file diff --git a/packages/wyatt_i18n/CHANGELOG.md b/packages/wyatt_i18n/CHANGELOG.md new file mode 100644 index 00000000..8d4adffe --- /dev/null +++ b/packages/wyatt_i18n/CHANGELOG.md @@ -0,0 +1,17 @@ +## 2.0.0 + +> Note: This release has breaking changes. + + - **FEAT**: change gitignore for symbolic link. + - **FEAT**: add i18n delegate + example. + - **FEAT**: implements network data source. + - **FEAT**: add default locale. + - **FEAT**: add getter/setter. + - **FEAT**: add ICU parser. + - **FEAT**: add arb, json and yaml parsers. + - **DOCS**: add docstrings on every classes. + - **BREAKING** **FEAT**: rename few files + add clearer documentation. + +## 1.0.0 + +- Initial version. diff --git a/packages/wyatt_i18n/LICENSE b/packages/wyatt_i18n/LICENSE new file mode 120000 index 00000000..30cff740 --- /dev/null +++ b/packages/wyatt_i18n/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/wyatt_i18n/README.md b/packages/wyatt_i18n/README.md new file mode 100644 index 00000000..b878a833 --- /dev/null +++ b/packages/wyatt_i18n/README.md @@ -0,0 +1,153 @@ + + +# Wyatt I18n + +

+ Style: Wyatt Analysis + SDK: Flutter +

+ +This package aims to facilitate and improve the internationalization of your applications. It allows, among other things, to load translation files on the fly during the execution of the application. + +## Features + +* Load translation files + + [x] Load translation files from assets + + [x] Load translation files from the network + + [ ] Load translation files from the file system + + [ ] Load translation files from multiple sources + +* Supports multiple formats + + [x] Supports JSON format + + [x] Supports YAML format + + [x] Supports ARB formats + + [ ] Supports CSV format + + [x] Supports custom formats parsers (see Parser class) + +* Usage + + [x] Detects the current locale + + [x] Act as a LocalizationDelegate + + [x] Act as a DataSource (in the sense of the Wyatt Architecture) + +* Other + + [ ] Generate translation constants from fallback translation files + +## Usage + +You can use this package as a LocalizationDelegate or as a DataSource. + +### As a LocalizationDelegate + +It is recommended to use this package as a LocalizationDelegate. This allows you to use the `context.i18n` method to translate your strings. It follows the standard of the `flutter_localizations` package and you can use it in the MaterialApp widget as follows: + +```dart +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + localizationsDelegates: [ + I18nDelegate( + dataSource: NetworkI18nDataSourceImpl( + baseUri: 'https://i18n.wyatt-studio.fr/apps/flutter_demo', + ), + localeTransformer: (locale) => locale.languageCode, + ), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate + ], + supportedLocales: [ + Locale('en'), + Locale('fr'), + ], + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} +``` + +And in your widgets: + +```dart +Text(context.i18n('youHavePushed', {'count': 42})), +// => 'You have pushed the button this many times: 42' in English +// => 'Vous avez appuyé sur le bouton ce nombre de fois: 42' in French +``` + +### As a DataSource + +This gives you more control over the internationalization of your application. You can handle the loading of the translation files yourself. + +For example, if you want to create a Repository that will handle the loading of the translation files, you can do it. + +Provide DataSource with GetIt: + +```dart +// Initialize i18n +final I18nDataSource i18nDataSource = + await AssetsI18nDataSourceImpl.withSystemLocale( + basePath: 'l10n', + baseName: 'intl', + localeTransformer: (locale) => locale.languageCode, +); + +// Initialize real sources/services +GetIt.I.registerLazySingleton( + () => i18nDataSource, +); +``` + +Create a Repository: + +```dart +class I18nRepository { + I18nRepository({ + required this.dataSource, + }); + + final I18nDataSource dataSource; + + Future load() async { + final i18n = await dataSource.load(); + return i18n; + } +} +``` + +And use it in your cubit: + +```dart +class MyCubit extends Cubit { + MyCubit({ + required this.i18nRepository, + }) : super(MyState()); + + final I18nRepository i18nRepository; + + Future loadI18n() async { + final i18n = await i18nRepository.load(); + emit(state.copyWith(i18n: i18n)); + } +} +``` + +> Note: you should create a cache system to avoid reloading the translation files every time. diff --git a/packages/wyatt_i18n/analysis_options.yaml b/packages/wyatt_i18n/analysis_options.yaml new file mode 100644 index 00000000..3302c602 --- /dev/null +++ b/packages/wyatt_i18n/analysis_options.yaml @@ -0,0 +1,26 @@ +include: package:wyatt_analysis/analysis_options.flutter.yaml + +analyzer: + plugins: + - dart_code_metrics +dart_code_metrics: + anti-patterns: + - long-method + - long-parameter-list + metrics: + cyclomatic-complexity: 20 + maximum-nesting-level: 5 + number-of-parameters: 4 + source-lines-of-code: 50 + metrics-exclude: + - test/** + rules: + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + - avoid-border-all + - prefer-const-border-radius + - prefer-using-list-view diff --git a/packages/wyatt_i18n/example/.gitignore b/packages/wyatt_i18n/example/.gitignore new file mode 100644 index 00000000..24476c5d --- /dev/null +++ b/packages/wyatt_i18n/example/.gitignore @@ -0,0 +1,44 @@ +# 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/ + +# 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_i18n/example/.metadata b/packages/wyatt_i18n/example/.metadata new file mode 100644 index 00000000..30e0d3ce --- /dev/null +++ b/packages/wyatt_i18n/example/.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: b06b8b2710955028a6b562f5aa6fe62941d6febf + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + - platform: web + create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf + + # 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_i18n/example/README.md b/packages/wyatt_i18n/example/README.md new file mode 100644 index 00000000..2b3fce4c --- /dev/null +++ b/packages/wyatt_i18n/example/README.md @@ -0,0 +1,16 @@ +# example + +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_i18n/example/analysis_options.yaml b/packages/wyatt_i18n/example/analysis_options.yaml new file mode 100644 index 00000000..8c9daa4e --- /dev/null +++ b/packages/wyatt_i18n/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:wyatt_analysis/analysis_options.flutter.yaml diff --git a/packages/wyatt_i18n/example/assets/i18n.en.arb b/packages/wyatt_i18n/example/assets/i18n.en.arb new file mode 100644 index 00000000..f59abc87 --- /dev/null +++ b/packages/wyatt_i18n/example/assets/i18n.en.arb @@ -0,0 +1,13 @@ +{ + "@@locale": "en", + "youHavePushed": "You have pushed {count} times the bouton !", + "@youHavePushed": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "btnAddFile": "Add file", + "btnAddFileCaption": "Max size: 20MB" +} \ No newline at end of file diff --git a/packages/wyatt_i18n/example/assets/i18n.en.json b/packages/wyatt_i18n/example/assets/i18n.en.json new file mode 100644 index 00000000..f59abc87 --- /dev/null +++ b/packages/wyatt_i18n/example/assets/i18n.en.json @@ -0,0 +1,13 @@ +{ + "@@locale": "en", + "youHavePushed": "You have pushed {count} times the bouton !", + "@youHavePushed": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "btnAddFile": "Add file", + "btnAddFileCaption": "Max size: 20MB" +} \ No newline at end of file diff --git a/packages/wyatt_i18n/example/assets/i18n.en.yaml b/packages/wyatt_i18n/example/assets/i18n.en.yaml new file mode 100644 index 00000000..e894e5d6 --- /dev/null +++ b/packages/wyatt_i18n/example/assets/i18n.en.yaml @@ -0,0 +1,8 @@ +"@@locale": en +youHavePushed: You have pushed {count} times the bouton ! +"@youHavePushed": + placeholders: + count: + type: int +btnAddFile: Add file +btnAddFileCaption: "Max size: 20MB" diff --git a/packages/wyatt_i18n/example/lib/main.dart b/packages/wyatt_i18n/example/lib/main.dart new file mode 100644 index 00000000..fa13f3f7 --- /dev/null +++ b/packages/wyatt_i18n/example/lib/main.dart @@ -0,0 +1,60 @@ +// Copyright (C) 2023 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:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; + +import 'package:wyatt_i18n/wyatt_i18n.dart'; + +void main(List args) { + runApp(const App()); +} + +class App extends StatelessWidget { + const App({super.key}); + + static const String title = 'Wyatt i18n Example'; + + @override + Widget build(BuildContext context) => MaterialApp( + title: title, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + localizationsDelegates: [ + I18nDelegate( + dataSource: NetworkI18nDataSourceImpl( + baseUri: Uri.parse( + 'https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/raw/commit/75f561a19e0484e67e511dbf29601ec5f58544aa/packages/wyatt_i18n/example/assets/', + ), + localeTransformer: (locale) => locale.languageCode, + ), + ), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate + ], + home: Scaffold( + appBar: AppBar( + title: const Text(title), + ), + body: Builder( + builder: (ctx) => Center( + child: Text(ctx.i18n('youHavePushed', {'count': 654})), + ), + ), + ), + ); +} diff --git a/packages/wyatt_i18n/example/pubspec.yaml b/packages/wyatt_i18n/example/pubspec.yaml new file mode 100644 index 00000000..18145fe9 --- /dev/null +++ b/packages/wyatt_i18n/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: wyatt_i18n_example +description: A new Flutter project. +version: 1.0.0 +publish_to: "none" +environment: + sdk: ">=2.19.0 <3.0.0" +dependencies: + flutter: { sdk: flutter } + flutter_localizations: { sdk: flutter } + wyatt_i18n: + path: "../" +dev_dependencies: + flutter_test: { sdk: flutter } + wyatt_analysis: + hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub + version: ^2.5.0 +# The following section is specific to Flutter. +flutter: + uses-material-design: true + assets: + - assets/ diff --git a/packages/wyatt_i18n/example/test/widget_test.dart b/packages/wyatt_i18n/example/test/widget_test.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/packages/wyatt_i18n/example/test/widget_test.dart @@ -0,0 +1 @@ + diff --git a/packages/wyatt_i18n/example/web/favicon.png b/packages/wyatt_i18n/example/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/packages/wyatt_i18n/example/web/favicon.png differ diff --git a/packages/wyatt_i18n/example/web/icons/Icon-192.png b/packages/wyatt_i18n/example/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/packages/wyatt_i18n/example/web/icons/Icon-192.png differ diff --git a/packages/wyatt_i18n/example/web/icons/Icon-512.png b/packages/wyatt_i18n/example/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/packages/wyatt_i18n/example/web/icons/Icon-512.png differ diff --git a/packages/wyatt_i18n/example/web/icons/Icon-maskable-192.png b/packages/wyatt_i18n/example/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/packages/wyatt_i18n/example/web/icons/Icon-maskable-192.png differ diff --git a/packages/wyatt_i18n/example/web/icons/Icon-maskable-512.png b/packages/wyatt_i18n/example/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/packages/wyatt_i18n/example/web/icons/Icon-maskable-512.png differ diff --git a/packages/wyatt_i18n/example/web/index.html b/packages/wyatt_i18n/example/web/index.html new file mode 100644 index 00000000..be820e83 --- /dev/null +++ b/packages/wyatt_i18n/example/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + + + diff --git a/packages/wyatt_i18n/example/web/manifest.json b/packages/wyatt_i18n/example/web/manifest.json new file mode 100644 index 00000000..096edf8f --- /dev/null +++ b/packages/wyatt_i18n/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/packages/wyatt_i18n/lib/src/core/core.dart b/packages/wyatt_i18n/lib/src/core/core.dart new file mode 100644 index 00000000..0e6487e1 --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/core.dart @@ -0,0 +1,20 @@ +// Copyright (C) 2023 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 'enums/format.dart'; +export 'exceptions/exceptions.dart'; +export 'extensions/build_context_extension.dart'; +export 'utils/utils.dart'; diff --git a/packages/wyatt_i18n/lib/src/core/enums/format.dart b/packages/wyatt_i18n/lib/src/core/enums/format.dart new file mode 100644 index 00000000..f428e25d --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/enums/format.dart @@ -0,0 +1,63 @@ +// Copyright (C) 2023 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:wyatt_i18n/src/core/utils/parser.dart'; +import 'package:wyatt_i18n/src/core/utils/parsers/arb_parser.dart'; +import 'package:wyatt_i18n/src/core/utils/parsers/json_parser.dart'; +import 'package:wyatt_i18n/src/core/utils/parsers/yaml_parser.dart'; + +/// Enum for i18n file formats and extensions. +/// +/// This enum is used to determine the parser to use for a given i18n file. +enum Format { + /// JSON i18n file format. + json, + + /// YAML i18n file format. + yaml, + yml, + + /// ARB i18n file format. + arb; + + /// Returns the [Format] that matches the given [ext]. + static Format? fromExtension(String ext) { + for (final format in Format.values) { + if (format.name == ext) { + return format; + } + } + + return null; + } + + /// Returns the [Format] that matches the given [path]. + static Format? extensionOf(String path) => + fromExtension(path.split('.').last); + + /// Returns the [Parser] associated with this [Format]. + Parser> get parser { + switch (this) { + case Format.json: + return const JsonParser(); + case Format.yaml: + case Format.yml: + return const YamlParser(); + case Format.arb: + return const ArbParser(); + } + } +} diff --git a/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart new file mode 100644 index 00000000..7947b0a3 --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart @@ -0,0 +1,70 @@ +// Copyright (C) 2023 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_i18n/src/core/enums/format.dart'; + +/// Exception thrown when the i18n file is not found. +/// +/// Source can be a file path or a URL. +class SourceNotFoundException extends ClientException { + SourceNotFoundException(String source, {required Format format}) + : super('Source `$source` (format: $format) not found.'); +} + +/// Exception thrown when the i18n file is not valid. +class NoLocaleException extends ClientException { + NoLocaleException() + : super('No `@@locale` key found in the source nor locale provided.'); +} + +/// Exception thrown when the i18n locale is not valid. +class InvalidLocaleException extends ClientException { + InvalidLocaleException(String locale, String expected) + : super('Invalid locale `$locale`. Expected `$expected`.'); +} + +/// Exception thrown when the key is not found in the i18n file. +class KeyNotFoundException extends ClientException { + KeyNotFoundException(String key, [Map arguments = const {}]) + : super( + 'Key `$key` not found. ${arguments.isNotEmpty ? '($arguments)' : ''}', + ); +} + +/// Exception thrown when the searched key requires arguments but none were +/// provided. +class ArgumentsRequiredException extends ClientException { + ArgumentsRequiredException(String key, String value) + : super('Key `$key` requires arguments. ($value)'); +} + +/// Exception thrown when the key references a malformed value. +class MalformedValueException extends ClientException { + MalformedValueException(String key, String value) + : super('Key `$key` references a malformed value. ($value)'); +} + +/// Exception thrown when the parser fails. +class ParserException extends ClientException { + ParserException(String message, StackTrace? stackTrace) + : super('$message\n\n$stackTrace'); +} + +/// Exception thrown when the i18n is not loaded. +class NotLoadedException extends ClientException { + NotLoadedException() : super('I18n not loaded.'); +} diff --git a/packages/wyatt_i18n/lib/src/core/extensions/build_context_extension.dart b/packages/wyatt_i18n/lib/src/core/extensions/build_context_extension.dart new file mode 100644 index 00000000..007134fc --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/extensions/build_context_extension.dart @@ -0,0 +1,36 @@ +// Copyright (C) 2023 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:flutter/widgets.dart'; +import 'package:wyatt_i18n/wyatt_i18n.dart'; + +/// Provides extensions for [BuildContext]. +extension BuildContextExtension on BuildContext { + /// Returns the current locale of the app. + String get locale => Localizations.localeOf(this).languageCode; + + /// Returns the current [I18n] instance. + /// + /// Throws a [NotLoadedException] if the [I18n] instance is not loaded. + I18n get i18n { + final i18n = Localizations.of(this, I18n); + if (i18n == null) { + throw NotLoadedException(); + } + + return i18n; + } +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/assets_utils.dart b/packages/wyatt_i18n/lib/src/core/utils/assets_utils.dart new file mode 100644 index 00000000..68b46caf --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/assets_utils.dart @@ -0,0 +1,41 @@ +// Copyright (C) 2023 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:convert'; + +import 'package:flutter/services.dart'; + +/// A class that contains utility methods for assets. +abstract class AssetsUtils { + /// Checks if the given [assetPath] is a local asset. + /// + /// In fact, this method loads the asset and checks if it is null. + static Future assetExists(String assetPath) async { + final encoded = utf8.encoder.convert( + Uri(path: Uri.encodeFull(assetPath)).path, + ); + final asset = await ServicesBinding.instance.defaultBinaryMessenger + .send('flutter/assets', encoded.buffer.asByteData()); + + return asset != null; + } + + /// Cleans the given [path] by removing all the consecutive slashes. + /// For example, `///a///b///c///` becomes `/a/b/c/`. + /// It also removes the first slash if it exists. + static String cleanPath(String path) => + path.replaceAll(RegExp(r'\/+'), '/').replaceFirst(RegExp(r'^\/'), ''); +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/intl_utils.dart b/packages/wyatt_i18n/lib/src/core/utils/intl_utils.dart new file mode 100644 index 00000000..1721168d --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/intl_utils.dart @@ -0,0 +1,24 @@ +// Copyright (C) 2023 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:intl/intl_standalone.dart' + if (dart.library.html) 'package:intl/intl_browser.dart'; + +/// Utility class for internationalization. +abstract class IntlUtils { + /// Returns system locale. + static Future getSystemLocale() => findSystemLocale(); +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/parser.dart b/packages/wyatt_i18n/lib/src/core/utils/parser.dart new file mode 100644 index 00000000..80331164 --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/parser.dart @@ -0,0 +1,26 @@ +// Copyright (C) 2023 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 . + +/// {@template parser} +/// A class that parses a given input into a given output. +/// {@endtemplate} +abstract class Parser { + /// {@macro parser} + const Parser(); + + /// Parses the given [input] of type [I] into a given output of type [O]. + O parse(I input); +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/parsers/arb_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/parsers/arb_parser.dart new file mode 100644 index 00000000..2ec303b6 --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/parsers/arb_parser.dart @@ -0,0 +1,34 @@ +// Copyright (C) 2023 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:wyatt_i18n/src/core/utils/parser.dart'; +import 'package:wyatt_i18n/src/core/utils/parsers/json_parser.dart'; + +/// {@template arb_parser} +/// A class that parses a given input of type [String] into a given output +/// of type [Map]. +/// {@endtemplate} +class ArbParser extends Parser> { + /// {@macro arb_parser} + const ArbParser() : super(); + + /// Parses the given [input] of type [String] into a given output of type + /// [Map]. + /// + /// ARB files are JSON files, so we can use the JSON parser. + @override + Map parse(String input) => const JsonParser().parse(input); +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/parsers/i18n_file_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/parsers/i18n_file_parser.dart new file mode 100644 index 00000000..3cc371e1 --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/parsers/i18n_file_parser.dart @@ -0,0 +1,142 @@ +// Copyright (C) 2023 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:collection/collection.dart'; +import 'package:intl/intl.dart'; +import 'package:wyatt_i18n/src/domain/entities/tokens.dart'; +import 'package:wyatt_i18n/wyatt_i18n.dart'; + +/// {@template i18n_file_parser} +/// This class is responsible for parsing the [I18n] and returning the +/// translated string using the [arguments] provided and the [IcuParser]. +/// {@endtemplate} +class I18nFileParser extends Parser { + /// {@macro i18n_file_parser} + const I18nFileParser({ + required this.i18n, + this.arguments = const {}, + }) : super(); + + /// The [I18n] to be parsed. + final I18n i18n; + + /// The arguments to be used in the translation. + final Map arguments; + + dynamic getArgument(String key) { + final arg = arguments[key]; + if (arg == null) { + throw ArgumentsRequiredException(key, 'value'); + } + + return arg; + } + + String pluralToString(Plural token) { + final List options = token.options; + final zero = + options.firstWhereOrNull((o) => o!.name == 'zero' || o.name == '=0'); + final one = + options.firstWhereOrNull((o) => o!.name == 'one' || o.name == '=1'); + final two = + options.firstWhereOrNull((o) => o!.name == 'two' || o.name == '=2'); + final few = options.firstWhereOrNull((o) => o!.name == 'few'); + final many = options.firstWhereOrNull((o) => o!.name == 'many'); + final other = options.firstWhereOrNull((o) => o!.name == 'other'); + final zeroStr = zero?.value.map(parsedElementToString).join() ?? ''; + final oneStr = one?.value.map(parsedElementToString).join() ?? ''; + final twoStr = two?.value.map(parsedElementToString).join() ?? ''; + final fewStr = few?.value.map(parsedElementToString).join() ?? ''; + final manyStr = many?.value.map(parsedElementToString).join() ?? ''; + final otherStr = other?.value.map(parsedElementToString).join() ?? ''; + + return Intl.plural( + getArgument(token.value) as num, + zero: zeroStr, + two: twoStr, + one: oneStr, + few: fewStr, + other: otherStr, + many: manyStr, + ); + } + + String genderToString(Gender token) { + final List options = token.options; + final other = options.firstWhereOrNull((o) => o!.name == 'other'); + final male = options.firstWhereOrNull((o) => o!.name == 'male'); + final female = options.firstWhereOrNull((o) => o!.name == 'female'); + final otherStr = other?.value.map(parsedElementToString).join() ?? ''; + final maleStr = male?.value.map(parsedElementToString).join() ?? ''; + final femaleStr = female?.value.map(parsedElementToString).join() ?? ''; + + return Intl.gender( + getArgument(token.value) as String, + other: otherStr, + female: femaleStr, + male: maleStr, + ); + } + + String selectToString(Select token) { + final Map cases = { + for (var e in token.options.map( + (o) => MapEntry( + o.name, + o.value.map(parsedElementToString).join(), + ), + )) + e.key: e.value, + }; + + return Intl.select( + getArgument(token.value) as String, + cases, + ); + } + + String parsedElementToString(Token token) { + switch (token.type) { + case TokenType.literal: + return token.value; + case TokenType.plural: + return pluralToString(token as Plural); + case TokenType.gender: + return genderToString(token as Gender); + case TokenType.argument: + return getArgument(token.value).toString(); + case TokenType.select: + return selectToString(token as Select); + } + } + + @override + String parse(String input, {String? key}) { + String? result; + try { + result = IcuParser().parse(input)?.map(parsedElementToString).join(); + if (result == null) { + throw MalformedValueException(key ?? '', input); + } + } on ArgumentsRequiredException catch (_) { + rethrow; + } catch (e) { + throw MalformedValueException(key ?? '', input); + } + + return result; + } +} diff --git a/packages/wyatt_i18n/lib/src/core/utils/parsers/icu_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/parsers/icu_parser.dart new file mode 100644 index 00000000..192e752b --- /dev/null +++ b/packages/wyatt_i18n/lib/src/core/utils/parsers/icu_parser.dart @@ -0,0 +1,181 @@ +// Copyright (C) 2023 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 . + +// ignore_for_file: avoid_dynamic_calls, inference_failure_on_untyped_parameter + +import 'package:petitparser/petitparser.dart' hide Token; +import 'package:wyatt_i18n/src/core/utils/parser.dart' as wyatt; +import 'package:wyatt_i18n/src/domain/entities/tokens.dart'; + +/// {@template icu_parser} +/// A parser for ICU messages. +/// See https://unicode-org.github.io/icu/userguide/format_parse/messages/ +/// for the syntax. +/// {@endtemplate} +class IcuParser extends wyatt.Parser?> { + /// {@macro icu_parser} + IcuParser() { + // There is a cycle here, so we need the explicit + // set to avoid infinite recursion. + interiorText.set(contents.plus() | empty); + } + Parser get openCurly => char('{'); + + Parser get closeCurly => char('}'); + + Parser get quotedCurly => (string("'{'") | string("'}'")).map((x) => x[1]); + + Parser get icuEscapedText => quotedCurly | twoSingleQuotes; + + Parser get curly => openCurly | closeCurly; + + Parser get notAllowedInIcuText => curly | char('<'); + + Parser get icuText => notAllowedInIcuText.neg(); + + Parser get notAllowedInNormalText => char('{'); + + Parser get normalText => notAllowedInNormalText.neg(); + + Parser get messageText => + (icuEscapedText | icuText).plus().flatten().map(Literal.new); + + Parser get nonIcuMessageText => normalText.plus().flatten().map(Literal.new); + + Parser get twoSingleQuotes => string("''").map((x) => "'"); + + Parser get number => digit().plus().flatten().trim().map(int.parse); + + Parser get id => (letter() & (word() | char('_')).star()).flatten().trim(); + + Parser get comma => char(',').trim(); + + /// Given a list of possible keywords, return a rule that accepts any of them. + /// e.g., given ["male", "female", "other"], accept any of them. + Parser asKeywords(List list) => + list.map(string).cast().reduce((a, b) => a | b).flatten().trim(); + + Parser get pluralKeyword => asKeywords( + ['=0', '=1', '=2', 'zero', 'one', 'two', 'few', 'many', 'other'], + ); + + Parser get genderKeyword => asKeywords(['female', 'male', 'other']); + + SettableParser interiorText = undefined(); + + Parser get preface => (openCurly & id & comma).map((values) => values[1]); + + Parser get pluralLiteral => string('plural'); + + Parser get pluralClause => + (pluralKeyword & openCurly & interiorText & closeCurly).trim().map( + (result) => Option( + result[0] as String, + List.from( + (result[2] is List ? result[2] as List : [result[2]]) + .cast(), + ), + ), + ); + + Parser get plural => + preface & pluralLiteral & comma & pluralClause.plus() & closeCurly; + + Parser get intlPlural => plural.map( + (result) => Plural( + result[0] as String, + List