GithubHelp home page GithubHelp logo

stacked-org / stacked Goto Github PK

View Code? Open in Web Editor NEW
935.0 935.0 256.0 62.97 MB

A Flutter application architecture created from real world scenarios

License: MIT License

Dart 90.46% Kotlin 0.07% Swift 0.51% Objective-C 0.01% Ruby 0.75% CMake 3.43% C++ 4.17% C 0.26% HTML 0.34%

stacked's People

Contributors

bats64mgutsi avatar buehler avatar carlomigueldy avatar creativecreatorormaybenot avatar daoxve avatar dvagala avatar eb-so avatar eimen2018 avatar elhe26 avatar eshetulucas avatar ferrarafer avatar filledstacks avatar gerfaut avatar hannnes1 avatar hurbes avatar isaacadariku avatar jonataslaw avatar merfire avatar mraaz97 avatar mrseth01 avatar pgudivadadiligent avatar r0hit-gupta avatar rodolfosilva avatar saileshbro avatar schefferbird avatar scullabyte avatar sebastianbuechler avatar semantic-release-bot avatar yazeedalkhalaf avatar zainulhassan815 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stacked's Issues

[stacked] Imports are faulty

When I want to import package:stacked/stacked.dart my IDE always recommends package:stacked/_reactive_service_mixin.dart etc.

I think that only the library file should be publicly visible.

Stacked_services - Compiler Error - Dependency on get

Hello,

Looks like dependency on get is outdated for anything

Because my_app depends on stacked_services any which depends on get ^1.17.3, get ^1.17.3 is required.

Getting error from compiler:

Launching lib\main.dart on Android SDK built for x86 in debug mode...

Compiler message:
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:279:8: Error: The method 'SnackRoute.install' has more required arguments than those of overridden method 'OverlayRoute.install'.
void install(OverlayEntry insertionPoint) {
^
/C:/flutter/packages/flutter/lib/src/widgets/routes.dart:41:8: Context: This is the overridden method ('install').
void install() {
^

Compiler message:
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:279:8: Error: The method 'SnackRoute.install' has more required arguments than those of overridden method 'OverlayRoute.install'.
void install(OverlayEntry insertionPoint) {
^
/C:/flutter/packages/flutter/lib/src/widgets/routes.dart:41:8: Context: This is the overridden method ('install').
void install() {
^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/routes/default_route.dart:242:9: Error: No named parameter with the name 'animation'.
animation: animation,
^^^^^^^^^
/C:/flutter/packages/flutter/lib/src/cupertino/route.dart:436:3: Context: Found this candidate, but the arguments don't match.
CupertinoFullscreenDialogTransition({
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:289:18: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
super.install(insertionPoint);
^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/routes/default_route.dart:242:9: Error: No named parameter with the name 'animation'.
animation: animation,
^^^^^^^^^
/C:/flutter/packages/flutter/lib/src/cupertino/route.dart:436:3: Context: Found this candidate, but the arguments don't match.
CupertinoFullscreenDialogTransition({
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:289:18: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
super.install(insertionPoint);
^
Target kernel_snapshot failed: Exception: Errors during snapshot creation: null
build failed.

FAILURE: Build failed with an exception.

  • Where:
    Script 'C:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 896

  • What went wrong:
    Execution failed for task ':app:compileFlutterBuildDebug'.

Process 'command 'C:\flutter\bin\flutter.bat'' finished with non-zero exit value 1

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

  • Get more help at https://help.gradle.org

BUILD FAILED in 23s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

This is version:
[√] Flutter (Channel dev, 1.18.0-9.0.pre, on Microsoft Windows [Version 10.0.18362.778], locale en-US)

Any ideas how to get around this?

Conditionally pause stream subscription

Currently the streamsSubscriptions map has @visibleForTesting attached to it, which doesn't let me conditionally pause a stream.

i.e.- I want to add this to stream1.onData:

if(condition){ 
	streamsSubscriptions['timer'].resume 
}else{ 
	streamsSubscriptions['timer'].pause; 
}

If there's a way to do this another way let me know.

StreamViewModel Widget Updates Broken after 1.2.4 update

Hi. I seem to have hit a problem with the StreamViewModel between the 1.2.4 and 1.3.0 update.

Quite simply I have a simple widget initiated like the usual from the docs ViewModelBuilder.reactive.

On my ViewModel I know I get data back within:

@override void onData(List<Offer> data) { print(data.length.toString()); }

Within my widget I am simply doing this:

child: model.data != null ? Container( etc etc etc) : SizedBox()

But the widget is not rebuilt with the data. This was and still working perfectly in 1.2.4. Am I missing something here which I have not interpreted from the docs?

Thank you

Documentation for MultipleStreamViewModel

Man, can you read minds?! :-D I just switchted my project-architecture to stacked, which clearly represents the architecture, I was searching for and works very well. And 2 days ago, I was working on a problem, where I thought, "hmmm.. That's something where a MultipleStreamViewModel would come in handy" ... and ... boom, the next day - there it is!

Unfortunatelly, there's no documentation providing how to set it up. Could you provide some in the README?

Cheers!

There is no way to find out if any Objects are busy in the BaseViewModel

I would suggest to add a method to the BaseViewModel that checks if any of the values of the busy map are still true. This is useful for specific use cases, like displaying a small loading indicator in app that tells the user that processes are running. To find that out in the current implementation, the viewModel would need to keep track of all the Objects it has used to set the busy state separately, which is unnecessarily verbose when the BaseViewModel could just expose a simple function.

For example:
return _busyStates.values.any((busy) => busy);

Pop Back...

I'm trying to implement the equivalent of Navigator.pop(context) in this architecture's Navigation Service.

the scenario is i have transitioned from ViewA to ViewB and that works fine... the transition is great ...

In ViewB i have a button to go back ... and in my onTapped I call a function on the model something like Future navigateBack() async {} ...

In this function if i do ... await _navigationService.navigateTo(Routes.viewA); ... it works but the transition is not great and looks wonky.

if I do await _navigationService.navigateWithTransition(HomeView(), transition: "leftToRight",); it works, the transition is better but not really the same as if I had to do Navigator.pop(context)

is there another call that i need to use?

Also note in the video you emulate on Android, which has a hardware back button which we don't have on iOS...

The transition i am after on iOS is the same as if I had to swipe the page to the right... which behaves like Navigator.pop(context);

Once you have called dispose() on a Model, it can no longer be used.

Hi,

i migrated to this package from your ArchitectureV3 and now facing the following issue;

I have a onModelReady Function with an await Future. Inside this future i call setBusy to true at start, another await Future in the Mid and than setBusy to false at End. When i for e.g. navigate Back before the Future returns, the last setBusy cause the error, that the Model no longer can be used.
The Workaround is to create a mounted variable suggested by Remi, but as we now have many Models, i wonder how to do it without having this boilerplate variable.

Example:

ViewModelBuilder<Model>.reactive(
        onModelReady: (model) async {
          await model.someFuture(parmeter: parameter);
        },
        viewModelBuilder: () => Model(),
        builder: (context, model, child) {
          return [....]
        });
class Model extends BaseViewModel {
setbusy(true);
Future.delayed(Duration(seconds: 5)).then((value) => setBusy(false));
}

Iam doing something wrong?

Navigation service unable to capture arguments from clearStackAndShow()

I'm trying to navigate to next view by clearing all the view from the stack and passing a single argument but not able to capture in the next view.

Code for navigating to next page

locator<NavigationService>().clearStackAndShow(
              Routes.profileViewRoute,
              arguments: ProfileViewArguments(fromLoginView: true));

Constructor on Profile View

ProfileView({this.fromLoginView});

router.g.dart Code for Profile View

case Routes.profileViewRoute:
        if (hasInvalidArgs<ProfileViewArguments>(args)) {
          return misTypedArgsRoute<ProfileViewArguments>(args);
        }
        final typedArgs =
            args as ProfileViewArguments ?? ProfileViewArguments();
        return MaterialPageRoute<dynamic>(
          builder: (context) =>
              ProfileView(fromLoginView: typedArgs.fromLoginView),
          settings: settings,
        );

Expected value on ProfileView of fromLoginView is true but when it is passed via clearStackAndShow() it get false

Note: It work with clearTillFirstAndShow() but not with clearStackAndShow()

How use : AutomaticKeepAliveClientMixin

Hello,

I am new in Flutter and I was looking for an architecture model.
After having seen your tutorial, I have decided to try to implement the Stacked philosophy.

I use some training codes I made to implement Stacked. Everything is fine with the View and Viewmodel.
In one code I use, there is a Scaffold and a bottomNavigationBar with 4 pages.
Each page has a list, and to preserve the scroll position, they implement : AutomaticKeepAliveClientMixin

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;
  
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text("Home"),
          subtitle: Text("$index"),
        );
      },
    );
  }
}

The tutorial is : https://cantaspinar.com/persistent-bottom-navigation-bar-in-flutter/

How implement AutomaticKeepAliveClientMixin using Stacked? I have tried with
... extends ViewModelBuilderWidget with AutomaticKeepAliveClientMixin
but I have an error

Thanks for your help

[stacked] What is the point of onModelReady?

Taking a look at the implementation of onModelReady, I can tell that the following two snippets of code do the exact same thing:

ViewModelBuilder.reactive(
  viewModelBuilder: () => FooViewModel(),
  onModelReady: (viewModel) => viewModel.init(),
  builder: ..,
)
// does the same as the following more concise snippet:
ViewModelBuilder.reactive(
  viewModelBuilder: () => FooViewModel()..init(),
  builder: ..,
)

So what is the point of onModelReady, now that you removed the onPostFrameCallback?

Complete Stacked Services Readme

Add the proper documentation for each of the Stacked Services that are provided into the readme. This should contain the reason they exist, the best way to make use of them and go through all the features that they provide.

Error when loading screen

Followed documentation not sure what could be causing this.

setState() or markNeedsBuild() called during build.


This _DefaultInheritedProviderScope<ProfileViewModel> widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

Manager use case

Could you please provide a simple use case on how to use the manager part of this architecture?

Here's how I understand it:

  1. We declare separate services (auth, storage, etc...).
  2. Each viewmodel will have access to one service (since they won't know other viewmodels).
  3. If a viewmodel needs more than one service, we use the manager to handle those services (since the manager is pointing to the individual services).

Regards,

Implementing showDialog?

Can't seem to get this working...

Amends....
locator.icondig.dart (although it says not to amend as generated....)

g.registerLazySingleton<DialogService>(() => DialogService());

home_viewmodel.dart

import 'package:new_architecture/app/locator.dart';
import 'package:new_architecture/services/dialog_service.dart';

final DialogService _dialogService = locator<DialogService>();
 Future showD() async{
    await _dialogService.showDialog(
          title: 'A Dialog',
          description: 'General Dialogue',
        );
  }

home_view.dart

floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Navigator.of(context).push(MaterialPageRoute(
            //   builder: (context) => StartupView(),
            // ));
            model.showD();
          },
        ),

but errors with

Restarted application in 1,911ms.
I/flutter (17729): HomeViewModel created
I/flutter (17729): HomeViewModel initialise
E/flutter (17729): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method 'dependOnInheritedWidgetOfExactType' was called on null.
E/flutter (17729): Receiver: null
E/flutter (17729): Tried calling: dependOnInheritedWidgetOfExactType<_InheritedTheme>()
�[38;5;244mE/flutter (17729): #0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:53:5)�[39;49m
�[38;5;244mE/flutter (17729): #1      Theme.of�[39;49m
�[38;5;248mE/flutter (17729): #2      Get.dialog�[39;49m
�[38;5;248mE/flutter (17729): #3      DialogService.showDialog�[39;49m
�[38;5;248mE/flutter (17729): #4      HomeViewModel.showD�[39;49m
�[38;5;248mE/flutter (17729): #5      HomeView.build.<anonymous closure>.<anonymous closure>�[39;49m
�[38;5;244mE/flutter (17729): #6      _InkResponseState._handleTap�[39;49m
�[38;5;244mE/flutter (17729): #7      _InkResponseState.build.<anonymous closure>�[39;49m
�[38;5;244mE/flutter (17729): #8      GestureRecognizer.invokeCallback�[39;49m
�[38;5;244mE/flutter (17729): #9      TapGestureRecognizer.handleTapUp�[39;49m
�[38;5;244mE/flutter (17729): #10     BaseTapGestureRecognizer._checkUp�[39;49m
�[38;5;244mE/flutter (17729): #11     BaseTapGestureRecognizer.handlePrimaryPointer�[39;49m
�[38;5;244mE/flutter (17729): #12     PrimaryPointerGestureRecognizer.handleEvent�[39;49m
�[38;5;244mE/flutter (17729): #13     PointerRouter._dispatch�[39;49m
�[38;5;244mE/flutter (17729): #14     PointerRouter._dispatchEventToRoutes.<anonymous closure>�[39;49m
�[38;5;244mE/flutter (17729): #15     _LinkedHashMapMixin.forEach  (dart:collection-patch/compact_hash.dart:379:8)�[39;49m
�[38;5;244mE/flutter (17729): #16     PointerRouter._dispatchEventToRoutes�[39;49m
�[38;5;244mE/flutter (17729): #17     PointerRouter.route�[39;49m
�[38;5;244mE/flutter (17729): #18     GestureBinding.handleEvent�[39;49m
�[38;5;244mE/flutter (17729): #19     GestureBinding.dispatchEvent�[39;49m
�[38;5;244mE/flutter (17729): #20     GestureBinding._handlePointerEvent�[39;49m
�[38;5;244mE/flutter (17729): #21     GestureBinding._flushPointerEventQueue�[39;49m
�[38;5;244mE/flutter (17729): #22     GestureBinding._handlePointerDataPacket�[39;49m
�[38;5;244mE/flutter (17729): #23     _rootRunUnary  (dart:async/zone.dart:1138:13)�[39;49m
�[38;5;244mE/flutter (17729): #24     _CustomZone.runUnary  (dart:async/zone.dart:1031:19)�[39;49m
�[38;5;244mE/flutter (17729): #25     _CustomZone.runUnaryGuarded  (dart:async/zone.dart:933:7)�[39;49m
�[38;5;244mE/flutter (17729): #26     _invoke1  (dart:ui/hooks.dart:273:10)�[39;49m
�[38;5;244mE/flutter (17729): #27     _dispatchPointerDataPacket  (dart:ui/hooks.dart:182:5)�[39;49m
E/flutter (17729):

Referring back to provider_architecture approach and the dialog_service there is different with a dialog_manager? So can't work out what might need amending...

Cheers.

PS also had to be on Stable flutter Channel for it to work with get package without changing get version.
dependencies:
get: ^1.17.3 // ^1.20.1-dev on beta/dev/master

The getter '_key' was called on null.

Okay, first of all, great package! And I love your architecture design principle.

I followed your tutorial in YouTube, and I am having trouble implementing NavigationService, and I keep getting this error:

The getter '_key' was called on null.
Receiver: null
Tried calling: _key

The relevant error-causing widget was:
MyApp file:///D:/Documents/AndroidStudioProjects/testing_app/lib/main.dart

It's pointing me to NavigationService.navigatorKey. Do you have any idea what I might have been missing?

About 3rd Party Integrations

IMO, 3rd party integrations like flutter_hooks should be optional and be provided via different packages. Otherwise the dependency stack of the core package can be huge and hard to maintain.

App Architecture

Hello Dane,

I am still trying to discover stacked and how to implement it in a full app.
I have quite easily transposed screens into views/viewmodel, and api into services. Thanks again for the tip about AutomaticKeepAliveClientMixin.

But now, I can't figure out how a view can influence another view.
For exemple :

If I have a MainView/MainViewModel : a Scaffold with some infos, a DrawerView/DrawerViewModel and a button to log in ...
The Login screen is a LoginView (stacked) with a LoginViewModel.
One the login is successful, how to update the Drawer (to see more options) and the MainView (change the log in button to a logout button)..

Thanks for your advice

Vincent

Stacked Services function typo

Hi,

There's a typo on one of the NavigationService functions:

  /// Pops the back stack until the predicate is satisfied
  void popUnitl(RoutePredicate predicate) {  // popUntil instead of popUnitl
    Get.key.currentState.popUntil(predicate);
  }

Regards,

Disposing in the view model

Image a view model which has a TextEditingController to get the text from a TextField in the view. This controller can be initialized with the help of ViewModelBuilder.onModelReady but how would it be disposed correctly?

Expose config settings for navigation service.

Hi,

This query is to expose config settings for navigation service. This can be achieve using Get.config:

Get.config(
      enableLog = true,
      defaultPopGesture = true,
      defaultTransition = Transitions.cupertino}

Regards,

Stacked services NavigationService.clearTillFirstAndShow throws error

Attempting to navigate to next page using locator<NavigationService>().clearTillFirstAndShow(Routes.appBaseViewRoute); but it throws error on popUntil()

Error
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: type '(dynamic) => dynamic' is not a subtype of type '(Route<dynamic>) => bool' of 'predicate'

StreamViewModel and initialise()

While exploring around with the StreamViewModel, I noticed it also has an option to call initialise().

By doing this, it does not get the stream since it overrides your implementation and logic thus initialise() does not do anything in this context.

If there is any other use case for this being here do let me know as I felt it is a bug, not sure I might be wrong but I thought it's worth bringing up :)

PS - Awesome work on the Stacked package, I've been following @FilledStacks since your TikTok UI video and it's been a great learning curve where I've learned and deployed few production apps already with it!

StreamViewModel - A ViewModel that makes it easier to react to stream values in a ViewModel

In a few of the implementations using v1 of this architecture (packaged in provider_architecture) there were many applications that make use of streams from the services. In most cases of using firestore this will be the case. The usual implementation of a ViewModel that makes use of a stream will look like below.

class OrdersViewModel extends BaseViewModel {
  final OrderService orderService = locator<OrderService>();
  
  List<Order> _orders;
  List<Order> get orders => _orders;

  Future initialise() {
   setBusy(true);
    orderService.ordersStream.listen((incomingOrders) {
       _orders = incomingOrders;
       notifyListeners();
       setBusy(false);
    }
  }
}

That's a general implementation of consuming a stream of a certain type from a service. To make is clear, I know it's possible to use the StreamBuilder to consume a stream but I want the ViewModel to control everything, I also like having that place where I can log the data.

That's the reason I am now suggesting that we implement a StreamViewModel along with the BaseViewModel and ReactiveViewModel that already exists. It will take care of the above boilerplate code for us along with disposing. I like the way that the StreamBuilder implements their functionality so something similar would be great.

An abstract class that requires you to override required methods and implements some base functionality.

  • onSubscribed: called when the stream is first subscribed and passes through the first value)
  • onData: called whenever a new value comes through
  • onError: called when the stream sends through an error
  • onCancel: if possible, called when the stream is unsubscribed.

In addition to above we also should be able to insert some additional logic before setting the data. This could be where we log data, transform the incoming date or add additional logic. For instance in one of the apps we built we had to close a details panel if the order that's selected is not in the orders returned. That calculation can be done here before notifyListeners is called.

We have to ensure that the stream is disposed properly and rebuilds of the widget does not cause any problems.

Stacked with responsive builder

Hi, I'm Trying to implement a very basic app, but it doesn’t carry over the state (from portrait to landscape) or vice-versa , Or there's something I'm missing
My snip code :

HomeView

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<HomeViewModel>.reactive(
      viewModelBuilder: () => HomeViewModel(),
      onModelReady: (model) => model.initialise(),
      builder: (context, model, child) => ScreenTypeLayout.builder(
        mobile: (context) => OrientationLayoutBuilder(
          portrait: (context) => HomeMobilePortrait(),
          landscape: (context) => HomeMobileLandscape(),
        ),
      ),
    );
  }
}

Portrait

class HomeMobilePortrait extends ViewModelWidget<HomeViewModel> {
  @override
  Widget build(BuildContext context, HomeViewModel model) {
    return Scaffold(
      body: Container(
        child: Text(model.title),
        alignment: Alignment.center,
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => model.updateTitle(),
      ),
    );
  }
}

Landscape

class HomeMobileLandscape extends ViewModelWidget<HomeViewModel> {
  @override
  Widget build(BuildContext context, HomeViewModel model) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: Text(
          model.title,
          style: TextStyle(color: Colors.purple),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => model.updateTitle(),
      ),
    );
  }
}

Stacked Services - Get Compiler error

When you see something similar to below you're most likely not using the stable branch of flutter. If that's the case you'll have to override the get package version to point to the dev-master version. It's the version on the right side of the two versions here

In your pubspec.yaml file add

dependency_overrides:
  get: '2.0.9-dev'

Excpected or similar output below. Anything with get in the paths provided.

Compiler message:
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:279:8: Error: The method 'SnackRoute.install' has more required arguments than those of overridden method 'OverlayRoute.install'.
void install(OverlayEntry insertionPoint) {
^
/C:/flutter/packages/flutter/lib/src/widgets/routes.dart:41:8: Context: This is the overridden method ('install').
void install() {
^
Compiler message:
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:279:8: Error: The method 'SnackRoute.install' has more required arguments than those of overridden method 'OverlayRoute.install'.
void install(OverlayEntry insertionPoint) {
^
/C:/flutter/packages/flutter/lib/src/widgets/routes.dart:41:8: Context: This is the overridden method ('install').
void install() {
^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/routes/default_route.dart:242:9: Error: No named parameter with the name 'animation'.
animation: animation,
^^^^^^^^^
/C:/flutter/packages/flutter/lib/src/cupertino/route.dart:436:3: Context: Found this candidate, but the arguments don't match.
CupertinoFullscreenDialogTransition({
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:289:18: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
super.install(insertionPoint);
^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/routes/default_route.dart:242:9: Error: No named parameter with the name 'animation'.
animation: animation,
^^^^^^^^^
/C:/flutter/packages/flutter/lib/src/cupertino/route.dart:436:3: Context: Found this candidate, but the arguments don't match.
CupertinoFullscreenDialogTransition({
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/get-1.17.3/lib/src/snackbar/snack_route.dart:289:18: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
super.install(insertionPoint);
^
Target kernel_snapshot failed: Exception: Errors during snapshot creation: null
build failed.

Arguments in NavigationService

When using the NavigationService to navigate to a new view, how do you access the navigation arguments in the ViewModel of the new View, I can't see anything in the NavigationService class that gives access to the passed arguments?

README update

Hi,

I was checking the documentation and there's an error on BaseViewModel example:

class WidgetOne extends StatelessWidget {
  ...
          // A bit silly to pass the same property back into the viewmodel
          // but here it makes sense
          child: model.busy(model.currentHuman) // This return true if we have the model
              ? Center(
                  child: CircularProgressIndicator(),
                )
              : Container(/* Human Details styling */)
        ),
      ),
    );
  }
}

It should be this:

class WidgetOne extends StatelessWidget {
  ...
          // A bit silly to pass the same property back into the viewmodel
          // but here it makes sense
          child: model.busy(model.currentHuman) // This return true if we have the model
              ? Container(/* Human Details styling */)
              :  Center(
                  child: CircularProgressIndicator(),
                )
        ),
      ),
    );
  }
}

This is based on the BaseViewModel implementation:

Map<int, bool> _busyStates = Map<int, bool>();

  /// Returns the busy status for an object if it exists. Returns false if not present
  bool busy(Object object) => _busyStates[object.hashCode] ?? false;

Regards,

Stacked_services clearStackAndShow

Hi
First of all thank u for this awesome package .
Second
I’m getting this error when I’m using clearStackAndShow method to navigate .

Unhandled Exception: Bad state: Future already completed

method pushNamedAndRemoveUntil works fine though .
Using Version ^0.2.2 .

More devs

Stacked seems very interesting, as it answers many of the architecture decisions a developer needs to make. Nice work @FilledStacks

As people start adopting this package, you will need help debugging the issues that arise, and implement new features. You will also need a technical writer, and give Stacked a website of its own.

Early adopters will test any new idea. But if you want to give this package a serious adoption rate, you need to get more devs on your team. I have seen how small teams have stifled projects. I makes sense to find a trusted second man for the project and its Github account.

NotifyListeners being called on disposed ViewModel

Hi Team,

Firstly, thanks for the library and the youtube channel.

I have been using the provider model and a variation of your initial framework for a couple of months and I am in the process of migrating to Stacked.

A common scenario we seem to experience is the following -

  1. Widget calls function in ViewModel
  2. View Model makes async call
  3. User navigates somewhere else before the async call is finished.
  4. Async call finishes
  5. Dart then continues running the code in the view model .. with the next line after the async call being notifyListeners.

The issue we are having is that we get an exception complaining about the ViewModel being disposed and that we should not call notify listeners.

I have solved this issue using the following code which is basically my own class that extends your BaseViewModel -

`
class BaseViewModelExtended extends BaseViewModel {

bool _disposed = false;
bool get disposed => _disposed;

void notifyListeners() {
safeNotifyListeners();
}

void safeNotifyListeners() {
if (!disposed) super.notifyListeners();
}

@OverRide
void dispose() {
super.dispose();
_disposed = true;
}
}
`
I am happy to know if I am missing something so I can correct the code. Otherwise, could you consider adding something similar to stacked?

Regards,
Tarek

responsive layout

Is this package a combination of responsive_builder and provider architecture packages (best of both worlds)?
Does this package support responsive layouts out of the box (different phone sizes)?

Awesome package. Thanks!!

Order changelogs by latest

Generally, it's considered a best practice to organize changelogs latest first.

Most changelogs in pub read most recent first, however stacked reads in reverse.

This means that if you're subscribing to pub changes via an RSS reader, or just viewing the changes on pub.dev, you will always have to scroll to see the latest version.

Screenshot_20200426-104830~2

MultipleStreamViewModel with parameters

How would you initialize/use MultipleStreamViewModel when a Stream which needs to take in parameters? And those parameters change over the lifetime of your model; and you have to cancel that stream and listen to a new stream with new values for your parameters.

e.g.:

Stream<int> getIdsByDate(DateTime date) async* {
 ...
}

How to access another VM?

In many cases, business logic needs to access a value of another ViewModel, such as the selected Id to request data, how to solve ? thanks for answer

[stacked] Updating View Models from a parent

I am not sure if this should be a feature request as I might be misunderstanding the proper usage of the stacked package in this scenario.

Essentially: what do I do if I need a view model that reacts to the widget tree.

Say, I have the following:

// A widget contains a ViewModelBuilder
viewModelBuilder: () => AppleViewModel(apples)

Now, the AppleViewModel will be initalized with 10. However, the AppleWidget might change and have 11 apples at a later point. Unfortunately, the view model needs to act differently with 11 apples. However, the viewModelBuilder will not be called again.

How do I update a view model based on a value that changed in the widget tree?


To add a little bit of context, the apples value would also be controlled by a view model. Thus, I basically want to update a view model from a parent view model.


If this is not yet implemented and I am not missing how to properly use the architecture, this would be a feature request 🙂 (let me know if my train of thought here is incorrect altogether)

StatefulWidget

Usually, this task would be accomplished using a StatefulWidget and to my understanding, I should not use them with stacked. In a StatefulWidget, I have access to didChangeDependencies, which allows me to solve the above problem using Provider/InheritedWidget or I can use didUpdateWidget if the value is passed as a parameter.

FutureViewModel - Not being rebuilt when view is rebuilt

At the outset, big thanks for sharing the library which helped me to simplify the state management. I wonder whether I am following the right way to rebuild FutureViewModel.

My initial view has a text field (for the user to enter search string) and a text that represent the search result.


class SearchFutureView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<SearchFutureViewModel>.reactive(
      builder: (context, viewModel, child) {
        return Scaffold(
          body: Padding(
            padding: const EdgeInsets.all(30.0),
            child: Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                _StringForm(),
                FutureExampleView(
                  searchString: viewModel.searchText ?? 'Yet to initiate the search',
                ),
              ],
            ),
          ),
        );
      },
      viewModelBuilder: () => SearchFutureViewModel(),
    );
  }
}

class _StringForm extends HookViewModelWidget<SearchFutureViewModel> {
  _StringForm({Key key}) : super(key: key, reactive: false);

  @override
  Widget buildViewModelWidget(BuildContext context, SearchFutureViewModel viewModel) {
    var text = useTextEditingController();
    return TextField(
      controller: text,
      onSubmitted: (value) {
        viewModel.updateSearchText(value);
      }
    );
  }
}

class SearchFutureViewModel extends BaseViewModel {
  String _searchText;
  String get searchText => _searchText;

  void updateSearchText(String value) {
    _searchText = value;
    notifyListeners();
  }
}

Modified your example on future to accept the searchString

class FutureExampleView extends StatelessWidget {
  final String searchString;

  const FutureExampleView({Key key, this.searchString}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<FutureExampleViewModel>.reactive(
      builder: (context, viewModel, child) {
        return Expanded(
          child: viewModel.hasError
              ? Container(color: Colors.red)
              : Center(
                  child: viewModel.isBusy ? CircularProgressIndicator() : Text(viewModel.data),
                ),
        );
      },
      viewModelBuilder: () => FutureExampleViewModel(searchString),
    );
  }
}

class FutureExampleViewModel extends FutureViewModel<String> {

  final _dialogService = locator<DialogService>();

  final String sampleData ;

  FutureExampleViewModel(this.sampleData);

  Future<String> getDataFromServer() async {
    await Future.delayed(Duration(seconds: 3));
    return sampleData;
  }

  @override
  Future<String> futureToRun() => getDataFromServer();

  @override
  void onError(error) {
    _dialogService.showDialog(
      title: 'Error with Future',
      description: error.toString(),
    );
    super.onError(error);
  }

  @override
  void dispose() {
    print('FutureExampleViewModel is getting disposed');
    super.dispose();
  }
}

Upon entering text in the text field, build method of FutureExampleView is getting called. However FutureExampleViewModel is not getting called. Can FutureExampleView be called in SearchFutureView should rebuild the FutureExampleViewModel.

Other approach is to call runFuture().

Thanks for looking into this.

StreamViewModel get data based on a parameter?

Hi. Absolutely loving the latest update but have a question regarding StreamViewModel.

Please could you advise how I can listen to a stream based on a provided parameter? It appears the get stream is called before providing any opportunity to pass in a parameter. I have tried the constructor to no avail.

return ViewModelBuilder<EventViewModel>.reactive( disposeViewModel: false, viewModelBuilder: () => EventViewModel(_eventId), builder: (context, model, child) =>

@override Stream<List<EventCategory>> get stream => _database.eventsCategory(_eventId);

Thank you.

_key was called on null

hi Dane

the navigatorKey that i am getting from Navigation services i am getting this error
error

Boilerplate-less binding through RxValue and Extensions

Imagine an extension to Widget that returns another widget that rebuilds based on a stream (it's like just a wrapper for StreamBuilder) but no need to have all the boilerplate in the UI, something like this:

Text('${model.title.value}')
.Bind(model.title)

In this case, model.title is a BindableProperty and calling .value on it will return the current value of it.

BindableProperty is an object that holds a value and whenever you set it will trigger rebuild on the binded widgets (behind the scenes it simply wraps a stream controller) and as mentioned, the .Bind wraps the widget in a StreamBuilder but I'm pretty sure this is where it stops being possible, maybe something different that by exploiting the extension methods we don't need so much boilerplate? I don't know, it's just an idea :)

Comment from Part 1 of the series with a great idea for boilerplate-less binding. Replace BindableProperty with RxValue from Observable-ish and we might have a pretty dope solution on our hands.

I haven'te technically vetted this but I like the idea.

Issue with Custom Dialog [IMPORTANT]

════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Builder(dirty, dependencies: [MediaQuery]):
Failed assertion: boolean expression must not be null

The relevant error-causing widget was
    MaterialApp 
lib\…\global\app_widget.dart:13
When the exception was thrown, this was the stack
#0      setupCustomDialogUI.<anonymous closure> 
package:split_it/…/utils/custom_dialog.dart:47
#1      DialogService.showCustomDialog.<anonymous closure>.<anonymous closure> 
package:stacked_services/…/dialog/dialog_service.dart:145
#2      Builder.build 
package:flutter/…/widgets/basic.dart:6998
#3      StatelessElement.build 
package:flutter/…/widgets/framework.dart:4576
#4      ComponentElement.performRebuild 
package:flutter/…/widgets/framework.dart:4502
...
════════════════════════════════════════════════════════════════════════════════

The issue is with this piece of code, it says boolean expression must not be null. Which means the dialogRequest.showIconInMainButton does not have a default value so I have to add this when showing a dialog:

await dialogService.showCustomDialog(
      title: 'My custom dialog',
      description: 'This is my dialog description',
      mainButtonTitle: 'Confirm',
      // this argument is not required nor does it have a default value which makes it weird and it 
      // makes an error, hope you got my point
      showIconInMainButton: true, 
    );

This is not so obvious nor documented. So I hope you can add a default value for dialogRequest.showIconInMainButton.

onModelReady method completion?

I have several StatefulWidgets that use exactly this syntax:
onModelReady: (model) => model.initialise(),

The model.initialise method does a setBusy(true), then gets on with reading data.
However, the first build of the page completes before setBusy(true) is set and notified, causing errors with incomplete data from the model.

I also tried this: onModelReady: (model) async => await model.initialise(),

Is there an easy way to halt until the onModelReady method has completed?

Missing Licenses

The packages should have proper LICENSE files. These files are included in the assets for any Flutter app that uses one the packages.

Multiple streams

How would you implement multiple streams with the StreamViewModel currently? I would imagine combining and transforming streams to get multiple types out of them could get tedious.

My two cents:

I would think the best implementation would be the way you set up Provider previously:

providers = [
    ..._independentServices,
    ..._dependentServices,
    ..._consumableServices,
  ];

Maybe it would it make sense to have something like this:

abstract class StreamsViewModel extends BaseViewModel {

List<StreamsMixin<T>> get streams;

StreamsViewModel(){
    _listenToStreams(streams);
}
  void _listenToStreams(List<StreamsMixin> streams) {
    _streams = streams;
    for (var stream in _streams) {
      stream.addListener(_indicateChange);
    }
  }

Where the StreamsMixin does the same thing that the StreamViewModel does. Does that make sense? If I'm missing something and this is already doable, then an example of multiple streams would go a long way. Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.