### Install Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Install the stacked_cli package globally on your machine to start using the CLI commands. ```bash dart pub global activate stacked_cli ``` -------------------------------- ### Multiple Streams Example ViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Demonstrates how to implement a MultipleStreamViewModel by overriding streamsMap to provide multiple streams with unique keys. Includes example streams for integers and strings. ```dart const String _NumbersStreamKey = 'numbers-stream'; const String _StringStreamKey = 'string-stream'; class MultipleStreamsExampleViewModel extends MultipleStreamViewModel { int numbersStreamDelay = 500; int stringStreamDelay = 2000; @override Map get streamsMap => { _NumbersStreamKey: StreamData(numbersStream(numbersStreamDelay)), _StringStreamKey: StreamData(stringStream(stringStreamDelay)), }; Stream numbersStream([int delay = 500]) async* { var random = Random(); while (true) { await Future.delayed(Duration(milliseconds: delay)); yield random.nextInt(999); } } Stream stringStream([int delay = 2000]) async* { var random = Random(); while (true) { await Future.delayed(Duration(milliseconds: delay)); var randomLength = random.nextInt(50); var randomString = ''; for (var i = 0; i < randomLength; i++) { randomString += String.fromCharCode(random.nextInt(50)); } yield randomString; } } } ``` -------------------------------- ### Stacked CLI Configuration File Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Example of a `stacked.json` file used to configure Stacked CLI paths and settings for custom project structures. ```json { "bottom_sheets_path": "lib/ui/custom_bottom_sheets", "dialogs_sheets_path": "lib/ui/custom_dialogs", "services_path": "lib/services/custom", "stacked_app_file_path": "lib/app/custom_app.dart", "test_helpers_file_path": "lib/helpers/custom_test_helpers.dart" } ``` -------------------------------- ### Activate Stacked CLI Source: https://stacked.filledstacks.com/docs/getting-started/overview Install the stacked_cli package globally using Dart pub to access Stacked development tools. ```bash dart pub global activate stacked_cli ``` -------------------------------- ### StreamCounterViewModel and StreamCounterView Example Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Demonstrates how to use StreamViewModel to listen to a stream of integers and display the data in a Flutter widget. Includes the ViewModel, the View, and a sample Service that provides the stream. ```dart class StreamCounterViewModel extends StreamViewModel { String get title => 'This is the time since epoch in seconds \n $data'; @override Stream get stream => locator().epochUpdatesNumbers(); } class StreamCounterView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( builder: (context, viewModel, child) => Scaffold( body: Center( child: Text(viewModel.title), ), ), viewModelBuilder: () => StreamCounterViewModel(), ); } } @lazySingleton class EpochService { Stream epochUpdatesNumbers() async* { while (true) { await Future.delayed(const Duration(seconds: 2)); yield DateTime.now().millisecondsSinceEpoch; } } } ``` -------------------------------- ### Minimal StreamViewModel Implementation Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Shows the essential two lines of code required to create a ViewModel that listens to a stream. This snippet focuses on the core setup for StreamViewModel. ```dart class StreamCounterViewModel extends StreamViewModel { @override Stream get stream => locator().epochUpdatesNumbers(); } ``` -------------------------------- ### Add a New Service Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Generate a new Service and add it to your application's dependency injection setup in app.dart. ```bash stacked create service stripe ``` -------------------------------- ### ViewModel with Direct HTTP Request and Deserialization Source: https://stacked.filledstacks.com/docs/in-depth/services This example shows a ViewModel directly handling HTTP requests, response validation, and data deserialization. It's an anti-pattern that violates the single responsibility principle. ```dart class HomeViewModel extends BaseViewModel { List _artists = []; Future fetchArtists() async { // #1: Structure the http request final response = await http.get(Uri.https('venu.is', '/artists')); // #2: Validate the request is successful if (response.statusCode < 400) { // #3: Convert the response into a map final responseBodyAsMap = jsonDecode(response.body); // #4: Get relevant data from the response final artistMaps = responseBodyAsMap['data'] as List>; // #5: Deserialize into a list of artists _artists = artistMaps.map(Artist.fromJson).toList(); } } } class Artist { final String name; final String coverImage; Artist({required this.name, required this.coverImage}); factory Artist.fromJson(Map data) => Artist( name: data['name'], coverImage: data['coverImage'], ); } ``` -------------------------------- ### HomeView with IndexTrackingViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Example of using IndexTrackingViewModel in a StatelessWidget to manage the current index for navigation, such as a bottom navigation bar. It integrates with ViewModelBuilder.reactive. ```dart class HomeView extends StatelessWidget { const HomeView({Key key}) : super(key: key); @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( builder: (context, viewModel, child) => Scaffold( body: getViewForIndex(viewModel.currentIndex), bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, backgroundColor: Colors.grey[800], currentIndex: viewModel.currentTabIndex, onTap: viewModel.setIndex, items: [ BottomNavigationBarItem( title: Text('Posts'), icon: Icon(Icons.art_track), ), BottomNavigationBarItem( title: Text('Todos'), icon: Icon(Icons.list), ), ], ), ), viewModelBuilder: () => HomeViewModel(), ); } Widget getViewForIndex(int index) { switch (index) { case 0: return PostsView(); case 1: return TodosView(); } } } ``` -------------------------------- ### Replace NavigationService with RouterService in app.dart Source: https://stacked.filledstacks.com/docs/stacked-router/routing-basics Replace the NavigationService with RouterService in your app.dart file to enable web-supported navigation. This setup is automatically included if you generate a Stacked project with the '--t web' option. ```dart @StackedApp( routes: [ ... ], dependencies: [ LazySingleton(classType: RouterService), LazySingleton(classType: DialogService), LazySingleton(classType: BottomSheetService), ] ) class App {} ``` -------------------------------- ### Define a Custom Validator Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Create a static function to validate input. This function should accept a nullable string and return a nullable string (the error message). Numbers are not allowed in this example. ```dart class TextReverseValidators { static String? validateReverseText(String? value) { if (value == null) { return null; } if (value.contains(RegExp(r'[0-9]'))) { return 'No numbers allowed'; } } } ``` -------------------------------- ### Implement Startup Logic Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Use this ViewModel to check user authentication and navigate to the appropriate view upon app startup. Ensure AuthenticationService and NavigationService are available via the locator. ```dart class StartupViewModel extends BaseViewModel { // 1. Get the Authentication and NavigationService final _authenticationService = locator(); final _navigationService = locator(); Future runStartupLogic() async { // 2. Check if the user is logged in if (_authenticationService.userLoggedIn()) { // 3. Navigate to HomeView _navigationService.replaceWith(Routes.homeView); } else { // 4. Or navigate to LoginView _navigationService.replaceWith(Routes.loginView); } } } ``` -------------------------------- ### Create Login View Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Generates a new LoginView using the Stacked CLI. This view will be used for navigation after the startup logic. ```bash stacked create view login ``` -------------------------------- ### Navigate to Home View with Argument Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Navigates to the HomeView and passes the required 'startingIndex' argument. ```dart _navigationService.navigateToHomeView(startingIndex: 0); ``` -------------------------------- ### Create a New View with Stacked CLI Source: https://stacked.filledstacks.com/docs/getting-started/how-it-works Use the Stacked CLI to generate the necessary files for a new View and its associated ViewModel. ```bash stacked create view counter ``` -------------------------------- ### Home View Constructor with Argument Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Defines the HomeView with a required 'startingIndex' argument in its constructor. ```dart class HomeView extends StackedView { final int startingIndex; const HomeView({Key? key, required this.startingIndex}) : super(key: key); ... } ``` -------------------------------- ### Create Stacked Service Source: https://stacked.filledstacks.com/docs/in-depth/services Command to generate a new service, including its implementation and unit test mock, and register it with the service locator. ```bash stacked create service api ``` -------------------------------- ### Navigate to Counter View Source: https://stacked.filledstacks.com/docs/getting-started/how-it-works Modify the StartupViewModel to navigate to the CounterView upon application startup. ```dart _navigationService.replaceWithCounterView(); ``` -------------------------------- ### Run a Stacked App Source: https://stacked.filledstacks.com/docs/getting-started/overview Execute your newly created Stacked application on a connected device or emulator using the standard Flutter command. ```bash flutter run ``` -------------------------------- ### Create a New Widget with Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Execute this command from your Stacked application's root folder to generate a new widget and its associated WidgetModel. The command also creates the WidgetModel test file. ```bash stacked create widget users_list ``` -------------------------------- ### Create a View with Stacked CLI Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Use the Stacked CLI to generate a new view for your form. This command initializes the basic structure for a new view. ```bash stacked create view textReverse ``` -------------------------------- ### Replace with Home View with Argument Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Replaces the current view with HomeView, passing the required 'startingIndex' argument. ```dart _navigationService.replaceWithHomeView(startingIndex: 0); ``` -------------------------------- ### Basic IndexTrackingViewModel Implementation Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels A minimal implementation of IndexTrackingViewModel, showing how to extend it for basic index tracking functionality. ```dart class HomeViewModel extends IndexTrackingViewModel {} ``` -------------------------------- ### Create a New Stacked App Source: https://stacked.filledstacks.com/docs/getting-started/overview Generate a new Stacked Flutter application with the default project structure and configurations. ```bash stacked create app my_first_app ``` -------------------------------- ### Create a New View with Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli This command generates all necessary files for a new View, including the View, ViewModel, and test files. It also automatically adds the route to your app.dart if template identifiers are present. ```bash stacked create view profile ``` -------------------------------- ### ArtistService Implementation Source: https://stacked.filledstacks.com/docs/in-depth/services This snippet demonstrates an App Service class that orchestrates calls to other services (Database, Authentication, API) to fetch and save artist data. It assumes other services are already created and locatable via a 'locator'. ```dart class ArtistService { final _databaseService = locator(); final _authenticationService = locator(); final _apiService = locator(); Future> getArtists() async { // Check if user is logged in if (_authenticationService.userLoggedIn()) { // Get the artists from the backend final newArtists = await _apiService.getArtists(); // Save to the database await _databaseService.saveArtists(newArtists); return newArtists; } throw Exception('User must be logged in to see artists'); } } ``` -------------------------------- ### Create Authentication Service Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Generates a new AuthenticationService using the Stacked CLI. This service will be used to check user login status. ```bash stacked create service authentication ``` -------------------------------- ### Create a New Dialog with Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Run this command from your Stacked application's root folder to create a new dialog. It generates the dialog file, adds it to app.dart, and optionally creates a DialogModel and unit test. ```bash stacked create dialog error ``` -------------------------------- ### Implement AuthenticationService Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Provides a basic implementation for the AuthenticationService. The `userLoggedIn` function currently returns a static true value for demonstration purposes. ```dart class AuthenticationService { bool userLoggedIn() { return true; } } ``` -------------------------------- ### Basic Counter ViewModel Source: https://stacked.filledstacks.com/docs/getting-started/how-it-works Create a ViewModel by extending BaseViewModel to manage state and actions. Use rebuildUi() to notify the UI of changes. ```dart class CounterViewModel extends BaseViewModel { int _counter = 0; int get counter => _counter; void incrementCounter() { _counter++; rebuildUi(); } } ``` -------------------------------- ### MultipleFuturesExampleView UI Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels A StatelessWidget that uses ViewModelBuilder to connect to the MultipleFuturesExampleViewModel. It displays fetched data or loading indicators based on the ViewModel's state for each future. ```dart class MultipleFuturesExampleView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( builder: (context, viewModel, child) => Scaffold( body: Center( child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 50, height: 50, alignment: Alignment.center, color: Colors.yellow, // Show busy for number future until the data is back or has failed child: viewModel.fetchingNumber ? CircularProgressIndicator() : Text(viewModel.fetchedNumber.toString()), ), SizedBox( width: 20, ), Container( width: 50, height: 50, alignment: Alignment.center, color: Colors.red, // Show busy for string future until the data is back or has failed child: viewModel.fetchingString ? CircularProgressIndicator() : Text(viewModel.fetchedString), ), ], ), ), ), viewModelBuilder: () => MultipleFuturesExampleViewModel()); } } ``` -------------------------------- ### Create Service Mock Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `test_helpers.dart` to indicate where a new service mock should be created and registered. ```dart // @stacked-mock-create ``` -------------------------------- ### Implementing ReactiveViewModel for Service Listening Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Extends ReactiveViewModel and implements `listenableServices` to react to changes in services. The service must use `ListenableServiceMixin` and `listenToReactiveValues`. ```dart class AnyViewModel extends ReactiveViewModel { final _postsService = locator(); int get postCount => _postsService.postCount; @override List get listenableServices => [_postsService]; } ``` -------------------------------- ### Navigate to Home View Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Navigates to the HomeView by adding it to the top of the navigation stack. ```dart _navigationService.navigateToHomeView(); ``` -------------------------------- ### ViewModel Using Facade Service Source: https://stacked.filledstacks.com/docs/in-depth/services The ViewModel now delegates the data fetching and deserialization to the ApiService, simplifying its own responsibilities to state management. ```dart class HomeViewModel extends BaseViewModel { final _apiService = locator(); List _artists = []; Future fetchArtists() async { _artists = await _apiService.getArtists(); // Do some stuff with artists or extract additional state e.g. // empty state, multi select, etc ... } } ``` -------------------------------- ### Facade Service Implementation Source: https://stacked.filledstacks.com/docs/in-depth/services This ApiService encapsulates the HTTP request and data deserialization logic, providing a clean interface for other parts of the application. ```dart class ApiService { Future> getArtists() async { final response = await http.get(Uri.https('venu.is', '/artists')); if (response.statusCode < 400) { final responseBodyAsMap = jsonDecode(response.body); final artistMaps = responseBodyAsMap['data'] as List>; return artistMaps.map(Artist.fromJson).toList(); } throw Exception('Response Code: ${response.statusCode} - ${response.body}'); } } ``` -------------------------------- ### Update Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Run this command to update the stacked_cli application to the latest version. It is a shortcut for 'dart pub global activate stacked_cli'. ```bash stacked update ``` -------------------------------- ### Clear Stack and Show Home View Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Clears the entire navigation stack and then displays the HomeView. ```dart _navigationService.clearStackAndShow(Routes.homeView); ``` -------------------------------- ### App Routes Configuration Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Defines the routes for a Stacked application. Views are automatically added when using the CLI. ```dart @StackedApp(routes: [ MaterialRoute(page: StartupView), MaterialRoute(page: HomeView), MaterialRoute(page: CounterView), // @stacked-route ]) class App {} ``` -------------------------------- ### Displaying Data from FutureViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Use ViewModelBuilder to connect your View to the FutureExampleViewModel. The UI can conditionally display a loading indicator or the fetched data based on the viewModel.isBusy and viewModel.data properties. ```dart class FutureExampleView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( builder: (context, viewModel, child) => Scaffold( body: Center( // viewModel will indicate busy until the future is fetched child: viewModel.isBusy ? CircularProgressIndicator() : Text(viewModel.data), ), ), viewModelBuilder: () => FutureExampleViewModel(), ); } } ``` -------------------------------- ### ViewModel Error Handling with runBusyFuture Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Demonstrates how runBusyFuture catches exceptions, sets the busy state, and stores the error. Use `hasError` and `modelError` to access the error when no key is provided. ```dart class ErrorExampleViewModel extends BaseViewModel { Future longUpdateStuff() async { // Sets busy to true before starting future and sets it to false after executing // You can also pass in an object as the busy object. Otherwise it'll use the ViewModel var result = await runBusyFuture(updateStuff()); } Future updateStuff() async { await Future.delayed(const Duration(seconds: 3)); throw Exception('Things went wrong'); } } ``` -------------------------------- ### Build a Custom Transition Widget Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Create a static function with the signature `Widget Function(BuildContext, Animation, Animation, Widget child)` to build your own custom transitions using Flutter's animation widgets. ```dart import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; class CustomRouteTransition { static Widget sharedAxis(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { // Here you can use any Existing Transition class in Flutter return SharedAxisTransition( animation: animation, secondaryAnimation: secondaryAnimation, transitionType: SharedAxisTransitionType.scaled, child: child, ); } } ``` -------------------------------- ### Default Stacked CLI Configuration Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli This JSON object represents the default configuration for the Stacked CLI. It specifies paths for various project directories like UI components, services, and test files, along with other settings such as line length and web preference. ```json { "bottom_sheets_path": "ui/bottom_sheets", "dialogs_path": "ui/dialogs", "line_length": 80, "locator_name": "locator", "prefer_web": true, "register_mocks_function": "registerServices", "services_path": "services", "stacked_app_file_path": "app/app.dart", "test_helpers_file_path": "helpers/test_helpers.dart", "test_services_path": "services", "test_views_path": "viewmodels", "test_widgets_path": "widget_models", "v1": false, "views_path": "ui/views", "widgets_path": "ui/widgets/common" } ``` -------------------------------- ### Use Custom Built Transition Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Integrate your custom transition builder by assigning it to the `transitionsBuilder` property in `CustomRoute` at the app level or when navigating. ```dart // In app.dart CustomRoute( page: CounterView, transitionsBuilder: CustomRouteTransition.sharedAxis, ), // When navigating await _navigationService.navigateTo( Routes.secondView, transition: transitionsBuilder: CustomRouteTransition.sharedAxis, ); ``` -------------------------------- ### BaseViewModel Implementation with State Handling Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Extend BaseViewModel to manage presentation logic, busy states for specific objects, and overall ViewModel busy states. Use runBusyFuture to automatically handle busy states during asynchronous operations. ```dart class WidgetOneViewModel extends BaseViewModel { Human _currentHuman; Human get currentHuman => _currentHuman; void setBusyOnProperty() { setBusyForObject(_currentHuman, true); // Fetch updated human data setBusyForObject(_currentHuman, false); } void setModelBusy() { setBusy(true); // Do things here setBusy(false); } Future longUpdateStuff() async { // Sets busy to true before starting future and sets it to false after executing // You can also pass in an object as the busy object. Otherwise it'll use the ViewModel var result = await runBusyFuture(updateStuff()); } Future updateStuff() { return Future.delayed(const Duration(seconds: 3)); } } ``` -------------------------------- ### Register Service in `registerServices` Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `test_helpers.dart` to indicate where a service should be registered within the `registerServices` function. ```dart // @stacked-mock-register ``` -------------------------------- ### Configure Stacked Logger Source: https://stacked.filledstacks.com/docs/in-depth/logger Add the StackedLogger to your StackedApp configuration to enable logging. ```dart @StackedApp( logger: StackedLogger(), ) ``` -------------------------------- ### ViewModel Error Handling with a Specific Key Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Shows how to use runBusyFuture with a specific key to manage busy states and errors. Errors can be retrieved using `viewModel.error(key)` or checked with `viewModel.hasErrorForKey(key)`. ```dart const String BusyObjectKey = 'my-busy-key'; class BusyExampleViewModel extends BaseViewModel { Future longUpdateStuff() async { // Sets busy to true before starting future and sets it to false after executing // You can also pass in an object as the busy object. Otherwise it'll use the ViewModel var result = await runBusyFuture(updateStuff(), busyObject: BusyObjectKey); } Future updateStuff() { return Future.delayed(const Duration(seconds: 3)); } } ``` -------------------------------- ### Replace with Home View Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Replaces the current view with the HomeView on the navigation stack. Can optionally pass arguments. ```dart _navigationService.replaceWith(Routes.homeView); ``` -------------------------------- ### Navigate Back Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Navigates back to the previous view on the navigation stack. ```dart _navigationService.back(); ``` -------------------------------- ### Configure LoginView Background Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Sets the background color of the LoginView to red. This is a placeholder for the actual login UI. ```dart class LoginView extends StackedView { const LoginView({Key? key}) : super(key: key); @override Widget builder( BuildContext context, LoginViewModel viewModel, Widget? child, ) { return Scaffold( backgroundColor: Colors.red, body: Container( padding: const EdgeInsets.only(left: 25.0, right: 25.0), ), ); } @override LoginViewModel viewModelBuilder( BuildContext context, ) => LoginViewModel(); } ``` -------------------------------- ### Navigate with Custom Transition Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics When navigating to a view defined as a `CustomRoute`, you can specify a transition using the `transition` parameter in the `navigateTo` method. ```dart await _navigationService.navigateTo( Routes.secondView, transition: TransitionsBuilders.fadeIn, ); ``` -------------------------------- ### Integrate Generated Form Mixin and Sync Functionality Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Import the generated form file, mixin the generated class, and call syncFormWithViewModel in onViewModelReady. This enables automatic synchronization between the View and ViewModel. ```dart import 'text_reverse_view.form.dart'; // 1. Import the generated file @FormView(fields: [ FormTextField(name: 'reverseInput'), ]) class TextReverseView extends StackedView with $TextReverseView { // 2. Mix in $TextReverseView Mixin @override Widget builder( BuildContext context, TextReverseViewModel viewModel, Widget? child, ) { return Scaffold( ... ); } @override void onViewModelReady(TextReverseViewModel viewModel) { syncFormWithViewModel(viewModel); } ... ``` -------------------------------- ### IndexTrackingViewModel for Web Navigation Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Demonstrates using setCurrentWebPageIndex within a ViewModel that extends IndexTrackingViewModel to manage the current index based on the URL for web applications. ```dart class BottomNavExampleViewModel extends IndexTrackingViewModel { final _routerService = exampleLocator(); BottomNavExampleViewModel() { setCurrentWebPageIndex(_routerService); } } ``` -------------------------------- ### Registering a Factory with Environment Filter Source: https://stacked.filledstacks.com/docs/in-depth/service-locator Register a service as a LazySingleton that is only available in a specific development environment. This ensures the service is only created when the application is run in the specified environment. ```dart LazySingleton( classType: NavigationService, environments: {Environment.dev}, ), ``` -------------------------------- ### Service Implementation for ReactiveViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels A service using `ListenableServiceMixin` that listens to reactive values. `notifyListeners()` is called to trigger updates in listening ViewModels. ```dart class PostService with ListenableServiceMixin { PostService() { listenToReactiveValues([_postCount]); } int _postCount = 0; int get postCount => _postCount; Future increment() async { _postCount++; notifyListeners(); // ViewModels listening postCount value are notified and their View is rebuild } } ``` -------------------------------- ### Generate Form Code Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Run the Stacked generate command after defining your form fields. This command creates the necessary form-related files, including a mixin for controller management. ```bash stacked generate ``` -------------------------------- ### Configure stacked_generator for Navigator 2.0 Source: https://stacked.filledstacks.com/docs/stacked-router/routing-basics Create a build.yaml file to configure the stacked_generator to use the v2 navigator. This ensures that a StackedRouter is generated based on Flutter's V2 navigator, which is better suited for web URL navigation. ```yaml targets: $default: builders: stacked_generator|stackedRouterGenerator: options: navigator2: true ``` -------------------------------- ### Generate Code with Stacked CLI Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Use this command to generate code when manual changes have been made or a new model has been added. It serves as an alternative to running 'flutter pub run build_runner build --delete-conflicting-outputs'. ```bash stacked generate ``` -------------------------------- ### MultipleFutureViewModel Implementation Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Defines a ViewModel that fetches data from multiple futures concurrently. Use this when your UI needs to display data from several independent asynchronous sources. The futuresMap defines which futures to run and their keys. ```dart import 'package:stacked/stacked.dart'; const String _NumberDelayFuture = 'delayedNumber'; const String _StringDelayFuture = 'delayedString'; class MultipleFuturesExampleViewModel extends MultipleFutureViewModel { int get fetchedNumber => dataMap[_NumberDelayFuture]; String get fetchedString => dataMap[_StringDelayFuture]; bool get fetchingNumber => busy(_NumberDelayFuture); bool get fetchingString => busy(_StringDelayFuture); @override Map get futuresMap => { _NumberDelayFuture: getNumberAfterDelay, _StringDelayFuture: getStringAfterDelay, }; Future getNumberAfterDelay() async { await Future.delayed(Duration(seconds: 2)); return 3; } Future getStringAfterDelay() async { await Future.delayed(Duration(seconds: 3)); return 'String data'; } } ``` -------------------------------- ### runBusyFuture with Custom Busy Object Key Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Use runBusyFuture with a specific 'busyObject' key to manage busy states for individual items or distinct operations within a ViewModel. This allows for granular UI updates. ```dart const String BusyObjectKey = 'my-busy-key'; class BusyExampleViewModel extends BaseViewModel { Future longUpdateStuff() async { // Sets busy to true before starting future and sets it to false after executing // You can also pass in an object as the busy object. Otherwise it'll use the ViewModel var result = await runBusyFuture(updateStuff(), busyObject: BusyObjectKey); } Future updateStuff() { return Future.delayed(const Duration(seconds: 3)); } } ``` -------------------------------- ### Register Service Mock Spec Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `test_helpers.dart` to indicate where a new mock specification should be added. ```dart // @stacked-mock-spec ``` -------------------------------- ### Register Service Dependency Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `lib/app/app.dart` to indicate where a new service dependency should be registered. ```dart // @stacked-service ``` -------------------------------- ### Navigate Back with Result Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Navigates back to the previous view and passes a result object to the calling function. The navigation call can be awaited. ```dart final result = await _navigationService.replaceWithHomeView(startingIndex: 0); print('Returned result: $result'); ``` ```dart _navigationService.back(result: 'From back call'); ``` -------------------------------- ### Use Logger in a ViewModel Source: https://stacked.filledstacks.com/docs/in-depth/logger Instantiate and use the logger within your ViewModel to log messages. The logger automatically captures the function name. ```dart class MyViewModel { final logger = getLogger('MyViewModel'); void doStuff() { logger.i(''); } } ``` -------------------------------- ### TextFormField with Controller Source: https://stacked.filledstacks.com/docs/getting-started/form-basics A simple TextFormField that uses a controller managed by Stacked's form system. ```dart TextFormField(controller: reverseInputController), ``` -------------------------------- ### runBusyFuture for Automatic Busy State Handling Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Utilize runBusyFuture to automatically manage the ViewModel's busy state during asynchronous operations. This simplifies the process of indicating activity to the UI. ```dart class BusyExampleViewModel extends BaseViewModel { Future longUpdateStuff() async { // Sets busy to true before starting future and sets it to false after executing // You can also pass in an object as the busy object. Otherwise it'll use the ViewModel var result = await runBusyFuture(updateStuff()); } Future updateStuff() { return Future.delayed(const Duration(seconds: 3)); } } ``` -------------------------------- ### Add Logger Dependency Source: https://stacked.filledstacks.com/docs/in-depth/logger Include the logger package in your pubspec.yaml file to use its functionalities. ```yaml dependencies: ... logger: ``` -------------------------------- ### Add Form Functionality to Existing ViewModel Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Mix the FormStateHelper into a ViewModel that already extends FutureViewModel or StreamViewModel to add form capabilities. ```dart // Original class that you want to add form functionality to class ContentViewModel extends FutureViewModel { ... } // Do instead class ContentViewModel extends FutureViewModel with FormStateHelper implements FormViewModel { ... } ``` -------------------------------- ### Register Dialog Dependency Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `lib/app/app.dart` within the `dialogs` property of `StackedApp` to indicate where a new dialog dependency should be registered. ```dart // @stacked-dialog ``` -------------------------------- ### Define Form Fields with @FormView Annotation Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Annotate your View class with @FormView to define the fields for your form. This tells Stacked which controllers to generate. ```dart import 'package:stacked/stacked_annotations.dart'; @FormView(fields: [ FormTextField(name: 'reverseInput'), ]) class TextReverseView extends StackedView { const TextReverseView({Key? key}) : super(key: key); ... ``` -------------------------------- ### Registering Dependencies in StackedApp Source: https://stacked.filledstacks.com/docs/in-depth/service-locator Register various types of dependencies like Singletons, LazySingletons, and Factories within the StackedApp annotation using the 'dependencies' property. This sets up the service locator with your application's components. ```dart @StackedApp( dependencies: [ Singleton(classType: NavigationService), LazySingleton(classType: ThemeService, resolveUsing: ThemeService.getInstance), LazySingleton(classType: FirebaseAuthService, asType: AuthService), InitializableSingleton(classType: SharedPreferencesService), Factory(classType: FactoryService), ], ) ``` -------------------------------- ### Stacked CLI Import Template Identifier Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this template identifier to your lib/app/app.dart file under the last import to indicate where Stacked CLI should add new imports when creating components like views. ```dart // @stacked-import ``` -------------------------------- ### Stacked CLI Route Template Identifier Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Place this template identifier in your lib/app/app.dart file underneath your last route definition. Stacked CLI will use this to automatically add new routes when creating views. ```dart // @stacked-route ``` -------------------------------- ### Counter View Structure Source: https://stacked.filledstacks.com/docs/getting-started/how-it-works Define a Flutter View by extending StackedView and implementing the builder and viewModelBuilder methods. ```dart class CounterView extends StackedView { @override // A builder function that gives us a ViewModel Widget builder( BuildContext context, CounterViewModel viewModel, Widget? child, ) { return Scaffold( ... ); } @override CounterViewModel viewModelBuilder(BuildContext context) => CounterViewModel(); } ``` -------------------------------- ### Add a New Bottom Sheet Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Create a new BottomSheet, its associated Model, and tests. The command also registers the BottomSheet in app.dart. Use --no-model to create a BottomSheet without a model. ```bash stacked create bottom_sheet alert ``` -------------------------------- ### Configure HomeView Background Source: https://stacked.filledstacks.com/docs/getting-started/startup-logic Sets the background color of the HomeView to purple. This view is navigated to if the user is logged in. ```dart class HomeView extends StackedView { const HomeView({Key? key}) : super(key: key); @override Widget builder( BuildContext context, HomeViewModel viewModel, Widget? child, ) { return Scaffold( backgroundColor: Colors.purple, body: Container( padding: const EdgeInsets.only(left: 25.0, right: 25.0), ), ); } @override HomeViewModel viewModelBuilder( BuildContext context, ) => HomeViewModel(); } ``` -------------------------------- ### Register BottomSheet Dependency Source: https://stacked.filledstacks.com/docs/tooling/stacked-cli Add this comment to `lib/app/app.dart` within the `bottomsheets` property of `StackedApp` to indicate where a new bottom sheet dependency should be registered. ```dart // @stacked-bottom-sheet ``` -------------------------------- ### Specify Transition Builder for Custom Route Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Assign a static builder function from `TransitionsBuilders` to the `transitionsBuilder` property of `CustomRoute` to apply a pre-defined transition like `fadeIn`. ```dart @StackedApp(routes: [ ... CustomRoute( page: CounterView, transitionsBuilder: TransitionsBuilders.fadeIn, ), // @stacked-route ]) class App {} ``` -------------------------------- ### TextReverseView Builder Widget Source: https://stacked.filledstacks.com/docs/getting-started/form-basics This code defines the UI for the Text Reverser view, including input fields, validation messages, and the reversed text display. It utilizes Stacked's form management for controllers. ```dart @override Widget builder( BuildContext context, TextReverseViewModel viewModel, Widget? child, ) { return Scaffold( appBar: AppBar(title: const Text('Text Reverser')), body: Container( padding: const EdgeInsets.only(left: 25.0, right: 25.0), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ verticalSpaceMedium, const Text( 'Text to Reverse', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700), ), verticalSpaceSmall, TextFormField(controller: reverseInputController), if (viewModel.hasReverseInputValidationMessage) ...[ verticalSpaceTiny, Text( viewModel.reverseInputValidationMessage!, style: const TextStyle( color: Colors.red, fontSize: 12, fontWeight: FontWeight.w700, ), ), ], verticalSpaceMedium, Text( viewModel.reversedText, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, ), ), ], ), ), ), ); } ``` -------------------------------- ### Display Counter and Increment on FAB Tap Source: https://stacked.filledstacks.com/docs/getting-started/how-it-works Update the CounterView's builder to display the counter value and trigger the incrementCounter function when the FloatingActionButton is pressed. ```dart @override Widget builder(BuildContext context, CounterViewModel viewModel, Widget? child) { return Scaffold( floatingActionButton: FloatingActionButton(onPressed: viewModel.incrementCounter), body: Center( child: Text( viewModel.counter.toString(), style: const TextStyle( fontSize: 30, fontWeight: FontWeight.bold, ), ), ), ); } ``` -------------------------------- ### Custom Logger Function Name Source: https://stacked.filledstacks.com/docs/in-depth/logger Customize the name of the logger retrieval function if 'getLogger' conflicts with existing code. This is done via the logHelperName property in the StackedApp configuration. ```dart @StackedApp( logger: StackedLogger( logHelperName: 'getStackedLogger', ) ) ``` -------------------------------- ### StackedView UI Integration with ViewModel State Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Integrate a StackedView with its ViewModel to react to busy states and trigger ViewModel actions. Use viewModel.isBusy and viewModel.busy(object) to conditionally render UI elements. ```dart class WidgetOneView extends StackedView { const WidgetOneView({Key? key}) : super(key: key); @override Widget builder( BuildContext context, WidgetOneViewModel viewModel, Widget? child, ) { return GestureDetector( onTap: () => viewModel.longUpdateStuff(), child: Container( width: 100, height: 100, // Use isBusy to check if the ViewModel is set to busy color: viewModel.isBusy ? Colors.green : Colors.red, alignment: Alignment.center, // A bit silly to pass the same property back into the ViewModel // but here it makes sense child: viewModel.busy(viewModel.currentHuman) ? Center( child: CircularProgressIndicator(), ) : Container(/* Human Details styling */) ), ), ); } } ``` -------------------------------- ### Define a FutureViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Extend FutureViewModel and override the futureToRun getter to provide the Future that fetches data. The ViewModel automatically manages the busy state and data availability. ```dart class FutureExampleViewModel extends FutureViewModel { @override Future futureToRun() => getDataFromServer(); Future getDataFromServer() async { await Future.delayed(const Duration(seconds: 3)); return 'This is fetched from everywhere'; } } ``` -------------------------------- ### Define Custom Route at App Level Source: https://stacked.filledstacks.com/docs/getting-started/navigation-basics Use `CustomRoute` in your `app.dart` to specify a custom transition for a specific view. This ensures all navigations to that view will use the defined transition. ```dart @StackedApp(routes: [ MaterialRoute(page: StartupView), MaterialRoute(page: HomeView), CustomRoute(page: CounterView), // <== Custom Route // @stacked-route ]) class App {} ``` -------------------------------- ### Extend ViewModel with FormViewModel Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Update your ViewModel to extend from FormViewModel instead of BaseViewModel. This provides the necessary base functionality for managing form data. ```dart class TextReverseViewModel extends FormViewModel { ... ``` -------------------------------- ### Displaying Error State from FutureViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels In your View, use the viewModel.hasError property to conditionally render an error message or fallback UI. This allows users to be informed when data fetching fails. ```dart class FutureExampleView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( builder: (context, viewModel, child) => Scaffold( body: viewModel.hasError ? Container( color: Colors.red, alignment: Alignment.center, child: Text( 'An error has occered while running the future', style: TextStyle(color: Colors.white), ), ) : Center( child: viewModel.isBusy ? CircularProgressIndicator() : Text(viewModel.data), ), ), viewModelBuilder: () => FutureExampleViewModel(), ); } } ``` -------------------------------- ### TextReverseViewModel with Reversed Text Property Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Defines the ViewModel for the TextReverseView. It includes a computed property 'reversedText' that reverses the input from the 'reverseInput' field. ```dart import 'package:stacked/stacked.dart'; import 'text_reverse_view.form.dart'; class TextReverseViewModel extends FormViewModel { String get reversedText => hasReverseInput ? reverseInputValue!.split('').reversed.join('') : '----'; } ``` -------------------------------- ### Dispose Form Controllers in ViewModel Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Overrides the onDispose function in the View to ensure form controllers are properly disposed of by calling the generated disposeForm() function. ```dart @override void onDispose(TextReverseViewModel viewModel) { super.onDispose(viewModel); disposeForm(); } ``` -------------------------------- ### Handling Errors in FutureViewModel Source: https://stacked.filledstacks.com/docs/in-depth/viewmodels Override the future getter and the onError function to handle errors during Future execution. The ViewModel exposes a hasError property to indicate if an error occurred. ```dart class FutureExampleViewModel extends FutureViewModel { @override Future get future => getDataFromServer(); Future getDataFromServer() async { await Future.delayed(const Duration(seconds: 3)); throw Exception('This is an error'); } @override void onError(error) { } } ``` -------------------------------- ### Apply Validator to FormTextField Source: https://stacked.filledstacks.com/docs/getting-started/form-basics Assign the custom validator function to the 'validator' property of the FormTextField annotation. ```dart @FormView( fields: [ FormTextField( name: 'reverseInput', validator: TextReverseValidators.validateReverseText, ), ], ) ... ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.