one_context 0.4.0
one_context: ^0.4.0

Flutter Android iOS web

OneContext provides a simple way to deal with Dialogs, Overlays, Navigations, Theme* and MediaQuery* with no need of BuildContext.

example/lib/main.dart

import 'dart:math';
import 'package:flutter/services.dart';
import 'package:one_context/one_context.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

bool debugShowCheckedModeBanner = false;
const localeEnglish = [Locale('en', '')];

void main() => OnePlatform.app = () => MyApp();

class MyApp extends StatelessWidget {
  MyApp() {
    print('MyApp loaded!');
    debugShowCheckedModeBanner = true;

    // Reseting light theme
    if (OneContext.hasContext)
      OneContext().oneTheme.changeThemeData(
          ThemeData(primarySwatch: Colors.green, brightness: Brightness.light));
  }

  @override
  Widget build(BuildContext context) {
    /// important: Use [OneContext().builder] in MaterialApp builder, in order to show dialogs, overlays and change the app theme.
    /// important: Use [OneContext().key] in MaterialApp navigatorKey, in order to navigate.

    return OneNotification<List<Locale>>(
      onVisited: (_, __) {
        print('Root widget visited!');
      },
      // This widget rebuild the Material app to update theme, supportedLocales, etc...
      stopBubbling: true, // avoid the data bubbling to ancestors widgets
      initialData:
          localeEnglish, // [data] is null during boot of the application, but you can set initialData ;)
      rebuildOnNull:
          true, // Allow other entities reload this widget without messing up currenty data (Data is cached on first event)

      builder: (context, dataLocale) {
        if (dataLocale != null && dataLocale != localeEnglish)
          print('Set Locale: $dataLocale');

        return OneNotification<OneThemeChangerEvent>(
            onVisited: (_, __) {
              print('Theme Changer widget visited!');
            },
            stopBubbling: true,
            builder: (context, data) {
              return MaterialApp(
                debugShowCheckedModeBanner: debugShowCheckedModeBanner,

                // Configure reactive theme mode and theme data (needs OneNotification above in the widget tree)
                themeMode: OneThemeController.initThemeMode(ThemeMode.light),
                theme: OneThemeController.initThemeData(ThemeData(
                    primarySwatch: Colors.green, brightness: Brightness.light)),
                darkTheme: OneThemeController.initDarkThemeData(
                    ThemeData(brightness: Brightness.dark)),

                // Configure [OneContext] to dialogs, overlays, snackbars, and ThemeMode
                builder: OneContext().builder,
                // builder: (context, widget) => OneContext().builder(context, widget, mediaQueryData: MediaQuery.of(context).copyWith(textScaleFactor: 1.0)),

                // Set navigator key in order to navigate
                navigatorKey: OneContext().key,

                // [data] comes through events
                supportedLocales: dataLocale ?? [const Locale('en', '')],

                title: 'OneContext Demo',
                home: MyHomePage(
                  title: 'OneContext Demo',
                ),
                routes: {'/second': (context) => SecondPage()},
              );
            });
      },
    );
  }
}

class MyApp2 extends StatelessWidget {
  MyApp2() {
    print('MyApp2 loaded!');
    OneContext().key = GlobalKey<NavigatorState>();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        theme: ThemeData(primarySwatch: Colors.pink),
        title: 'OneContext Demo',
        home: MyHomePage2(title: 'BOOT A NEW APPLICATION'),
        routes: {'/second': (context) => SecondPage()},
        builder: OneContext().builder,
        navigatorKey: OneContext().key);
  }
}

class MyHomePage2 extends StatefulWidget {
  MyHomePage2({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePage2State createState() => _MyHomePage2State();
}

class _MyHomePage2State extends State<MyHomePage2> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        color: Colors.pink,
        alignment: Alignment.center,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
                child: Text('COME BACK TO THE OLD APP'),
                onPressed: () {
                  OnePlatform.reboot(
                    setUp: () {
                      OneContext().key = GlobalKey<NavigatorState>();
                    },
                    builder: () => MyApp(),
                  );
                }),
            RaisedButton(
                child: Text('Navigate to Second Page'),
                onPressed: () {
                  OneContext().pushNamed('/second');
                })
          ],
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String reloadAppButtonLabel;
  MyHomePage({Key key, this.title, this.reloadAppButtonLabel})
      : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Map<String, Offset> randomOffset = Map<String, Offset>();
  AnimationController _controller;
  Animation<Offset> _offsetAnimation;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      duration: const Duration(milliseconds: 1000),
      vsync: this,
    );

    _offsetAnimation = Tween<Offset>(
      begin: Offset(0, -1),
      end: const Offset(0, 0),
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOutCubic,
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Container(
          alignment: Alignment.center,
          padding: EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              SizedBox(height: 20),
              RaisedButton(
                child: Text(
                    'Soft Reload (ShowModeBanner = $debugShowCheckedModeBanner)'),
                onPressed: () {
                  debugShowCheckedModeBanner = !debugShowCheckedModeBanner;
                  OneNotification.softReloadRoot(
                      context); // It will visit ancestors till the root OneNotificationBuilder widget)
                },
              ),
              RaisedButton(
                child: Text('Hard Reload'),
                onPressed: () {
                  OneNotification.hardReloadRoot(context);
                },
              ),
              RaisedButton(
                child: Text('Soft Reeboot the app'),
                onPressed: () {
                  OnePlatform.reboot(setUp: () => print('Reboot the app!'));
                },
              ),
              RaisedButton(
                child: Text('Setup and Hard Reeboot'),
                onPressed: () {
                  OnePlatform.reboot(
                      builder: () => MyApp(),
                      setUp: () {
                        print(
                            '\n\nSetting debugShowCheckedModeBanner = true, so the debug banner should appear on the app right now.'
                            '\n\n That is useful for load environment variables and project configuration before boot the app!'
                            '\n And if you just need run some stuffs and reload the app without change it.');
                        debugShowCheckedModeBanner = true;
                      });
                },
              ),
              RaisedButton(
                child: Text('Load another app'),
                onPressed: () {
                  OnePlatform.reboot(
                      setUp: () {
                        OneContext().key = GlobalKey<NavigatorState>();
                      },
                      builder: () => MyApp2());
                },
              ),
              RaisedButton(
                child: Text('Change ThemeData Light'),
                onPressed: () {
                  OneContext().oneTheme.changeThemeData(ThemeData(
                      primarySwatch: Colors.purple,
                      brightness: Brightness.light));
                },
              ),
              RaisedButton(
                child: Text('Change ThemeData Dark'),
                onPressed: () {
                  OneContext().oneTheme.changeDarkThemeData(ThemeData(
                      primarySwatch: Colors.amber,
                      brightness: Brightness.dark));
                },
              ),
              RaisedButton(
                child: Text('Toggle ThemeMode (Dark/Light)'),
                onPressed: () {
                  OneContext().oneTheme.toggleMode();
                },
              ),
              RaisedButton(
                child: Text('Change to english locale support'),
                onPressed: () {
                  OneNotification.notify<List<Locale>>(context,
                      payload: NotificationPayload(data: [
                        Locale('en', ''), // English
                      ]));
                },
              ),
              RaisedButton(
                child: Text('Show SnackBar'),
                onPressed: () {
                  showTipsOnScreen('OneContext().showSnackBar()');
                  OneContext()
                      .dismissSnackBar(); // Dismiss snackbar before show another ;)
                  OneContext().showSnackBar(
                      builder: (context) => SnackBar(
                            content: Text(
                              'My awesome snackBar!',
                              textAlign: TextAlign.center,
                              style: Theme.of(context)
                                  .textTheme
                                  .title
                                  .copyWith(color: Colors.white),
                            ),
                            action: SnackBarAction(
                                label: 'DISMISS', onPressed: () {}),
                          ));
                },
              ),
              RaisedButton(
                child: Text('Show Dialog'),
                onPressed: () async {
                  showTipsOnScreen('OneContext().showDialog<String>()');

                  var result = await OneContext().showDialog<String>(
                      // Don't need context to show alertDialog
                      builder: (context) => AlertDialog(
                            title: new Text("The Title"),
                            content: new Text("The Body"),
                            actions: <Widget>[
                              new FlatButton(
                                  child: new Text("OK"),
                                  onPressed: () =>
                                      OneContext().popDialog('ok')),
                              new FlatButton(
                                  child: new Text("CANCEL"),
                                  onPressed: () =>
                                      OneContext().popDialog('cancel')),
                            ],
                          ));
                  print(result);
                },
              ),
              RaisedButton(
                child: Text('Show modalBottomSheet'),
                onPressed: () async {
                  showTipsOnScreen(
                      'OneContext().showModalBottomSheet<String>()');
                  var result = await OneContext().showModalBottomSheet<String>(
                      builder: (context) => Container(
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              children: <Widget>[
                                ListTile(
                                    leading: Icon(Icons.music_note),
                                    title: Text('Music'),
                                    onTap: () =>
                                        OneContext().popDialog('Music')),
                                ListTile(
                                    leading: Icon(Icons.videocam),
                                    title: Text('Video'),
                                    onTap: () =>
                                        OneContext().popDialog('Video')),
                                SizedBox(height: 45)
                              ],
                            ),
                          ));
                  print(result);
                },
              ),
              RaisedButton(
                child: Text('Show bottomSheet'),
                onPressed: () {
                  showTipsOnScreen('OneContext().showBottomSheet()');
                  OneContext().showBottomSheet(
                    builder: (context) => Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.all(Radius.circular(10)),
                        color: Colors.red,
                      ),
                      margin: EdgeInsets.all(16),
                      alignment: Alignment.topCenter,
                      height: 200,
                      child: IconButton(
                          icon: Icon(Icons.arrow_drop_down),
                          iconSize: 50,
                          color: Colors.white,
                          onPressed: () => OneContext().popDialog()),
                    ),
                  );
                },
              ),
              RaisedButton(
                  child: Text('Show and block till input'),
                  onPressed: () async {
                    showTipsOnScreen('OneContext().showDialog<int>()');
                    switch (await OneContext().showDialog<int>(
                        barrierDismissible: false,
                        builder: (BuildContext context) {
                          return SimpleDialog(
                            shape: RoundedRectangleBorder(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10))),
                            title: const Text('Select assignment'),
                            children: <Widget>[
                              SimpleDialogOption(
                                onPressed: () {
                                  OneContext().popDialog(1);
                                },
                                child: const Text('Number 1'),
                              ),
                              SimpleDialogOption(
                                onPressed: () {
                                  OneContext().popDialog(2);
                                },
                                child: const Text('Number 2'),
                              ),
                            ],
                          );
                        })) {
                      case 1:
                        print('number one');
                        break;
                      case 2:
                        print('number two');
                        break;
                    }
                  }),
              RaisedButton(
                child: Text('Show default progress indicator'),
                onPressed: () {
                  showTipsOnScreen('OneContext().showProgressIndicator()');

                  OneContext().showProgressIndicator();
                  Future.delayed(Duration(seconds: 2),
                      () => OneContext().hideProgressIndicator());
                },
              ),
              RaisedButton(
                child: Text('Show progress indicator colored'),
                onPressed: () {
                  showTipsOnScreen(
                      'OneContext().showProgressIndicator(backgroundColor, circularProgressIndicatorColor)');
                  OneContext().showProgressIndicator(
                      backgroundColor: Colors.blue.withOpacity(.3),
                      circularProgressIndicatorColor: Colors.red);
                  Future.delayed(Duration(seconds: 2),
                      () => OneContext().hideProgressIndicator());
                },
              ),
              RaisedButton(
                child: Text('Show custom progress indicator'),
                onPressed: () {
                  showTipsOnScreen(
                      'OneContext().showProgressIndicator(backgroundColor, circularProgressIndicatorColor)');
                  OneContext().showProgressIndicator(
                    builder: (_) => Container(
                        color: Colors.black38,
                        alignment: Alignment.center,
                        child: SizedBox(
                          height: 80,
                          width: 80,
                          child: Card(
                            color: Colors.white,
                            elevation: 0,
                            // shape: RoundedRectangleBorder(),
                            child: Center(child: CircularProgressIndicator()),
                          ),
                        )),
                  );
                  Future.delayed(Duration(seconds: 2),
                      () => OneContext().hideProgressIndicator());
                },
              ),
              RaisedButton(
                child: Text('Show custom animated indicator'),
                onPressed: () {
                  showTipsOnScreen(
                      'OneContext().showProgressIndicator(builder)');
                  OneContext().showProgressIndicator(
                      builder: (_) => SlideTransition(
                            position: _offsetAnimation,
                            child: Container(
                              padding: EdgeInsets.only(top: 120),
                              alignment: Alignment.topCenter,
                              child: Container(
                                  alignment: Alignment.center,
                                  height: 60,
                                  width: 60,
                                  decoration: BoxDecoration(
                                    color: Colors.yellow,
                                    borderRadius: BorderRadius.circular(30),
                                  ),
                                  child: CircularProgressIndicator()),
                            ),
                          ),
                      backgroundColor: Colors.transparent);
                  _controller.reset();
                  _controller.forward();
                  Future.delayed(Duration(seconds: 3), () {
                    _controller.reverse().whenComplete(
                        () => OneContext().hideProgressIndicator());
                  });
                },
              ),
              RaisedButton(
                child: Text('Add a generic overlay'),
                onPressed: () {
                  showTipsOnScreen('OneContext().addOverlay(builder)');
                  String overId = UniqueKey().toString();
                  double getY() => Random()
                      .nextInt(
                          (MediaQuery.of(context).size.height - 50).toInt())
                      .toDouble();
                  double getX() => Random()
                      .nextInt((MediaQuery.of(context).size.width - 50).toInt())
                      .toDouble();
                  randomOffset.putIfAbsent(
                      overId, () => Offset(getX(), getY()));
                  Widget w = RaisedButton(
                      child: Text(
                        'CLOSE OR DRAG',
                        style: TextStyle(color: Colors.white),
                      ),
                      color: Colors.blue,
                      onPressed: () {
                        OneContext().removeOverlay(overId);
                      });
                  OneContext().addOverlay(
                      builder: (_) => Positioned(
                          top: randomOffset[overId].dy,
                          left: randomOffset[overId].dx,
                          child: Draggable(
                            onDragEnd: (DraggableDetails detail) =>
                                randomOffset[overId] = detail.offset,
                            childWhenDragging: Container(),
                            child: w,
                            feedback: w,
                          )),
                      overlayId: overId);
                },
              ),
              RaisedButton(
                child: Text('Push a second page (push)'),
                onPressed: () async {
                  showTipsOnScreen('OneContext().push()');
                  String result = await OneContext().push<String>(
                      MaterialPageRoute(builder: (_) => SecondPage()));
                  print('$result from OneContext().push()');
                },
              ),
              RaisedButton(
                child: Text('Push a second page (pushNamed)'),
                onPressed: () async {
                  showTipsOnScreen('OneContext().pushNamed()');
                  Object result = await OneContext().pushNamed('/second');
                  print('$result from OneContext().pushNamed()');
                },
              ),
              RaisedButton(
                child: Text('Show MediaQuery info'),
                onPressed: () async {
                  MediaQueryData mediaQuery = OneContext().mediaQuery;
                  String info =
                      'orientation: ${mediaQuery.orientation.toString()}\n'
                      'devicePixelRatio: ${mediaQuery.devicePixelRatio}\n'
                      'platformBrightness: ${mediaQuery.platformBrightness.toString()}\n'
                      'width: ${mediaQuery.size.width}\n'
                      'height: ${mediaQuery.size.height}\n'
                      'textScaleFactor: ${mediaQuery.textScaleFactor}';
                  print(info);
                  showTipsOnScreen(info, size: 200, seconds: 5);
                },
              ),
              RaisedButton(
                child: Text('Show Theme info'),
                onPressed: () async {
                  ThemeData theme = OneContext().theme;
                  String info = 'platform: ${theme.platform}\n'
                      'primaryColor: ${theme.primaryColor}\n'
                      'accentColor: ${theme.accentColor}\n'
                      'title.color: ${theme.textTheme.title.color}';
                  print(info);
                  showTipsOnScreen(info, size: 200, seconds: 5);
                },
              ),
              SizedBox(height: 24),
            ],
          ),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(
      appBar: AppBar(),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('Second Page'),
          RaisedButton(
            child: Text('Go Back - pop("success")'),
            onPressed: () {
              // showTipsOnScreen('OneContext().pop("success")');
              OneContext().pop('success');
            },
          ),
        ],
      )));
}

// Dont need context, so features can be create in any place ;)
void showTipsOnScreen(String text, {double size, int seconds}) {
  String id = UniqueKey().toString();
  OneContext().addOverlay(
    overlayId: id,
    builder: (_) => Align(
      alignment: Alignment.topCenter,
      child: Container(
          alignment: Alignment.bottomCenter,
          padding: EdgeInsets.symmetric(
              horizontal: kFloatingActionButtonMargin, vertical: 8),
          child: FlatButton(
            onPressed: null,
            child: Text(
              text,
              style: TextStyle(color: Colors.white, fontSize: 16),
            ),
          ),
          color: Colors.red,
          height: size ?? 100,
          width: double.infinity),
    ),
  );
  Future.delayed(
      Duration(seconds: seconds ?? 2), () => OneContext().removeOverlay(id));
}
34
likes
100
pub points
83%
popularity

OneContext provides a simple way to deal with Dialogs, Overlays, Navigations, Theme* and MediaQuery* with no need of BuildContext.

Repository (GitHub)
View/report issues

Documentation

API reference

Uploader

fastencoding@gmail.com

License

BSD (LICENSE)

Dependencies

flutter, shared_preferences

More

Packages that depend on one_context