Fedi — Flutter open-source social network client. Part 4. Used packages.
List of packages used by Fedi with examples and notes: provider, hive, moor, easy_dispose, intl, logging, and much more.
Fedi is an open-source client for Pleroma and Mastodon social networks written using Flutter available on iOS(Beta) and Android(Beta)
Series:
- Part 1. Architecture.
- Part 2. Code.
- Part 3. Build & Config.
- Part 4. Used packages.
- Part 5. Android Studio Plugins & Feature Plans.
In this part:
· Intro
∘ Specify version numbers without bounds
∘ Outdated packages
∘ How to find new packages
· Packages
∘ build_runner — code generator
∘ provider — dependency injection
∘ intl — localization with code generation
∘ fluttericon.com — icon font generator
∘ moor — SQLite ORM
∘ hive — key-value storage
∘ panache & flex_color_scheme — color schemes
∘ easy_dispose — dispose and clean up resources
∘ url_launcher & uni_links — OAuth login
∘ Working with files on devices
∘ overlay_support — in-app overlay toasts
∘ firebase_messaging & awesome_notifications — rich push notifications
∘ json_serializable
∘ nested_scroll_controller & extended_nested_scroll_view — ScrollView in ScrollView
∘ video_player
∘ cached_network_image
∘ package_info_plus — build details at Runtime
∘ flutter_html — render HTML
∘ permission_handler
∘ web_socket_channel — WebSockets API
∘ share_plus — share to other apps
∘ receive_sharing_intent — receive shares from other apps
∘ collection — null-safety collection extension
∘ extended_text_field — highlight mentions in text field
∘ flutter_slidable — list view item actions on slide
∘ flutter_keyboard_visibility
∘ flutter_reorderable_list
∘ scrollable_positioned_list — ListView with scrollToItem()
∘ logging — log support
∘ jiffy & timeago — DateTime & Duration utils
Intro
You can find up-to-date packages list in Fedi pubspec.yaml with a single-line comment about why these packages are used.
Specify version numbers without bounds
When you import a package from pub.dev you usually use ^1.0.0
notation. Which actually means >=1.0.0 <2.0.0
. That means that any version above and equal to 1.0.0
and below 2.0.0
is acceptable. See version constraints in official docs.
It should be OK to use ^1.0.0
because all versions before major 2.0.0
update should have backward compatibility (no API changes, only mark as deprecated is possible).
Unfortunately, not all package authors follow backward compatibility and you may have issues when the version will be upgraded. Additionally, sometimes even minor version updates may add bugs to the package.
So, a simple pub get
run even without changes in pubspec.yaml
or cloning repo to another machine may add unexpected errors.
Solution: Fedi uses only explicit versions like 1.0.0
to avoid backward compatibility issues. This may cause versions conflict which you should manually fix. So it is not acceptable for packages published on pub.dev(because other people depend on them) but is OK for applications like Fedi.
Outdated packages
Flutter development is under active development and sometimes community creates new better packages which completely replace old solutions. So I suggest always check package Github page to understand package development activity.
How to find new packages
- pub.dev — have cool rating feature and have own libraries features and Flutter Favourite for best packages
- fluttergems.dev — another good place to find good libraries similar to android-arsenal.com
Packages
build_runner — code generator
Is used to run code generations tasks for moor, json_serializable, mockito etc
provider — dependency injection
The most popular dependency injection framework for Flutter. It is used everywhere in Fedi.
Extended with easy_dispose_provider package.
intl — localization with code generation
Localization via .arb(looks like json) files with .dart code generation.
Localization context is injected on the app level, so you should re-run app to change locale.
Generated .dart classes provide cool features:
- IDE autocomplete
- bugfree — you always know that specified keys exist
By default, you should apply intl-utils package from the command line to re-generate .dart classes. However, you can use Intl Android Studio Plugin to achieve automated code generation.
You can learn more about localization from official docs
Open-source(free self-hosted or paid cloud) localization web application with .arb files support. It has modern features(screenshot attachment to key to show context, git integration, ready for crowd translations) and easy to use.
You can see how Fedi Weblate project looks.
fluttericon.com — icon font generator
In order to turn SVG into icon font, you should make Compound Path. It is possible with Adobe Illustrator or Inkscape.
In Adobe Illustrator you can follow the next steps:
- Select all
- Ungroup
- Outline stroke(optional) — sometimes making a compound path is not possible without this and outline stroke can modify original shapes
- Make compound path
You can find config using by Fedi in icons_export folder
You can use font_awesome_flutter font if you don’t need custom icons
moor — SQLite ORM
It’s like Room for Android.
Pros:
- Dart query builder with autocomplete & suggestions
- Have database version migration mechanism;
- You can watch() data for Select query. So you will have Stream which updates every time when the database is updated.
- Almost all SQLite features like indexes, foreign keys, transactions etc are supported
- There is moor_inspector
Cons:
- It is not possible to implement all possible SQL operations with dart query builder. Sometimes you should use raw SQL queries and integrate them with moor(tell which data is updated);
- You should use .moor files(just contains SQL queries) for some things. For example, Fedi uses it to create indexes;
- Strange bug: If DAO is used in .moor you shouldn’t add it in @Database annotation: app_database.dart
Usage in Fedi:
moor_flutter — extension to use moor with flutter
moor_inspector is dart package and Android Studio plugin to view moor databases.
You can connect and view the database in Android Studio when app is running.
Dump DB from Android Emulator
hive — key-value storage
It’s like shared_preferences, but even better.
Pros:
- Fast;
- Secure.
Cons:
- You should annotate all data classes and register adapters;
- Adapters Ids implementation is really strange. You should put global id in data classes annotation. You should remember the last used id and increment it each time;
- Only for simple key-value, SQLite is better for complex data structures.
Usage in Fedi:
hive_flutter — required extension to work with flutter
panache & flex_color_scheme — color schemes
Fedi uses custom design with day/night themes support.
However, previously Fedi had used themes generated with panache. It is a cool web application to generate Dart theme code.
Unfortunately, panache hasn’t been receiving updates for a long time, so generated code needs small manual changes to work with Flutter 2. You can also use forks or another similar solution of flex_color_scheme
easy_dispose — dispose and clean up resources
easy_dispose, easy_dispose_flutter, easy_dispose_provider, easy_dispose_rxdart packages were part of Fedi but now they are separated to own packages
Example from easy_dispose. You can explore specific packages for more details and examples.
Almost all Provider are DisposableProvider and dispose themselves when needed.
url_launcher & uni_links — OAuth login
Fedi uses OAuth to login to different instances.
To implement OAuth, you should launch OAuth URL via url_launcher (custom) and handle redirect URL with uni_links.
Different browsers work in different ways. For example, Chrome on Android just brings the app to foreground and uni_links linkStream is fired. However, Firefox on Android fully restart apps and you should handle getInitialUri() from uni_link.
You can see pleroma_api_oauth_service_impl.dart file for details.
There is uni_links2 package, which is a fork of uni_links and was created due to long uni_links inactivity. However, currently, uni_links is under active development. uni_links2 also supports reading NFC tags by default so iOS Review team will ask you why you use NFC.
Working with files on devices
Picking and saving files in Flutter is not simple due to differences in Android and iOS. Even more, different OS versions have different behavior and you(or packages you use) should support all variants.
Fetch albums and photos from device. See/lib/media/device
A package that allows you to use the native file explorer to pick single or multiple files, with extensions filtering support.
Usage in Fedi:
post_message_select_media_attachment_type_to_pick_widget.dart
A Flutter plugin for iOS and Android for picking images from the image library and taking new pictures with the camera.
It is sed to pick image from Camera: camera_media_service_impl.dart
When you pick image from iOS gallery it may be picked in .heic format which is usually not supported in other softwear, so you need to re-compress the image
Usage in Fedi — photo_manager/photo_manager_media_device_file_model.dart
Saves images and videos from the network or temporary files to external storage.
Usage in Fedi — media_attachment_add_to_gallery_helper.dart
overlay_support — in-app overlay toasts
Sometimes you want to display notifications when an app is on the foreground
Usage in Fedi — overlay_notification_service_impl.dart
Why not Snackbar?
Because overlay_support is more customizable
firebase_messaging & awesome_notifications — rich push notifications
By default, firebase_messaging displays a simple(just title and body) notification from FCM notification message:
- You should localize messages on the server-side;
- You can’t add actions like ‘Reply’ to notifications;
- You can’t customize notification layout like ‘Big Picture’;
- You can’t run custom code and modify notification content before display.
To fix all issues mentioned above Fedi uses awesome_notifications. However currently(during the migrating period) Fedi supports both push notification delivery approaches. Check Readme for details.
Note: awesome_notifications version is under 1.0.0 right now and that is a problem. API may be changed several times before the 1.0.0 stable release. Think twice before taking risks.
Usage in Fedi:
json_serializable
Most popular package to parse Map from JSON String and vice versa.
This option is disabled by default, however, you must enable it if you want to include nested objects with toJson. Otherwise nested objects will be included via toString()
nested_scroll_controller & extended_nested_scroll_view — ScrollView in ScrollView
Almost all timelines in Fedi are actually tabs with ScrollView inside another ScrollView.
Additionally Fedi show/hide some UI elements depending on scroll and this requires additional tricks. nested_scroll_controller & extended_nested_scroll_view help implement such things
Usage in Fedi:
- fedi_nested_scroll_view_with_nested_scrollable_tabs_widget.dart
- fedi_nested_scroll_view_bloc_impl.dart
video_player
A Flutter plugin for iOS, Android and Web for playing back video on a Widget surface.
Currently, Fedi has custom UI for Video/Audio players. Previously Fedi had used chewie and chewie_audio UI. Another good UI is better_player
This is a Package that allows you to keep the device screen awake, i.e. prevent the screen from sleeping
Usage in Fedi — /lib/media/player
cached_network_image
A flutter library to show images from the internet and keep them in the cache directory.
Used internally by cached_network_image and imported manually to control cache config.
Usage in Fedi: files_cache_service_impl.dart
package_info_plus — build details at Runtime
This Flutter plugin provides an API for querying information about an application package.
Displays version number on splash screen: config_service_impl.dart
flutter_html — render HTML
A lot of text in Fedi may have html tags and flutter_html helps with that.
Pros:
- Good performance.
Cons:
- Doesn’t support text selection (only partial selection in the latest updates).
Usage in Fedi: html_text_widget.dart
Helps to transform text with HTML tags to raw text
permission_handler
This plugin provides a cross-platform (iOS, Android) API to request permissions and check their status. You can also open the device’s app settings so users can grant permission.
In Fedi each permission have own bloc: /lib/permission
web_socket_channel — WebSockets API
In addition to push notifications, Fedi can receive updates via WebSockets API provided by Pleroma and Mastodon.
Notes:
- WebSockets drain battery. Always provide an option to disable features that may cause problems for use;
- It is not possible to handle WebSockets updates in background. iOS doesn’t have API to run tasks in background.
Usage in Fedi: web_sockets_channel_source_impl.dart
share_plus — share to other apps
Share content from Fedi to other apps
Usage in Fedi: external_share_service_impl.dart
receive_sharing_intent — receive shares from other apps
Receive share intents from other apps to Fedi
Pros:
- Only one package to receive sharing intents on Flutter right now.
Cons
- It is hard to integrate and it doesn’t support flavors without additional changes. Check out my fork /xal/receive_sharing_intent.
Usage in Fedi: external_share_service_impl.dart
collection — null-safety collection extension
Useful IterableExtension
- firstOrNull
- whereNotNull
extended_text_field — highlight mentions in text field
Extended official text field to build special text like inline image, @somebody, custom background etc.
Is used to highlight @user mentions in text field
flutter_slidable — list view item actions on slide
A Flutter implementation of slidable list item with directional slide actions that can be dismissed.
Usage in Fedi — notification_list_item_widget.dart
flutter_keyboard_visibility
React to keyboard visibility changes.
Usage in Fedi — upload_media_attachment_list_all_widget.dart
flutter_reorderable_list
Reorderable list with animations
Usage in Fedi — timelines_home_tab_storage_widget.dart
scrollable_positioned_list — ListView with scrollToItem()
Flutter ListView doesn’t have scrollToItem() and scrollable_positioned_list does
Usage in Fedi — status_thread_widget.dart
logging — log support
Logging library from dart.dev team.
- Fedi prints a lot of messages to log each second;
- Grep Console Android Studio Plugin helps filter messages which you really need right now;
- Don’t forget to disable log in production builds, because many print() calls may highly decrease performance. Additionally, you may put sensitive data in the console which is not good
Pros:
- Supports Log Tag
- Supports putting error and stackTrace from catch
- Supports printing via functions(see example) and via simple String
Cons:
- Nested Log tags is not supported
- Strange(as for me ) log levels like fine, finer, finest
Prefer log with anonymous function instead of raw string.
It doesn’t have any sense while logging is enabled.
However, it does have a sense when you disable log in release builds by simple disabling print() calls somewhere in one place (like logging/logging_service_impl.dart in Fedi).
Benefits(when log is disabled):
- You may use function/getter which calculates something for log which will be not executed in disabled state
- Don’t create new String objects and don’t clean up them with Garbage Collector. I don’t know how actually GC works in Flutter, but in Android this have a sense
jiffy & timeago — DateTime & Duration utils
Jiffy is a Flutter (Android, IOS and Web) date time package inspired by moment.js for parsing, manipulating, querying and formatting dates
Usage in Fedi — duration_date_time_form_field_row_widget.dart
This library is useful for creating fuzzy timestamps. (e.g. “5 minutes ago”)
Usage in Fedi — date_time_dynamic_time_ago_widget.dart
Final Words
Feel free to comment and fill issue if you don’t agree with something or have suggestions.
Next part — Part 5. Android Studio Plugins & Feature Plans.
Start using Pleroma and Mastodon with Fedi if you still not in Fediverse: iOS(Beta) and Android(Beta). Any feedback is welcome.
If you are interested in Fedi and want to help to develop it you can start from Readme.