From 800360f26a063a8e59d0fde73abf744220bacc00 Mon Sep 17 00:00:00 2001 From: Fernando Ferrara Date: Mon, 22 Jun 2026 12:03:38 -0300 Subject: [PATCH 1/4] fix(examples): modernize Android build and fix integration tests Migrate navigator_example and router_example to the modern Flutter Android toolchain so they build on current JDKs again, and fix the Dart/test breakages this surfaced. Android (both examples): - Gradle 5.6.x -> 8.7, AGP 3.5.0 -> 8.6.0, declarative plugins DSL - replace dead jcenter() with mavenCentral(), drop android.enableR8 - add namespace, remove manifest package=, add android:exported - backfill namespace + pin JVM target for legacy plugins via subprojects Dart: - update onError overrides to (error, stackTrace) signature - map logger 2.x calls back to the resolved 1.x API router_example integration test: - present NonReactiveView as a full-screen route (was a non-opaque modal bottom sheet that left the Home FAB onstage -> 2 FABs) - seed a valid form email so validation no longer blocks navigation to the bottom-nav view Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01NbVU8hfegQuqXaszwsmjji --- .../android/app/build.gradle | 67 +- .../android/app/src/debug/AndroidManifest.xml | 3 +- .../android/app/src/main/AndroidManifest.xml | 4 +- .../app/src/profile/AndroidManifest.xml | 3 +- .../navigator_example/android/build.gradle | 59 +- .../android/gradle.properties | 7 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../navigator_example/android/settings.gradle | 30 +- .../lib/app/app.bottomsheets.dart | 1 - .../lib/app/app.dialogs.dart | 1 - .../lib/app/app.locator.dart | 1 - .../navigator_example/lib/app/app.logger.dart | 24 +- .../navigator_example/lib/app/app.router.dart | 594 +++++++----------- .../select_location_view.form.dart | 30 +- .../lib/ui/form/example_form_view.form.dart | 124 ++-- .../stream_view/stream_counter_viewmodel.dart | 2 +- .../router_example/android/app/build.gradle | 67 +- .../android/app/src/debug/AndroidManifest.xml | 3 +- .../android/app/src/main/AndroidManifest.xml | 4 +- .../app/src/profile/AndroidManifest.xml | 3 +- example/router_example/android/build.gradle | 59 +- .../router_example/android/gradle.properties | 7 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../router_example/android/settings.gradle | 30 +- .../integration_test/app_test.dart | 2 +- example/router_example/lib/app/app.dart | 37 +- .../router_example/lib/app/app.logger.dart | 24 +- .../router_example/lib/app/app.router.dart | 6 +- .../services/shared_preferences_service.dart | 4 +- .../lib/ui/form/example_form_view.dart | 2 +- .../lib/ui/form/example_form_view.form.dart | 2 +- .../lib/ui/form/example_form_viewmodel.dart | 2 +- .../future_example_viewmodel.dart | 2 +- .../stream_view/stream_counter_viewmodel.dart | 2 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 +- .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + 37 files changed, 526 insertions(+), 690 deletions(-) diff --git a/example/navigator_example/android/app/build.gradle b/example/navigator_example/android/app/build.gradle index 2243edfa1..e3cec84b2 100644 --- a/example/navigator_example/android/app/build.gradle +++ b/example/navigator_example/android/app/build.gradle @@ -1,67 +1,70 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') +def localPropertiesFile = rootProject.file("local.properties") if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> + localPropertiesFile.withReader("UTF-8") { reader -> localProperties.load(reader) } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = '1' + flutterVersionCode = "1" } -def flutterVersionName = localProperties.getProperty('flutter.versionName') +def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = '1.0' + flutterVersionName = "1.0" } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 31 + namespace = "com.example.new_architecture" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 } - lintOptions { - disable 'InvalidPackage' + sourceSets { + main.java.srcDirs += "src/main/kotlin" } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.new_architecture" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "com.example.new_architecture" + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' + source = "../.." } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + testImplementation "junit:junit:4.13.2" + androidTestImplementation "androidx.test:runner:1.5.2" + androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1" } diff --git a/example/navigator_example/android/app/src/debug/AndroidManifest.xml b/example/navigator_example/android/app/src/debug/AndroidManifest.xml index dcb365cd6..f880684a6 100644 --- a/example/navigator_example/android/app/src/debug/AndroidManifest.xml +++ b/example/navigator_example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/navigator_example/android/app/src/main/AndroidManifest.xml b/example/navigator_example/android/app/src/main/AndroidManifest.xml index 09fe11a9d..db7a04c46 100644 --- a/example/navigator_example/android/app/src/main/AndroidManifest.xml +++ b/example/navigator_example/android/app/src/main/AndroidManifest.xml @@ -1,11 +1,11 @@ - + - + diff --git a/example/navigator_example/android/app/src/profile/AndroidManifest.xml b/example/navigator_example/android/app/src/profile/AndroidManifest.xml index dcb365cd6..f880684a6 100644 --- a/example/navigator_example/android/app/src/profile/AndroidManifest.xml +++ b/example/navigator_example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/navigator_example/android/build.gradle b/example/navigator_example/android/build.gradle index 7087ad19f..aacc6d0f3 100644 --- a/example/navigator_example/android/build.gradle +++ b/example/navigator_example/android/build.gradle @@ -1,31 +1,56 @@ -buildscript { - ext.kotlin_version = '1.4.10' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } + +// Some older Flutter plugins still declare their package via the manifest's +// `package` attribute and don't set an AGP `namespace`, which AGP 8+ requires. +// Backfill the namespace from the manifest package so these plugins keep building. +// Registered before `evaluationDependsOn(":app")` below, which would otherwise +// force-evaluate projects before this hook is attached. +subprojects { + afterEvaluate { project -> + if (project.hasProperty("android")) { + project.android { + if (namespace == null) { + def manifestFile = android.sourceSets.main.manifest.srcFile + def manifestPackage = new XmlSlurper() + .parse(manifestFile) + .@package + .text() + if (manifestPackage) { + namespace = manifestPackage + } + } + + // Older plugins don't pin a JVM target, so Kotlin defaults to the + // running JDK (21) while Java compiles at 1.8, which AGP rejects. + // Force both onto a consistent target. + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + if (project.plugins.hasPlugin("org.jetbrains.kotlin.android")) { + project.android.kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + } + } + } +} + subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/navigator_example/android/gradle.properties b/example/navigator_example/android/gradle.properties index 38c8d4544..4147ba381 100644 --- a/example/navigator_example/android/gradle.properties +++ b/example/navigator_example/android/gradle.properties @@ -1,4 +1,7 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/example/navigator_example/android/gradle/wrapper/gradle-wrapper.properties b/example/navigator_example/android/gradle/wrapper/gradle-wrapper.properties index 296b146b7..7aeeb11c6 100644 --- a/example/navigator_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/navigator_example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip diff --git a/example/navigator_example/android/settings.gradle b/example/navigator_example/android/settings.gradle index 5a2f14fb1..8ea797467 100644 --- a/example/navigator_example/android/settings.gradle +++ b/example/navigator_example/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.6.0" apply false + id "org.jetbrains.kotlin.android" version "1.9.24" apply false } + +include ":app" diff --git a/example/navigator_example/lib/app/app.bottomsheets.dart b/example/navigator_example/lib/app/app.bottomsheets.dart index 0fe3dfd8b..df8a623d9 100644 --- a/example/navigator_example/lib/app/app.bottomsheets.dart +++ b/example/navigator_example/lib/app/app.bottomsheets.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/navigator_example/lib/app/app.dialogs.dart b/example/navigator_example/lib/app/app.dialogs.dart index d88b69705..ae7251eba 100644 --- a/example/navigator_example/lib/app/app.dialogs.dart +++ b/example/navigator_example/lib/app/app.dialogs.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/navigator_example/lib/app/app.locator.dart b/example/navigator_example/lib/app/app.locator.dart index 8286a1d31..c4c9b215a 100644 --- a/example/navigator_example/lib/app/app.locator.dart +++ b/example/navigator_example/lib/app/app.locator.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/navigator_example/lib/app/app.logger.dart b/example/navigator_example/lib/app/app.logger.dart index 1e82ef264..26ab3f947 100644 --- a/example/navigator_example/lib/app/app.logger.dart +++ b/example/navigator_example/lib/app/app.logger.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -7,9 +6,9 @@ // ignore_for_file: avoid_print, depend_on_referenced_packages -// Maybe this should be generated for the user as well? -// -// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; +/// Maybe this should be generated for the user as well? +/// +/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; @@ -28,14 +27,10 @@ class SimpleLogPrinter extends LogPrinter { this.showOnlyClass, }); - final printer = PrettyPrinter( - levelColors: PrettyPrinter.defaultLevelColors, - levelEmojis: PrettyPrinter.defaultLevelEmojis, - ); @override List log(LogEvent event) { - var color = printer.levelColors?[event.level]; - var emoji = printer.levelEmojis?[event.level]; + var color = PrettyPrinter.levelColors[event.level]; + var emoji = PrettyPrinter.levelEmojis[event.level]; var methodName = _getMethodName(); var methodNameSection = @@ -44,12 +39,9 @@ class SimpleLogPrinter extends LogPrinter { var output = '$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}'; - if (exludeLogsFromClasses.any( - (excludeClass) => className == excludeClass, - ) || - (showOnlyClass != null && className != showOnlyClass)) { - return []; - } + if (exludeLogsFromClasses + .any((excludeClass) => className == excludeClass) || + (showOnlyClass != null && className != showOnlyClass)) return []; final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk List result = []; diff --git a/example/navigator_example/lib/app/app.router.dart b/example/navigator_example/lib/app/app.router.dart index 773266e6f..2279636f3 100644 --- a/example/navigator_example/lib/app/app.router.dart +++ b/example/navigator_example/lib/app/app.router.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -48,11 +47,26 @@ class Routes { class StackedRouter extends _i2.RouterBase { final _routes = <_i2.RouteDef>[ - _i2.RouteDef(Routes.homeView, page: _i3.HomeView), - _i2.RouteDef(Routes.bottomNavExample, page: _i4.BottomNavExample), - _i2.RouteDef(Routes.streamCounterView, page: _i5.StreamCounterView), - _i2.RouteDef(Routes.exampleFormView, page: _i6.ExampleFormView), - _i2.RouteDef(Routes.nonReactiveView, page: _i7.NonReactiveView), + _i2.RouteDef( + Routes.homeView, + page: _i3.HomeView, + ), + _i2.RouteDef( + Routes.bottomNavExample, + page: _i4.BottomNavExample, + ), + _i2.RouteDef( + Routes.streamCounterView, + page: _i5.StreamCounterView, + ), + _i2.RouteDef( + Routes.exampleFormView, + page: _i6.ExampleFormView, + ), + _i2.RouteDef( + Routes.nonReactiveView, + page: _i7.NonReactiveView, + ), ]; final _pagesMap = { @@ -62,21 +76,17 @@ class StackedRouter extends _i2.RouterBase { ); return _i8.MaterialPageRoute( builder: (context) => _i3.HomeView( - key: args.key, - title: args.title, - isLoggedIn: args.isLoggedIn, - clashableGetter: args.clashableGetter, - homeTypes: args.homeTypes, - ), + key: args.key, + title: args.title, + isLoggedIn: args.isLoggedIn, + clashableGetter: args.clashableGetter, + homeTypes: args.homeTypes), settings: data, ); }, _i4.BottomNavExample: (data) { - final args = data.getArgs( - orElse: () => const BottomNavExampleArguments(), - ); return _i8.MaterialPageRoute( - builder: (context) => _i4.BottomNavExample(key: args.key), + builder: (context) => const _i4.BottomNavExample(), settings: data, ); }, @@ -84,9 +94,7 @@ class StackedRouter extends _i2.RouterBase { final args = data.getArgs(nullOk: false); return _i8.MaterialPageRoute( builder: (context) => _i5.StreamCounterView( - key: args.key, - clashableTwo: args.clashableTwo, - ), + key: args.key, clashableTwo: args.clashableTwo), settings: data, ); }, @@ -99,12 +107,9 @@ class StackedRouter extends _i2.RouterBase { ); }, _i7.NonReactiveView: (data) { - final args = data.getArgs( - orElse: () => const NonReactiveViewArguments(), - ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - _i7.NonReactiveView(key: args.key), + const _i7.NonReactiveView(), settings: data, transitionsBuilder: data.transition ?? _i9.CustomRouteTransition.sharedAxis, @@ -163,30 +168,11 @@ class HomeViewArguments { } } -class BottomNavExampleArguments { - const BottomNavExampleArguments({this.key}); - - final _i8.Key? key; - - @override - String toString() { - return '{"key": "$key"}'; - } - - @override - bool operator ==(covariant BottomNavExampleArguments other) { - if (identical(this, other)) return true; - return other.key == key; - } - - @override - int get hashCode { - return key.hashCode; - } -} - class StreamCounterViewArguments { - const StreamCounterViewArguments({this.key, required this.clashableTwo}); + const StreamCounterViewArguments({ + this.key, + required this.clashableTwo, + }); final _i8.Key? key; @@ -210,7 +196,10 @@ class StreamCounterViewArguments { } class ExampleFormViewArguments { - const ExampleFormViewArguments({this.key, required this.clashableOne}); + const ExampleFormViewArguments({ + this.key, + required this.clashableOne, + }); final _i8.Key? key; @@ -233,28 +222,6 @@ class ExampleFormViewArguments { } } -class NonReactiveViewArguments { - const NonReactiveViewArguments({this.key}); - - final _i8.Key? key; - - @override - String toString() { - return '{"key": "$key"}'; - } - - @override - bool operator ==(covariant NonReactiveViewArguments other) { - if (identical(this, other)) return true; - return other.key == key; - } - - @override - int get hashCode { - return key.hashCode; - } -} - class BottomNavExampleRoutes { static const historyView = 'history-view'; @@ -262,27 +229,34 @@ class BottomNavExampleRoutes { static const profileView = 'profile-view'; - static const all = {historyView, favoritesView, profileView}; + static const all = { + historyView, + favoritesView, + profileView, + }; } class BottomNavExampleRouter extends _i2.RouterBase { final _routes = <_i2.RouteDef>[ - _i2.RouteDef(BottomNavExampleRoutes.historyView, page: _i12.HistoryView), + _i2.RouteDef( + BottomNavExampleRoutes.historyView, + page: _i12.HistoryView, + ), _i2.RouteDef( BottomNavExampleRoutes.favoritesView, page: _i13.FavoritesView, ), - _i2.RouteDef(BottomNavExampleRoutes.profileView, page: _i14.ProfileView), + _i2.RouteDef( + BottomNavExampleRoutes.profileView, + page: _i14.ProfileView, + ), ]; final _pagesMap = { _i12.HistoryView: (data) { - final args = data.getArgs( - orElse: () => const NestedHistoryViewArguments(), - ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - _i12.HistoryView(key: args.key), + const _i12.HistoryView(), settings: data, transitionsBuilder: data.transition ?? _i2.TransitionsBuilders.fadeIn, ); @@ -297,11 +271,8 @@ class BottomNavExampleRouter extends _i2.RouterBase { ); }, _i14.ProfileView: (data) { - final args = data.getArgs( - orElse: () => const NestedProfileViewArguments(), - ); return _i15.CupertinoPageRoute( - builder: (context) => _i14.ProfileView(key: args.key), + builder: (context) => const _i14.ProfileView(), settings: data, ); }, @@ -314,30 +285,11 @@ class BottomNavExampleRouter extends _i2.RouterBase { Map get pagesMap => _pagesMap; } -class NestedHistoryViewArguments { - const NestedHistoryViewArguments({this.key}); - - final _i8.Key? key; - - @override - String toString() { - return '{"key": "$key"}'; - } - - @override - bool operator ==(covariant NestedHistoryViewArguments other) { - if (identical(this, other)) return true; - return other.key == key; - } - - @override - int get hashCode { - return key.hashCode; - } -} - class FavoritesViewArguments { - const FavoritesViewArguments({this.key, this.id}); + const FavoritesViewArguments({ + this.key, + this.id, + }); final _i8.Key? key; @@ -360,34 +312,15 @@ class FavoritesViewArguments { } } -class NestedProfileViewArguments { - const NestedProfileViewArguments({this.key}); - - final _i8.Key? key; - - @override - String toString() { - return '{"key": "$key"}'; - } - - @override - bool operator ==(covariant NestedProfileViewArguments other) { - if (identical(this, other)) return true; - return other.key == key; - } - - @override - int get hashCode { - return key.hashCode; - } -} - class FavoritesViewRoutes { static const multipleFuturesExampleView = 'multiple-futures-example-view'; static const historyView = 'history-view'; - static const all = {multipleFuturesExampleView, historyView}; + static const all = { + multipleFuturesExampleView, + historyView, + }; } class FavoritesViewRouter extends _i2.RouterBase { @@ -396,26 +329,23 @@ class FavoritesViewRouter extends _i2.RouterBase { FavoritesViewRoutes.multipleFuturesExampleView, page: _i16.MultipleFuturesExampleView, ), - _i2.RouteDef(FavoritesViewRoutes.historyView, page: _i12.HistoryView), + _i2.RouteDef( + FavoritesViewRoutes.historyView, + page: _i12.HistoryView, + ), ]; final _pagesMap = { _i16.MultipleFuturesExampleView: (data) { - final args = data.getArgs( - orElse: () => const NestedMultipleFuturesExampleViewArguments(), - ); return _i8.MaterialPageRoute( - builder: (context) => _i16.MultipleFuturesExampleView(key: args.key), + builder: (context) => const _i16.MultipleFuturesExampleView(), settings: data, ); }, _i12.HistoryView: (data) { - final args = data.getArgs( - orElse: () => const NestedHistoryViewArguments(), - ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - _i12.HistoryView(key: args.key), + const _i12.HistoryView(), settings: data, transitionsBuilder: data.transition ?? (context, animation, secondaryAnimation, child) { @@ -432,28 +362,6 @@ class FavoritesViewRouter extends _i2.RouterBase { Map get pagesMap => _pagesMap; } -class NestedMultipleFuturesExampleViewArguments { - const NestedMultipleFuturesExampleViewArguments({this.key}); - - final _i8.Key? key; - - @override - String toString() { - return '{"key": "$key"}'; - } - - @override - bool operator ==(covariant NestedMultipleFuturesExampleViewArguments other) { - if (identical(this, other)) return true; - return other.key == key; - } - - @override - int get hashCode { - return key.hashCode; - } -} - extension NavigatorStateExtension on _i17.NavigationService { Future navigateToHomeView({ _i8.Key? key, @@ -462,7 +370,7 @@ extension NavigatorStateExtension on _i17.NavigationService { _i10.Clashable Function(String)? clashableGetter, List<_i1.HomeType> homeTypes = const [ _i1.HomeType.apartment, - _i1.HomeType.house, + _i1.HomeType.house ], int? routerId, bool preventDuplicates = true, @@ -470,38 +378,31 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return navigateTo( - Routes.homeView, - arguments: HomeViewArguments( - key: key, - title: title, - isLoggedIn: isLoggedIn, - clashableGetter: clashableGetter, - homeTypes: homeTypes, - ), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); - } - - Future navigateToBottomNavExample({ - _i8.Key? key, + return navigateTo(Routes.homeView, + arguments: HomeViewArguments( + key: key, + title: title, + isLoggedIn: isLoggedIn, + clashableGetter: clashableGetter, + homeTypes: homeTypes), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToBottomNavExample([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - Routes.bottomNavExample, - arguments: BottomNavExampleArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(Routes.bottomNavExample, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future navigateToStreamCounterView({ @@ -513,17 +414,13 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return navigateTo( - Routes.streamCounterView, - arguments: StreamCounterViewArguments( - key: key, - clashableTwo: clashableTwo, - ), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return navigateTo(Routes.streamCounterView, + arguments: + StreamCounterViewArguments(key: key, clashableTwo: clashableTwo), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future navigateToExampleFormView({ @@ -535,50 +432,41 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return navigateTo( - Routes.exampleFormView, - arguments: ExampleFormViewArguments(key: key, clashableOne: clashableOne), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return navigateTo(Routes.exampleFormView, + arguments: + ExampleFormViewArguments(key: key, clashableOne: clashableOne), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future navigateToNonReactiveView({ - _i8.Key? key, + Future navigateToNonReactiveView([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - Routes.nonReactiveView, - arguments: NonReactiveViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(Routes.nonReactiveView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future navigateToNestedHistoryViewInBottomNavExampleRouter({ - _i8.Key? key, + Future navigateToNestedHistoryViewInBottomNavExampleRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - BottomNavExampleRoutes.historyView, - arguments: NestedHistoryViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(BottomNavExampleRoutes.historyView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future navigateToFavoritesView({ @@ -590,69 +478,55 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return navigateTo( - BottomNavExampleRoutes.favoritesView, - arguments: FavoritesViewArguments(key: key, id: id), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return navigateTo(BottomNavExampleRoutes.favoritesView, + arguments: FavoritesViewArguments(key: key, id: id), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future navigateToNestedProfileViewInBottomNavExampleRouter({ - _i8.Key? key, + Future navigateToNestedProfileViewInBottomNavExampleRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - BottomNavExampleRoutes.profileView, - arguments: NestedProfileViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(BottomNavExampleRoutes.profileView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future - navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter({ - _i8.Key? key, + navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - FavoritesViewRoutes.multipleFuturesExampleView, - arguments: NestedMultipleFuturesExampleViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(FavoritesViewRoutes.multipleFuturesExampleView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future navigateToNestedHistoryViewInFavoritesViewRouter({ - _i8.Key? key, + Future navigateToNestedHistoryViewInFavoritesViewRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return navigateTo( - FavoritesViewRoutes.historyView, - arguments: NestedHistoryViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return navigateTo(FavoritesViewRoutes.historyView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future replaceWithHomeView({ @@ -662,7 +536,7 @@ extension NavigatorStateExtension on _i17.NavigationService { _i10.Clashable Function(String)? clashableGetter, List<_i1.HomeType> homeTypes = const [ _i1.HomeType.apartment, - _i1.HomeType.house, + _i1.HomeType.house ], int? routerId, bool preventDuplicates = true, @@ -670,38 +544,31 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return replaceWith( - Routes.homeView, - arguments: HomeViewArguments( - key: key, - title: title, - isLoggedIn: isLoggedIn, - clashableGetter: clashableGetter, - homeTypes: homeTypes, - ), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); - } - - Future replaceWithBottomNavExample({ - _i8.Key? key, + return replaceWith(Routes.homeView, + arguments: HomeViewArguments( + key: key, + title: title, + isLoggedIn: isLoggedIn, + clashableGetter: clashableGetter, + homeTypes: homeTypes), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithBottomNavExample([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - Routes.bottomNavExample, - arguments: BottomNavExampleArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(Routes.bottomNavExample, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future replaceWithStreamCounterView({ @@ -713,17 +580,13 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return replaceWith( - Routes.streamCounterView, - arguments: StreamCounterViewArguments( - key: key, - clashableTwo: clashableTwo, - ), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return replaceWith(Routes.streamCounterView, + arguments: + StreamCounterViewArguments(key: key, clashableTwo: clashableTwo), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future replaceWithExampleFormView({ @@ -735,50 +598,41 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return replaceWith( - Routes.exampleFormView, - arguments: ExampleFormViewArguments(key: key, clashableOne: clashableOne), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return replaceWith(Routes.exampleFormView, + arguments: + ExampleFormViewArguments(key: key, clashableOne: clashableOne), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future replaceWithNonReactiveView({ - _i8.Key? key, + Future replaceWithNonReactiveView([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - Routes.nonReactiveView, - arguments: NonReactiveViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(Routes.nonReactiveView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future replaceWithNestedHistoryViewInBottomNavExampleRouter({ - _i8.Key? key, + Future replaceWithNestedHistoryViewInBottomNavExampleRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - BottomNavExampleRoutes.historyView, - arguments: NestedHistoryViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(BottomNavExampleRoutes.historyView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future replaceWithFavoritesView({ @@ -790,68 +644,54 @@ extension NavigatorStateExtension on _i17.NavigationService { Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return replaceWith( - BottomNavExampleRoutes.favoritesView, - arguments: FavoritesViewArguments(key: key, id: id), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + return replaceWith(BottomNavExampleRoutes.favoritesView, + arguments: FavoritesViewArguments(key: key, id: id), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future replaceWithNestedProfileViewInBottomNavExampleRouter({ - _i8.Key? key, + Future replaceWithNestedProfileViewInBottomNavExampleRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - BottomNavExampleRoutes.profileView, - arguments: NestedProfileViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(BottomNavExampleRoutes.profileView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } Future - replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter({ - _i8.Key? key, + replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - FavoritesViewRoutes.multipleFuturesExampleView, - arguments: NestedMultipleFuturesExampleViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(FavoritesViewRoutes.multipleFuturesExampleView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } - Future replaceWithNestedHistoryViewInFavoritesViewRouter({ - _i8.Key? key, + Future replaceWithNestedHistoryViewInFavoritesViewRouter([ int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - }) async { - return replaceWith( - FavoritesViewRoutes.historyView, - arguments: NestedHistoryViewArguments(key: key), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition, - ); + ]) async { + return replaceWith(FavoritesViewRoutes.historyView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); } } diff --git a/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart b/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart index 21a38d2b5..00a859056 100644 --- a/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart +++ b/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -32,7 +31,7 @@ final Map ProvinceValueToTitleMap = { mixin $SelectLocationView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormStateHelper model) {} + void syncFormWithViewModel(FormViewModel model) {} /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values @@ -48,16 +47,9 @@ mixin $SelectLocationView { } } -extension ValueProperties on FormStateHelper { - bool get hasAnyValidationMessage => this - .fieldsValidationMessages - .values - .any((validation) => validation != null); - - bool get isFormValid { - return !hasAnyValidationMessage; - } - +extension ValueProperties on FormViewModel { + bool get isFormValid => + this.fieldsValidationMessages.values.every((element) => element == null); String? get countryValue => this.formValueMap[CountryValueKey] as String?; String? get provinceValue => this.formValueMap[ProvinceValueKey] as String?; @@ -75,22 +67,18 @@ extension ValueProperties on FormStateHelper { this.fieldsValidationMessages[ProvinceValueKey]; } -extension Methods on FormStateHelper { +extension Methods on FormViewModel { void setCountry(String country) { - this.setData( - this.formValueMap..addAll({CountryValueKey: country}), - ); + this.setData(this.formValueMap..addAll({CountryValueKey: country})); } void setProvince(String province) { - this.setData( - this.formValueMap..addAll({ProvinceValueKey: province}), - ); + this.setData(this.formValueMap..addAll({ProvinceValueKey: province})); } - void setCountryValidationMessage(String? validationMessage) => + setCountryValidationMessage(String? validationMessage) => this.fieldsValidationMessages[CountryValueKey] = validationMessage; - void setProvinceValidationMessage(String? validationMessage) => + setProvinceValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ProvinceValueKey] = validationMessage; /// Clears text input fields on the Form diff --git a/example/navigator_example/lib/ui/form/example_form_view.form.dart b/example/navigator_example/lib/ui/form/example_form_view.form.dart index 02732adf6..5f98d5f4b 100644 --- a/example/navigator_example/lib/ui/form/example_form_view.form.dart +++ b/example/navigator_example/lib/ui/form/example_form_view.form.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -12,8 +11,6 @@ import 'package:example/ui/form/validators.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; -const bool _autoTextFieldValidation = false; - const String EmailValueKey = 'email'; const String PasswordValueKey = 'password'; const String ShortBioValueKey = 'shortBio'; @@ -41,10 +38,23 @@ mixin $ExampleFormView { TextEditingController get emailController => _getFormTextEditingController(EmailValueKey, initialValue: 'Lorem'); CustomEditingController get passwordController => - _getPasswordCustomFormTextEditingController(PasswordValueKey); + _getCustomFormTextEditingController(PasswordValueKey); TextEditingController get shortBioController => _getFormTextEditingController(ShortBioValueKey); + CustomEditingController _getCustomFormTextEditingController( + String key, + ) { + if (_ExampleFormViewTextEditingControllers.containsKey(key)) { + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + _ExampleFormViewTextEditingControllers[key] = + CustomEditingController.getCustomEditingController(); + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey); FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey); FocusNode get shortBioFocusNode => _getFormFocusNode(ShortBioValueKey); @@ -62,19 +72,6 @@ mixin $ExampleFormView { return _ExampleFormViewTextEditingControllers[key]!; } - CustomEditingController _getPasswordCustomFormTextEditingController( - String key, - ) { - if (_ExampleFormViewTextEditingControllers.containsKey(key)) { - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } - _ExampleFormViewTextEditingControllers[key] = - CustomEditingController.getCustomEditingController(); - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } - FocusNode _getFormFocusNode(String key) { if (_ExampleFormViewFocusNodes.containsKey(key)) { return _ExampleFormViewFocusNodes[key]!; @@ -85,12 +82,10 @@ mixin $ExampleFormView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormStateHelper model) { + void syncFormWithViewModel(FormViewModel model) { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); - - _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Registers a listener on every generated controller that calls [model.setData()] @@ -103,12 +98,16 @@ mixin $ExampleFormView { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); + } - _updateFormData(model, forceValidate: _autoTextFieldValidation); + static const bool _autoTextFieldValidation = false; + bool validateFormFields(FormViewModel model) { + _updateFormData(model, forceValidate: true); + return model.isFormValid; } /// Updates the formData on the FormViewModel - void _updateFormData(FormStateHelper model, {bool forceValidate = false}) { + void _updateFormData(FormViewModel model, {bool forceValidate = false}) { model.setData( model.formValueMap ..addAll({ @@ -123,11 +122,6 @@ mixin $ExampleFormView { } } - bool validateFormFields(FormViewModel model) { - _updateFormData(model, forceValidate: true); - return model.isFormValid; - } - /// Calls dispose on all the generated controllers and focus nodes void disposeForm() { // The dispose function for a TextEditingController sets all listeners to null @@ -144,18 +138,9 @@ mixin $ExampleFormView { } } -extension ValueProperties on FormStateHelper { - bool get hasAnyValidationMessage => this - .fieldsValidationMessages - .values - .any((validation) => validation != null); - - bool get isFormValid { - if (!_autoTextFieldValidation) this.validateForm(); - - return !hasAnyValidationMessage; - } - +extension ValueProperties on FormViewModel { + bool get isFormValid => + this.fieldsValidationMessages.values.every((element) => element == null); String? get emailValue => this.formValueMap[EmailValueKey] as String?; String? get passwordValue => this.formValueMap[PasswordValueKey] as String?; String? get shortBioValue => this.formValueMap[ShortBioValueKey] as String?; @@ -166,7 +151,10 @@ extension ValueProperties on FormStateHelper { set emailValue(String? value) { this.setData( - this.formValueMap..addAll({EmailValueKey: value}), + this.formValueMap + ..addAll({ + EmailValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(EmailValueKey)) { @@ -176,7 +164,10 @@ extension ValueProperties on FormStateHelper { set passwordValue(String? value) { this.setData( - this.formValueMap..addAll({PasswordValueKey: value}), + this.formValueMap + ..addAll({ + PasswordValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(PasswordValueKey)) { @@ -187,7 +178,10 @@ extension ValueProperties on FormStateHelper { set shortBioValue(String? value) { this.setData( - this.formValueMap..addAll({ShortBioValueKey: value}), + this.formValueMap + ..addAll({ + ShortBioValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(ShortBioValueKey)) { @@ -232,46 +226,37 @@ extension ValueProperties on FormStateHelper { this.fieldsValidationMessages[DoYouLoveFoodValueKey]; } -extension Methods on FormStateHelper { - Future selectBirthDate({ - required BuildContext context, - required DateTime initialDate, - required DateTime firstDate, - required DateTime lastDate, - }) async { +extension Methods on FormViewModel { + Future selectBirthDate( + {required BuildContext context, + required DateTime initialDate, + required DateTime firstDate, + required DateTime lastDate}) async { final selectedDate = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate, - ); - + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate); if (selectedDate != null) { this.setData( - this.formValueMap..addAll({BirthDateValueKey: selectedDate}), - ); + this.formValueMap..addAll({BirthDateValueKey: selectedDate})); } - - if (_autoTextFieldValidation) this.validateForm(); } void setDoYouLoveFood(String doYouLoveFood) { this.setData( - this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood}), - ); - - if (_autoTextFieldValidation) this.validateForm(); + this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood})); } - void setEmailValidationMessage(String? validationMessage) => + setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - void setPasswordValidationMessage(String? validationMessage) => + setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - void setShortBioValidationMessage(String? validationMessage) => + setShortBioValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ShortBioValueKey] = validationMessage; - void setBirthDateValidationMessage(String? validationMessage) => + setBirthDateValidationMessage(String? validationMessage) => this.fieldsValidationMessages[BirthDateValueKey] = validationMessage; - void setDoYouLoveFoodValidationMessage(String? validationMessage) => + setDoYouLoveFoodValidationMessage(String? validationMessage) => this.fieldsValidationMessages[DoYouLoveFoodValueKey] = validationMessage; /// Clears text input fields on the Form @@ -304,8 +289,7 @@ String? getValidationMessage(String key) { } /// Updates the fieldsValidationMessages on the FormViewModel -void updateValidationData(FormStateHelper model) => - model.setValidationMessages({ +void updateValidationData(FormViewModel model) => model.setValidationMessages({ EmailValueKey: getValidationMessage(EmailValueKey), PasswordValueKey: getValidationMessage(PasswordValueKey), ShortBioValueKey: getValidationMessage(ShortBioValueKey), diff --git a/example/navigator_example/lib/ui/stream_view/stream_counter_viewmodel.dart b/example/navigator_example/lib/ui/stream_view/stream_counter_viewmodel.dart index 0e091bcdb..c1f97c0cc 100644 --- a/example/navigator_example/lib/ui/stream_view/stream_counter_viewmodel.dart +++ b/example/navigator_example/lib/ui/stream_view/stream_counter_viewmodel.dart @@ -38,7 +38,7 @@ class StreamCounterViewModel extends StreamViewModel { void onSubscribed() {} @override - void onError(error) {} + void onError(dynamic error, StackTrace? stackTrace) {} void changeStreamSources() { isSlowEpochNumbers = !isSlowEpochNumbers; diff --git a/example/router_example/android/app/build.gradle b/example/router_example/android/app/build.gradle index 587620b3d..e3cec84b2 100644 --- a/example/router_example/android/app/build.gradle +++ b/example/router_example/android/app/build.gradle @@ -1,67 +1,70 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') +def localPropertiesFile = rootProject.file("local.properties") if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> + localPropertiesFile.withReader("UTF-8") { reader -> localProperties.load(reader) } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = '1' + flutterVersionCode = "1" } -def flutterVersionName = localProperties.getProperty('flutter.versionName') +def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = '1.0' + flutterVersionName = "1.0" } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 31 + namespace = "com.example.new_architecture" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 } - lintOptions { - disable 'InvalidPackage' + sourceSets { + main.java.srcDirs += "src/main/kotlin" } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.new_architecture" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "com.example.new_architecture" + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' + source = "../.." } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + testImplementation "junit:junit:4.13.2" + androidTestImplementation "androidx.test:runner:1.5.2" + androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1" } diff --git a/example/router_example/android/app/src/debug/AndroidManifest.xml b/example/router_example/android/app/src/debug/AndroidManifest.xml index dcb365cd6..f880684a6 100644 --- a/example/router_example/android/app/src/debug/AndroidManifest.xml +++ b/example/router_example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/router_example/android/app/src/main/AndroidManifest.xml b/example/router_example/android/app/src/main/AndroidManifest.xml index 09fe11a9d..db7a04c46 100644 --- a/example/router_example/android/app/src/main/AndroidManifest.xml +++ b/example/router_example/android/app/src/main/AndroidManifest.xml @@ -1,11 +1,11 @@ - + - + diff --git a/example/router_example/android/app/src/profile/AndroidManifest.xml b/example/router_example/android/app/src/profile/AndroidManifest.xml index dcb365cd6..f880684a6 100644 --- a/example/router_example/android/app/src/profile/AndroidManifest.xml +++ b/example/router_example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/router_example/android/build.gradle b/example/router_example/android/build.gradle index 7087ad19f..aacc6d0f3 100644 --- a/example/router_example/android/build.gradle +++ b/example/router_example/android/build.gradle @@ -1,31 +1,56 @@ -buildscript { - ext.kotlin_version = '1.4.10' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } + +// Some older Flutter plugins still declare their package via the manifest's +// `package` attribute and don't set an AGP `namespace`, which AGP 8+ requires. +// Backfill the namespace from the manifest package so these plugins keep building. +// Registered before `evaluationDependsOn(":app")` below, which would otherwise +// force-evaluate projects before this hook is attached. +subprojects { + afterEvaluate { project -> + if (project.hasProperty("android")) { + project.android { + if (namespace == null) { + def manifestFile = android.sourceSets.main.manifest.srcFile + def manifestPackage = new XmlSlurper() + .parse(manifestFile) + .@package + .text() + if (manifestPackage) { + namespace = manifestPackage + } + } + + // Older plugins don't pin a JVM target, so Kotlin defaults to the + // running JDK (21) while Java compiles at 1.8, which AGP rejects. + // Force both onto a consistent target. + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + if (project.plugins.hasPlugin("org.jetbrains.kotlin.android")) { + project.android.kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + } + } + } +} + subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/router_example/android/gradle.properties b/example/router_example/android/gradle.properties index 38c8d4544..4147ba381 100644 --- a/example/router_example/android/gradle.properties +++ b/example/router_example/android/gradle.properties @@ -1,4 +1,7 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/example/router_example/android/gradle/wrapper/gradle-wrapper.properties b/example/router_example/android/gradle/wrapper/gradle-wrapper.properties index bc24dcf03..7aeeb11c6 100644 --- a/example/router_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/router_example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip diff --git a/example/router_example/android/settings.gradle b/example/router_example/android/settings.gradle index 5a2f14fb1..8ea797467 100644 --- a/example/router_example/android/settings.gradle +++ b/example/router_example/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.6.0" apply false + id "org.jetbrains.kotlin.android" version "1.9.24" apply false } + +include ":app" diff --git a/example/router_example/integration_test/app_test.dart b/example/router_example/integration_test/app_test.dart index 561ec54aa..2387e2c24 100644 --- a/example/router_example/integration_test/app_test.dart +++ b/example/router_example/integration_test/app_test.dart @@ -34,7 +34,7 @@ void main() { // Example Form View Widgets final exampleFormTitle = find.text('Example Form View'); - final formLoremText = find.text('Lorem'); + final formLoremText = find.text('lorem@test.com'); final formPasswordTextField = find.byKey(const ValueKey('passwordField')); final passwordErrorText = find.text('Password should not be empty'); final dobButton = find.text('Select your Date of birth'); diff --git a/example/router_example/lib/app/app.dart b/example/router_example/lib/app/app.dart index e20c59174..f6ace933f 100644 --- a/example/router_example/lib/app/app.dart +++ b/example/router_example/lib/app/app.dart @@ -49,14 +49,7 @@ import 'package:stacked_themes/stacked_themes.dart'; ]), MaterialRoute(page: StreamCounterView), MaterialRoute(page: ExampleFormView), - // CustomRoute( - // page: NonReactiveView, - // transitionsBuilder: CustomRouteTransition.sharedAxis, - // ), - CustomRoute( - page: NonReactiveView, - customRouteBuilder: RouteBuilders.bottomSheetBuilder, - ) + MaterialRoute(page: NonReactiveView), ], dependencies: [ // Lazy singletons @@ -100,31 +93,3 @@ import 'package:stacked_themes/stacked_themes.dart'; class App { /// This class has no puporse besides housing the annotation that generates the required functionality } - -abstract class RouteBuilders { - static Route bottomSheetBuilder( - BuildContext context, - Widget child, - CustomPage page, - ) { - return ModalBottomSheetRoute( - builder: page.buildPage, - settings: page, - isScrollControlled: false, - isDismissible: false, - enableDrag: false, - useSafeArea: true, - showDragHandle: false, - scrollControlDisabledMaxHeightRatio: 0.5, - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height * 0.8, - ), - backgroundColor: Colors.amber, - modalBarrierColor: Colors.black.withValues(alpha: 0.6), - elevation: 5, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(12)), - ), - ); - } -} diff --git a/example/router_example/lib/app/app.logger.dart b/example/router_example/lib/app/app.logger.dart index 1e82ef264..26ab3f947 100644 --- a/example/router_example/lib/app/app.logger.dart +++ b/example/router_example/lib/app/app.logger.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -7,9 +6,9 @@ // ignore_for_file: avoid_print, depend_on_referenced_packages -// Maybe this should be generated for the user as well? -// -// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; +/// Maybe this should be generated for the user as well? +/// +/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; @@ -28,14 +27,10 @@ class SimpleLogPrinter extends LogPrinter { this.showOnlyClass, }); - final printer = PrettyPrinter( - levelColors: PrettyPrinter.defaultLevelColors, - levelEmojis: PrettyPrinter.defaultLevelEmojis, - ); @override List log(LogEvent event) { - var color = printer.levelColors?[event.level]; - var emoji = printer.levelEmojis?[event.level]; + var color = PrettyPrinter.levelColors[event.level]; + var emoji = PrettyPrinter.levelEmojis[event.level]; var methodName = _getMethodName(); var methodNameSection = @@ -44,12 +39,9 @@ class SimpleLogPrinter extends LogPrinter { var output = '$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}'; - if (exludeLogsFromClasses.any( - (excludeClass) => className == excludeClass, - ) || - (showOnlyClass != null && className != showOnlyClass)) { - return []; - } + if (exludeLogsFromClasses + .any((excludeClass) => className == excludeClass) || + (showOnlyClass != null && className != showOnlyClass)) return []; final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk List result = []; diff --git a/example/router_example/lib/app/app.router.dart b/example/router_example/lib/app/app.router.dart index 8794a1bd8..c1296b314 100644 --- a/example/router_example/lib/app/app.router.dart +++ b/example/router_example/lib/app/app.router.dart @@ -23,7 +23,6 @@ import '../ui/multiple_futures_example/multiple_futures_example_view.dart' as _i10; import '../ui/nonreactive/nonreactive_view.dart' as _i6; import '../ui/stream_view/stream_counter_view.dart' as _i4; -import 'app.dart' as _i14; final stackedRouter = StackedRouterWeb( navigatorKey: _i11.StackedService.navigatorKey, @@ -83,12 +82,9 @@ class StackedRouterWeb extends _i12.RootStackRouter { final args = routeData.argsAs( orElse: () => const NonReactiveViewArgs(), ); - return _i12.CustomPage( + return _i12.MaterialPageX( routeData: routeData, child: _i6.NonReactiveView(key: args.key), - customRouteBuilder: _i14.RouteBuilders.bottomSheetBuilder, - opaque: true, - barrierDismissible: false, ); }, FavoritesViewRoute.name: (routeData) { diff --git a/example/router_example/lib/services/shared_preferences_service.dart b/example/router_example/lib/services/shared_preferences_service.dart index 14912efe0..9497f8d0b 100644 --- a/example/router_example/lib/services/shared_preferences_service.dart +++ b/example/router_example/lib/services/shared_preferences_service.dart @@ -27,12 +27,12 @@ class SharedPreferencesService implements InitializableDependency { Object? getFromDisk(String key) { final value = _preferences.get(key); - if (enableLogs) _log.t('key:$key value:$value'); + if (enableLogs) _log.v('key:$key value:$value'); return value; } void saveToDisk(String key, dynamic content) { - if (enableLogs) _log.t('key:$key value:$content'); + if (enableLogs) _log.v('key:$key value:$content'); if (content is String) { _preferences.setString(key, content); diff --git a/example/router_example/lib/ui/form/example_form_view.dart b/example/router_example/lib/ui/form/example_form_view.dart index d35aeb377..0593a7df4 100644 --- a/example/router_example/lib/ui/form/example_form_view.dart +++ b/example/router_example/lib/ui/form/example_form_view.dart @@ -13,7 +13,7 @@ import 'example_form_viewmodel.dart'; fields: [ FormTextField( name: 'email', - initialValue: "Lorem", + initialValue: "lorem@test.com", validator: FormValidators.emailValidator, ), FormTextField( diff --git a/example/router_example/lib/ui/form/example_form_view.form.dart b/example/router_example/lib/ui/form/example_form_view.form.dart index 35b39f258..3404cac66 100644 --- a/example/router_example/lib/ui/form/example_form_view.form.dart +++ b/example/router_example/lib/ui/form/example_form_view.form.dart @@ -39,7 +39,7 @@ final Map _ExampleFormViewTextValidations = mixin $ExampleFormView { TextEditingController get emailController => - _getFormTextEditingController(EmailValueKey, initialValue: 'Lorem'); + _getFormTextEditingController(EmailValueKey, initialValue: 'lorem@test.com'); CustomEditingController get passwordController => _getPasswordCustomFormTextEditingController(PasswordValueKey); CustomEditingController get shortBioController => diff --git a/example/router_example/lib/ui/form/example_form_viewmodel.dart b/example/router_example/lib/ui/form/example_form_viewmodel.dart index 61762b0df..e0858e3a8 100644 --- a/example/router_example/lib/ui/form/example_form_viewmodel.dart +++ b/example/router_example/lib/ui/form/example_form_viewmodel.dart @@ -14,7 +14,7 @@ class ExampleFormViewModel extends FormViewModel { final _preferences = exampleLocator(); ExampleFormViewModel() { - log.f('hash:${_preferences.hashCode}'); + log.wtf('hash:${_preferences.hashCode}'); } void populateForm() { diff --git a/example/router_example/lib/ui/future_example_view/future_example_viewmodel.dart b/example/router_example/lib/ui/future_example_view/future_example_viewmodel.dart index 49521d0a0..8a40a5997 100644 --- a/example/router_example/lib/ui/future_example_view/future_example_viewmodel.dart +++ b/example/router_example/lib/ui/future_example_view/future_example_viewmodel.dart @@ -8,7 +8,7 @@ class FutureExampleViewModel extends FutureViewModel { } @override - void onError(error) {} + void onError(dynamic error, StackTrace? stackTrace) {} @override Future futureToRun() => getDataFromServer(); diff --git a/example/router_example/lib/ui/stream_view/stream_counter_viewmodel.dart b/example/router_example/lib/ui/stream_view/stream_counter_viewmodel.dart index 6c88f1f7e..58b9357e6 100644 --- a/example/router_example/lib/ui/stream_view/stream_counter_viewmodel.dart +++ b/example/router_example/lib/ui/stream_view/stream_counter_viewmodel.dart @@ -38,7 +38,7 @@ class StreamCounterViewModel extends StreamViewModel { void onSubscribed() {} @override - void onError(error) {} + void onError(dynamic error, StackTrace? stackTrace) {} void changeStreamSources() { isSlowEpochNumbers = !isSlowEpochNumbers; diff --git a/example/router_example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/router_example/macos/Flutter/GeneratedPluginRegistrant.swift index 2e86147d3..860d705af 100644 --- a/example/router_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/router_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -15,6 +15,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) - FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/example/router_example/windows/flutter/generated_plugin_registrant.cc b/example/router_example/windows/flutter/generated_plugin_registrant.cc index 8b6d4680a..1a82e7d01 100644 --- a/example/router_example/windows/flutter/generated_plugin_registrant.cc +++ b/example/router_example/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); } diff --git a/example/router_example/windows/flutter/generated_plugins.cmake b/example/router_example/windows/flutter/generated_plugins.cmake index b93c4c30c..fa8a39bab 100644 --- a/example/router_example/windows/flutter/generated_plugins.cmake +++ b/example/router_example/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + firebase_core ) list(APPEND FLUTTER_FFI_PLUGIN_LIST From 8b345d9bc0c80f5a46c5330d188b9dbee9520ed1 Mon Sep 17 00:00:00 2001 From: Fernando Ferrara Date: Mon, 22 Jun 2026 12:49:30 -0300 Subject: [PATCH 2/4] chore(router_example): regenerate from fixed generator Regenerate router_example's generated files with the repaired stacked_generator so they match generator output instead of the hand-edited recovery versions, and migrate the form to the current validation API. - app.locator.dart now registers FactoryService (factory params) and the InitializableSingleton services (SharedPreferencesService, NativeActionsService) via the await-init pattern - app.router.dart no longer duplicates HistoryView navigation helpers - example_form_view.form.dart emits a single custom-controller helper - saveData() now calls validateForm() before checking isFormValid; newer generated forms no longer validate implicitly inside isFormValid Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01NbVU8hfegQuqXaszwsmjji --- .../lib/app/app.bottomsheets.dart | 1 - .../router_example/lib/app/app.dialogs.dart | 1 - .../router_example/lib/app/app.locator.dart | 1 - .../router_example/lib/app/app.router.dart | 364 ++++++++---------- .../select_location_view.form.dart | 31 +- .../lib/ui/form/example_form_view.form.dart | 142 +++---- .../lib/ui/form/example_form_viewmodel.dart | 3 + 7 files changed, 232 insertions(+), 311 deletions(-) diff --git a/example/router_example/lib/app/app.bottomsheets.dart b/example/router_example/lib/app/app.bottomsheets.dart index 0fe3dfd8b..df8a623d9 100644 --- a/example/router_example/lib/app/app.bottomsheets.dart +++ b/example/router_example/lib/app/app.bottomsheets.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/router_example/lib/app/app.dialogs.dart b/example/router_example/lib/app/app.dialogs.dart index d88b69705..ae7251eba 100644 --- a/example/router_example/lib/app/app.dialogs.dart +++ b/example/router_example/lib/app/app.dialogs.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/router_example/lib/app/app.locator.dart b/example/router_example/lib/app/app.locator.dart index 7b479eaab..6923bf14c 100644 --- a/example/router_example/lib/app/app.locator.dart +++ b/example/router_example/lib/app/app.locator.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** diff --git a/example/router_example/lib/app/app.router.dart b/example/router_example/lib/app/app.router.dart index c1296b314..020f130d1 100644 --- a/example/router_example/lib/app/app.router.dart +++ b/example/router_example/lib/app/app.router.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -10,8 +9,8 @@ import 'package:flutter/material.dart' as _i13; import 'package:stacked/stacked.dart' as _i12; import 'package:stacked_services/stacked_services.dart' as _i11; -import '../datamodels/clashable_one.dart' as _i15; -import '../datamodels/clashable_two.dart' as _i16; +import '../datamodels/clashable_one.dart' as _i14; +import '../datamodels/clashable_two.dart' as _i15; import '../datamodels/home_type.dart' as _i1; import '../ui/bottom_nav/bottom_nav_example.dart' as _i3; import '../ui/bottom_nav/favorites/favorites_view.dart' as _i7; @@ -24,9 +23,8 @@ import '../ui/multiple_futures_example/multiple_futures_example_view.dart' import '../ui/nonreactive/nonreactive_view.dart' as _i6; import '../ui/stream_view/stream_counter_view.dart' as _i4; -final stackedRouter = StackedRouterWeb( - navigatorKey: _i11.StackedService.navigatorKey, -); +final stackedRouter = + StackedRouterWeb(navigatorKey: _i11.StackedService.navigatorKey); class StackedRouterWeb extends _i12.RootStackRouter { StackedRouterWeb({_i13.GlobalKey<_i13.NavigatorState>? navigatorKey}) @@ -35,9 +33,8 @@ class StackedRouterWeb extends _i12.RootStackRouter { @override final Map pagesMap = { HomeViewRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const HomeViewArgs(), - ); + final args = + routeData.argsAs(orElse: () => const HomeViewArgs()); return _i12.MaterialPageX( routeData: routeData, child: _i2.HomeView( @@ -50,12 +47,9 @@ class StackedRouterWeb extends _i12.RootStackRouter { ); }, BottomNavExampleRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const BottomNavExampleArgs(), - ); return _i12.MaterialPageX( routeData: routeData, - child: _i3.BottomNavExample(key: args.key), + child: const _i3.BottomNavExample(), ); }, StreamCounterViewRoute.name: (routeData) { @@ -79,58 +73,51 @@ class StackedRouterWeb extends _i12.RootStackRouter { ); }, NonReactiveViewRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const NonReactiveViewArgs(), - ); return _i12.MaterialPageX( routeData: routeData, - child: _i6.NonReactiveView(key: args.key), + child: const _i6.NonReactiveView(), ); }, FavoritesViewRoute.name: (routeData) { final args = routeData.argsAs( - orElse: () => const FavoritesViewArgs(), - ); + orElse: () => const FavoritesViewArgs()); return _i12.AdaptivePage( routeData: routeData, - child: _i7.FavoritesView(key: args.key, id: args.id), + child: _i7.FavoritesView( + key: args.key, + id: args.id, + ), opaque: true, ); }, HistoryViewRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const HistoryViewArgs(), - ); return _i12.CustomPage( routeData: routeData, - child: _i8.HistoryView(key: args.key), + child: const _i8.HistoryView(), opaque: true, barrierDismissible: false, ); }, ProfileViewRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const ProfileViewArgs(), - ); return _i12.CupertinoPageX( routeData: routeData, - child: _i9.ProfileView(key: args.key), + child: const _i9.ProfileView(), ); }, MultipleFuturesExampleViewRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const MultipleFuturesExampleViewArgs(), - ); return _i12.MaterialPageX( routeData: routeData, - child: _i10.MultipleFuturesExampleView(key: args.key), + child: const _i10.MultipleFuturesExampleView(), ); }, }; @override List<_i12.RouteConfig> get routes => [ - _i12.RouteConfig(HomeViewRoute.name, path: '/'), + _i12.RouteConfig( + HomeViewRoute.name, + path: '/', + ), _i12.RouteConfig( BottomNavExampleRoute.name, path: '/bottom-nav-example', @@ -171,10 +158,18 @@ class StackedRouterWeb extends _i12.RootStackRouter { ), ], ), - _i12.RouteConfig(StreamCounterViewRoute.name, - path: '/stream-counter-view'), - _i12.RouteConfig(ExampleFormViewRoute.name, path: '/example-form-view'), - _i12.RouteConfig(NonReactiveViewRoute.name, path: '/non-reactive-view'), + _i12.RouteConfig( + StreamCounterViewRoute.name, + path: '/stream-counter-view', + ), + _i12.RouteConfig( + ExampleFormViewRoute.name, + path: '/example-form-view', + ), + _i12.RouteConfig( + NonReactiveViewRoute.name, + path: '/non-reactive-view', + ), ]; } @@ -185,10 +180,10 @@ class HomeViewRoute extends _i12.PageRouteInfo { _i13.Key? key, String? title = 'hello', bool? isLoggedIn = false, - _i15.Clashable Function(String)? clashableGetter, + _i14.Clashable Function(String)? clashableGetter, List<_i1.HomeType> homeTypes = const [ _i1.HomeType.apartment, - _i1.HomeType.house, + _i1.HomeType.house ], }) : super( HomeViewRoute.name, @@ -220,7 +215,7 @@ class HomeViewArgs { final bool? isLoggedIn; - final _i15.Clashable Function(String)? clashableGetter; + final _i14.Clashable Function(String)? clashableGetter; final List<_i1.HomeType> homeTypes; @@ -232,50 +227,44 @@ class HomeViewArgs { /// generated route for /// [_i3.BottomNavExample] -class BottomNavExampleRoute extends _i12.PageRouteInfo { - BottomNavExampleRoute({_i13.Key? key, List<_i12.PageRouteInfo>? children}) +class BottomNavExampleRoute extends _i12.PageRouteInfo { + const BottomNavExampleRoute({List<_i12.PageRouteInfo>? children}) : super( BottomNavExampleRoute.name, path: '/bottom-nav-example', - args: BottomNavExampleArgs(key: key), initialChildren: children, ); static const String name = 'BottomNavExample'; } -class BottomNavExampleArgs { - const BottomNavExampleArgs({this.key}); - - final _i13.Key? key; - - @override - String toString() { - return 'BottomNavExampleArgs{key: $key}'; - } -} - /// generated route for /// [_i4.StreamCounterView] class StreamCounterViewRoute extends _i12.PageRouteInfo { StreamCounterViewRoute({ _i13.Key? key, - required List<_i16.Clashable> clashableTwo, + required List<_i15.Clashable> clashableTwo, }) : super( StreamCounterViewRoute.name, path: '/stream-counter-view', - args: StreamCounterViewArgs(key: key, clashableTwo: clashableTwo), + args: StreamCounterViewArgs( + key: key, + clashableTwo: clashableTwo, + ), ); static const String name = 'StreamCounterView'; } class StreamCounterViewArgs { - const StreamCounterViewArgs({this.key, required this.clashableTwo}); + const StreamCounterViewArgs({ + this.key, + required this.clashableTwo, + }); final _i13.Key? key; - final List<_i16.Clashable> clashableTwo; + final List<_i15.Clashable> clashableTwo; @override String toString() { @@ -286,22 +275,30 @@ class StreamCounterViewArgs { /// generated route for /// [_i5.ExampleFormView] class ExampleFormViewRoute extends _i12.PageRouteInfo { - ExampleFormViewRoute({_i13.Key? key, required _i15.Clashable clashableOne}) - : super( + ExampleFormViewRoute({ + _i13.Key? key, + required _i14.Clashable clashableOne, + }) : super( ExampleFormViewRoute.name, path: '/example-form-view', - args: ExampleFormViewArgs(key: key, clashableOne: clashableOne), + args: ExampleFormViewArgs( + key: key, + clashableOne: clashableOne, + ), ); static const String name = 'ExampleFormView'; } class ExampleFormViewArgs { - const ExampleFormViewArgs({this.key, required this.clashableOne}); + const ExampleFormViewArgs({ + this.key, + required this.clashableOne, + }); final _i13.Key? key; - final _i15.Clashable clashableOne; + final _i14.Clashable clashableOne; @override String toString() { @@ -311,28 +308,16 @@ class ExampleFormViewArgs { /// generated route for /// [_i6.NonReactiveView] -class NonReactiveViewRoute extends _i12.PageRouteInfo { - NonReactiveViewRoute({_i13.Key? key}) +class NonReactiveViewRoute extends _i12.PageRouteInfo { + const NonReactiveViewRoute() : super( NonReactiveViewRoute.name, path: '/non-reactive-view', - args: NonReactiveViewArgs(key: key), ); static const String name = 'NonReactiveView'; } -class NonReactiveViewArgs { - const NonReactiveViewArgs({this.key}); - - final _i13.Key? key; - - @override - String toString() { - return 'NonReactiveViewArgs{key: $key}'; - } -} - /// generated route for /// [_i7.FavoritesView] class FavoritesViewRoute extends _i12.PageRouteInfo { @@ -343,7 +328,10 @@ class FavoritesViewRoute extends _i12.PageRouteInfo { }) : super( FavoritesViewRoute.name, path: 'favourites', - args: FavoritesViewArgs(key: key, id: id), + args: FavoritesViewArgs( + key: key, + id: id, + ), initialChildren: children, ); @@ -351,7 +339,10 @@ class FavoritesViewRoute extends _i12.PageRouteInfo { } class FavoritesViewArgs { - const FavoritesViewArgs({this.key, this.id}); + const FavoritesViewArgs({ + this.key, + this.id, + }); final _i13.Key? key; @@ -365,86 +356,49 @@ class FavoritesViewArgs { /// generated route for /// [_i8.HistoryView] -class HistoryViewRoute extends _i12.PageRouteInfo { - HistoryViewRoute({_i13.Key? key}) +class HistoryViewRoute extends _i12.PageRouteInfo { + const HistoryViewRoute() : super( HistoryViewRoute.name, path: 'history-view', - args: HistoryViewArgs(key: key), ); static const String name = 'HistoryView'; } -class HistoryViewArgs { - const HistoryViewArgs({this.key}); - - final _i13.Key? key; - - @override - String toString() { - return 'HistoryViewArgs{key: $key}'; - } -} - /// generated route for /// [_i9.ProfileView] -class ProfileViewRoute extends _i12.PageRouteInfo { - ProfileViewRoute({_i13.Key? key}) +class ProfileViewRoute extends _i12.PageRouteInfo { + const ProfileViewRoute() : super( ProfileViewRoute.name, path: 'profile-view', - args: ProfileViewArgs(key: key), ); static const String name = 'ProfileView'; } -class ProfileViewArgs { - const ProfileViewArgs({this.key}); - - final _i13.Key? key; - - @override - String toString() { - return 'ProfileViewArgs{key: $key}'; - } -} - /// generated route for /// [_i10.MultipleFuturesExampleView] -class MultipleFuturesExampleViewRoute - extends _i12.PageRouteInfo { - MultipleFuturesExampleViewRoute({_i13.Key? key}) +class MultipleFuturesExampleViewRoute extends _i12.PageRouteInfo { + const MultipleFuturesExampleViewRoute() : super( MultipleFuturesExampleViewRoute.name, path: 'multiple-futures-example-view', - args: MultipleFuturesExampleViewArgs(key: key), ); static const String name = 'MultipleFuturesExampleView'; } -class MultipleFuturesExampleViewArgs { - const MultipleFuturesExampleViewArgs({this.key}); - - final _i13.Key? key; - - @override - String toString() { - return 'MultipleFuturesExampleViewArgs{key: $key}'; - } -} - extension RouterStateExtension on _i11.RouterService { Future navigateToHomeView({ _i13.Key? key, String? title = 'hello', bool? isLoggedIn = false, - _i15.Clashable Function(String)? clashableGetter, + _i14.Clashable Function(String)? clashableGetter, List<_i1.HomeType> homeTypes = const [ _i1.HomeType.apartment, - _i1.HomeType.house, + _i1.HomeType.house ], void Function(_i12.NavigationFailure)? onFailure, }) async { @@ -460,40 +414,48 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future navigateToBottomNavExample({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return navigateTo(BottomNavExampleRoute(key: key), onFailure: onFailure); + Future navigateToBottomNavExample( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return navigateTo( + const BottomNavExampleRoute(), + onFailure: onFailure, + ); } Future navigateToStreamCounterView({ _i13.Key? key, - required List<_i16.Clashable> clashableTwo, + required List<_i15.Clashable> clashableTwo, void Function(_i12.NavigationFailure)? onFailure, }) async { return navigateTo( - StreamCounterViewRoute(key: key, clashableTwo: clashableTwo), + StreamCounterViewRoute( + key: key, + clashableTwo: clashableTwo, + ), onFailure: onFailure, ); } Future navigateToExampleFormView({ _i13.Key? key, - required _i15.Clashable clashableOne, + required _i14.Clashable clashableOne, void Function(_i12.NavigationFailure)? onFailure, }) async { return navigateTo( - ExampleFormViewRoute(key: key, clashableOne: clashableOne), + ExampleFormViewRoute( + key: key, + clashableOne: clashableOne, + ), onFailure: onFailure, ); } - Future navigateToNonReactiveView({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return navigateTo(NonReactiveViewRoute(key: key), onFailure: onFailure); + Future navigateToNonReactiveView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return navigateTo( + const NonReactiveViewRoute(), + onFailure: onFailure, + ); } Future navigateToFavoritesView({ @@ -502,51 +464,46 @@ extension RouterStateExtension on _i11.RouterService { void Function(_i12.NavigationFailure)? onFailure, }) async { return navigateTo( - FavoritesViewRoute(key: key, id: id), + FavoritesViewRoute( + key: key, + id: id, + ), onFailure: onFailure, ); } - Future navigateToNestedHistoryViewInBottomNavExampleRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return navigateTo(HistoryViewRoute(key: key), onFailure: onFailure); - } - - Future navigateToNestedProfileViewInBottomNavExampleRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return navigateTo(ProfileViewRoute(key: key), onFailure: onFailure); + Future navigateToHistoryView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return navigateTo( + const HistoryViewRoute(), + onFailure: onFailure, + ); } - Future - navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { + Future navigateToProfileView( + {void Function(_i12.NavigationFailure)? onFailure}) async { return navigateTo( - MultipleFuturesExampleViewRoute(key: key), + const ProfileViewRoute(), onFailure: onFailure, ); } - Future navigateToNestedHistoryViewInFavoritesViewRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return navigateTo(HistoryViewRoute(key: key), onFailure: onFailure); + Future navigateToMultipleFuturesExampleView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return navigateTo( + const MultipleFuturesExampleViewRoute(), + onFailure: onFailure, + ); } Future replaceWithHomeView({ _i13.Key? key, String? title = 'hello', bool? isLoggedIn = false, - _i15.Clashable Function(String)? clashableGetter, + _i14.Clashable Function(String)? clashableGetter, List<_i1.HomeType> homeTypes = const [ _i1.HomeType.apartment, - _i1.HomeType.house, + _i1.HomeType.house ], void Function(_i12.NavigationFailure)? onFailure, }) async { @@ -562,40 +519,48 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future replaceWithBottomNavExample({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return replaceWith(BottomNavExampleRoute(key: key), onFailure: onFailure); + Future replaceWithBottomNavExample( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return replaceWith( + const BottomNavExampleRoute(), + onFailure: onFailure, + ); } Future replaceWithStreamCounterView({ _i13.Key? key, - required List<_i16.Clashable> clashableTwo, + required List<_i15.Clashable> clashableTwo, void Function(_i12.NavigationFailure)? onFailure, }) async { return replaceWith( - StreamCounterViewRoute(key: key, clashableTwo: clashableTwo), + StreamCounterViewRoute( + key: key, + clashableTwo: clashableTwo, + ), onFailure: onFailure, ); } Future replaceWithExampleFormView({ _i13.Key? key, - required _i15.Clashable clashableOne, + required _i14.Clashable clashableOne, void Function(_i12.NavigationFailure)? onFailure, }) async { return replaceWith( - ExampleFormViewRoute(key: key, clashableOne: clashableOne), + ExampleFormViewRoute( + key: key, + clashableOne: clashableOne, + ), onFailure: onFailure, ); } - Future replaceWithNonReactiveView({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return replaceWith(NonReactiveViewRoute(key: key), onFailure: onFailure); + Future replaceWithNonReactiveView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return replaceWith( + const NonReactiveViewRoute(), + onFailure: onFailure, + ); } Future replaceWithFavoritesView({ @@ -604,40 +569,35 @@ extension RouterStateExtension on _i11.RouterService { void Function(_i12.NavigationFailure)? onFailure, }) async { return replaceWith( - FavoritesViewRoute(key: key, id: id), + FavoritesViewRoute( + key: key, + id: id, + ), onFailure: onFailure, ); } - Future replaceWithNestedHistoryViewInBottomNavExampleRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return replaceWith(HistoryViewRoute(key: key), onFailure: onFailure); - } - - Future replaceWithNestedProfileViewInBottomNavExampleRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return replaceWith(ProfileViewRoute(key: key), onFailure: onFailure); + Future replaceWithHistoryView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return replaceWith( + const HistoryViewRoute(), + onFailure: onFailure, + ); } - Future - replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { + Future replaceWithProfileView( + {void Function(_i12.NavigationFailure)? onFailure}) async { return replaceWith( - MultipleFuturesExampleViewRoute(key: key), + const ProfileViewRoute(), onFailure: onFailure, ); } - Future replaceWithNestedHistoryViewInFavoritesViewRouter({ - _i13.Key? key, - void Function(_i12.NavigationFailure)? onFailure, - }) async { - return replaceWith(HistoryViewRoute(key: key), onFailure: onFailure); + Future replaceWithMultipleFuturesExampleView( + {void Function(_i12.NavigationFailure)? onFailure}) async { + return replaceWith( + const MultipleFuturesExampleViewRoute(), + onFailure: onFailure, + ); } } diff --git a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart index f990d00fd..00a859056 100644 --- a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart +++ b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -7,6 +6,7 @@ // ignore_for_file: public_member_api_docs, constant_identifier_names, non_constant_identifier_names,unnecessary_this +import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; const String CountryValueKey = 'country'; @@ -31,7 +31,7 @@ final Map ProvinceValueToTitleMap = { mixin $SelectLocationView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormStateHelper model) {} + void syncFormWithViewModel(FormViewModel model) {} /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values @@ -47,16 +47,9 @@ mixin $SelectLocationView { } } -extension ValueProperties on FormStateHelper { - bool get hasAnyValidationMessage => this - .fieldsValidationMessages - .values - .any((validation) => validation != null); - - bool get isFormValid { - return !hasAnyValidationMessage; - } - +extension ValueProperties on FormViewModel { + bool get isFormValid => + this.fieldsValidationMessages.values.every((element) => element == null); String? get countryValue => this.formValueMap[CountryValueKey] as String?; String? get provinceValue => this.formValueMap[ProvinceValueKey] as String?; @@ -74,22 +67,18 @@ extension ValueProperties on FormStateHelper { this.fieldsValidationMessages[ProvinceValueKey]; } -extension Methods on FormStateHelper { +extension Methods on FormViewModel { void setCountry(String country) { - this.setData( - this.formValueMap..addAll({CountryValueKey: country}), - ); + this.setData(this.formValueMap..addAll({CountryValueKey: country})); } void setProvince(String province) { - this.setData( - this.formValueMap..addAll({ProvinceValueKey: province}), - ); + this.setData(this.formValueMap..addAll({ProvinceValueKey: province})); } - void setCountryValidationMessage(String? validationMessage) => + setCountryValidationMessage(String? validationMessage) => this.fieldsValidationMessages[CountryValueKey] = validationMessage; - void setProvinceValidationMessage(String? validationMessage) => + setProvinceValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ProvinceValueKey] = validationMessage; /// Clears text input fields on the Form diff --git a/example/router_example/lib/ui/form/example_form_view.form.dart b/example/router_example/lib/ui/form/example_form_view.form.dart index 3404cac66..145785780 100644 --- a/example/router_example/lib/ui/form/example_form_view.form.dart +++ b/example/router_example/lib/ui/form/example_form_view.form.dart @@ -1,4 +1,3 @@ -// dart format width=80 // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** @@ -12,8 +11,6 @@ import 'package:example/ui/form/validators.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; -const bool _autoTextFieldValidation = false; - const String EmailValueKey = 'email'; const String PasswordValueKey = 'password'; const String ShortBioValueKey = 'shortBio'; @@ -39,30 +36,14 @@ final Map _ExampleFormViewTextValidations = mixin $ExampleFormView { TextEditingController get emailController => - _getFormTextEditingController(EmailValueKey, initialValue: 'lorem@test.com'); + _getFormTextEditingController(EmailValueKey, + initialValue: 'lorem@test.com'); CustomEditingController get passwordController => - _getPasswordCustomFormTextEditingController(PasswordValueKey); + _getCustomFormTextEditingController(PasswordValueKey); CustomEditingController get shortBioController => - _getShortBioCustomFormTextEditingController(ShortBioValueKey); - - FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey); - FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey); - FocusNode get shortBioFocusNode => _getFormFocusNode(ShortBioValueKey); - - TextEditingController _getFormTextEditingController( - String key, { - String? initialValue, - }) { - if (_ExampleFormViewTextEditingControllers.containsKey(key)) { - return _ExampleFormViewTextEditingControllers[key]!; - } + _getCustomFormTextEditingController(ShortBioValueKey); - _ExampleFormViewTextEditingControllers[key] = - TextEditingController(text: initialValue); - return _ExampleFormViewTextEditingControllers[key]!; - } - - CustomEditingController _getPasswordCustomFormTextEditingController( + CustomEditingController _getCustomFormTextEditingController( String key, ) { if (_ExampleFormViewTextEditingControllers.containsKey(key)) { @@ -75,17 +56,21 @@ mixin $ExampleFormView { as CustomEditingController; } - CustomEditingController _getShortBioCustomFormTextEditingController( - String key, - ) { + FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey); + FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey); + FocusNode get shortBioFocusNode => _getFormFocusNode(ShortBioValueKey); + + TextEditingController _getFormTextEditingController( + String key, { + String? initialValue, + }) { if (_ExampleFormViewTextEditingControllers.containsKey(key)) { - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; + return _ExampleFormViewTextEditingControllers[key]!; } + _ExampleFormViewTextEditingControllers[key] = - CustomEditingController.getCustomEditingController(); - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; + TextEditingController(text: initialValue); + return _ExampleFormViewTextEditingControllers[key]!; } FocusNode _getFormFocusNode(String key) { @@ -98,12 +83,10 @@ mixin $ExampleFormView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormStateHelper model) { + void syncFormWithViewModel(FormViewModel model) { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); - - _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Registers a listener on every generated controller that calls [model.setData()] @@ -116,12 +99,16 @@ mixin $ExampleFormView { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); + } - _updateFormData(model, forceValidate: _autoTextFieldValidation); + static const bool _autoTextFieldValidation = false; + bool validateFormFields(FormViewModel model) { + _updateFormData(model, forceValidate: true); + return model.isFormValid; } /// Updates the formData on the FormViewModel - void _updateFormData(FormStateHelper model, {bool forceValidate = false}) { + void _updateFormData(FormViewModel model, {bool forceValidate = false}) { model.setData( model.formValueMap ..addAll({ @@ -136,11 +123,6 @@ mixin $ExampleFormView { } } - bool validateFormFields(FormViewModel model) { - _updateFormData(model, forceValidate: true); - return model.isFormValid; - } - /// Calls dispose on all the generated controllers and focus nodes void disposeForm() { // The dispose function for a TextEditingController sets all listeners to null @@ -157,18 +139,9 @@ mixin $ExampleFormView { } } -extension ValueProperties on FormStateHelper { - bool get hasAnyValidationMessage => this - .fieldsValidationMessages - .values - .any((validation) => validation != null); - - bool get isFormValid { - if (!_autoTextFieldValidation) this.validateForm(); - - return !hasAnyValidationMessage; - } - +extension ValueProperties on FormViewModel { + bool get isFormValid => + this.fieldsValidationMessages.values.every((element) => element == null); String? get emailValue => this.formValueMap[EmailValueKey] as String?; String? get passwordValue => this.formValueMap[PasswordValueKey] as String?; String? get shortBioValue => this.formValueMap[ShortBioValueKey] as String?; @@ -179,7 +152,10 @@ extension ValueProperties on FormStateHelper { set emailValue(String? value) { this.setData( - this.formValueMap..addAll({EmailValueKey: value}), + this.formValueMap + ..addAll({ + EmailValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(EmailValueKey)) { @@ -189,7 +165,10 @@ extension ValueProperties on FormStateHelper { set passwordValue(String? value) { this.setData( - this.formValueMap..addAll({PasswordValueKey: value}), + this.formValueMap + ..addAll({ + PasswordValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(PasswordValueKey)) { @@ -200,7 +179,10 @@ extension ValueProperties on FormStateHelper { set shortBioValue(String? value) { this.setData( - this.formValueMap..addAll({ShortBioValueKey: value}), + this.formValueMap + ..addAll({ + ShortBioValueKey: value, + }), ); if (_ExampleFormViewTextEditingControllers.containsKey(ShortBioValueKey)) { @@ -245,46 +227,37 @@ extension ValueProperties on FormStateHelper { this.fieldsValidationMessages[DoYouLoveFoodValueKey]; } -extension Methods on FormStateHelper { - Future selectBirthDate({ - required BuildContext context, - required DateTime initialDate, - required DateTime firstDate, - required DateTime lastDate, - }) async { +extension Methods on FormViewModel { + Future selectBirthDate( + {required BuildContext context, + required DateTime initialDate, + required DateTime firstDate, + required DateTime lastDate}) async { final selectedDate = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate, - ); - + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate); if (selectedDate != null) { this.setData( - this.formValueMap..addAll({BirthDateValueKey: selectedDate}), - ); + this.formValueMap..addAll({BirthDateValueKey: selectedDate})); } - - if (_autoTextFieldValidation) this.validateForm(); } void setDoYouLoveFood(String doYouLoveFood) { this.setData( - this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood}), - ); - - if (_autoTextFieldValidation) this.validateForm(); + this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood})); } - void setEmailValidationMessage(String? validationMessage) => + setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - void setPasswordValidationMessage(String? validationMessage) => + setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - void setShortBioValidationMessage(String? validationMessage) => + setShortBioValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ShortBioValueKey] = validationMessage; - void setBirthDateValidationMessage(String? validationMessage) => + setBirthDateValidationMessage(String? validationMessage) => this.fieldsValidationMessages[BirthDateValueKey] = validationMessage; - void setDoYouLoveFoodValidationMessage(String? validationMessage) => + setDoYouLoveFoodValidationMessage(String? validationMessage) => this.fieldsValidationMessages[DoYouLoveFoodValueKey] = validationMessage; /// Clears text input fields on the Form @@ -317,8 +290,7 @@ String? getValidationMessage(String key) { } /// Updates the fieldsValidationMessages on the FormViewModel -void updateValidationData(FormStateHelper model) => - model.setValidationMessages({ +void updateValidationData(FormViewModel model) => model.setValidationMessages({ EmailValueKey: getValidationMessage(EmailValueKey), PasswordValueKey: getValidationMessage(PasswordValueKey), ShortBioValueKey: getValidationMessage(ShortBioValueKey), diff --git a/example/router_example/lib/ui/form/example_form_viewmodel.dart b/example/router_example/lib/ui/form/example_form_viewmodel.dart index e0858e3a8..2def7b478 100644 --- a/example/router_example/lib/ui/form/example_form_viewmodel.dart +++ b/example/router_example/lib/ui/form/example_form_viewmodel.dart @@ -37,6 +37,9 @@ class ExampleFormViewModel extends FormViewModel { // data to the backend or db. Future saveData() async { + // Run the field validators before checking validity. Newer generated forms + // no longer validate implicitly inside `isFormValid`. + validateForm(); if (!isFormValid) return; // here we can run custom functionality to save to our api From 95160eef124b34e0bf4c5903bbade403760a6a0a Mon Sep 17 00:00:00 2001 From: Fernando Ferrara Date: Mon, 22 Jun 2026 12:58:47 -0300 Subject: [PATCH 3/4] chore(examples): adopt stacked_generator 2.0.4, restore logger 2.x Instead of patching the stale local generator (1.3.3), update the local path dependencies to their current releases and regenerate against them: - stacked_generator 1.3.3 -> 2.0.4 (already has InitializableSingleton, factory-param detection, and dedup fixes for analyzer 14) - stacked_crashlytics -> 0.2.2 (logger ^2.5.0), which resolves the logger 1.x/2.x conflict that previously forced logger 1.4.0 With logger now resolving to 2.x, revert the interim 1.x API workarounds: - example_form_viewmodel: log.f (was log.wtf) - shared_preferences_service: _log.t (was _log.v) - app.logger.dart regenerates to the 2.x PrettyPrinter API Both example integration tests pass end-to-end against the updated toolchain. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01NbVU8hfegQuqXaszwsmjji --- .../lib/app/app.bottomsheets.dart | 1 + .../lib/app/app.dialogs.dart | 1 + .../lib/app/app.locator.dart | 7 +- .../navigator_example/lib/app/app.logger.dart | 28 ++- .../navigator_example/lib/app/app.router.dart | 213 +++++++++++++--- .../select_location_view.form.dart | 30 ++- .../lib/ui/form/example_form_view.form.dart | 126 +++++----- .../lib/app/app.bottomsheets.dart | 1 + .../router_example/lib/app/app.dialogs.dart | 1 + .../router_example/lib/app/app.locator.dart | 10 +- .../router_example/lib/app/app.logger.dart | 28 ++- .../router_example/lib/app/app.router.dart | 232 ++++++++++++++---- .../services/shared_preferences_service.dart | 4 +- .../select_location_view.form.dart | 30 ++- .../lib/ui/form/example_form_view.form.dart | 141 ++++++----- .../lib/ui/form/example_form_viewmodel.dart | 2 +- 16 files changed, 618 insertions(+), 237 deletions(-) diff --git a/example/navigator_example/lib/app/app.bottomsheets.dart b/example/navigator_example/lib/app/app.bottomsheets.dart index df8a623d9..6ea1d2fcd 100644 --- a/example/navigator_example/lib/app/app.bottomsheets.dart +++ b/example/navigator_example/lib/app/app.bottomsheets.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedBottomsheetGenerator diff --git a/example/navigator_example/lib/app/app.dialogs.dart b/example/navigator_example/lib/app/app.dialogs.dart index ae7251eba..587f9fbb0 100644 --- a/example/navigator_example/lib/app/app.dialogs.dart +++ b/example/navigator_example/lib/app/app.dialogs.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedDialogGenerator diff --git a/example/navigator_example/lib/app/app.locator.dart b/example/navigator_example/lib/app/app.locator.dart index c4c9b215a..0563bf448 100644 --- a/example/navigator_example/lib/app/app.locator.dart +++ b/example/navigator_example/lib/app/app.locator.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedLocatorGenerator @@ -20,10 +21,8 @@ import '../ui/bottom_nav/history/history_viewmodel.dart'; final exampleLocator = StackedLocator.instance; -Future setupExampleLocator({ - String? environment, - EnvironmentFilter? environmentFilter, -}) async { +Future setupExampleLocator( + {String? environment, EnvironmentFilter? environmentFilter}) async { // Register environments exampleLocator.registerEnvironment( environment: environment, environmentFilter: environmentFilter); diff --git a/example/navigator_example/lib/app/app.logger.dart b/example/navigator_example/lib/app/app.logger.dart index 26ab3f947..c3a3830ad 100644 --- a/example/navigator_example/lib/app/app.logger.dart +++ b/example/navigator_example/lib/app/app.logger.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedLoggerGenerator @@ -6,9 +7,9 @@ // ignore_for_file: avoid_print, depend_on_referenced_packages -/// Maybe this should be generated for the user as well? -/// -/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; +// Maybe this should be generated for the user as well? +// +// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; @@ -27,21 +28,28 @@ class SimpleLogPrinter extends LogPrinter { this.showOnlyClass, }); + final printer = PrettyPrinter( + levelColors: PrettyPrinter.defaultLevelColors, + levelEmojis: PrettyPrinter.defaultLevelEmojis, + ); @override List log(LogEvent event) { - var color = PrettyPrinter.levelColors[event.level]; - var emoji = PrettyPrinter.levelEmojis[event.level]; + var color = PrettyPrinter.defaultLevelColors[event.level]; + var emoji = PrettyPrinter.defaultLevelEmojis[event.level]; var methodName = _getMethodName(); var methodNameSection = printCallingFunctionName && methodName != null ? ' | $methodName' : ''; - var stackLog = event.stackTrace.toString(); + var stackLog = event.stackTrace?.toString() ?? ''; var output = '$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}'; - if (exludeLogsFromClasses - .any((excludeClass) => className == excludeClass) || - (showOnlyClass != null && className != showOnlyClass)) return []; + if (exludeLogsFromClasses.any( + (excludeClass) => className == excludeClass, + ) || + (showOnlyClass != null && className != showOnlyClass)) { + return []; + } final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk List result = []; @@ -51,7 +59,7 @@ class SimpleLogPrinter extends LogPrinter { if (kReleaseMode) { return match.group(0)!; } else { - return color!(match.group(0)!); + return color != null ? color(match.group(0)!) : match.group(0)!; } })); } diff --git a/example/navigator_example/lib/app/app.router.dart b/example/navigator_example/lib/app/app.router.dart index 2279636f3..ea5cb1a1c 100644 --- a/example/navigator_example/lib/app/app.router.dart +++ b/example/navigator_example/lib/app/app.router.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedNavigatorGenerator @@ -85,8 +86,11 @@ class StackedRouter extends _i2.RouterBase { ); }, _i4.BottomNavExample: (data) { + final args = data.getArgs( + orElse: () => const BottomNavExampleArguments(), + ); return _i8.MaterialPageRoute( - builder: (context) => const _i4.BottomNavExample(), + builder: (context) => _i4.BottomNavExample(key: args.key), settings: data, ); }, @@ -107,9 +111,12 @@ class StackedRouter extends _i2.RouterBase { ); }, _i7.NonReactiveView: (data) { + final args = data.getArgs( + orElse: () => const NonReactiveViewArguments(), + ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - const _i7.NonReactiveView(), + _i7.NonReactiveView(key: args.key), settings: data, transitionsBuilder: data.transition ?? _i9.CustomRouteTransition.sharedAxis, @@ -168,6 +175,28 @@ class HomeViewArguments { } } +class BottomNavExampleArguments { + const BottomNavExampleArguments({this.key}); + + final _i8.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant BottomNavExampleArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class StreamCounterViewArguments { const StreamCounterViewArguments({ this.key, @@ -222,6 +251,28 @@ class ExampleFormViewArguments { } } +class NonReactiveViewArguments { + const NonReactiveViewArguments({this.key}); + + final _i8.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant NonReactiveViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class BottomNavExampleRoutes { static const historyView = 'history-view'; @@ -254,9 +305,12 @@ class BottomNavExampleRouter extends _i2.RouterBase { final _pagesMap = { _i12.HistoryView: (data) { + final args = data.getArgs( + orElse: () => const NestedHistoryViewArguments(), + ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - const _i12.HistoryView(), + _i12.HistoryView(key: args.key), settings: data, transitionsBuilder: data.transition ?? _i2.TransitionsBuilders.fadeIn, ); @@ -271,8 +325,11 @@ class BottomNavExampleRouter extends _i2.RouterBase { ); }, _i14.ProfileView: (data) { + final args = data.getArgs( + orElse: () => const NestedProfileViewArguments(), + ); return _i15.CupertinoPageRoute( - builder: (context) => const _i14.ProfileView(), + builder: (context) => _i14.ProfileView(key: args.key), settings: data, ); }, @@ -285,6 +342,28 @@ class BottomNavExampleRouter extends _i2.RouterBase { Map get pagesMap => _pagesMap; } +class NestedHistoryViewArguments { + const NestedHistoryViewArguments({this.key}); + + final _i8.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant NestedHistoryViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class FavoritesViewArguments { const FavoritesViewArguments({ this.key, @@ -312,6 +391,28 @@ class FavoritesViewArguments { } } +class NestedProfileViewArguments { + const NestedProfileViewArguments({this.key}); + + final _i8.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant NestedProfileViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class FavoritesViewRoutes { static const multipleFuturesExampleView = 'multiple-futures-example-view'; @@ -337,15 +438,21 @@ class FavoritesViewRouter extends _i2.RouterBase { final _pagesMap = { _i16.MultipleFuturesExampleView: (data) { + final args = data.getArgs( + orElse: () => const NestedMultipleFuturesExampleViewArguments(), + ); return _i8.MaterialPageRoute( - builder: (context) => const _i16.MultipleFuturesExampleView(), + builder: (context) => _i16.MultipleFuturesExampleView(key: args.key), settings: data, ); }, _i12.HistoryView: (data) { + final args = data.getArgs( + orElse: () => const NestedHistoryViewArguments(), + ); return _i8.PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => - const _i12.HistoryView(), + _i12.HistoryView(key: args.key), settings: data, transitionsBuilder: data.transition ?? (context, animation, secondaryAnimation, child) { @@ -362,6 +469,28 @@ class FavoritesViewRouter extends _i2.RouterBase { Map get pagesMap => _pagesMap; } +class NestedMultipleFuturesExampleViewArguments { + const NestedMultipleFuturesExampleViewArguments({this.key}); + + final _i8.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant NestedMultipleFuturesExampleViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + extension NavigatorStateExtension on _i17.NavigationService { Future navigateToHomeView({ _i8.Key? key, @@ -391,14 +520,16 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future navigateToBottomNavExample([ + Future navigateToBottomNavExample({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.bottomNavExample, + arguments: BottomNavExampleArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -441,28 +572,32 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future navigateToNonReactiveView([ + Future navigateToNonReactiveView({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.nonReactiveView, + arguments: NonReactiveViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToNestedHistoryViewInBottomNavExampleRouter([ + Future navigateToNestedHistoryViewInBottomNavExampleRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(BottomNavExampleRoutes.historyView, + arguments: NestedHistoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -486,14 +621,16 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future navigateToNestedProfileViewInBottomNavExampleRouter([ + Future navigateToNestedProfileViewInBottomNavExampleRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(BottomNavExampleRoutes.profileView, + arguments: NestedProfileViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -501,28 +638,32 @@ extension NavigatorStateExtension on _i17.NavigationService { } Future - navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter([ + navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(FavoritesViewRoutes.multipleFuturesExampleView, + arguments: NestedMultipleFuturesExampleViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToNestedHistoryViewInFavoritesViewRouter([ + Future navigateToNestedHistoryViewInFavoritesViewRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(FavoritesViewRoutes.historyView, + arguments: NestedHistoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -557,14 +698,16 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future replaceWithBottomNavExample([ + Future replaceWithBottomNavExample({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.bottomNavExample, + arguments: BottomNavExampleArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -607,28 +750,32 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future replaceWithNonReactiveView([ + Future replaceWithNonReactiveView({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.nonReactiveView, + arguments: NonReactiveViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithNestedHistoryViewInBottomNavExampleRouter([ + Future replaceWithNestedHistoryViewInBottomNavExampleRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(BottomNavExampleRoutes.historyView, + arguments: NestedHistoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -652,14 +799,16 @@ extension NavigatorStateExtension on _i17.NavigationService { transition: transition); } - Future replaceWithNestedProfileViewInBottomNavExampleRouter([ + Future replaceWithNestedProfileViewInBottomNavExampleRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(BottomNavExampleRoutes.profileView, + arguments: NestedProfileViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -667,28 +816,32 @@ extension NavigatorStateExtension on _i17.NavigationService { } Future - replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter([ + replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(FavoritesViewRoutes.multipleFuturesExampleView, + arguments: NestedMultipleFuturesExampleViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithNestedHistoryViewInFavoritesViewRouter([ + Future replaceWithNestedHistoryViewInFavoritesViewRouter({ + _i8.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(FavoritesViewRoutes.historyView, + arguments: NestedHistoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, diff --git a/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart b/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart index 00a859056..3391ac4f9 100644 --- a/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart +++ b/example/navigator_example/lib/ui/drop_down_menu_from/select_location_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -31,7 +32,7 @@ final Map ProvinceValueToTitleMap = { mixin $SelectLocationView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormViewModel model) {} + void syncFormWithViewModel(FormStateHelper model) {} /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values @@ -47,9 +48,16 @@ mixin $SelectLocationView { } } -extension ValueProperties on FormViewModel { - bool get isFormValid => - this.fieldsValidationMessages.values.every((element) => element == null); +extension ValueProperties on FormStateHelper { + bool get hasAnyValidationMessage => this + .fieldsValidationMessages + .values + .any((validation) => validation != null); + + bool get isFormValid { + return !hasAnyValidationMessage; + } + String? get countryValue => this.formValueMap[CountryValueKey] as String?; String? get provinceValue => this.formValueMap[ProvinceValueKey] as String?; @@ -67,18 +75,22 @@ extension ValueProperties on FormViewModel { this.fieldsValidationMessages[ProvinceValueKey]; } -extension Methods on FormViewModel { +extension Methods on FormStateHelper { void setCountry(String country) { - this.setData(this.formValueMap..addAll({CountryValueKey: country})); + this.setData( + this.formValueMap..addAll({CountryValueKey: country}), + ); } void setProvince(String province) { - this.setData(this.formValueMap..addAll({ProvinceValueKey: province})); + this.setData( + this.formValueMap..addAll({ProvinceValueKey: province}), + ); } - setCountryValidationMessage(String? validationMessage) => + void setCountryValidationMessage(String? validationMessage) => this.fieldsValidationMessages[CountryValueKey] = validationMessage; - setProvinceValidationMessage(String? validationMessage) => + void setProvinceValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ProvinceValueKey] = validationMessage; /// Clears text input fields on the Form diff --git a/example/navigator_example/lib/ui/form/example_form_view.form.dart b/example/navigator_example/lib/ui/form/example_form_view.form.dart index 5f98d5f4b..2475022c5 100644 --- a/example/navigator_example/lib/ui/form/example_form_view.form.dart +++ b/example/navigator_example/lib/ui/form/example_form_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -11,6 +12,8 @@ import 'package:example/ui/form/validators.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +const bool _autoTextFieldValidation = false; + const String EmailValueKey = 'email'; const String PasswordValueKey = 'password'; const String ShortBioValueKey = 'shortBio'; @@ -38,23 +41,10 @@ mixin $ExampleFormView { TextEditingController get emailController => _getFormTextEditingController(EmailValueKey, initialValue: 'Lorem'); CustomEditingController get passwordController => - _getCustomFormTextEditingController(PasswordValueKey); + _getPasswordCustomFormTextEditingController(PasswordValueKey); TextEditingController get shortBioController => _getFormTextEditingController(ShortBioValueKey); - CustomEditingController _getCustomFormTextEditingController( - String key, - ) { - if (_ExampleFormViewTextEditingControllers.containsKey(key)) { - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } - _ExampleFormViewTextEditingControllers[key] = - CustomEditingController.getCustomEditingController(); - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } - FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey); FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey); FocusNode get shortBioFocusNode => _getFormFocusNode(ShortBioValueKey); @@ -72,6 +62,19 @@ mixin $ExampleFormView { return _ExampleFormViewTextEditingControllers[key]!; } + CustomEditingController _getPasswordCustomFormTextEditingController( + String key, + ) { + if (_ExampleFormViewTextEditingControllers.containsKey(key)) { + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + _ExampleFormViewTextEditingControllers[key] = + CustomEditingController.getCustomEditingController(); + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + FocusNode _getFormFocusNode(String key) { if (_ExampleFormViewFocusNodes.containsKey(key)) { return _ExampleFormViewFocusNodes[key]!; @@ -82,10 +85,12 @@ mixin $ExampleFormView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormViewModel model) { + void syncFormWithViewModel(FormStateHelper model) { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); + + _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Registers a listener on every generated controller that calls [model.setData()] @@ -98,16 +103,12 @@ mixin $ExampleFormView { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); - } - static const bool _autoTextFieldValidation = false; - bool validateFormFields(FormViewModel model) { - _updateFormData(model, forceValidate: true); - return model.isFormValid; + _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Updates the formData on the FormViewModel - void _updateFormData(FormViewModel model, {bool forceValidate = false}) { + void _updateFormData(FormStateHelper model, {bool forceValidate = false}) { model.setData( model.formValueMap ..addAll({ @@ -122,6 +123,11 @@ mixin $ExampleFormView { } } + bool validateFormFields(FormViewModel model) { + _updateFormData(model, forceValidate: true); + return model.isFormValid; + } + /// Calls dispose on all the generated controllers and focus nodes void disposeForm() { // The dispose function for a TextEditingController sets all listeners to null @@ -138,9 +144,18 @@ mixin $ExampleFormView { } } -extension ValueProperties on FormViewModel { - bool get isFormValid => - this.fieldsValidationMessages.values.every((element) => element == null); +extension ValueProperties on FormStateHelper { + bool get hasAnyValidationMessage => this + .fieldsValidationMessages + .values + .any((validation) => validation != null); + + bool get isFormValid { + if (!_autoTextFieldValidation) this.validateForm(); + + return !hasAnyValidationMessage; + } + String? get emailValue => this.formValueMap[EmailValueKey] as String?; String? get passwordValue => this.formValueMap[PasswordValueKey] as String?; String? get shortBioValue => this.formValueMap[ShortBioValueKey] as String?; @@ -151,10 +166,7 @@ extension ValueProperties on FormViewModel { set emailValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - EmailValueKey: value, - }), + this.formValueMap..addAll({EmailValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(EmailValueKey)) { @@ -164,10 +176,7 @@ extension ValueProperties on FormViewModel { set passwordValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - PasswordValueKey: value, - }), + this.formValueMap..addAll({PasswordValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(PasswordValueKey)) { @@ -178,10 +187,7 @@ extension ValueProperties on FormViewModel { set shortBioValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - ShortBioValueKey: value, - }), + this.formValueMap..addAll({ShortBioValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(ShortBioValueKey)) { @@ -226,37 +232,46 @@ extension ValueProperties on FormViewModel { this.fieldsValidationMessages[DoYouLoveFoodValueKey]; } -extension Methods on FormViewModel { - Future selectBirthDate( - {required BuildContext context, - required DateTime initialDate, - required DateTime firstDate, - required DateTime lastDate}) async { +extension Methods on FormStateHelper { + Future selectBirthDate({ + required BuildContext context, + required DateTime initialDate, + required DateTime firstDate, + required DateTime lastDate, + }) async { final selectedDate = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate); + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + ); + if (selectedDate != null) { this.setData( - this.formValueMap..addAll({BirthDateValueKey: selectedDate})); + this.formValueMap..addAll({BirthDateValueKey: selectedDate}), + ); } + + if (_autoTextFieldValidation) this.validateForm(); } void setDoYouLoveFood(String doYouLoveFood) { this.setData( - this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood})); + this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood}), + ); + + if (_autoTextFieldValidation) this.validateForm(); } - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setPasswordValidationMessage(String? validationMessage) => + void setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - setShortBioValidationMessage(String? validationMessage) => + void setShortBioValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ShortBioValueKey] = validationMessage; - setBirthDateValidationMessage(String? validationMessage) => + void setBirthDateValidationMessage(String? validationMessage) => this.fieldsValidationMessages[BirthDateValueKey] = validationMessage; - setDoYouLoveFoodValidationMessage(String? validationMessage) => + void setDoYouLoveFoodValidationMessage(String? validationMessage) => this.fieldsValidationMessages[DoYouLoveFoodValueKey] = validationMessage; /// Clears text input fields on the Form @@ -282,14 +297,15 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _ExampleFormViewTextEditingControllers[key]!.text, + _ExampleFormViewTextEditingControllers[key]?.text, ); return validationMessageForKey; } /// Updates the fieldsValidationMessages on the FormViewModel -void updateValidationData(FormViewModel model) => model.setValidationMessages({ +void updateValidationData(FormStateHelper model) => + model.setValidationMessages({ EmailValueKey: getValidationMessage(EmailValueKey), PasswordValueKey: getValidationMessage(PasswordValueKey), ShortBioValueKey: getValidationMessage(ShortBioValueKey), diff --git a/example/router_example/lib/app/app.bottomsheets.dart b/example/router_example/lib/app/app.bottomsheets.dart index df8a623d9..6ea1d2fcd 100644 --- a/example/router_example/lib/app/app.bottomsheets.dart +++ b/example/router_example/lib/app/app.bottomsheets.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedBottomsheetGenerator diff --git a/example/router_example/lib/app/app.dialogs.dart b/example/router_example/lib/app/app.dialogs.dart index ae7251eba..587f9fbb0 100644 --- a/example/router_example/lib/app/app.dialogs.dart +++ b/example/router_example/lib/app/app.dialogs.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedDialogGenerator diff --git a/example/router_example/lib/app/app.locator.dart b/example/router_example/lib/app/app.locator.dart index 6923bf14c..2b3341461 100644 --- a/example/router_example/lib/app/app.locator.dart +++ b/example/router_example/lib/app/app.locator.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedLocatorGenerator @@ -24,11 +25,10 @@ import 'app.router.dart'; final exampleLocator = StackedLocator.instance; -Future setupExampleLocator({ - String? environment, - EnvironmentFilter? environmentFilter, - StackedRouterWeb? stackedRouter, -}) async { +Future setupExampleLocator( + {String? environment, + EnvironmentFilter? environmentFilter, + StackedRouterWeb? stackedRouter}) async { // Register environments exampleLocator.registerEnvironment( environment: environment, environmentFilter: environmentFilter); diff --git a/example/router_example/lib/app/app.logger.dart b/example/router_example/lib/app/app.logger.dart index 26ab3f947..c3a3830ad 100644 --- a/example/router_example/lib/app/app.logger.dart +++ b/example/router_example/lib/app/app.logger.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedLoggerGenerator @@ -6,9 +7,9 @@ // ignore_for_file: avoid_print, depend_on_referenced_packages -/// Maybe this should be generated for the user as well? -/// -/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; +// Maybe this should be generated for the user as well? +// +// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; @@ -27,21 +28,28 @@ class SimpleLogPrinter extends LogPrinter { this.showOnlyClass, }); + final printer = PrettyPrinter( + levelColors: PrettyPrinter.defaultLevelColors, + levelEmojis: PrettyPrinter.defaultLevelEmojis, + ); @override List log(LogEvent event) { - var color = PrettyPrinter.levelColors[event.level]; - var emoji = PrettyPrinter.levelEmojis[event.level]; + var color = PrettyPrinter.defaultLevelColors[event.level]; + var emoji = PrettyPrinter.defaultLevelEmojis[event.level]; var methodName = _getMethodName(); var methodNameSection = printCallingFunctionName && methodName != null ? ' | $methodName' : ''; - var stackLog = event.stackTrace.toString(); + var stackLog = event.stackTrace?.toString() ?? ''; var output = '$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}'; - if (exludeLogsFromClasses - .any((excludeClass) => className == excludeClass) || - (showOnlyClass != null && className != showOnlyClass)) return []; + if (exludeLogsFromClasses.any( + (excludeClass) => className == excludeClass, + ) || + (showOnlyClass != null && className != showOnlyClass)) { + return []; + } final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk List result = []; @@ -51,7 +59,7 @@ class SimpleLogPrinter extends LogPrinter { if (kReleaseMode) { return match.group(0)!; } else { - return color!(match.group(0)!); + return color != null ? color(match.group(0)!) : match.group(0)!; } })); } diff --git a/example/router_example/lib/app/app.router.dart b/example/router_example/lib/app/app.router.dart index 020f130d1..65c3bf7b3 100644 --- a/example/router_example/lib/app/app.router.dart +++ b/example/router_example/lib/app/app.router.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedRouterGenerator @@ -47,9 +48,11 @@ class StackedRouterWeb extends _i12.RootStackRouter { ); }, BottomNavExampleRoute.name: (routeData) { + final args = routeData.argsAs( + orElse: () => const BottomNavExampleArgs()); return _i12.MaterialPageX( routeData: routeData, - child: const _i3.BottomNavExample(), + child: _i3.BottomNavExample(key: args.key), ); }, StreamCounterViewRoute.name: (routeData) { @@ -73,9 +76,11 @@ class StackedRouterWeb extends _i12.RootStackRouter { ); }, NonReactiveViewRoute.name: (routeData) { + final args = routeData.argsAs( + orElse: () => const NonReactiveViewArgs()); return _i12.MaterialPageX( routeData: routeData, - child: const _i6.NonReactiveView(), + child: _i6.NonReactiveView(key: args.key), ); }, FavoritesViewRoute.name: (routeData) { @@ -91,23 +96,29 @@ class StackedRouterWeb extends _i12.RootStackRouter { ); }, HistoryViewRoute.name: (routeData) { + final args = routeData.argsAs( + orElse: () => const HistoryViewArgs()); return _i12.CustomPage( routeData: routeData, - child: const _i8.HistoryView(), + child: _i8.HistoryView(key: args.key), opaque: true, barrierDismissible: false, ); }, ProfileViewRoute.name: (routeData) { + final args = routeData.argsAs( + orElse: () => const ProfileViewArgs()); return _i12.CupertinoPageX( routeData: routeData, - child: const _i9.ProfileView(), + child: _i9.ProfileView(key: args.key), ); }, MultipleFuturesExampleViewRoute.name: (routeData) { + final args = routeData.argsAs( + orElse: () => const MultipleFuturesExampleViewArgs()); return _i12.MaterialPageX( routeData: routeData, - child: const _i10.MultipleFuturesExampleView(), + child: _i10.MultipleFuturesExampleView(key: args.key), ); }, }; @@ -227,17 +238,31 @@ class HomeViewArgs { /// generated route for /// [_i3.BottomNavExample] -class BottomNavExampleRoute extends _i12.PageRouteInfo { - const BottomNavExampleRoute({List<_i12.PageRouteInfo>? children}) - : super( +class BottomNavExampleRoute extends _i12.PageRouteInfo { + BottomNavExampleRoute({ + _i13.Key? key, + List<_i12.PageRouteInfo>? children, + }) : super( BottomNavExampleRoute.name, path: '/bottom-nav-example', + args: BottomNavExampleArgs(key: key), initialChildren: children, ); static const String name = 'BottomNavExample'; } +class BottomNavExampleArgs { + const BottomNavExampleArgs({this.key}); + + final _i13.Key? key; + + @override + String toString() { + return 'BottomNavExampleArgs{key: $key}'; + } +} + /// generated route for /// [_i4.StreamCounterView] class StreamCounterViewRoute extends _i12.PageRouteInfo { @@ -308,16 +333,28 @@ class ExampleFormViewArgs { /// generated route for /// [_i6.NonReactiveView] -class NonReactiveViewRoute extends _i12.PageRouteInfo { - const NonReactiveViewRoute() +class NonReactiveViewRoute extends _i12.PageRouteInfo { + NonReactiveViewRoute({_i13.Key? key}) : super( NonReactiveViewRoute.name, path: '/non-reactive-view', + args: NonReactiveViewArgs(key: key), ); static const String name = 'NonReactiveView'; } +class NonReactiveViewArgs { + const NonReactiveViewArgs({this.key}); + + final _i13.Key? key; + + @override + String toString() { + return 'NonReactiveViewArgs{key: $key}'; + } +} + /// generated route for /// [_i7.FavoritesView] class FavoritesViewRoute extends _i12.PageRouteInfo { @@ -356,40 +393,77 @@ class FavoritesViewArgs { /// generated route for /// [_i8.HistoryView] -class HistoryViewRoute extends _i12.PageRouteInfo { - const HistoryViewRoute() +class HistoryViewRoute extends _i12.PageRouteInfo { + HistoryViewRoute({_i13.Key? key}) : super( HistoryViewRoute.name, path: 'history-view', + args: HistoryViewArgs(key: key), ); static const String name = 'HistoryView'; } +class HistoryViewArgs { + const HistoryViewArgs({this.key}); + + final _i13.Key? key; + + @override + String toString() { + return 'HistoryViewArgs{key: $key}'; + } +} + /// generated route for /// [_i9.ProfileView] -class ProfileViewRoute extends _i12.PageRouteInfo { - const ProfileViewRoute() +class ProfileViewRoute extends _i12.PageRouteInfo { + ProfileViewRoute({_i13.Key? key}) : super( ProfileViewRoute.name, path: 'profile-view', + args: ProfileViewArgs(key: key), ); static const String name = 'ProfileView'; } +class ProfileViewArgs { + const ProfileViewArgs({this.key}); + + final _i13.Key? key; + + @override + String toString() { + return 'ProfileViewArgs{key: $key}'; + } +} + /// generated route for /// [_i10.MultipleFuturesExampleView] -class MultipleFuturesExampleViewRoute extends _i12.PageRouteInfo { - const MultipleFuturesExampleViewRoute() +class MultipleFuturesExampleViewRoute + extends _i12.PageRouteInfo { + MultipleFuturesExampleViewRoute({_i13.Key? key}) : super( MultipleFuturesExampleViewRoute.name, path: 'multiple-futures-example-view', + args: MultipleFuturesExampleViewArgs(key: key), ); static const String name = 'MultipleFuturesExampleView'; } +class MultipleFuturesExampleViewArgs { + const MultipleFuturesExampleViewArgs({this.key}); + + final _i13.Key? key; + + @override + String toString() { + return 'MultipleFuturesExampleViewArgs{key: $key}'; + } +} + extension RouterStateExtension on _i11.RouterService { Future navigateToHomeView({ _i13.Key? key, @@ -414,10 +488,14 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future navigateToBottomNavExample( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future navigateToBottomNavExample({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return navigateTo( - const BottomNavExampleRoute(), + BottomNavExampleRoute( + key: key, + ), onFailure: onFailure, ); } @@ -450,10 +528,14 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future navigateToNonReactiveView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future navigateToNonReactiveView({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return navigateTo( - const NonReactiveViewRoute(), + NonReactiveViewRoute( + key: key, + ), onFailure: onFailure, ); } @@ -472,26 +554,51 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future navigateToHistoryView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future navigateToNestedHistoryViewInBottomNavExampleRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { + return navigateTo( + HistoryViewRoute( + key: key, + ), + onFailure: onFailure, + ); + } + + Future navigateToNestedProfileViewInBottomNavExampleRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return navigateTo( - const HistoryViewRoute(), + ProfileViewRoute( + key: key, + ), onFailure: onFailure, ); } - Future navigateToProfileView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future + navigateToNestedMultipleFuturesExampleViewInFavoritesViewRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return navigateTo( - const ProfileViewRoute(), + MultipleFuturesExampleViewRoute( + key: key, + ), onFailure: onFailure, ); } - Future navigateToMultipleFuturesExampleView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future navigateToNestedHistoryViewInFavoritesViewRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return navigateTo( - const MultipleFuturesExampleViewRoute(), + HistoryViewRoute( + key: key, + ), onFailure: onFailure, ); } @@ -519,10 +626,14 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future replaceWithBottomNavExample( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future replaceWithBottomNavExample({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return replaceWith( - const BottomNavExampleRoute(), + BottomNavExampleRoute( + key: key, + ), onFailure: onFailure, ); } @@ -555,10 +666,14 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future replaceWithNonReactiveView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future replaceWithNonReactiveView({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return replaceWith( - const NonReactiveViewRoute(), + NonReactiveViewRoute( + key: key, + ), onFailure: onFailure, ); } @@ -577,26 +692,51 @@ extension RouterStateExtension on _i11.RouterService { ); } - Future replaceWithHistoryView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future replaceWithNestedHistoryViewInBottomNavExampleRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { + return replaceWith( + HistoryViewRoute( + key: key, + ), + onFailure: onFailure, + ); + } + + Future replaceWithNestedProfileViewInBottomNavExampleRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return replaceWith( - const HistoryViewRoute(), + ProfileViewRoute( + key: key, + ), onFailure: onFailure, ); } - Future replaceWithProfileView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future + replaceWithNestedMultipleFuturesExampleViewInFavoritesViewRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return replaceWith( - const ProfileViewRoute(), + MultipleFuturesExampleViewRoute( + key: key, + ), onFailure: onFailure, ); } - Future replaceWithMultipleFuturesExampleView( - {void Function(_i12.NavigationFailure)? onFailure}) async { + Future replaceWithNestedHistoryViewInFavoritesViewRouter({ + _i13.Key? key, + void Function(_i12.NavigationFailure)? onFailure, + }) async { return replaceWith( - const MultipleFuturesExampleViewRoute(), + HistoryViewRoute( + key: key, + ), onFailure: onFailure, ); } diff --git a/example/router_example/lib/services/shared_preferences_service.dart b/example/router_example/lib/services/shared_preferences_service.dart index 9497f8d0b..14912efe0 100644 --- a/example/router_example/lib/services/shared_preferences_service.dart +++ b/example/router_example/lib/services/shared_preferences_service.dart @@ -27,12 +27,12 @@ class SharedPreferencesService implements InitializableDependency { Object? getFromDisk(String key) { final value = _preferences.get(key); - if (enableLogs) _log.v('key:$key value:$value'); + if (enableLogs) _log.t('key:$key value:$value'); return value; } void saveToDisk(String key, dynamic content) { - if (enableLogs) _log.v('key:$key value:$content'); + if (enableLogs) _log.t('key:$key value:$content'); if (content is String) { _preferences.setString(key, content); diff --git a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart index 00a859056..3391ac4f9 100644 --- a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart +++ b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -31,7 +32,7 @@ final Map ProvinceValueToTitleMap = { mixin $SelectLocationView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormViewModel model) {} + void syncFormWithViewModel(FormStateHelper model) {} /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values @@ -47,9 +48,16 @@ mixin $SelectLocationView { } } -extension ValueProperties on FormViewModel { - bool get isFormValid => - this.fieldsValidationMessages.values.every((element) => element == null); +extension ValueProperties on FormStateHelper { + bool get hasAnyValidationMessage => this + .fieldsValidationMessages + .values + .any((validation) => validation != null); + + bool get isFormValid { + return !hasAnyValidationMessage; + } + String? get countryValue => this.formValueMap[CountryValueKey] as String?; String? get provinceValue => this.formValueMap[ProvinceValueKey] as String?; @@ -67,18 +75,22 @@ extension ValueProperties on FormViewModel { this.fieldsValidationMessages[ProvinceValueKey]; } -extension Methods on FormViewModel { +extension Methods on FormStateHelper { void setCountry(String country) { - this.setData(this.formValueMap..addAll({CountryValueKey: country})); + this.setData( + this.formValueMap..addAll({CountryValueKey: country}), + ); } void setProvince(String province) { - this.setData(this.formValueMap..addAll({ProvinceValueKey: province})); + this.setData( + this.formValueMap..addAll({ProvinceValueKey: province}), + ); } - setCountryValidationMessage(String? validationMessage) => + void setCountryValidationMessage(String? validationMessage) => this.fieldsValidationMessages[CountryValueKey] = validationMessage; - setProvinceValidationMessage(String? validationMessage) => + void setProvinceValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ProvinceValueKey] = validationMessage; /// Clears text input fields on the Form diff --git a/example/router_example/lib/ui/form/example_form_view.form.dart b/example/router_example/lib/ui/form/example_form_view.form.dart index 145785780..d5d63950c 100644 --- a/example/router_example/lib/ui/form/example_form_view.form.dart +++ b/example/router_example/lib/ui/form/example_form_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -11,6 +12,8 @@ import 'package:example/ui/form/validators.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +const bool _autoTextFieldValidation = false; + const String EmailValueKey = 'email'; const String PasswordValueKey = 'password'; const String ShortBioValueKey = 'shortBio'; @@ -39,22 +42,9 @@ mixin $ExampleFormView { _getFormTextEditingController(EmailValueKey, initialValue: 'lorem@test.com'); CustomEditingController get passwordController => - _getCustomFormTextEditingController(PasswordValueKey); + _getPasswordCustomFormTextEditingController(PasswordValueKey); CustomEditingController get shortBioController => - _getCustomFormTextEditingController(ShortBioValueKey); - - CustomEditingController _getCustomFormTextEditingController( - String key, - ) { - if (_ExampleFormViewTextEditingControllers.containsKey(key)) { - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } - _ExampleFormViewTextEditingControllers[key] = - CustomEditingController.getCustomEditingController(); - return _ExampleFormViewTextEditingControllers[key]! - as CustomEditingController; - } + _getShortBioCustomFormTextEditingController(ShortBioValueKey); FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey); FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey); @@ -73,6 +63,32 @@ mixin $ExampleFormView { return _ExampleFormViewTextEditingControllers[key]!; } + CustomEditingController _getPasswordCustomFormTextEditingController( + String key, + ) { + if (_ExampleFormViewTextEditingControllers.containsKey(key)) { + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + _ExampleFormViewTextEditingControllers[key] = + CustomEditingController.getCustomEditingController(); + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + + CustomEditingController _getShortBioCustomFormTextEditingController( + String key, + ) { + if (_ExampleFormViewTextEditingControllers.containsKey(key)) { + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + _ExampleFormViewTextEditingControllers[key] = + CustomEditingController.getCustomEditingController(); + return _ExampleFormViewTextEditingControllers[key]! + as CustomEditingController; + } + FocusNode _getFormFocusNode(String key) { if (_ExampleFormViewFocusNodes.containsKey(key)) { return _ExampleFormViewFocusNodes[key]!; @@ -83,10 +99,12 @@ mixin $ExampleFormView { /// Registers a listener on every generated controller that calls [model.setData()] /// with the latest textController values - void syncFormWithViewModel(FormViewModel model) { + void syncFormWithViewModel(FormStateHelper model) { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); + + _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Registers a listener on every generated controller that calls [model.setData()] @@ -99,16 +117,12 @@ mixin $ExampleFormView { emailController.addListener(() => _updateFormData(model)); passwordController.addListener(() => _updateFormData(model)); shortBioController.addListener(() => _updateFormData(model)); - } - static const bool _autoTextFieldValidation = false; - bool validateFormFields(FormViewModel model) { - _updateFormData(model, forceValidate: true); - return model.isFormValid; + _updateFormData(model, forceValidate: _autoTextFieldValidation); } /// Updates the formData on the FormViewModel - void _updateFormData(FormViewModel model, {bool forceValidate = false}) { + void _updateFormData(FormStateHelper model, {bool forceValidate = false}) { model.setData( model.formValueMap ..addAll({ @@ -123,6 +137,11 @@ mixin $ExampleFormView { } } + bool validateFormFields(FormViewModel model) { + _updateFormData(model, forceValidate: true); + return model.isFormValid; + } + /// Calls dispose on all the generated controllers and focus nodes void disposeForm() { // The dispose function for a TextEditingController sets all listeners to null @@ -139,9 +158,18 @@ mixin $ExampleFormView { } } -extension ValueProperties on FormViewModel { - bool get isFormValid => - this.fieldsValidationMessages.values.every((element) => element == null); +extension ValueProperties on FormStateHelper { + bool get hasAnyValidationMessage => this + .fieldsValidationMessages + .values + .any((validation) => validation != null); + + bool get isFormValid { + if (!_autoTextFieldValidation) this.validateForm(); + + return !hasAnyValidationMessage; + } + String? get emailValue => this.formValueMap[EmailValueKey] as String?; String? get passwordValue => this.formValueMap[PasswordValueKey] as String?; String? get shortBioValue => this.formValueMap[ShortBioValueKey] as String?; @@ -152,10 +180,7 @@ extension ValueProperties on FormViewModel { set emailValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - EmailValueKey: value, - }), + this.formValueMap..addAll({EmailValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(EmailValueKey)) { @@ -165,10 +190,7 @@ extension ValueProperties on FormViewModel { set passwordValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - PasswordValueKey: value, - }), + this.formValueMap..addAll({PasswordValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(PasswordValueKey)) { @@ -179,10 +201,7 @@ extension ValueProperties on FormViewModel { set shortBioValue(String? value) { this.setData( - this.formValueMap - ..addAll({ - ShortBioValueKey: value, - }), + this.formValueMap..addAll({ShortBioValueKey: value}), ); if (_ExampleFormViewTextEditingControllers.containsKey(ShortBioValueKey)) { @@ -227,37 +246,46 @@ extension ValueProperties on FormViewModel { this.fieldsValidationMessages[DoYouLoveFoodValueKey]; } -extension Methods on FormViewModel { - Future selectBirthDate( - {required BuildContext context, - required DateTime initialDate, - required DateTime firstDate, - required DateTime lastDate}) async { +extension Methods on FormStateHelper { + Future selectBirthDate({ + required BuildContext context, + required DateTime initialDate, + required DateTime firstDate, + required DateTime lastDate, + }) async { final selectedDate = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate); + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + ); + if (selectedDate != null) { this.setData( - this.formValueMap..addAll({BirthDateValueKey: selectedDate})); + this.formValueMap..addAll({BirthDateValueKey: selectedDate}), + ); } + + if (_autoTextFieldValidation) this.validateForm(); } void setDoYouLoveFood(String doYouLoveFood) { this.setData( - this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood})); + this.formValueMap..addAll({DoYouLoveFoodValueKey: doYouLoveFood}), + ); + + if (_autoTextFieldValidation) this.validateForm(); } - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setPasswordValidationMessage(String? validationMessage) => + void setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - setShortBioValidationMessage(String? validationMessage) => + void setShortBioValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ShortBioValueKey] = validationMessage; - setBirthDateValidationMessage(String? validationMessage) => + void setBirthDateValidationMessage(String? validationMessage) => this.fieldsValidationMessages[BirthDateValueKey] = validationMessage; - setDoYouLoveFoodValidationMessage(String? validationMessage) => + void setDoYouLoveFoodValidationMessage(String? validationMessage) => this.fieldsValidationMessages[DoYouLoveFoodValueKey] = validationMessage; /// Clears text input fields on the Form @@ -283,14 +311,15 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _ExampleFormViewTextEditingControllers[key]!.text, + _ExampleFormViewTextEditingControllers[key]?.text, ); return validationMessageForKey; } /// Updates the fieldsValidationMessages on the FormViewModel -void updateValidationData(FormViewModel model) => model.setValidationMessages({ +void updateValidationData(FormStateHelper model) => + model.setValidationMessages({ EmailValueKey: getValidationMessage(EmailValueKey), PasswordValueKey: getValidationMessage(PasswordValueKey), ShortBioValueKey: getValidationMessage(ShortBioValueKey), diff --git a/example/router_example/lib/ui/form/example_form_viewmodel.dart b/example/router_example/lib/ui/form/example_form_viewmodel.dart index 2def7b478..ea78ed762 100644 --- a/example/router_example/lib/ui/form/example_form_viewmodel.dart +++ b/example/router_example/lib/ui/form/example_form_viewmodel.dart @@ -14,7 +14,7 @@ class ExampleFormViewModel extends FormViewModel { final _preferences = exampleLocator(); ExampleFormViewModel() { - log.wtf('hash:${_preferences.hashCode}'); + log.f('hash:${_preferences.hashCode}'); } void populateForm() { From 164aaa8180a23c36c74669760d2b6c14f4f4d096 Mon Sep 17 00:00:00 2001 From: Fernando Ferrara Date: Mon, 22 Jun 2026 13:15:34 -0300 Subject: [PATCH 4/4] chore(examples): drop unused get dependency for stacked_services PR #46 Removes the leftover `get: ^4.6.3` direct dependency from both example apps. stacked_services (Stacked-Org/services#46) reimplements all services on native Flutter APIs and removes get, and neither example imports package:get directly. Integration tests pass on both apps. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_019CMCmDQ72hkkmvGnsSu8n9 --- example/navigator_example/pubspec.yaml | 1 - example/router_example/pubspec.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/example/navigator_example/pubspec.yaml b/example/navigator_example/pubspec.yaml index 8c89cd7a6..9e589d738 100644 --- a/example/navigator_example/pubspec.yaml +++ b/example/navigator_example/pubspec.yaml @@ -35,7 +35,6 @@ dependencies: flutter_hooks: ^0.18.4 # navigation - get: ^4.6.3 animations: ^2.0.3 dependency_overrides: diff --git a/example/router_example/pubspec.yaml b/example/router_example/pubspec.yaml index 5ffc30b66..8315f7ef7 100644 --- a/example/router_example/pubspec.yaml +++ b/example/router_example/pubspec.yaml @@ -35,7 +35,6 @@ dependencies: flutter_hooks: ^0.18.4 # navigation - get: ^4.6.3 animations: ^2.0.3 url_strategy: ^0.2.0 shared_preferences: ^2.1.1