hasan_utils 2.0.0 copy "hasan_utils: ^2.0.0" to clipboard
hasan_utils: ^2.0.0 copied to clipboard

A set of commonly used utilities for faster Flutter development.

hasan_utils #

A set of commonly used utilities for Flutter development.

Getting Started #

Add the following to your dependencies in pubspec.yaml

hasan_utils: <last_version>

Requires Flutter 3.44+ and an app built on material_ui (dart fix --apply --code=migrate_design_widgets). The package uses material_ui itself, so no MaterialUiCompatibilityBridge is needed for it.

Utilities #

  • Api: A simple Dio wrapper for API calls
  • Validate: Simple data validator
  • Navigation: A Navigator wrapper that works without a BuildContext
  • FileUtils: File utilities e.g. delete()
  • Alert: Alert dialogs (simple and confirmation)
  • Storage: A Shared Preferences wrapper
  • Persistence: A data persistence tool for settings and more.
  • FileDownloader: A cancellable file downloader with progress.
  • Toast: Native toasts via fluttertoast, Toast.show(text), defaults via Toast.options(...)
  • InternetChecker: Connectivity status singleton (ChangeNotifier) built on connectivity_plus
// main.dart
runApp(
  NavigationScope(
    builder: (context) => MaterialApp(
      navigatorKey: Navigation.navigatorKey,
      home: HomeScreen(),
    ),
  ),
);

// anywhere: push notifications, drawers, services, ...
Navigation.navigate(AboutScreen());
Navigation.reset(HomeScreen());
Navigation.goBack();
Alert.show(title, text);
Api.post('users/self/logout');

// a specific navigator is still supported
Navigation.navigate(AboutScreen(), context: context);

NavigationScope creates a fresh Navigation.navigatorKey every time it is mounted, so apps that rebuild their whole tree (for example LocalizationApp.reload() from fast_localization) never reuse a stale navigator. Register singleton providers with ChangeNotifierProvider.value when the tree can be rebuilt.

When a context is still needed #

  • Navigation.openDrawer(context) needs the Scaffold context
  • Pushing on a nested Navigator (tabs, CupertinoTabView, a Navigator inside a screen): pass context: context, the default is the root navigator
  • Without a MaterialApp that uses Navigation.navigatorKey (widget tests, plain Dart): Navigation.context throws a StateError and Api skips its error alert

Translation keys #

Alert and Api read their default texts through fast_localization:

Text Default key
Alert OK button actions.ok
Alert Cancel button actions.cancel
Alert single button same as OK
Api error alert title errors.title
Validate.message.* validate.errors.*

Override once at startup to match your own map:

Alert.translationKeys(ok: 'ok', cancel: 'cancel', close: 'back');
Api.translationKeys(errorTitle: 'error');

Migrating from 1.x #

The full guide is in MIGRATION.md.

  1. Wrap the app in NavigationScope and pass Navigation.navigatorKey to MaterialApp.navigatorKey (see above)

  2. Rewrite the call sites:

    dart run hasan_utils:migrate_v2 lib
    dart format lib
    
    1.x 2.0
    Navigation.navigate(context, Screen()) Navigation.navigate(Screen(), context: context)
    await Navigation.goBack(context) Navigation.goBack(context: context)
    Alert.show(context, title, text) Alert.show(title, text, context: context)
    Api.post(url, context, params: params) Api.post(url, params: params, context: context)
    Api.post(url, null, params: params) Api.post(url, params: params)

    Add --drop-context to remove the contexts instead (Navigation.navigate(Screen())). The tool refuses to drop them when the project has nested navigators (Navigator(...), CupertinoTabView, rootNavigator: false) unless --force is passed. --dry-run only reports the files that would change

  3. If your translations keep the top-level ok, cancel and error keys, call Alert.translationKeys(ok: 'ok', cancel: 'cancel') and Api.translationKeys(errorTitle: 'error') at startup

TODO #

  • ❌ Add examples
  • ❌ Add more tests
  • ❌ Support Storage version migration

PRs are always welcome and appreciated!