xcontext 0.1.0+1

  • Readme
  • Changelog
  • Example
  • Installing
  • new50

xcontext #

This simple package adds static extension methods and getters to the BuildContext context object from the widgets, material, and cupertino libraries.

xcontext makes it easy for you to add static extensions methods and getters to your context from Flutter's widgets, material, and cupertino libraries. You have total control over which methods and getters you want to add to your context, with all the type safety guarantees Dart provides, while keeping your code concise and clean.

Continuous Integration xcontext Published by dartside.dev GitHub Stars Count

About this package #

This package is an experiment to get rid of the SomeClass.of(context).someMethod calls in a codebase. As I was talking to people new to Flutter, I noticed that some people just can't wrap their heads around it, while simple getters and methods just feel intuitive to all of them. The package also simplifies other function calls that require the context to be passed in. I wrote the package in a way that is easy to customize to your needs and selectively add or hide extensions.

Using the package will hopefully make your code easier to type, read and understand.

It's important to mention that the .of static methods should not be considered harmful in any way. If you like that idiom, please feel free to continue using it!

Usage #

// Add all methods and getters to BuildContext
import 'package:xcontext/xcontext.dart';

BuildContext context;
// then...
context.navigator.pushNamed('/other');
context.scaffold;
context.mediaQuery.platformBrightness;
context.theme;
context.dividerTheme;
context.cupertinoLocalizations;
context.cupertinoTheme;
context.showCupertinoDialog(builder: b, useRootNavigator: true); // Don't forget to define the builder.
context.showTimePicker(initialTime: TimeOfDay.now());

If you prefer to be even more concise, use the "tiny" version:

// tiny_xcontext uses shorter names and does not add all getters
import 'package:xcontext/tiny_xcontext.dart';

BuildContext context;
// then...
context.nav.pushNamed('/other');
context.scaf;
context.mq.platformBrightness;
context.theme; // Not all getters are shortened. Theme is short enough already
// context.dividerTheme; // Not all getters are available in "tiny" mode
context.cupL10n;
context.cuptheme;
context.showCupDialog(builder: builder, useRootNavigator: true); // Don't forget to define the builder.
context.showTP(initialTime: TimeOfDay.now());

The libraries of this package #

// Add all methods and getters to BuildContext
import 'package:xcontext/xcontext.dart';
// Alternatively, if you want to extend only from some libraries:
import 'package:xcontext/cupertino.dart';
import 'package:xcontext/material.dart';
import 'package:xcontext/widgets.dart';

// Add some methods and getters to BuildContext, some are shortened
import 'package:xcontext/tiny_xcontext.dart';
// Alternatively, if you want to extend only from some libraries with the short version
import 'package:xcontext/tiny_cupertino.dart';
import 'package:xcontext/tiny_material.dart';
import 'package:xcontext/tiny_widgets.dart';

Libraries: xcontext, cupertino, material, widgets, tiny_xcontext tiny_cupertino tiny_material tiny_widgets

From Navigator.of(context) to context.navigator #

The xcontext package lets you access Something.of(context).someMethod directly on the context as context.something.someMethod. It adds all the .of static methods from the official widgets, material, and cupertino libraries' return value as getters.

So after you imported 'package:xcontext/xcontext.dart', you will be able to write:

import 'package:xcontext/xcontext.dart';

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Instead of Theme.of(context), just write: 
    final theme = context.theme;
    // ...and use the theme as usual:
    print('Current brightness is ${theme.brightness}');
    // ...
    return RaisedButton(
      onPressed: () {
        // Instead of Navigator.of(context), use context.navigator
        context.navigator.pushNamed('/other');
      },
      child: Text('Navigator push'),
    );
  }
}

In case the .of static method accepts extra parameters, those values are exposed in a different getter, such as:

// Navigator.of(context, rootNavigator: true)
context.rootNavigator;
// Theme.of(this, shadowThemeOnly: true);
context.shadowTheme;

Show this, show that! #

All showXYZ methods are added, as well, so now you can write:

import 'package:xcontext/xcontext.dart';
// You can import either xcontext or only material to get showAboutDialog
// import 'package:xcontext/material.dart';

RaisedButton(
  onPressed: () {
    context.showAboutDialog(
      applicationName: 'xcontext example app',
      applicationIcon: FlutterLogo(),
      applicationLegalese: 'Copyright 2020',
      applicationVersion: '1.2.3',
      children: [
        Text('Thank you for using this package!'),
        Text('❤️'),
      ],
    );
  },
);

hide/show #

While the extensions might improve the discoverability of some values, seeing tens of extra methods popping up in your IDE whenever you type "context." can be annoying. For this reason, every getter and method is added as a separate extension, so you can hide or show them as you like.

// // HIDE // //
// If one or more extensions annoy you, hide them.
import 'package:xcontext/material.dart' hide XContextNavigationRailTheme;

// // SHOW // //
// If you only need some extensions, show them, and hide all others.
// Only show context.navigator and context.rootNavigator
import 'package:xcontext/widgets.dart' show XContextNavigator, XContextRootNavigator;

You can export only what you need #

You might conclude that, while using some extensions from the package is great, the other extensions are less great, so you want see only a subset of the extensions everywhere.

Just create a new Dart file, for example your_favorite_extensions.dart, export the extensions you like, and import this file in the rest of your codebase.

// your_favorite_extensions.dart
export 'package:xcontext/xcontext.dart'
    show XContextShowGeneralDialog,  // context.showGeneralDialog
         XContextNavigator, // context.navigator
         XContextRootNavigator, // context.rootNavigator
         XContextScaffold,  // context.scaffold
         XContextMediaQuery; // context.mediaQuery

// You may even write your own context extensions here.
// Some other file...
import 'package:your_awesome_app/your_favorite_extensions.dart';

The tiny variation #

This package also has a tiny variation of the extensions. The tiny version is great is you prefer brevity. 'package:xcontext/tiny_xcontext.dart' does not include all the possible getters and methods, and some getters were renamed so that you can write less code while keeping everything straightforward:

import 'package:xcontext/tiny_xcontext.dart';

// then...
context.nav.pop();
final isLight = context.mq.platformBrightness == Brightness.light;

0.1.0 - May 24, 2020 #

Initial release. This simple package adds static extension methods and getters to the BuildContext context object from the widgets, material, and cupertino libraries.

0.1.0+1 includes docs improvements.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'package:xcontext/xcontext.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('xcontext'),
        ),
        body: Example(),
      ),
    );
  }
}

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final TextDirection textDirection = context.textDirection;
    print('Text direction: $textDirection}');
    return Wrap(
      children: [
        for (final button in [
          RaisedButton(
            color: Colors.orange,
            onPressed: () {
              context.showDatePicker(
                initialDate: DateTime.now(),
                firstDate: DateTime.now(),
                lastDate: DateTime.now().add(Duration(days: 7)),
              );
            },
            child: Text('Date picker'),
          ),
          RaisedButton(
            color: Colors.red,
            onPressed: () {
              context.navigator
                  .push(MaterialPageRoute(builder: (_) => ExampleRoute()));
            },
            child: Text('Navigator push'),
          ),
          RaisedButton(
            color: Colors.indigo,
            onPressed: () {
              context.showModalBottomSheet(
                builder: (_) => BottomSheet(
                  builder: (_) => Padding(
                    padding: const EdgeInsets.all(28.0),
                    child: Popper(),
                  ),
                  onClosing: () {},
                ),
              );
            },
            child: Text('Show Modal Bottom Sheet'),
          ),
          RaisedButton(
            color: Colors.cyanAccent,
            onPressed: () {
              final time = context.showTimePicker(initialTime: TimeOfDay.now());
              print('selected time is $time');
            },
            child: Text('Show Time Picker'),
          ),
          RaisedButton(
            color: Colors.green,
            onPressed: () {
              context.showAboutDialog(
                  applicationName: 'xcontext example app',
                  applicationIcon: FlutterLogo(),
                  applicationLegalese: 'Copyright 2020',
                  applicationVersion: '1.2.3',
                  children: [
                    Text('Thank you for using this package!'),
                    Text('❤️'),
                  ]);
            },
            child: Text('Show About Dialog'),
          ),
        ])
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            child: button,
          )
      ],
    );
  }
}

class ExampleRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Popper(),
      ),
    );
  }
}

class Popper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        context.navigator.pop();
      },
      child: Text('pop!'),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  xcontext: ^0.1.0+1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:xcontext/xcontext.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
50
Learn more about scoring.

We analyzed this package on May 24, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.1
  • pana: 0.13.8-dev
  • Flutter: 1.17.0

Health suggestions

Fix lib/src/widgets/tiny_widgets.dart. (-0.50 points)

Analysis of lib/src/widgets/tiny_widgets.dart reported 1 hint:

line 1 col 8: Unused import: 'package:flutter/services.dart'.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test