How to update a Map of key-value pairs in Dart

 How to update a Map of key-value pairs in Dart

A common requirement when working with maps is to:

  • Update the value if a given key already exists
  • Set the value if it doesn't

You may be tempted to implement some conditional logic to handle this:


class ShoppingCart { final Map<String, int> items = {}; void add(String key, int quantity) { if (items.containsKey(key)) { // item exists: update it items[key] = quantity + items[key]!; } else { // item does not exist: set it items[key] = quantity; } } }

Alternatively, a shorter version would be:

class ShoppingCart { final Map<String, int> items = {}; void add(String key, int quantity) { // add 0 if items[key] does not exist items[key] = quantity + (items[key] ?? 0); } }

Either way, the code is not very readable.

And the update() method offers a simpler (and more expressive) way of doing the same thing: 👇

class ShoppingCart { final Map<String, int> items = {}; void add(String key, int quantity) { items.update( key, (value) => quantity + value, ifAbsent: () => quantity, ); } }

Learn more here: Map.update() method.

Happy coding!

Using underscores for unused builder arguments in Dart

Using underscores for unused builder arguments in Dart


The builder pattern is an essential building block for creating composable UIs in Flutter.

As such, Flutter exposes convenience builder types that are used as arguments in many widget classes.

Here are a couple of examples from the Flutter SDK:

/// Signature for a function that creates a widget, e.g. [StatelessWidget.build] /// or [State.build]. typedef WidgetBuilder = Widget Function(BuildContext context); /// Signature for a function that creates a widget for a given index, e.g., in a /// list. typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);

A very common use case of builders is when pushing a new route with Navigator:

Navigator.of(context).push(MaterialPageRoute( builder: (context) => DetailPage(), ));

However, if the context argument in the builder is not used, it can be replaced with _ (which is a valid identifier name in Dart):

Navigator.of(context).push(MaterialPageRoute( builder: (_) => DetailPage(), ));

This also works with builders that take more than one argument. For example, here's a ListView where both the context and index arguments are not used:

ListView.builder( itemBuilder: (_, __) => ListTile(title: Text('a list item')), );

Note how we use __ (double underscore) for the second argument, to differentiate it from the first one.

Takeaway: using _ for unused builder arguments carries meaning, and makes the code more concise.



Adding top and bottom separators with ListView.separated

 Adding top and bottom separators with ListView.separated

ListView.separated is a handy API that we can use to add separators between items inside a Flutter ListView.

According to the documentation:

Separators only appear between list items: separator 0 appears after item 0 and the last separator appears before the last item.

This means that there are no separators above the first item, and below the last item.

This is visually noticeable on iOS, where lists can over-scroll by default.

Here's some code to set things straight, and add top and bottom separators to your ListViews:

class ListViewWithAllSeparators<T> extends StatelessWidget { const ListViewWithAllSeparators({Key key, this.items, this.itemBuilder}) : super(key: key); final List<T> items; final Widget Function(BuildContext context, T item) itemBuilder; @override Widget build(BuildContext context) { return ListView.separated( itemCount: items.length + 2, separatorBuilder: (_, __) => Divider(height: 0.5), itemBuilder: (context, index) { if (index == 0 || index == items.length + 1) { return Container(); // zero height: not visible } return itemBuilder(context, items[index - 1]); }, ); } }

You're welcome. 😉

Force Update with Remote Config

Force Update with Remote Config


Ever needed a force update prompt that is controlled remotely?

There's a package for that: force\_update\_helper.

This works by comparing the current app version with a required app version that is fetched from a remote source.



The package requires a bit of setup, and this is all documented in the README:

Firebase Initialization with Multiple Flavors in Dart

 Firebase Initialization with Multiple Flavors in Dart

Did you know?

If your Flutter app has multiple flavors, you can put all the Firebase initialization logic in one file and switch based on the appFlavor.




Note: when you do this, all the Firebase config files are bundled in the final app, which is not ideal.

A better solution is to create three entry points that load the corresponding config file and pass it to the function that performs the actual initialization.

When running, you can use the -t flag to specify the entry point:



This requires a bit more work but is more secure. 👍



 


What does flutter pub upgrade do?


 What does flutter pub upgrade do?


Did you know?

There's a subtle difference between pub get and pub upgrade:

  • pub get will get all dependencies, keeping the versions inside pubspec.lock.
  • pub upgrade will upgrade all dependencies to the latest non-major version, ignoring the pubspec.lock file.


    Also note:

    • If pubspec.lock doesn't exist yet, both commands behave identically.
    • Neither command updates any dependencies that are locked to a specific version (no caret syntax).

    To learn more, read these resources:

    Happy coding!

Declaring Riverpod Providers with Ref

 Declaring Riverpod Providers with Ref


Did you know?

Since Riverpod 2.6.0, all generated providers can be declared with a Ref argument.

The old [ProviderName]Ref syntax is deprecated.

To upgrade existing projects, simply run: dart run custom_lint --fix. 👍



Note: in order to update all providers in your codebase, custom_lint needs to be installed and configured:

# pubspec.yaml dev_dependencies: custom_lint: 0.7.0 riverpod_lint: 2.6.2
# analysis_options.yaml analyzer: plugins: - custom_lint

Once this is done, run: dart run custom_lint --fix.

Happy coding!

Error.throwWithStackTrace

 Error.throwWithStackTrace

Did you know?

Using domain-specific exceptions makes your code easier to test and maintain.

But don’t lose the original stack trace for debugging!

With Error.throwWithStackTrace, you can throw custom exceptions while keeping the original stack trace intact. 👇




To learn more, read the official docs:

Happy coding!

How to extract filename from Uri?

Now, we can extract filename with and without extension :) You will convert your bitmap to uri and get the real path of your file. Now w...