From c570a54aa35ffdb931f2b169bfc4ea9132ca87c4 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:53:50 -0300
Subject: [PATCH 01/11] Bumps Flutter to `2.10.3` and updates all dependencies
 to the latest version

---
 .github/workflows/analyze-tests.yml           |   2 +-
 .github/workflows/android-build.yaml          |   2 +-
 .github/workflows/ios-build.yaml              |   2 +-
 .github/workflows/release.yml                 |   2 +-
 .gitignore                                    | 294 +++++++++++++++---
 android/.gitignore                            |  23 --
 android/app/build.gradle                      |   4 +-
 android/build.gradle                          |   2 +-
 ios/.gitignore                                |  39 ---
 ios/Podfile.lock                              | 152 ++++-----
 ios/Runner.xcodeproj/project.pbxproj          |   4 +-
 .../xcshareddata/xcschemes/Runner.xcscheme    |   2 +-
 .../pages/execution/execution_terminal.dart   |   6 +-
 .../widgets/theme/rich_text_field.dart        |   4 +-
 pubspec.lock                                  | 255 ++++++++++-----
 pubspec.yaml                                  |  32 +-
 16 files changed, 544 insertions(+), 281 deletions(-)
 delete mode 100644 android/.gitignore
 delete mode 100644 ios/.gitignore

diff --git a/.github/workflows/analyze-tests.yml b/.github/workflows/analyze-tests.yml
index d58674c5..01906b8d 100644
--- a/.github/workflows/analyze-tests.yml
+++ b/.github/workflows/analyze-tests.yml
@@ -7,7 +7,7 @@ on:
       - main
 
 env:
-  flutter_version: "2.5.3"
+  flutter_version: "2.10.3"
   flutter_channel: "stable"
 
 jobs:
diff --git a/.github/workflows/android-build.yaml b/.github/workflows/android-build.yaml
index 5edab25d..4c3354c3 100644
--- a/.github/workflows/android-build.yaml
+++ b/.github/workflows/android-build.yaml
@@ -9,7 +9,7 @@ on:
       - "android/**"
 
 env:
-  flutter_version: "2.5.3"
+  flutter_version: "2.10.3"
   flutter_channel: "stable"
 
 jobs:
diff --git a/.github/workflows/ios-build.yaml b/.github/workflows/ios-build.yaml
index 928b5db3..02871c17 100644
--- a/.github/workflows/ios-build.yaml
+++ b/.github/workflows/ios-build.yaml
@@ -9,7 +9,7 @@ on:
       - "ios/**"
 
 env:
-  flutter_version: "2.5.3"
+  flutter_version: "2.10.3"
   flutter_channel: "stable"
 
 jobs:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0bd93a75..dd355713 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -6,7 +6,7 @@ on:
       - published
 
 env:
-  flutter_version: "2.5.3"
+  flutter_version: "2.10.3"
   java_version: "12.x"
   flutter_channel: "stable"
 
diff --git a/.gitignore b/.gitignore
index 5202b581..1c0ac546 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,49 +1,271 @@
-# Miscellaneous
-*.class
-*.log
-*.pyc
-*.swp
-.DS_Store
-.atom/
-.buildlog/
-.history
-.svn/
 
-# IntelliJ related
-*.iml
-*.ipr
-*.iws
-.idea/
+# Created by https://www.toptal.com/developers/gitignore/api/dart,flutter,androidstudio,fastlane
+# Edit at https://www.toptal.com/developers/gitignore?templates=dart,flutter,androidstudio,fastlane
 
-# The .vscode folder contains launch configuration and tasks you configure in
-# VS Code which you may wish to be included in version control, so this line
-# is commented out by default.
-#.vscode/
+### Dart ###
+# See https://www.dartlang.org/guides/libraries/private-files
 
-# Flutter/Dart/Pub related
-**/doc/api/
-**/ios/Flutter/.last_build_id
+# Files and directories created by pub
 .dart_tool/
+.packages
+build/
+# If you're building an application, you may want to check-in your pubspec.lock
+pubspec.lock
+
+# Directory created by dartdoc
+# If you don't generate documentation locally you can remove this line.
+doc/api/
+
+# dotenv environment variables file
+.env*
+
+# Avoid committing generated Javascript files:
+*.dart.js
+*.info.json      # Produced by the --dump-info flag.
+*.js             # When generated by dart2js. Don't specify *.js if your
+                 # project includes source files written in JavaScript.
+*.js_
+*.js.deps
+*.js.map
+
 .flutter-plugins
 .flutter-plugins-dependencies
-.packages
+
+### Dart Patch ###
+# dotenv environment variables file
+.env
+
+### fastlane ###
+# fastlane - A streamlined workflow tool for Cocoa deployment
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+# fastlane specific
+ios/fastlane/report.xml
+ios/fastlane/README.md
+android/fastlane/report.xml
+android/fastlane/README.md
+
+# deliver temporary files
+ios/fastlane/Preview.html
+android/fastlane/Preview.html
+
+# snapshot generated screenshots
+ios/fastlane/screenshots/**/*.png
+ios/fastlane/screenshots/screenshots.html
+android/fastlane/screenshots/**/*.png
+android/fastlane/screenshots/screenshots.html
+
+# scan temporary files
+ios/fastlane/test_output
+android/fastlane/test_output
+
+# Fastlane.swift runner binary
+ios/fastlane/FastlaneRunner
+android/fastlane/FastlaneRunner
+
+### Flutter ###
+# Flutter/Dart/Pub related
+**/doc/api/
+.fvm/
 .pub-cache/
 .pub/
-/build/
-
-# Web related
+coverage/
 lib/generated_plugin_registrant.dart
+# For library packages, don’t commit the pubspec.lock file.
+# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.
+# See https://dart.dev/guides/libraries/private-files#pubspeclock
+#pubspec.lock
+
+# Android related
+**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/key.properties
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/.last_build_id
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
+
+### AndroidStudio ###
+# Covers files to be ignored for android development using Android Studio.
+
+# Built application files
+*.apk
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle
+.gradle/
+
+# Signing files
+.signing/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio
+/*/build/
+/*/local.properties
+/*/out
+/*/*/build
+/*/*/production
+captures/
+.navigation/
+*.ipr
+*~
+*.swp
+
+# Keystore files
+*.jks
+*.keystore
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Android Patch
+gen-external-apklibs
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# NDK
+obj/
+
+# IntelliJ IDEA
+*.iml
+*.iws
+/out/
+
+# User-specific configurations
+.idea/caches/
+.idea/libraries/
+.idea/shelf/
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/scopes/scope_settings.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+.idea/datasources.xml
+.idea/dataSources.ids
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+.idea/assetWizardSettings.xml
+.idea/gradle.xml
+.idea/jarRepositories.xml
+.idea/navEditor.xml
+
+# Legacy Eclipse project files
+.classpath
+.project
+.cproject
+.settings/
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+
+# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
+hs_err_pid*
+
+## Plugin-specific files:
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Mongo Explorer plugin
+.idea/mongoSettings.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+### AndroidStudio Patch ###
 
-# Symbolication related
-app.*.symbols
+!/gradle/wrapper/gradle-wrapper.jar
 
-# Obfuscation related
-app.*.map.json
+# End of https://www.toptal.com/developers/gitignore/api/dart,flutter,androidstudio,fastlane
 
-# Android Studio will place build artifacts here
-/android/app/debug
-/android/app/profile
-/android/app/release
+# Android Secret files
+android/key.properties
+android/gcp_service_account.json
+android/app/keystore.jks
+android/key.properties
+android/app/google-services.json
+android/firebase_distribution_service_account.json
 
-# Firebase Distribution Service Account
-firebase_distribution_service_account.json
\ No newline at end of file
+# Google Services Info.plist
+ios/Runner/GoogleService-Info.plist
\ No newline at end of file
diff --git a/android/.gitignore b/android/.gitignore
deleted file mode 100644
index a02db0b0..00000000
--- a/android/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-gradle-wrapper.jar
-/.gradle
-/captures/
-/gradlew
-/gradlew.bat
-/local.properties
-GeneratedPluginRegistrant.java
-
-# Remember to never publicly share your keystore.
-# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
-key.properties
-
-# Secret files
-gcp_service_account.json
-app/keystore.jks
-key.properties
-
-# Fastlane auto-generated files
-fastlane/*.xml
-fastlane/README.md
-
-# Firebase Google Services
-app/google-services.json
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 40ab2b23..0e1c8348 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -31,7 +31,7 @@ apply plugin: 'kotlin-android'
 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
 
 android {
-    compileSdkVersion 30
+    compileSdkVersion 31
 
     sourceSets {
         main.java.srcDirs += 'src/main/kotlin'
@@ -40,7 +40,7 @@ android {
     defaultConfig {
         applicationId "com.olmps.memoClient"
         minSdkVersion 17
-        targetSdkVersion 30
+        targetSdkVersion 31
         versionCode 7
         versionName flutterVersionName
     }
diff --git a/android/build.gradle b/android/build.gradle
index bcf592ef..2f9f362e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -9,7 +9,7 @@ buildscript {
         classpath 'com.android.tools.build:gradle:4.1.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         classpath 'com.google.gms:google-services:4.3.5'
-        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1'
+        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
     }
 }
 
diff --git a/ios/.gitignore b/ios/.gitignore
deleted file mode 100644
index 3c1a77c2..00000000
--- a/ios/.gitignore
+++ /dev/null
@@ -1,39 +0,0 @@
-*.mode1v3
-*.mode2v3
-*.moved-aside
-*.pbxuser
-*.perspectivev3
-**/*sync/
-.sconsign.dblite
-.tags*
-**/.vagrant/
-**/DerivedData/
-Icon?
-**/Pods/
-**/.symlinks/
-profile
-xcuserdata
-**/.generated/
-Flutter/App.framework
-Flutter/Flutter.framework
-Flutter/Flutter.podspec
-Flutter/Generated.xcconfig
-Flutter/app.flx
-Flutter/app.zip
-Flutter/flutter_assets/
-Flutter/flutter_export_environment.sh
-ServiceDefinitions.json
-Runner/GeneratedPluginRegistrant.*
-
-# Exceptions to above rules.
-!default.mode1v3
-!default.mode2v3
-!default.pbxuser
-!default.perspectivev3
-
-# Fastlane auto-generated files
-fastlane/*.xml
-fastlane/README.md
-
-# Google Services Info.plist
-Runner/GoogleService-Info.plist
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index ec63c5c4..62675245 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,52 +1,54 @@
 PODS:
-  - Firebase/AnalyticsWithoutAdIdSupport (8.8.0):
+  - device_info_plus (0.0.1):
+    - Flutter
+  - Firebase/AnalyticsWithoutAdIdSupport (8.11.0):
     - Firebase/CoreOnly
-    - FirebaseAnalytics/WithoutAdIdSupport (~> 8.8.0)
-  - Firebase/CoreOnly (8.8.0):
-    - FirebaseCore (= 8.8.0)
-  - Firebase/Crashlytics (8.8.0):
+    - FirebaseAnalytics/WithoutAdIdSupport (~> 8.11.0)
+  - Firebase/CoreOnly (8.11.0):
+    - FirebaseCore (= 8.11.0)
+  - Firebase/Crashlytics (8.11.0):
     - Firebase/CoreOnly
-    - FirebaseCrashlytics (~> 8.8.0)
-  - firebase_analytics (8.3.4):
-    - Firebase/AnalyticsWithoutAdIdSupport (= 8.8.0)
+    - FirebaseCrashlytics (~> 8.11.0)
+  - firebase_analytics (9.1.2):
+    - Firebase/AnalyticsWithoutAdIdSupport (= 8.11.0)
     - firebase_core
     - Flutter
-  - firebase_core (1.8.0):
-    - Firebase/CoreOnly (= 8.8.0)
+  - firebase_core (1.13.1):
+    - Firebase/CoreOnly (= 8.11.0)
     - Flutter
-  - firebase_crashlytics (2.2.4):
-    - Firebase/Crashlytics (= 8.8.0)
+  - firebase_crashlytics (2.5.3):
+    - Firebase/Crashlytics (= 8.11.0)
     - firebase_core
     - Flutter
-  - FirebaseAnalytics/WithoutAdIdSupport (8.8.0):
+  - FirebaseAnalytics/WithoutAdIdSupport (8.11.0):
     - FirebaseCore (~> 8.0)
     - FirebaseInstallations (~> 8.0)
-    - GoogleAppMeasurement/WithoutAdIdSupport (= 8.8.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
-    - GoogleUtilities/MethodSwizzler (~> 7.4)
-    - GoogleUtilities/Network (~> 7.4)
-    - "GoogleUtilities/NSData+zlib (~> 7.4)"
+    - GoogleAppMeasurement/WithoutAdIdSupport (= 8.11.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
+    - GoogleUtilities/MethodSwizzler (~> 7.7)
+    - GoogleUtilities/Network (~> 7.7)
+    - "GoogleUtilities/NSData+zlib (~> 7.7)"
     - nanopb (~> 2.30908.0)
-  - FirebaseCore (8.8.0):
+  - FirebaseCore (8.11.0):
     - FirebaseCoreDiagnostics (~> 8.0)
-    - GoogleUtilities/Environment (~> 7.4)
-    - GoogleUtilities/Logger (~> 7.4)
-  - FirebaseCoreDiagnostics (8.9.0):
+    - GoogleUtilities/Environment (~> 7.7)
+    - GoogleUtilities/Logger (~> 7.7)
+  - FirebaseCoreDiagnostics (8.13.0):
     - GoogleDataTransport (~> 9.1)
-    - GoogleUtilities/Environment (~> 7.6)
-    - GoogleUtilities/Logger (~> 7.6)
+    - GoogleUtilities/Environment (~> 7.7)
+    - GoogleUtilities/Logger (~> 7.7)
     - nanopb (~> 2.30908.0)
-  - FirebaseCrashlytics (8.8.0):
+  - FirebaseCrashlytics (8.11.0):
     - FirebaseCore (~> 8.0)
     - FirebaseInstallations (~> 8.0)
-    - GoogleDataTransport (~> 9.0)
-    - GoogleUtilities/Environment (~> 7.4)
+    - GoogleDataTransport (~> 9.1)
+    - GoogleUtilities/Environment (~> 7.7)
     - nanopb (~> 2.30908.0)
     - PromisesObjC (< 3.0, >= 1.2)
-  - FirebaseInstallations (8.9.0):
+  - FirebaseInstallations (8.13.0):
     - FirebaseCore (~> 8.0)
-    - GoogleUtilities/Environment (~> 7.6)
-    - GoogleUtilities/UserDefaults (~> 7.6)
+    - GoogleUtilities/Environment (~> 7.7)
+    - GoogleUtilities/UserDefaults (~> 7.7)
     - PromisesObjC (< 3.0, >= 1.2)
   - Flutter (1.0.0)
   - flutter_inappwebview (0.0.1):
@@ -58,34 +60,36 @@ PODS:
     - OrderedSet (~> 5.0)
   - flutter_keyboard_visibility (0.0.1):
     - Flutter
-  - GoogleAppMeasurement/WithoutAdIdSupport (8.8.0):
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
-    - GoogleUtilities/MethodSwizzler (~> 7.4)
-    - GoogleUtilities/Network (~> 7.4)
-    - "GoogleUtilities/NSData+zlib (~> 7.4)"
+  - gallery_saver (0.0.1):
+    - Flutter
+  - GoogleAppMeasurement/WithoutAdIdSupport (8.11.0):
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
+    - GoogleUtilities/MethodSwizzler (~> 7.7)
+    - GoogleUtilities/Network (~> 7.7)
+    - "GoogleUtilities/NSData+zlib (~> 7.7)"
     - nanopb (~> 2.30908.0)
   - GoogleDataTransport (9.1.2):
     - GoogleUtilities/Environment (~> 7.2)
     - nanopb (~> 2.30908.0)
     - PromisesObjC (< 3.0, >= 1.2)
-  - GoogleUtilities/AppDelegateSwizzler (7.6.0):
+  - GoogleUtilities/AppDelegateSwizzler (7.7.0):
     - GoogleUtilities/Environment
     - GoogleUtilities/Logger
     - GoogleUtilities/Network
-  - GoogleUtilities/Environment (7.6.0):
+  - GoogleUtilities/Environment (7.7.0):
     - PromisesObjC (< 3.0, >= 1.2)
-  - GoogleUtilities/Logger (7.6.0):
+  - GoogleUtilities/Logger (7.7.0):
     - GoogleUtilities/Environment
-  - GoogleUtilities/MethodSwizzler (7.6.0):
+  - GoogleUtilities/MethodSwizzler (7.7.0):
     - GoogleUtilities/Logger
-  - GoogleUtilities/Network (7.6.0):
+  - GoogleUtilities/Network (7.7.0):
     - GoogleUtilities/Logger
     - "GoogleUtilities/NSData+zlib"
     - GoogleUtilities/Reachability
-  - "GoogleUtilities/NSData+zlib (7.6.0)"
-  - GoogleUtilities/Reachability (7.6.0):
+  - "GoogleUtilities/NSData+zlib (7.7.0)"
+  - GoogleUtilities/Reachability (7.7.0):
     - GoogleUtilities/Logger
-  - GoogleUtilities/UserDefaults (7.6.0):
+  - GoogleUtilities/UserDefaults (7.7.0):
     - GoogleUtilities/Logger
   - image_picker (0.0.1):
     - Flutter
@@ -97,26 +101,28 @@ PODS:
   - OrderedSet (5.0.0)
   - package_info_plus (0.4.5):
     - Flutter
-  - path_provider (0.0.1):
+  - path_provider_ios (0.0.1):
     - Flutter
   - PromisesObjC (2.0.0)
-  - url_launcher (0.0.1):
+  - url_launcher_ios (0.0.1):
     - Flutter
-  - video_player (0.0.1):
+  - video_player_avfoundation (0.0.1):
     - Flutter
 
 DEPENDENCIES:
+  - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
   - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
   - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
   - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
   - Flutter (from `Flutter`)
   - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
   - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
+  - gallery_saver (from `.symlinks/plugins/gallery_saver/ios`)
   - image_picker (from `.symlinks/plugins/image_picker/ios`)
   - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
-  - path_provider (from `.symlinks/plugins/path_provider/ios`)
-  - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
-  - video_player (from `.symlinks/plugins/video_player/ios`)
+  - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
+  - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
+  - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
 
 SPEC REPOS:
   trunk:
@@ -134,6 +140,8 @@ SPEC REPOS:
     - PromisesObjC
 
 EXTERNAL SOURCES:
+  device_info_plus:
+    :path: ".symlinks/plugins/device_info_plus/ios"
   firebase_analytics:
     :path: ".symlinks/plugins/firebase_analytics/ios"
   firebase_core:
@@ -146,41 +154,45 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/flutter_inappwebview/ios"
   flutter_keyboard_visibility:
     :path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
+  gallery_saver:
+    :path: ".symlinks/plugins/gallery_saver/ios"
   image_picker:
     :path: ".symlinks/plugins/image_picker/ios"
   package_info_plus:
     :path: ".symlinks/plugins/package_info_plus/ios"
-  path_provider:
-    :path: ".symlinks/plugins/path_provider/ios"
-  url_launcher:
-    :path: ".symlinks/plugins/url_launcher/ios"
-  video_player:
-    :path: ".symlinks/plugins/video_player/ios"
+  path_provider_ios:
+    :path: ".symlinks/plugins/path_provider_ios/ios"
+  url_launcher_ios:
+    :path: ".symlinks/plugins/url_launcher_ios/ios"
+  video_player_avfoundation:
+    :path: ".symlinks/plugins/video_player_avfoundation/ios"
 
 SPEC CHECKSUMS:
-  Firebase: 629510f1a9ddb235f3a7c5c8ceb23ba887f0f814
-  firebase_analytics: ebba4a4815cf045ff915c3609c58e2a3da900459
-  firebase_core: 3b4c707f5a8eff38f52fd5580895bcd89357bf42
-  firebase_crashlytics: 5e4c7b5695a7ffe144a55dacfddebbf8eb36028a
-  FirebaseAnalytics: 5506ea8b867d8423485a84b4cd612d279f7b0b8a
-  FirebaseCore: 98b29e3828f0a53651c363937a7f7d92a19f1ba2
-  FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34
-  FirebaseCrashlytics: 3660c045c8e45cc4276110562a0ef44cf43c8157
-  FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85
+  device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
+  Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c
+  firebase_analytics: 816a4f02c5a0dbd67c5ee281944aa321b4445816
+  firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9
+  firebase_crashlytics: 28149c943342a73fefe1afef224d345cfb35e1ee
+  FirebaseAnalytics: 4e4b13031034e6561ed3bd1d47b6fdabbd6487c6
+  FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0
+  FirebaseCoreDiagnostics: c2836d254a8f0bbb4121ff18f2c2ea39d118fd08
+  FirebaseCrashlytics: 62268addefae79601057818156e8bc69d71fee41
+  FirebaseInstallations: 60edbf7e11d91ae4c751d26c200dfd037099abe0
   Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
   flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
   flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
-  GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91
+  gallery_saver: 9fc173c9f4fcc48af53b2a9ebea1b643255be542
+  GoogleAppMeasurement: aa3cb422fab2b05d2efac543a5720d1a85b9dea5
   GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940
-  GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237
-  image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
+  GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
+  image_picker: 541dcbb3b9cf32d87eacbd957845d8651d6c62c3
   nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
   OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
   package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
-  path_provider: d1e9807085df1f9cc9318206cd649dc0b76be3de
+  path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
   PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
-  url_launcher: b6e016d912f04be9f5bf6e8e82dc599b7ba59649
-  video_player: ecd305f42e9044793efd34846e1ce64c31ea6fcb
+  url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
+  video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
 
 PODFILE CHECKSUM: 93c13a6b510094ca189e0993ce1f80877faea644
 
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index f0d77f40..e061390a 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -165,7 +165,7 @@
 		97C146E61CF9000F007C117D /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1020;
+				LastUpgradeCheck = 1300;
 				ORGANIZATIONNAME = "";
 				TargetAttributes = {
 					97C146ED1CF9000F007C117D = {
@@ -262,7 +262,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "${PODS_ROOT}/FirebaseCrashlytics/run\n";
+			shellScript = "$PODS_ROOT/FirebaseCrashlytics/upload-symbols --build-phase --validate -ai 1:591590867443:ios:0d678803f83cd148b3d286\n$PODS_ROOT/FirebaseCrashlytics/upload-symbols --build-phase -ai 1:591590867443:ios:0d678803f83cd148b3d286\n";
 		};
 		9740EEB61CF901F6004384FC /* Run Script */ = {
 			isa = PBXShellScriptBuildPhase;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 7785fe32..c87d15a3 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1250"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/lib/application/pages/execution/execution_terminal.dart b/lib/application/pages/execution/execution_terminal.dart
index 907720c2..7c3367cd 100644
--- a/lib/application/pages/execution/execution_terminal.dart
+++ b/lib/application/pages/execution/execution_terminal.dart
@@ -2,9 +2,9 @@ import 'dart:ui' as ui;
 
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_quill/models/documents/document.dart' as quill_doc;
-import 'package:flutter_quill/widgets/controller.dart';
-import 'package:flutter_quill/widgets/editor.dart';
+import 'package:flutter_quill/src/models/documents/document.dart' as quill_doc;
+import 'package:flutter_quill/src/widgets/controller.dart';
+import 'package:flutter_quill/src/widgets/editor.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
diff --git a/lib/application/widgets/theme/rich_text_field.dart b/lib/application/widgets/theme/rich_text_field.dart
index d03b3ef6..c4d39738 100644
--- a/lib/application/widgets/theme/rich_text_field.dart
+++ b/lib/application/widgets/theme/rich_text_field.dart
@@ -508,12 +508,12 @@ class _QuillControllerHookState extends HookState<quill.QuillController, _QuillC
     final selection = hook.textController?.selection;
     final hasSelection = selection != null && selection.isValid;
 
-    final document = hasText ? quill.Document.fromJson(json.decode(text!) as List<dynamic>) : quill.Document();
+    final document = hasText ? quill.Document.fromJson(json.decode(text) as List<dynamic>) : quill.Document();
     final selectionOffset = document.toPlainText().isNotEmpty ? document.toPlainText().length - 1 : 0;
 
     _controller = quill.QuillController(
       document: document,
-      selection: hasSelection ? selection! : TextSelection.collapsed(offset: selectionOffset),
+      selection: hasSelection ? selection : TextSelection.collapsed(offset: selectionOffset),
     );
   }
 
diff --git a/pubspec.lock b/pubspec.lock
index fa07be2d..869f6b99 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -7,35 +7,35 @@ packages:
       name: _fe_analyzer_shared
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "30.0.0"
+    version: "31.0.0"
   analyzer:
     dependency: transitive
     description:
       name: analyzer
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.7.0"
+    version: "2.8.0"
   archive:
     dependency: transitive
     description:
       name: archive
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.1.2"
+    version: "3.2.2"
   args:
     dependency: transitive
     description:
       name: args
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.0"
   async:
     dependency: transitive
     description:
       name: async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.8.1"
+    version: "2.8.2"
   boolean_selector:
     dependency: transitive
     description:
@@ -49,7 +49,7 @@ packages:
       name: characters
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   charcode:
     dependency: transitive
     description:
@@ -63,7 +63,7 @@ packages:
       name: cli_util
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.3"
+    version: "0.3.5"
   clock:
     dependency: transitive
     description:
@@ -98,7 +98,7 @@ packages:
       name: cross_file
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.1+4"
+    version: "0.3.2"
   crypto:
     dependency: transitive
     description:
@@ -113,6 +113,48 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.17.1"
+  device_info_plus:
+    dependency: transitive
+    description:
+      name: device_info_plus
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.2.2"
+  device_info_plus_linux:
+    dependency: transitive
+    description:
+      name: device_info_plus_linux
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.1"
+  device_info_plus_macos:
+    dependency: transitive
+    description:
+      name: device_info_plus_macos
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.2.2"
+  device_info_plus_platform_interface:
+    dependency: transitive
+    description:
+      name: device_info_plus_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.3.0+1"
+  device_info_plus_web:
+    dependency: transitive
+    description:
+      name: device_info_plus_web
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.0"
+  device_info_plus_windows:
+    dependency: transitive
+    description:
+      name: device_info_plus_windows
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.1"
   diff_match_patch:
     dependency: transitive
     description:
@@ -148,69 +190,62 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "6.1.2"
-  firebase:
-    dependency: transitive
-    description:
-      name: firebase
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "9.0.1"
   firebase_analytics:
     dependency: "direct main"
     description:
       name: firebase_analytics
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "8.3.4"
+    version: "9.1.2"
   firebase_analytics_platform_interface:
     dependency: transitive
     description:
       name: firebase_analytics_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "3.1.1"
   firebase_analytics_web:
     dependency: transitive
     description:
       name: firebase_analytics_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.0+1"
+    version: "0.4.0+8"
   firebase_core:
     dependency: "direct main"
     description:
       name: firebase_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.0"
+    version: "1.13.1"
   firebase_core_platform_interface:
     dependency: transitive
     description:
       name: firebase_core_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.0.1"
+    version: "4.2.5"
   firebase_core_web:
     dependency: transitive
     description:
       name: firebase_core_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.6.1"
   firebase_crashlytics:
     dependency: "direct main"
     description:
       name: firebase_crashlytics
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.4"
+    version: "2.5.3"
   firebase_crashlytics_platform_interface:
     dependency: transitive
     description:
       name: firebase_crashlytics_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.1.4"
+    version: "3.2.1"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -222,14 +257,14 @@ packages:
       name: flutter_colorpicker
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.6.0"
+    version: "1.0.3"
   flutter_hooks:
     dependency: transitive
     description:
       name: flutter_hooks
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.18.1"
+    version: "0.18.2+1"
   flutter_inappwebview:
     dependency: transitive
     description:
@@ -243,7 +278,7 @@ packages:
       name: flutter_keyboard_visibility
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.3"
+    version: "5.2.0"
   flutter_keyboard_visibility_platform_interface:
     dependency: transitive
     description:
@@ -264,35 +299,35 @@ packages:
       name: flutter_launcher_icons
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.1"
+    version: "0.9.2"
   flutter_native_splash:
     dependency: "direct dev"
     description:
       name: flutter_native_splash
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0"
+    version: "1.3.3"
   flutter_plugin_android_lifecycle:
     dependency: transitive
     description:
       name: flutter_plugin_android_lifecycle
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.5"
   flutter_quill:
     dependency: "direct main"
     description:
       name: flutter_quill
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.22"
+    version: "4.0.10"
   flutter_riverpod:
     dependency: "direct main"
     description:
       name: flutter_riverpod
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.0.3"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -310,6 +345,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.2"
+  gallery_saver:
+    dependency: transitive
+    description:
+      name: gallery_saver
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.3.2"
   gettext_parser:
     dependency: transitive
     description:
@@ -323,14 +365,14 @@ packages:
       name: glob
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.2"
   hooks_riverpod:
     dependency: "direct main"
     description:
       name: hooks_riverpod
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.0.3"
   html:
     dependency: transitive
     description:
@@ -344,14 +386,14 @@ packages:
       name: http
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.13.3"
+    version: "0.13.4"
   http_multi_server:
     dependency: transitive
     description:
       name: http_multi_server
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.1"
+    version: "3.2.0"
   http_parser:
     dependency: transitive
     description:
@@ -365,35 +407,35 @@ packages:
       name: i18n_extension
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.1.3"
+    version: "4.2.0"
   image:
     dependency: transitive
     description:
       name: image
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.2"
+    version: "3.1.3"
   image_picker:
     dependency: transitive
     description:
       name: image_picker
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.8.4+4"
+    version: "0.8.4+11"
   image_picker_for_web:
     dependency: transitive
     description:
       name: image_picker_for_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.2"
+    version: "2.1.6"
   image_picker_platform_interface:
     dependency: transitive
     description:
       name: image_picker_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.4.1"
+    version: "2.4.4"
   intl:
     dependency: transitive
     description:
@@ -428,14 +470,21 @@ packages:
       name: logging
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.1"
+    version: "1.0.2"
   matcher:
     dependency: transitive
     description:
       name: matcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.10"
+    version: "0.12.11"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.3"
   meta:
     dependency: "direct main"
     description:
@@ -449,14 +498,14 @@ packages:
       name: mime
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.0.1"
   mocktail:
     dependency: "direct dev"
     description:
       name: mocktail
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.4"
+    version: "0.3.0"
   node_preamble:
     dependency: transitive
     description:
@@ -470,14 +519,14 @@ packages:
       name: package_config
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.0.2"
   package_info_plus:
     dependency: "direct main"
     description:
       name: package_info_plus
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.3.0"
+    version: "1.4.0"
   package_info_plus_linux:
     dependency: transitive
     description:
@@ -526,35 +575,49 @@ packages:
       name: path_provider
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.6"
+    version: "2.0.9"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.12"
+  path_provider_ios:
+    dependency: transitive
+    description:
+      name: path_provider_ios
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.8"
   path_provider_linux:
     dependency: transitive
     description:
       name: path_provider_linux
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.2"
+    version: "2.1.5"
   path_provider_macos:
     dependency: transitive
     description:
       name: path_provider_macos
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.5"
   path_provider_platform_interface:
     dependency: transitive
     description:
       name: path_provider_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.3"
   path_provider_windows:
     dependency: transitive
     description:
       name: path_provider_windows
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.3"
+    version: "2.0.5"
   pedantic:
     dependency: transitive
     description:
@@ -568,7 +631,7 @@ packages:
       name: petitparser
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.1.0"
+    version: "4.4.0"
   photo_view:
     dependency: transitive
     description:
@@ -582,14 +645,14 @@ packages:
       name: platform
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.0"
+    version: "3.1.0"
   plugin_platform_interface:
     dependency: transitive
     description:
       name: plugin_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "2.1.2"
   pool:
     dependency: transitive
     description:
@@ -603,28 +666,28 @@ packages:
       name: process
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.2.3"
+    version: "4.2.4"
   pub_semver:
     dependency: transitive
     description:
       name: pub_semver
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.1"
   quiver:
     dependency: transitive
     description:
       name: quiver
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.1"
+    version: "3.0.1+1"
   riverpod:
     dependency: transitive
     description:
       name: riverpod
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.0.3"
   rxdart:
     dependency: "direct main"
     description:
@@ -638,7 +701,7 @@ packages:
       name: sembast
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.1.1"
+    version: "3.2.0"
   shelf:
     dependency: transitive
     description:
@@ -713,7 +776,7 @@ packages:
       name: state_notifier
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.7.0"
+    version: "0.7.2+1"
   stream_channel:
     dependency: transitive
     description:
@@ -727,7 +790,7 @@ packages:
       name: strict
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0"
+    version: "1.4.0"
   string_scanner:
     dependency: transitive
     description:
@@ -762,21 +825,21 @@ packages:
       name: test
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.17.10"
+    version: "1.19.5"
   test_api:
     dependency: transitive
     description:
       name: test_api
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.2"
+    version: "0.4.8"
   test_core:
     dependency: transitive
     description:
       name: test_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.0"
+    version: "0.4.9"
   tuple:
     dependency: transitive
     description:
@@ -804,91 +867,119 @@ packages:
       name: url_launcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "6.0.12"
+    version: "6.0.20"
+  url_launcher_android:
+    dependency: transitive
+    description:
+      name: url_launcher_android
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "6.0.15"
+  url_launcher_ios:
+    dependency: transitive
+    description:
+      name: url_launcher_ios
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "6.0.15"
   url_launcher_linux:
     dependency: transitive
     description:
       name: url_launcher_linux
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.0"
   url_launcher_macos:
     dependency: transitive
     description:
       name: url_launcher_macos
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.0"
   url_launcher_platform_interface:
     dependency: transitive
     description:
       name: url_launcher_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.4"
+    version: "2.0.5"
   url_launcher_web:
     dependency: transitive
     description:
       name: url_launcher_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.9"
   url_launcher_windows:
     dependency: transitive
     description:
       name: url_launcher_windows
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.0"
   uuid:
     dependency: "direct main"
     description:
       name: uuid
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.5"
+    version: "3.0.6"
   vector_math:
     dependency: transitive
     description:
       name: vector_math
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.1"
   video_player:
     dependency: transitive
     description:
       name: video_player
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.6"
+    version: "2.3.0"
+  video_player_android:
+    dependency: transitive
+    description:
+      name: video_player_android
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.3.1"
+  video_player_avfoundation:
+    dependency: transitive
+    description:
+      name: video_player_avfoundation
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.3.1"
   video_player_platform_interface:
     dependency: transitive
     description:
       name: video_player_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.2.0"
+    version: "5.1.0"
   video_player_web:
     dependency: transitive
     description:
       name: video_player_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.4"
+    version: "2.0.7"
   vm_service:
     dependency: transitive
     description:
       name: vm_service
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "6.2.0"
+    version: "7.5.0"
   watcher:
     dependency: transitive
     description:
       name: watcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.0.1"
   web_socket_channel:
     dependency: transitive
     description:
@@ -909,21 +1000,21 @@ packages:
       name: win32
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.5"
+    version: "2.4.2"
   xdg_directories:
     dependency: transitive
     description:
       name: xdg_directories
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.0"
+    version: "0.2.0+1"
   xml:
     dependency: transitive
     description:
       name: xml
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.1.2"
+    version: "5.3.1"
   yaml:
     dependency: transitive
     description:
@@ -939,5 +1030,5 @@ packages:
     source: hosted
     version: "8.0.0"
 sdks:
-  dart: ">=2.14.0 <3.0.0"
-  flutter: ">=2.5.3"
+  dart: ">=2.16.1 <3.0.0"
+  flutter: ">=2.10.3"
diff --git a/pubspec.yaml b/pubspec.yaml
index 408ef3a1..98954ca0 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -8,8 +8,8 @@ publish_to: "none"
 version: 0.2.0+0
 
 environment:
-  sdk: ">=2.14.0 <3.0.0"
-  flutter: 2.5.3
+  sdk: ">=2.16.0 <3.0.0"
+  flutter: 2.10.3
 
 dependencies:
   flutter:
@@ -18,27 +18,27 @@ dependencies:
   ###
   # Core
   ###
-  meta: ^1.6.0
+  meta: ^1.7.0
   equatable: ^2.0.3
   path: ^1.8.0
-  path_provider: ^2.0.6
-  url_launcher: ^6.0.12
-  package_info_plus: ^1.3.0
-  firebase_core: ^1.8.0
-  firebase_crashlytics: ^2.2.4
-  firebase_analytics: ^8.3.4
+  path_provider: ^2.0.9
+  url_launcher: ^6.0.20
+  package_info_plus: ^1.4.0
+  firebase_core: ^1.13.1
+  firebase_crashlytics: ^2.5.3
+  firebase_analytics: ^9.1.2
 
   ###
   # Database & Storage
   ###
-  sembast: ^3.1.1
-  uuid: ^3.0.5
+  sembast: ^3.2.0
+  uuid: ^3.0.6
 
   ###
   # State Management
   ###
-  flutter_riverpod: ^1.0.0
-  hooks_riverpod: ^1.0.0
+  flutter_riverpod: ^1.0.3
+  hooks_riverpod: ^1.0.3
   rxdart: ^0.27.3
 
   ###
@@ -47,7 +47,7 @@ dependencies:
   layoutr: ^1.0.0
 
   # Keep dependency locked, as we need it to be the exact same in `memo-editor`
-  flutter_quill: 2.0.22
+  flutter_quill: 4.0.10
 
 dev_dependencies:
   flutter_test:
@@ -56,12 +56,12 @@ dev_dependencies:
   ###
   # Lint
   ###
-  strict: ^1.2.0
+  strict: ^1.4.0
 
   ###
   # Testing
   ###
-  mocktail: ^0.1.0
+  mocktail: ^0.3.0
 
   ###
   # Icon auto-generator

From 93a869cc1e33c3a1aa057857458cd3c5e07931d4 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:55:51 -0300
Subject: [PATCH 02/11] Fixes `require_trailing_comma` analyzer issues

---
 .../rich_text_field_controller_hook.dart      | 14 +++-
 .../details/collection_details_page.dart      |  7 +-
 .../pages/details/contributor_view.dart       |  4 +-
 .../completed_execution_contents.dart         |  3 +-
 .../pages/execution/execution_terminal.dart   | 13 +++-
 .../home/collections/collections_page.dart    | 31 ++++----
 .../update/update_collection_details.dart     | 44 ++++++-----
 .../update/update_collection_memos.dart       | 72 +++++++++--------
 .../update/update_collection_page.dart        | 15 ++--
 .../details/collection_details_vm.dart        |  8 +-
 .../execution/collection_execution_vm.dart    |  7 +-
 .../home/update_collection_vm.dart            | 10 ++-
 lib/application/widgets/theme/link.dart       | 28 ++++---
 .../widgets/theme/rich_text_field.dart        | 28 ++++---
 lib/data/gateways/sembast_database.dart       |  3 +-
 .../repositories/collection_repository.dart   |  3 +-
 lib/main.dart                                 | 11 ++-
 test/assets_test.dart                         | 14 +++-
 .../collection_memos_serializer_test.dart     | 77 ++++++++++++-------
 .../collection_serializer_test.dart           | 77 ++++++++++++-------
 .../contributor_serializer_test.dart          | 11 ++-
 ...o_collection_metadata_serializer_test.dart | 37 +++++----
 .../memo_execution_serializer_test.dart       | 77 ++++++++++++-------
 .../serializers/memo_serializer_test.dart     | 44 +++++++----
 .../serializers/resource_serializer_test.dart | 55 ++++++++-----
 test/utils/widget_pump.dart                   | 14 ++--
 26 files changed, 443 insertions(+), 264 deletions(-)

diff --git a/lib/application/hooks/rich_text_field_controller_hook.dart b/lib/application/hooks/rich_text_field_controller_hook.dart
index 144d3a5c..be4d5b87 100644
--- a/lib/application/hooks/rich_text_field_controller_hook.dart
+++ b/lib/application/hooks/rich_text_field_controller_hook.dart
@@ -25,9 +25,12 @@ class _RichTextEditingControllerHookCreator {
 }
 
 class _RichTextEditingControllerHook extends Hook<RichTextFieldController> {
-  const _RichTextEditingControllerHook(this.initialRichText, this.initialPlainText, this.initialSelection,
-      [List<Object?>? keys])
-      : super(keys: keys);
+  const _RichTextEditingControllerHook(
+    this.initialRichText,
+    this.initialPlainText,
+    this.initialSelection, [
+    List<Object?>? keys,
+  ]) : super(keys: keys);
 
   final String? initialRichText;
   final String? initialPlainText;
@@ -41,7 +44,10 @@ class _RichTextEditingControllerHook extends Hook<RichTextFieldController> {
 
 class _RichTextEditingControllerHookState extends HookState<RichTextFieldController, _RichTextEditingControllerHook> {
   late final _controller = RichTextFieldController(
-      richText: hook.initialRichText, plainText: hook.initialPlainText, selection: hook.initialSelection);
+    richText: hook.initialRichText,
+    plainText: hook.initialPlainText,
+    selection: hook.initialSelection,
+  );
 
   @override
   RichTextFieldController build(BuildContext context) => _controller;
diff --git a/lib/application/pages/details/collection_details_page.dart b/lib/application/pages/details/collection_details_page.dart
index b4d10533..03ee7516 100644
--- a/lib/application/pages/details/collection_details_page.dart
+++ b/lib/application/pages/details/collection_details_page.dart
@@ -125,6 +125,9 @@ class CollectionDetailsPage extends ConsumerWidget {
     return const Scaffold(body: Center(child: CircularProgressIndicator()));
   }
 
-  Widget _buildSectionTitle(BuildContext context, WidgetRef ref, String text) => Text(text,
-      style: Theme.of(context).textTheme.subtitle1?.copyWith(color: ref.watch(themeController).neutralSwatch.shade300));
+  Widget _buildSectionTitle(BuildContext context, WidgetRef ref, String text) => Text(
+        text,
+        style:
+            Theme.of(context).textTheme.subtitle1?.copyWith(color: ref.watch(themeController).neutralSwatch.shade300),
+      );
 }
diff --git a/lib/application/pages/details/contributor_view.dart b/lib/application/pages/details/contributor_view.dart
index 5c472772..b0712ad6 100644
--- a/lib/application/pages/details/contributor_view.dart
+++ b/lib/application/pages/details/contributor_view.dart
@@ -21,7 +21,9 @@ import 'package:memo/application/widgets/theme/link.dart';
 class MultiContributorsView extends ConsumerWidget {
   const MultiContributorsView(this.contributors)
       : assert(
-            contributors.length > 1, 'At least 2 contributors must be provided. Use `SingleContributorView` instead.');
+          contributors.length > 1,
+          'At least 2 contributors must be provided. Use `SingleContributorView` instead.',
+        );
 
   static const _visibleContributorsLimit = 5;
 
diff --git a/lib/application/pages/execution/completed_execution_contents.dart b/lib/application/pages/execution/completed_execution_contents.dart
index af3789cc..0eaaa3e8 100644
--- a/lib/application/pages/execution/completed_execution_contents.dart
+++ b/lib/application/pages/execution/completed_execution_contents.dart
@@ -97,7 +97,8 @@ class CompletedExecutionContents extends ConsumerWidget {
       progressSemanticValue = strings.linearIndicatorCollectionRecallLabel(completeState.readableRecall);
     } else {
       throw InconsistentStateError.layout(
-          'Unexpected `FinishedCollectionExecutionState` subtype: ${state.runtimeType}');
+        'Unexpected `FinishedCollectionExecutionState` subtype: ${state.runtimeType}',
+      );
     }
 
     final showsRecallLevelLink = state is FinishedCompleteCollectionExecutionState;
diff --git a/lib/application/pages/execution/execution_terminal.dart b/lib/application/pages/execution/execution_terminal.dart
index 7c3367cd..4dd0c47d 100644
--- a/lib/application/pages/execution/execution_terminal.dart
+++ b/lib/application/pages/execution/execution_terminal.dart
@@ -129,8 +129,11 @@ class TerminalController extends ChangeNotifier {
       // Reverse the editor animation (to fade out its contents).
       editorAnimationController.reverse(),
       // ... and make sure that the editor scroll goes to the top.
-      editorScrollController.animateTo(0,
-          duration: anims.terminalAnimationDuration, curve: anims.defaultAnimationCurve),
+      editorScrollController.animateTo(
+        0,
+        duration: anims.terminalAnimationDuration,
+        curve: anims.defaultAnimationCurve,
+      ),
       // Respectively hide/show the actions depending on the `isDisplayingQuestion`.
       if (isDisplayingQuestion) actionsAnimationController.forward() else actionsAnimationController.reverse(),
     ]);
@@ -403,7 +406,11 @@ class _TerminalActions extends HookWidget {
   }
 
   Widget _buildDifficultyAction(
-      bool isMarkedAnswer, Image difficultyEmoji, Color highlightColor, Color actionBackgroundColor) {
+    bool isMarkedAnswer,
+    Image difficultyEmoji,
+    Color highlightColor,
+    Color actionBackgroundColor,
+  ) {
     final hasMarkedAnswer = markedAnswer != null;
 
     final blurFilter = BackdropFilter(
diff --git a/lib/application/pages/home/collections/collections_page.dart b/lib/application/pages/home/collections/collections_page.dart
index 893f4b63..fbf39f1d 100644
--- a/lib/application/pages/home/collections/collections_page.dart
+++ b/lib/application/pages/home/collections/collections_page.dart
@@ -21,22 +21,25 @@ class CollectionsPage extends HookConsumerWidget {
       initialIndex: initialState.segmentIndex,
     );
 
-    useEffect(() {
-      void tabListener() {
-        final currentState = ref.read(collectionsVM);
-
-        // Mandatory check because this listener is called multiple times by the tab controller.
-        //
-        // Should only call the VM when the `indexIsChanging` AND if the current segment is different.
-        if (collectionsTabController.indexIsChanging && currentState.segmentIndex != collectionsTabController.index) {
-          final newTab = availableSegments.elementAt(collectionsTabController.index);
-          ref.read(collectionsVM.notifier).updateCollectionsSegment(newTab);
+    useEffect(
+      () {
+        void tabListener() {
+          final currentState = ref.read(collectionsVM);
+
+          // Mandatory check because this listener is called multiple times by the tab controller.
+          //
+          // Should only call the VM when the `indexIsChanging` AND if the current segment is different.
+          if (collectionsTabController.indexIsChanging && currentState.segmentIndex != collectionsTabController.index) {
+            final newTab = availableSegments.elementAt(collectionsTabController.index);
+            ref.read(collectionsVM.notifier).updateCollectionsSegment(newTab);
+          }
         }
-      }
 
-      collectionsTabController.addListener(tabListener);
-      return () => collectionsTabController.removeListener(tabListener);
-    }, [collectionsTabController]);
+        collectionsTabController.addListener(tabListener);
+        return () => collectionsTabController.removeListener(tabListener);
+      },
+      [collectionsTabController],
+    );
 
     final tabs = availableSegments.map(_widgetForTab).toList();
     return Column(
diff --git a/lib/application/pages/home/collections/update/update_collection_details.dart b/lib/application/pages/home/collections/update/update_collection_details.dart
index ee9caeb9..7c6e5427 100644
--- a/lib/application/pages/home/collections/update/update_collection_details.dart
+++ b/lib/application/pages/home/collections/update/update_collection_details.dart
@@ -24,7 +24,9 @@ class UpdateCollectionDetails extends ConsumerWidget {
     final parentVM = ref.watch(updateCollectionVM.notifier);
 
     ref.listen<UpdatedDetailsState>(
-        updateCollectionDetailsVM, (_, state) => parentVM.updateMetadata(metadata: state.metadata));
+      updateCollectionDetailsVM,
+      (_, state) => parentVM.updateMetadata(metadata: state.metadata),
+    );
 
     return UnfocusPointer(
       child: SingleChildScrollView(
@@ -84,15 +86,18 @@ class _TagsField extends HookConsumerWidget {
     final hasInitialData = useState(false);
     final controller = useTagsController(tags: state.metadata.tags);
 
-    useEffect(() {
-      void onTagsUpdate() {
-        vm.updateTags(controller.tags);
-        hasInitialData.value = true;
-      }
+    useEffect(
+      () {
+        void onTagsUpdate() {
+          vm.updateTags(controller.tags);
+          hasInitialData.value = true;
+        }
 
-      controller.addListener(onTagsUpdate);
-      return () => controller.removeListener(onTagsUpdate);
-    }, []);
+        controller.addListener(onTagsUpdate);
+        return () => controller.removeListener(onTagsUpdate);
+      },
+      [],
+    );
 
     return StreamBuilder(
       stream: vm.tags,
@@ -119,17 +124,20 @@ class _DescriptionField extends HookConsumerWidget {
     final hasInitialData = useState(false);
     final controller = useRichTextEditingController(richText: state.metadata.description.richContent);
 
-    useEffect(() {
-      void onDescriptionUpdate() {
-        final content = mapRichTextValueToMemoUpdateContent(controller.value);
-        vm.updateDescription(content);
-        hasInitialData.value = true;
-      }
+    useEffect(
+      () {
+        void onDescriptionUpdate() {
+          final content = mapRichTextValueToMemoUpdateContent(controller.value);
+          vm.updateDescription(content);
+          hasInitialData.value = true;
+        }
 
-      controller.addListener(onDescriptionUpdate);
+        controller.addListener(onDescriptionUpdate);
 
-      return () => controller.removeListener(onDescriptionUpdate);
-    }, []);
+        return () => controller.removeListener(onDescriptionUpdate);
+      },
+      [],
+    );
 
     final descriptionLength = state.metadata.description.plainContent.length;
 
diff --git a/lib/application/pages/home/collections/update/update_collection_memos.dart b/lib/application/pages/home/collections/update/update_collection_memos.dart
index 431384cc..385604f8 100644
--- a/lib/application/pages/home/collections/update/update_collection_memos.dart
+++ b/lib/application/pages/home/collections/update/update_collection_memos.dart
@@ -29,12 +29,15 @@ class UpdateCollectionMemos extends HookConsumerWidget {
     final parentVM = ref.watch(updateCollectionVM.notifier);
     ref.listen<UpdateMemosState>(updateCollectionMemosVM, (_, state) => parentVM.updateMemos(memos: state.memos));
 
-    useEffect(() {
-      void onPageUpdate() => currentPageIndex.value = controller.page!.toInt();
-
-      controller.addListener(onPageUpdate);
-      return () => controller.removeListener(onPageUpdate);
-    }, []);
+    useEffect(
+      () {
+        void onPageUpdate() => currentPageIndex.value = controller.page!.toInt();
+
+        controller.addListener(onPageUpdate);
+        return () => controller.removeListener(onPageUpdate);
+      },
+      [],
+    );
 
     // Uses `PageView.custom` to support pages reordering.
     final pagesView = PageView.custom(
@@ -116,33 +119,36 @@ class _MemoPage extends HookConsumerWidget {
     final answerValue = mapMemoUpdateContentToRichTextValue(metadata.answer);
     final answerController = RichTextFieldController.fromValue(answerValue);
 
-    useEffect(() {
-      void onQuestionUpdate() {
-        final updatedContent = MemoUpdateContent(
-          richContent: questionController.value.richText,
-          plainContent: questionController.value.plainText,
-        );
-
-        onUpdate(metadata.copyWith(question: updatedContent));
-      }
-
-      void onAnswerUpdate() {
-        final updatedContent = MemoUpdateContent(
-          richContent: answerController.value.richText,
-          plainContent: answerController.value.plainText,
-        );
-
-        onUpdate(metadata.copyWith(answer: updatedContent));
-      }
-
-      questionController.addListener(onQuestionUpdate);
-      answerController.addListener(onAnswerUpdate);
-
-      return () {
-        questionController.removeListener(onQuestionUpdate);
-        answerController.removeListener(onAnswerUpdate);
-      };
-    }, []);
+    useEffect(
+      () {
+        void onQuestionUpdate() {
+          final updatedContent = MemoUpdateContent(
+            richContent: questionController.value.richText,
+            plainContent: questionController.value.plainText,
+          );
+
+          onUpdate(metadata.copyWith(question: updatedContent));
+        }
+
+        void onAnswerUpdate() {
+          final updatedContent = MemoUpdateContent(
+            richContent: answerController.value.richText,
+            plainContent: answerController.value.plainText,
+          );
+
+          onUpdate(metadata.copyWith(answer: updatedContent));
+        }
+
+        questionController.addListener(onQuestionUpdate);
+        answerController.addListener(onAnswerUpdate);
+
+        return () {
+          questionController.removeListener(onQuestionUpdate);
+          answerController.removeListener(onAnswerUpdate);
+        };
+      },
+      [],
+    );
 
     return UpdateMemoTerminal(
       memoIndex: pageIndex + 1,
diff --git a/lib/application/pages/home/collections/update/update_collection_page.dart b/lib/application/pages/home/collections/update/update_collection_page.dart
index 17d55ce9..fc6f8a3a 100644
--- a/lib/application/pages/home/collections/update/update_collection_page.dart
+++ b/lib/application/pages/home/collections/update/update_collection_page.dart
@@ -32,12 +32,15 @@ class UpdateCollectionPage extends HookConsumerWidget {
     final tabController = useTabController(initialLength: _Segment.values.length);
     final memosPageController = usePageController(viewportFraction: dimens.memosPageControllerViewportFraction);
 
-    useEffect(() {
-      void tabListener() => selectedSegment.value = _Segment.values[tabController.index];
-
-      tabController.addListener(tabListener);
-      return () => tabController.removeListener(tabListener);
-    }, []);
+    useEffect(
+      () {
+        void tabListener() => selectedSegment.value = _Segment.values[tabController.index];
+
+        tabController.addListener(tabListener);
+        return () => tabController.removeListener(tabListener);
+      },
+      [],
+    );
 
     final tabs = _Segment.values.map((segment) => Text(segment.title)).toList();
 
diff --git a/lib/application/view-models/details/collection_details_vm.dart b/lib/application/view-models/details/collection_details_vm.dart
index d59c91bb..888b9e39 100644
--- a/lib/application/view-models/details/collection_details_vm.dart
+++ b/lib/application/view-models/details/collection_details_vm.dart
@@ -23,9 +23,11 @@ abstract class CollectionDetailsVM extends StateNotifier<CollectionDetailsState>
 }
 
 class CollectionDetailsVMImpl extends CollectionDetailsVM {
-  CollectionDetailsVMImpl(
-      {required this.collectionId, required this.collectionServices, required this.resourceServices})
-      : super(LoadingCollectionDetailsState()) {
+  CollectionDetailsVMImpl({
+    required this.collectionId,
+    required this.collectionServices,
+    required this.resourceServices,
+  }) : super(LoadingCollectionDetailsState()) {
     _loadCollection();
   }
 
diff --git a/lib/application/view-models/execution/collection_execution_vm.dart b/lib/application/view-models/execution/collection_execution_vm.dart
index d9862668..3cf72f45 100644
--- a/lib/application/view-models/execution/collection_execution_vm.dart
+++ b/lib/application/view-models/execution/collection_execution_vm.dart
@@ -149,8 +149,11 @@ abstract class CollectionExecutionState extends Equatable {
 class LoadingCollectionExecutionState extends CollectionExecutionState {}
 
 class LoadedCollectionExecutionState extends CollectionExecutionState {
-  LoadedCollectionExecutionState(
-      {required this.initialMemo, required this.completionValue, required this.collectionName});
+  LoadedCollectionExecutionState({
+    required this.initialMemo,
+    required this.completionValue,
+    required this.collectionName,
+  });
 
   final String collectionName;
   final MemoMetadata initialMemo;
diff --git a/lib/application/view-models/home/update_collection_vm.dart b/lib/application/view-models/home/update_collection_vm.dart
index 8fb5e150..f3b7da27 100644
--- a/lib/application/view-models/home/update_collection_vm.dart
+++ b/lib/application/view-models/home/update_collection_vm.dart
@@ -159,10 +159,16 @@ class UpdateCollectionLoaded extends UpdateCollectionState {
       );
 
   UpdateCollectionSaving copyForSaving() => UpdateCollectionSaving(
-      metadata: collectionMetadata, memosMetadata: memosMetadata, hasValidDetails: hasValidDetails);
+        metadata: collectionMetadata,
+        memosMetadata: memosMetadata,
+        hasValidDetails: hasValidDetails,
+      );
 
   UpdateCollectionSaved copyForSaved() => UpdateCollectionSaved(
-      metadata: collectionMetadata, memosMetadata: memosMetadata, hasValidDetails: hasValidDetails);
+        metadata: collectionMetadata,
+        memosMetadata: memosMetadata,
+        hasValidDetails: hasValidDetails,
+      );
 
   @override
   List<Object?> get props => [...super.props, collectionMetadata, memosMetadata, hasValidDetails];
diff --git a/lib/application/widgets/theme/link.dart b/lib/application/widgets/theme/link.dart
index 06ee4f27..831ac054 100644
--- a/lib/application/widgets/theme/link.dart
+++ b/lib/application/widgets/theme/link.dart
@@ -102,10 +102,14 @@ class UrlLinkButton extends StatelessWidget {
     this.textStyle,
     Key? key,
   }) : super(key: key) {
-    _allowedSchemes.firstWhere((scheme) => url.toLowerCase().startsWith(scheme), orElse: () {
-      throw InconsistentStateError.layout(
-          'All links must start with one of the following schemes: $_allowedSchemes - actual: "$url"');
-    });
+    _allowedSchemes.firstWhere(
+      (scheme) => url.toLowerCase().startsWith(scheme),
+      orElse: () {
+        throw InconsistentStateError.layout(
+          'All links must start with one of the following schemes: $_allowedSchemes - actual: "$url"',
+        );
+      },
+    );
   }
 
   final String url;
@@ -154,10 +158,14 @@ class UnderlinedUrlLink extends ConsumerWidget {
     this.onFailLaunchingUrl,
     Key? key,
   }) : super(key: key) {
-    _allowedSchemes.firstWhere((scheme) => url.toLowerCase().startsWith(scheme), orElse: () {
-      throw InconsistentStateError.layout(
-          'All links must start with one of the following schemes: $_allowedSchemes - actual: "$url"');
-    });
+    _allowedSchemes.firstWhere(
+      (scheme) => url.toLowerCase().startsWith(scheme),
+      orElse: () {
+        throw InconsistentStateError.layout(
+          'All links must start with one of the following schemes: $_allowedSchemes - actual: "$url"',
+        );
+      },
+    );
   }
 
   final String url;
@@ -179,7 +187,9 @@ class UnderlinedUrlLink extends ConsumerWidget {
         child: Text(
           text ?? url,
           style: Theme.of(context).textTheme.caption?.copyWith(
-              color: ref.watch(themeController).neutralSwatch.shade300, decoration: TextDecoration.underline),
+                color: ref.watch(themeController).neutralSwatch.shade300,
+                decoration: TextDecoration.underline,
+              ),
         ),
       ),
     );
diff --git a/lib/application/widgets/theme/rich_text_field.dart b/lib/application/widgets/theme/rich_text_field.dart
index c4d39738..e2c204fa 100644
--- a/lib/application/widgets/theme/rich_text_field.dart
+++ b/lib/application/widgets/theme/rich_text_field.dart
@@ -58,11 +58,13 @@ class RichTextFieldController extends ValueNotifier<RichTextEditingValue> {
     String? richText,
     String? plainText,
     TextSelection? selection,
-  }) : super(RichTextEditingValue(
-          richText: richText ?? '',
-          plainText: plainText ?? '',
-          selection: selection ?? const TextSelection.collapsed(offset: -1),
-        ));
+  }) : super(
+          RichTextEditingValue(
+            richText: richText ?? '',
+            plainText: plainText ?? '',
+            selection: selection ?? const TextSelection.collapsed(offset: -1),
+          ),
+        );
 
   RichTextFieldController.fromValue(RichTextEditingValue value) : super(value);
 
@@ -453,13 +455,15 @@ class _RichTextFieldToolbar extends HookConsumerWidget {
     bool isSelected(quill.Attribute attribute) => selectedAttributes.value.contains(attribute);
 
     final attributesIcons = _toolBarAsset.keys
-        .map((attribute) => AssetIconButton(
-              _toolBarAsset[attribute]!,
-              iconColor: isSelected(attribute) ? theme.neutralSwatch.shade800 : null,
-              iconBackgroundColor: isSelected(attribute) ? theme.neutralSwatch.shade500 : null,
-              isSplashEffectEnabled: false,
-              onPressed: () => onToggle(attribute),
-            ))
+        .map(
+          (attribute) => AssetIconButton(
+            _toolBarAsset[attribute]!,
+            iconColor: isSelected(attribute) ? theme.neutralSwatch.shade800 : null,
+            iconBackgroundColor: isSelected(attribute) ? theme.neutralSwatch.shade500 : null,
+            isSplashEffectEnabled: false,
+            onPressed: () => onToggle(attribute),
+          ),
+        )
         .toList();
 
     return ThemedBottomContainer(
diff --git a/lib/data/gateways/sembast_database.dart b/lib/data/gateways/sembast_database.dart
index 13f81a3e..26a5000c 100644
--- a/lib/data/gateways/sembast_database.dart
+++ b/lib/data/gateways/sembast_database.dart
@@ -35,7 +35,8 @@ abstract class SembastTransactionHandler implements DatabaseTransactionHandler {
       // ignore: avoid_catches_without_on_clauses
     } catch (error, stack) {
       throw InconsistentStateError.gateway(
-          'Failed transaction with Error:\n${error.toString()} \nStackTrace:\n${stack.toString()}');
+        'Failed transaction with Error:\n${error.toString()} \nStackTrace:\n${stack.toString()}',
+      );
     } finally {
       currentTransaction = null;
     }
diff --git a/lib/data/repositories/collection_repository.dart b/lib/data/repositories/collection_repository.dart
index d7ba1e95..d6b5ee9d 100644
--- a/lib/data/repositories/collection_repository.dart
+++ b/lib/data/repositories/collection_repository.dart
@@ -58,7 +58,8 @@ class CollectionRepositoryImpl implements CollectionRepository {
     final rawCollection = await _db.get(id: id, store: _collectionStore);
     if (rawCollection == null) {
       throw InconsistentStateError.repository(
-          'Missing required collection (of record "$id") in store "$_collectionStore"');
+        'Missing required collection (of record "$id") in store "$_collectionStore"',
+      );
     }
 
     return _collectionSerializer.from(rawCollection);
diff --git a/lib/main.dart b/lib/main.dart
index eee13e8c..82038561 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -18,9 +18,12 @@ Future<void> main() async {
   FlutterError.onError = crashlytics.recordFlutterError;
 
   // Wraps `AppRoot` in a guarded zone where all errors are reported to `crashlytics.recordError`.
-  runZonedGuarded(() {
-    final appVM = AppVMImpl();
+  runZonedGuarded(
+    () {
+      final appVM = AppVMImpl();
 
-    runApp(AppRoot(appVM));
-  }, crashlytics.recordError);
+      runApp(AppRoot(appVM));
+    },
+    crashlytics.recordError,
+  );
 }
diff --git a/test/assets_test.dart b/test/assets_test.dart
index 4083dd75..4265deb1 100644
--- a/test/assets_test.dart
+++ b/test/assets_test.dart
@@ -31,8 +31,11 @@ void main() {
       final collectionId = collections[index][CollectionMemosKeys.id] as String;
       final fullCollectionPath = collectionsPaths[index];
 
-      expect(fullCollectionPath.contains('/$collectionId.json'), isTrue,
-          reason: 'Collection had id "$collectionId" but file path "$fullCollectionPath"');
+      expect(
+        fullCollectionPath.contains('/$collectionId.json'),
+        isTrue,
+        reason: 'Collection had id "$collectionId" but file path "$fullCollectionPath"',
+      );
     }
   });
 
@@ -53,8 +56,11 @@ void main() {
       ).forEach(
         (rawMemo) {
           final memoUniqueId = rawMemo[MemoCollectionMetadataKeys.uniqueId] as String;
-          expect(memosIds.contains(memoUniqueId), isFalse,
-              reason: 'Duplicate memo id "$memoUniqueId" in collection "$collection"');
+          expect(
+            memosIds.contains(memoUniqueId),
+            isFalse,
+            reason: 'Duplicate memo id "$memoUniqueId" in collection "$collection"',
+          );
           memosIds.add(memoUniqueId);
         },
       );
diff --git a/test/data/serializers/collection_memos_serializer_test.dart b/test/data/serializers/collection_memos_serializer_test.dart
index 05c7be8d..ec788b29 100644
--- a/test/data/serializers/collection_memos_serializer_test.dart
+++ b/test/data/serializers/collection_memos_serializer_test.dart
@@ -40,33 +40,54 @@ void main() {
   });
 
   test('CollectionMemosSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.id);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.name);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.description);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.category);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.tags);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.contributors);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionMemosKeys.memosMetadata);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.id);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.name);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.description);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.category);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.tags);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.contributors);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionMemosKeys.memosMetadata);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 }
diff --git a/test/data/serializers/collection_serializer_test.dart b/test/data/serializers/collection_serializer_test.dart
index c256074c..ed7de15f 100644
--- a/test/data/serializers/collection_serializer_test.dart
+++ b/test/data/serializers/collection_serializer_test.dart
@@ -32,34 +32,55 @@ void main() {
   });
 
   test('CollectionSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.id);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.name);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.description);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.category);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.tags);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.contributors);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawCollection = completeFixture()..remove(CollectionKeys.uniqueMemosAmount);
-      serializer.from(rawCollection);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.id);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.name);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.description);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.category);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.tags);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.contributors);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawCollection = completeFixture()..remove(CollectionKeys.uniqueMemosAmount);
+        serializer.from(rawCollection);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 
   test('CollectionSerializer should decode with optional properties', () {
diff --git a/test/data/serializers/contributor_serializer_test.dart b/test/data/serializers/contributor_serializer_test.dart
index 47167b2f..e199dcc0 100644
--- a/test/data/serializers/contributor_serializer_test.dart
+++ b/test/data/serializers/contributor_serializer_test.dart
@@ -19,10 +19,13 @@ void main() {
   });
 
   test('ContributorSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawContributor = fixtures.contributor()..remove(ContributorKeys.name);
-      serializer.from(rawContributor);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawContributor = fixtures.contributor()..remove(ContributorKeys.name);
+        serializer.from(rawContributor);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 
   test('ContributorSerializer should decode with optional properties', () {
diff --git a/test/data/serializers/memo_collection_metadata_serializer_test.dart b/test/data/serializers/memo_collection_metadata_serializer_test.dart
index 457321a1..1cdec0b3 100644
--- a/test/data/serializers/memo_collection_metadata_serializer_test.dart
+++ b/test/data/serializers/memo_collection_metadata_serializer_test.dart
@@ -24,19 +24,28 @@ void main() {
   });
 
   test('MemoCollectionMetadataSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.uniqueId);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
-
-    expect(() {
-      final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.rawQuestion);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
-
-    expect(() {
-      final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.rawAnswer);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.uniqueId);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
+
+    expect(
+      () {
+        final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.rawQuestion);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
+
+    expect(
+      () {
+        final rawMemo = fixtures.memoCollectionMetadata()..remove(MemoCollectionMetadataKeys.rawAnswer);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 }
diff --git a/test/data/serializers/memo_execution_serializer_test.dart b/test/data/serializers/memo_execution_serializer_test.dart
index 324dc1a5..2e1a3875 100644
--- a/test/data/serializers/memo_execution_serializer_test.dart
+++ b/test/data/serializers/memo_execution_serializer_test.dart
@@ -31,34 +31,55 @@ void main() {
     });
 
     test('should fail to decode without required properties', () {
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.uniqueId);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.collectionId);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.started);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.finished);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.rawQuestion);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.rawAnswer);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
-      expect(() {
-        final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.markedDifficulty);
-        serializer.from(rawExecution);
-      }, throwsA(isA<TypeError>()));
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.uniqueId);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.collectionId);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.started);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.finished);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.rawQuestion);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.rawAnswer);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
+      expect(
+        () {
+          final rawExecution = fixtures.memoExecution()..remove(MemoExecutionKeys.markedDifficulty);
+          serializer.from(rawExecution);
+        },
+        throwsA(isA<TypeError>()),
+      );
     });
   });
 }
diff --git a/test/data/serializers/memo_serializer_test.dart b/test/data/serializers/memo_serializer_test.dart
index 90a87186..5e5e79df 100644
--- a/test/data/serializers/memo_serializer_test.dart
+++ b/test/data/serializers/memo_serializer_test.dart
@@ -28,25 +28,37 @@ void main() {
   });
 
   test('MemoSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawMemo = fixtures.memo()..remove(MemoKeys.uniqueId);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawMemo = fixtures.memo()..remove(MemoKeys.uniqueId);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
 
-    expect(() {
-      final rawMemo = fixtures.memo()..remove(MemoKeys.collectionId);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawMemo = fixtures.memo()..remove(MemoKeys.collectionId);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
 
-    expect(() {
-      final rawMemo = fixtures.memo()..remove(MemoKeys.rawQuestion);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawMemo = fixtures.memo()..remove(MemoKeys.rawQuestion);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
 
-    expect(() {
-      final rawMemo = fixtures.memo()..remove(MemoKeys.rawAnswer);
-      serializer.from(rawMemo);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawMemo = fixtures.memo()..remove(MemoKeys.rawAnswer);
+        serializer.from(rawMemo);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 
   test('MemoSerializer should decode with optional properties', () {
diff --git a/test/data/serializers/resource_serializer_test.dart b/test/data/serializers/resource_serializer_test.dart
index 1dec3003..44aafed5 100644
--- a/test/data/serializers/resource_serializer_test.dart
+++ b/test/data/serializers/resource_serializer_test.dart
@@ -27,25 +27,40 @@ void main() {
   });
 
   test('ResourceSerializer should fail to decode without required properties', () {
-    expect(() {
-      final rawBlock = fixtures.resource()..remove('id');
-      serializer.from(rawBlock);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawBlock = fixtures.resource()..remove('description');
-      serializer.from(rawBlock);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawBlock = fixtures.resource()..remove('url');
-      serializer.from(rawBlock);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawBlock = fixtures.resource()..remove('tags');
-      serializer.from(rawBlock);
-    }, throwsA(isA<TypeError>()));
-    expect(() {
-      final rawBlock = fixtures.resource()..remove('type');
-      serializer.from(rawBlock);
-    }, throwsA(isA<TypeError>()));
+    expect(
+      () {
+        final rawBlock = fixtures.resource()..remove('id');
+        serializer.from(rawBlock);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawBlock = fixtures.resource()..remove('description');
+        serializer.from(rawBlock);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawBlock = fixtures.resource()..remove('url');
+        serializer.from(rawBlock);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawBlock = fixtures.resource()..remove('tags');
+        serializer.from(rawBlock);
+      },
+      throwsA(isA<TypeError>()),
+    );
+    expect(
+      () {
+        final rawBlock = fixtures.resource()..remove('type');
+        serializer.from(rawBlock);
+      },
+      throwsA(isA<TypeError>()),
+    );
   });
 }
diff --git a/test/utils/widget_pump.dart b/test/utils/widget_pump.dart
index bdc62c72..91c23ebf 100644
--- a/test/utils/widget_pump.dart
+++ b/test/utils/widget_pump.dart
@@ -17,11 +17,13 @@ Future<void> pumpProviderScoped(WidgetTester tester, Widget widget, [List<Overri
     tester.pumpWidget(
       ProviderScope(
         overrides: overrides,
-        child: Consumer(builder: (context, ref, child) {
-          return MaterialApp(
-            theme: ref.read(themeController.notifier).currentThemeData(context),
-            home: Scaffold(body: widget),
-          );
-        }),
+        child: Consumer(
+          builder: (context, ref, child) {
+            return MaterialApp(
+              theme: ref.read(themeController.notifier).currentThemeData(context),
+              home: Scaffold(body: widget),
+            );
+          },
+        ),
       ),
     );

From 3f5cedef4672671329acea43fd33722c53c42c6c Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:56:17 -0300
Subject: [PATCH 03/11] Fixes `use_decorated_box` analyzer issues

---
 lib/application/pages/execution/execution_terminal.dart | 2 +-
 lib/application/pages/home/progress/progress_page.dart  | 2 +-
 lib/application/widgets/material/asset_icon_button.dart | 2 +-
 lib/application/widgets/theme/collection_card.dart      | 2 +-
 lib/application/widgets/theme/custom_text_field.dart    | 2 +-
 lib/application/widgets/theme/themed_container.dart     | 4 ++--
 6 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/application/pages/execution/execution_terminal.dart b/lib/application/pages/execution/execution_terminal.dart
index 4dd0c47d..1a661d1f 100644
--- a/lib/application/pages/execution/execution_terminal.dart
+++ b/lib/application/pages/execution/execution_terminal.dart
@@ -421,7 +421,7 @@ class _TerminalActions extends HookWidget {
       child: Container(color: Colors.transparent),
     );
 
-    final highlightDecoration = Container(
+    final highlightDecoration = DecoratedBox(
       decoration: BoxDecoration(
         shape: BoxShape.circle,
         color: Colors.transparent,
diff --git a/lib/application/pages/home/progress/progress_page.dart b/lib/application/pages/home/progress/progress_page.dart
index 27973ca8..467c911d 100644
--- a/lib/application/pages/home/progress/progress_page.dart
+++ b/lib/application/pages/home/progress/progress_page.dart
@@ -168,7 +168,7 @@ class _ProgressContainer extends ConsumerWidget {
       border: Border.all(color: borderColor, width: dimens.cardBorderWidth),
     );
 
-    return Container(
+    return DecoratedBox(
       decoration: decoration,
       child: contents.withAllPadding(context, Spacing.large),
     );
diff --git a/lib/application/widgets/material/asset_icon_button.dart b/lib/application/widgets/material/asset_icon_button.dart
index 225ba51c..54b55127 100644
--- a/lib/application/widgets/material/asset_icon_button.dart
+++ b/lib/application/widgets/material/asset_icon_button.dart
@@ -30,7 +30,7 @@ class AssetIconButton extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     final imageAsset = AssetImage(asset);
-    final icon = Container(
+    final icon = DecoratedBox(
       decoration: BoxDecoration(
         color: iconBackgroundColor,
         borderRadius: dimens.genericRoundedElementBorderRadius,
diff --git a/lib/application/widgets/theme/collection_card.dart b/lib/application/widgets/theme/collection_card.dart
index b3bca87c..8c98f350 100644
--- a/lib/application/widgets/theme/collection_card.dart
+++ b/lib/application/widgets/theme/collection_card.dart
@@ -68,7 +68,7 @@ class CollectionCard extends ConsumerWidget {
     // We are not using the `Card` widget because we need to customize the background with border + painter.
     return GestureDetector(
       onTap: onTap,
-      child: Container(
+      child: DecoratedBox(
         decoration: _buildCardDecoration(theme),
         child: CustomPaint(
           painter: _buildBackgroundPainter(theme),
diff --git a/lib/application/widgets/theme/custom_text_field.dart b/lib/application/widgets/theme/custom_text_field.dart
index a0902e4c..f6ba43a3 100644
--- a/lib/application/widgets/theme/custom_text_field.dart
+++ b/lib/application/widgets/theme/custom_text_field.dart
@@ -116,7 +116,7 @@ class CustomTextField extends HookConsumerWidget {
         ? textTheme.caption?.copyWith(color: neutralSwatch.shade300)
         : textTheme.subtitle1;
 
-    final textField = Container(
+    final textField = DecoratedBox(
       decoration: BoxDecoration(
         color: _hasErrorText ? theme.destructiveSwatch : null,
         borderRadius: dimens.genericRoundedElementBorderRadius,
diff --git a/lib/application/widgets/theme/themed_container.dart b/lib/application/widgets/theme/themed_container.dart
index 8318c068..f59f1ef6 100644
--- a/lib/application/widgets/theme/themed_container.dart
+++ b/lib/application/widgets/theme/themed_container.dart
@@ -17,7 +17,7 @@ class ThemedTopContainer extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final theme = ref.watch(themeController);
 
-    return Container(
+    return DecoratedBox(
       decoration: BoxDecoration(
         border: Border(bottom: _useThemedBorderSide(theme)),
       ),
@@ -39,7 +39,7 @@ class ThemedBottomContainer extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final theme = ref.watch(themeController);
 
-    return Container(
+    return DecoratedBox(
       decoration: BoxDecoration(
         border: Border(top: _useThemedBorderSide(theme)),
       ),

From 56813d7a5cbb03b1ee5a203f0096326ae9ef9d10 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:56:55 -0300
Subject: [PATCH 04/11] Removes unnecessary imports and adds missing references
 to `pubspec`

---
 .../pages/execution/execution_terminal.dart         | 13 +++++--------
 .../collections/update/update_collection_memos.dart |  1 -
 .../collections/update/update_collection_page.dart  |  3 ---
 .../collections/update/update_memo_terminal.dart    |  1 -
 lib/application/widgets/theme/rich_text_field.dart  |  1 -
 lib/application/widgets/theme/tags_field.dart       |  1 -
 pubspec.lock                                        |  6 +++---
 pubspec.yaml                                        |  3 +++
 8 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/lib/application/pages/execution/execution_terminal.dart b/lib/application/pages/execution/execution_terminal.dart
index 1a661d1f..55b25ece 100644
--- a/lib/application/pages/execution/execution_terminal.dart
+++ b/lib/application/pages/execution/execution_terminal.dart
@@ -2,10 +2,7 @@ import 'dart:ui' as ui;
 
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_quill/src/models/documents/document.dart' as quill_doc;
-import 'package:flutter_quill/src/widgets/controller.dart';
-import 'package:flutter_quill/src/widgets/editor.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_quill/flutter_quill.dart' as quill;
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/animations.dart' as anims;
@@ -197,7 +194,7 @@ class _ExecutionTerminalState extends ConsumerState<ExecutionTerminal> {
       ),
     );
     final editor = _TerminalQuillEditor(
-      document: quill_doc.Document.fromJson(controller.rawContents),
+      document: quill.Document.fromJson(controller.rawContents),
       animationController: controller.editorAnimationController,
       scrollController: controller.editorScrollController,
     );
@@ -247,18 +244,18 @@ class _TerminalQuillEditor extends StatelessWidget {
     required this.scrollController,
   });
 
-  final quill_doc.Document document;
+  final quill.Document document;
   final AnimationController animationController;
   final ScrollController scrollController;
 
   @override
   Widget build(BuildContext context) {
-    final quillController = QuillController(
+    final quillController = quill.QuillController(
       document: document,
       selection: const TextSelection.collapsed(offset: 0),
     );
 
-    final quillEditor = QuillEditor(
+    final quillEditor = quill.QuillEditor(
       controller: quillController,
       focusNode: FocusNode(),
       scrollController: scrollController,
diff --git a/lib/application/pages/home/collections/update/update_collection_memos.dart b/lib/application/pages/home/collections/update/update_collection_memos.dart
index 385604f8..307fe4c5 100644
--- a/lib/application/pages/home/collections/update/update_collection_memos.dart
+++ b/lib/application/pages/home/collections/update/update_collection_memos.dart
@@ -1,6 +1,5 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/animations.dart' as anims;
diff --git a/lib/application/pages/home/collections/update/update_collection_page.dart b/lib/application/pages/home/collections/update/update_collection_page.dart
index fc6f8a3a..0728b294 100644
--- a/lib/application/pages/home/collections/update/update_collection_page.dart
+++ b/lib/application/pages/home/collections/update/update_collection_page.dart
@@ -1,8 +1,5 @@
-import 'dart:ui';
-
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/animations.dart' as anims;
diff --git a/lib/application/pages/home/collections/update/update_memo_terminal.dart b/lib/application/pages/home/collections/update/update_memo_terminal.dart
index df615fac..8060e1a4 100644
--- a/lib/application/pages/home/collections/update/update_memo_terminal.dart
+++ b/lib/application/pages/home/collections/update/update_memo_terminal.dart
@@ -1,5 +1,4 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/dimensions.dart' as dimens;
diff --git a/lib/application/widgets/theme/rich_text_field.dart b/lib/application/widgets/theme/rich_text_field.dart
index e2c204fa..b9f69f3a 100644
--- a/lib/application/widgets/theme/rich_text_field.dart
+++ b/lib/application/widgets/theme/rich_text_field.dart
@@ -3,7 +3,6 @@ import 'dart:convert';
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:flutter_quill/flutter_quill.dart' as quill;
-import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/dimensions.dart' as dimens;
diff --git a/lib/application/widgets/theme/tags_field.dart b/lib/application/widgets/theme/tags_field.dart
index 786e9991..dbd284a6 100644
--- a/lib/application/widgets/theme/tags_field.dart
+++ b/lib/application/widgets/theme/tags_field.dart
@@ -1,7 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:layoutr/common_layout.dart';
 import 'package:memo/application/constants/animations.dart' as anims;
diff --git a/pubspec.lock b/pubspec.lock
index 869f6b99..35466b23 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -72,7 +72,7 @@ packages:
     source: hosted
     version: "1.1.0"
   collection:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: collection
       url: "https://pub.dartlang.org"
@@ -259,7 +259,7 @@ packages:
     source: hosted
     version: "1.0.3"
   flutter_hooks:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: flutter_hooks
       url: "https://pub.dartlang.org"
@@ -841,7 +841,7 @@ packages:
     source: hosted
     version: "0.4.9"
   tuple:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: tuple
       url: "https://pub.dartlang.org"
diff --git a/pubspec.yaml b/pubspec.yaml
index 98954ca0..bdfe79c3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -20,6 +20,8 @@ dependencies:
   ###
   meta: ^1.7.0
   equatable: ^2.0.3
+  collection: ^1.15.0
+  tuple: ^2.0.0
   path: ^1.8.0
   path_provider: ^2.0.9
   url_launcher: ^6.0.20
@@ -38,6 +40,7 @@ dependencies:
   # State Management
   ###
   flutter_riverpod: ^1.0.3
+  flutter_hooks: ^0.18.2+1
   hooks_riverpod: ^1.0.3
   rxdart: ^0.27.3
 

From cdbcadeb7c854c2f92bf96055096efd5a5d571fb Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:58:39 -0300
Subject: [PATCH 05/11] Fixes `library_private_types_in_public_api`

---
 lib/application/widgets/animatable_progress.dart | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/application/widgets/animatable_progress.dart b/lib/application/widgets/animatable_progress.dart
index 595bcef7..5a70c33b 100644
--- a/lib/application/widgets/animatable_progress.dart
+++ b/lib/application/widgets/animatable_progress.dart
@@ -115,11 +115,11 @@ class AnimatableLinearProgress extends AnimatableProgress implements ProgressPai
   final double? minWidth;
 
   @override
-  _AnimatableLinearProgressState createState() => _AnimatableLinearProgressState();
+  AnimatableLinearProgressState createState() => AnimatableLinearProgressState();
 }
 
 /// Implements the [AnimatableProgressState] for a linear-styled progress indicator.
-class _AnimatableLinearProgressState extends AnimatableProgressState<AnimatableLinearProgress> {
+class AnimatableLinearProgressState extends AnimatableProgressState<AnimatableLinearProgress> {
   CustomPaint _progressPaintBuilder(BuildContext context, Widget? child) {
     return CustomPaint(
       painter: _LinearProgressPainter(
@@ -248,11 +248,11 @@ class AnimatableCircularProgress extends AnimatableProgress implements ProgressP
   final double? minSize;
 
   @override
-  _AnimatableCircularProgressState createState() => _AnimatableCircularProgressState();
+  AnimatableCircularProgressState createState() => AnimatableCircularProgressState();
 }
 
 /// Implements the [AnimatableProgressState] for a circular-styled progress indicator.
-class _AnimatableCircularProgressState extends AnimatableProgressState<AnimatableCircularProgress> {
+class AnimatableCircularProgressState extends AnimatableProgressState<AnimatableCircularProgress> {
   CustomPaint _progressPaintBuilder(BuildContext context, Widget? child) {
     return CustomPaint(
       painter: _CircularProgressPainter(

From 50bd1fa79d6cb43a8d87f150d45e65923144fd83 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 14:06:14 -0300
Subject: [PATCH 06/11] Undo unnecessary states exposure

---
 lib/application/widgets/animatable_progress.dart | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/application/widgets/animatable_progress.dart b/lib/application/widgets/animatable_progress.dart
index 5a70c33b..64e0036e 100644
--- a/lib/application/widgets/animatable_progress.dart
+++ b/lib/application/widgets/animatable_progress.dart
@@ -115,11 +115,11 @@ class AnimatableLinearProgress extends AnimatableProgress implements ProgressPai
   final double? minWidth;
 
   @override
-  AnimatableLinearProgressState createState() => AnimatableLinearProgressState();
+  AnimatableProgressState<AnimatableLinearProgress> createState() => _AnimatableLinearProgressState();
 }
 
 /// Implements the [AnimatableProgressState] for a linear-styled progress indicator.
-class AnimatableLinearProgressState extends AnimatableProgressState<AnimatableLinearProgress> {
+class _AnimatableLinearProgressState extends AnimatableProgressState<AnimatableLinearProgress> {
   CustomPaint _progressPaintBuilder(BuildContext context, Widget? child) {
     return CustomPaint(
       painter: _LinearProgressPainter(
@@ -248,11 +248,11 @@ class AnimatableCircularProgress extends AnimatableProgress implements ProgressP
   final double? minSize;
 
   @override
-  AnimatableCircularProgressState createState() => AnimatableCircularProgressState();
+  AnimatableProgressState<AnimatableCircularProgress> createState() => _AnimatableCircularProgressState();
 }
 
 /// Implements the [AnimatableProgressState] for a circular-styled progress indicator.
-class AnimatableCircularProgressState extends AnimatableProgressState<AnimatableCircularProgress> {
+class _AnimatableCircularProgressState extends AnimatableProgressState<AnimatableCircularProgress> {
   CustomPaint _progressPaintBuilder(BuildContext context, Widget? child) {
     return CustomPaint(
       painter: _CircularProgressPainter(

From 056c543825cbaaedeee513cd5b2be46432f2e8c9 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:52:02 -0300
Subject: [PATCH 07/11] Fixes missing return

---
 .../view-models/execution/collection_execution_vm.dart          | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/application/view-models/execution/collection_execution_vm.dart b/lib/application/view-models/execution/collection_execution_vm.dart
index 3cf72f45..1d4f88cf 100644
--- a/lib/application/view-models/execution/collection_execution_vm.dart
+++ b/lib/application/view-models/execution/collection_execution_vm.dart
@@ -100,6 +100,8 @@ class CollectionExecutionVMImpl extends CollectionExecutionVM {
           totalUniqueMemos: updatedCollection.uniqueMemosAmount,
         );
       }
+
+      return null;
     } else {
       // Otherwise we proceed with the next available memo and start counting a new start date.
       final completionValue = _executions.length / _memos.length;

From 45b40620289f0b4e1573b65e3ee09a477c844ae8 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Fri, 25 Mar 2022 08:52:27 -0300
Subject: [PATCH 08/11] Uses `Offset.zero` over `Offset(0, 0)`

---
 test/application/widgets/theme/custom_button_test.dart | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/application/widgets/theme/custom_button_test.dart b/test/application/widgets/theme/custom_button_test.dart
index 6eb50b12..eafa7e5b 100644
--- a/test/application/widgets/theme/custom_button_test.dart
+++ b/test/application/widgets/theme/custom_button_test.dart
@@ -203,7 +203,7 @@ Future<void> _pumpAndTap<T extends Widget>(WidgetTester tester, T button) async
 /// Pumps [button] and press (a single pointer down gesture) it.
 Future<void> _pumpAndPress<T extends Widget>(WidgetTester tester, T button) async {
   await pumpProviderScoped(tester, button);
-  await tester.startGesture(const Offset(0, 0));
+  await tester.startGesture(Offset.zero);
   await tester.pump();
 }
 

From 0c21a3c471caf7f1cc72790a7ca2c4b64326f81d Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Wed, 6 Apr 2022 16:20:08 -0300
Subject: [PATCH 09/11] Fixes broken tests

---
 test/application/widgets/theme/custom_text_field_test.dart | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/application/widgets/theme/custom_text_field_test.dart b/test/application/widgets/theme/custom_text_field_test.dart
index 04c28c5c..d45aa566 100644
--- a/test/application/widgets/theme/custom_text_field_test.dart
+++ b/test/application/widgets/theme/custom_text_field_test.dart
@@ -114,8 +114,8 @@ void main() {
 
         await pumpProviderScoped(tester, textField);
 
-        final wrapperContainer = find.byType(Container).first.evaluate().single.widget as Container;
-        final containerDecoration = wrapperContainer.decoration! as BoxDecoration;
+        final wrapperContainer = find.byType(DecoratedBox).first.evaluate().single.widget as DecoratedBox;
+        final containerDecoration = wrapperContainer.decoration as BoxDecoration;
 
         expect(containerDecoration.color, expectedColor);
       });

From bd41459f0297a68c83c768a8be4211a0097b3950 Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Wed, 6 Apr 2022 16:42:20 -0300
Subject: [PATCH 10/11] Bumps Kotlin version

---
 android/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/build.gradle b/android/build.gradle
index 2f9f362e..98a47a44 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,5 @@
 buildscript {
-    ext.kotlin_version = '1.3.50'
+    ext.kotlin_version = '1.6.20'
     repositories {
         google()
         jcenter()

From 38963f8be54b60ac75032621104fef9e24d30d0a Mon Sep 17 00:00:00 2001
From: Guilherme Girotto <guiga741@gmail.com>
Date: Wed, 6 Apr 2022 16:44:46 -0300
Subject: [PATCH 11/11] Bumps min Android SDK version

---
 android/app/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/app/build.gradle b/android/app/build.gradle
index 0e1c8348..f965613f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -39,7 +39,7 @@ android {
 
     defaultConfig {
         applicationId "com.olmps.memoClient"
-        minSdkVersion 17
+        minSdkVersion 21
         targetSdkVersion 31
         versionCode 7
         versionName flutterVersionName