observable_pattern 1.0.6 copy "observable_pattern: ^1.0.6" to clipboard
observable_pattern: ^1.0.6 copied to clipboard

outdated

Observable Pattern is a pattern that use a class to hold a value to manage changes to dispatch notification for every callbacks

Observable Pattern #

Example #

import 'package:flutter/material.dart';
import 'package:observable_pattern/observable_pattern.dart';

//Create a store with variables of type Observable
class MyStore {
  final email = Observable<String, String>();
  final password = Observable<String, String>();
  Observable<bool, void> _canSubmit;
  final loading = Observable<bool, void>(false);
  final done = Observable<bool, void>(false);

  MyStore() {
    email.transformer = (event) {
      if (event == null || event.isEmpty) {
        return 'Type your email';
      } else {
        return null;
      }
    };
    password.transformer = (event) {
      if (event == null || event.isEmpty) {
        return 'Type your password';
      } else {
        return null;
      }
    };
  }

  void signIn() async {
    if (loading.value) return;
    canSubmit.validate();
    if (!canSubmit.value) return;
    loading.add(true);
    await Future.delayed(const Duration(seconds: 3));
    loading.add(false);
    done.add(true);
  }

  Observable<bool, void> get canSubmit {
    if (_canSubmit == null) {
      _canSubmit = Observable.combine<String, String>([email, password]);
    }
    return _canSubmit;
  }
}

//Initialize your app
class MyApp extends StatelessWidget {
  final String title;

  const MyApp({Key key, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: title,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: LoginScreen(title: title),
    );
  }
}

//Create your own stateful screen
class LoginScreen extends StatefulWidget {
  final String title;

  const LoginScreen({Key key, this.title}) : super(key: key);

  @override
  _LoginScreenState createState() => _LoginScreenState();
}

//Into your state class put your store and the magic will begin
class _LoginScreenState extends State<LoginScreen> {
  final store = MyStore();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback(callback);
  }

  void callback(_) {
    final focus = FocusScope.of(context);
    store.loading.addListener((bool event) {
      if (event) {
        focus.unfocus();
        //do something...
      }
    });
    store.done.addListener((bool event) {
      if (event) {
        //do something...
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: <Widget>[
        Scaffold(
          appBar: AppBar(
            centerTitle: true,
            title: Text(widget.title),
          ),
          body: Padding(
            padding: const EdgeInsets.all(24.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Observer<String, String>(
                  observable: store.email,
                  builder:
                      (BuildContext context, AsyncSnapshot<String> snapshot) =>
                          TextField(
                    decoration: InputDecoration(
                      labelText: 'E-mail',
                      errorText: snapshot.error,
                    ),
                    onChanged: store.email.add,
                  ),
                ),
                Observer<String, String>(
                  observable: store.password,
                  builder:
                      (BuildContext context, AsyncSnapshot<String> snapshot) =>
                          TextField(
                    decoration: InputDecoration(
                      labelText: 'Password',
                      errorText: snapshot.error,
                    ),
                    obscureText: true,
                    onChanged: store.password.add,
                  ),
                ),
                const SizedBox(height: 24.0),
                RaisedButton(
                  shape: StadiumBorder(),
                  color: Colors.blue,
                  onPressed: store.signIn,
                  child: Text(
                    'Sign in without reactive',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
                const SizedBox(height: 24.0),
                Observer<bool, void>(
                  observable: store.canSubmit,
                  builder:
                      (BuildContext context, AsyncSnapshot<bool> snapshot) =>
                          RaisedButton(
                    shape: StadiumBorder(),
                    color: Colors.blue,
                    onPressed: snapshot.data ? store.signIn : null,
                    child: Text(
                      'Sign in with reactive',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
        Observer<bool, void>(
          observable: store.loading,
          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) =>
              snapshot.data
                  ? Material(
                      color: Colors.black54,
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          CircularProgressIndicator(
                            valueColor:
                                AlwaysStoppedAnimation<Color>(Colors.white),
                          ),
                        ],
                      ),
                    )
                  : Container(),
        )
      ],
    );
  }
}

//Initialize your dart app
void main() => runApp(MyApp(title: 'Observable Pattern Example'));

Observable class #

//This is how initialize the observable class that holds a value and listen to changes
//you don't need to pass an initial value, but you can set an initial value
Observable<T, E>('Initial Value'); // you can type like T is the type of the value and E is the type of the error.

//you can pass a function to validate the value and reproduce an error object.
 Observable.transformer = (event) {
      if (event == null || event.isEmpty) {
        // return the type of the error if something is wrong
        return 'Type your email';
      } else {
        //return null if everything is ok
        return null;
      }
    };

//You can listen to changes when the value change with addListener.
Observable.addListener((event) {
// do something...
});

//you can change the value with two ways
Observable<String,String>.value  = 'New Value';
//or
Observable<String,String>.add('New Value');
//after this the object will listen to the new value and validate automatically

//you can validate manually by yourself using
Observable.validate();

//you can validate and listen to all objects into one using a static function from the object
Observable.combine<T,E>(<Observable<T,E>>[object1, object2])
/*
this static function will return an Observable<bool,void> that listen for every elements inside and validate then using
Observable.validate(); and hold a bool value that indicate if every object inside is validated without error if false
it'll indicate that an object has an error.
*/ 

Observer Widget #

Observer Widget is a widget that listen changes when a value inside Observable class and change rebuild only where it's localized

in this example only the text widget will be rebuild.

   Observer<T, E>(
          observable: observableObject,
          builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
            return Text('${snapshot.hasData ? snapshot.data : ''}'); 
          },

ObserverInjection #

It is a simple way to inject dependencies using Inherited Widget and listen if the object injected change and rebuild everything that is inside it

//Inject
ObserverInjection<UserData>(
builder: (context) => UserData(),
child: Container(),
//If necessary you can dispose
dispose: (context, UserData user) => user.dispose(),
);

//Read
final UserData user = ObserverInjection.of<UserData>(context);
2
likes
0
pub points
0%
popularity

Publisher

verified publishervegasdevelopments.com

Observable Pattern is a pattern that use a class to hold a value to manage changes to dispatch notification for every callbacks

Homepage

License

unknown (LICENSE)

Dependencies

flutter

More

Packages that depend on observable_pattern