diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..9751e5e
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,13 @@
+# Each line is a file pattern followed by one or more owners.
+
+# These owners will be the default owners for everything in
+# the repo. Unless a later match takes precedence,
+# the global owners will be requested for
+# review when someone opens a pull request.
+* @lishaduck @MattsAttack
+
+*.dart @lishaduck @MattsAttack
+/.github/ @lishaduck
+/assets/ @MattsAttack
+/tests/ @lishaduck @MattsAttack
+pubspec.* @lishaduck
diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml
new file mode 100644
index 0000000..0aabbc7
--- /dev/null
+++ b/.github/dependabot.yaml
@@ -0,0 +1,41 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "daily"
+ assignees:
+ - "lishaduck"
+ groups:
+ github:
+ patterns:
+ - "actions/*"
+
+ - package-ecosystem: "pub" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "daily"
+ assignees:
+ - "lishaduck"
+ groups:
+ riverpod:
+ patterns:
+ - "*riverpod*"
+ go_router:
+ patterns:
+ - "go_router*"
+ freezed:
+ patterns:
+ - "freezed*"
+ - "json_*"
+ build:
+ patterns:
+ - "build*"
+ envied:
+ patterns:
+ - "envied*"
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000..8aaca46
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,335 @@
+---
+name: CI/CD
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ merge_group:
+ schedule:
+ - cron: "0 14 * * 1" # every monday at 9 in the morning CST
+ workflow_dispatch:
+
+env:
+ CI: true
+
+permissions:
+ contents: read
+
+jobs:
+ setup:
+ name: Setup
+ needs: []
+ timeout-minutes: 5
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+
+ steps:
+ - name: ๐ Git checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ฆ Set up Flutter
+ id: flutter
+ uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2.16.0
+ with:
+ flutter-version-file: true
+ cache: true
+ - name: ๐ Disable analytics
+ run: flutter --disable-analytics
+ - name: ๐ฆ Install dependencies
+ run: flutter pub get
+ - name: โ๏ธ Cache generated files
+ uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
+ with:
+ path: |
+ .dart_tool/
+ lib/gen/*.gen.dart
+ lib/features/**/*.g.dart
+ lib/features/**/*.freezed.dart
+ lib/utils/*.g.dart
+ lib/utils/*.freezed.dart
+ lib/app/*.gr.dart
+ lib/app/*.gm.dart
+ lib/l10n/app_localizations.dart
+ lib/l10n/app_localizations_*.dart
+ key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
+ - name: ๐ Generate files
+ run: |
+ flutter gen-l10n
+ dart run build_runner build -d
+
+ build:
+ name: Build
+ needs: ["setup"]
+ timeout-minutes: ${{ (matrix.target == 'web') && 5 || 10 }}
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ target:
+ - web
+ - appbundle
+ # - ios
+ # - macos
+ # - windows
+ include:
+ - target: web
+ os: ubuntu-latest
+ flutter-flags: --release
+ - target: appbundle
+ os: ubuntu-latest
+ flutter-flags: --debug --no-tree-shake-icons --no-shrink
+ # - target: ios
+ # os: macos-latest
+ # flutter-flags: --debug --no-tree-shake-icons
+ # - target: macos
+ # os: macos-latest
+ # flutter-flags: --debug --no-tree-shake-icons
+ # - target: windows
+ # os: windows-latest
+ # flutter-flags: --debug --no-tree-shake-icons
+
+ steps:
+ - name: ๐ Git checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ฆ Set up Flutter
+ id: flutter
+ uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2.16.0
+ with:
+ flutter-version-file: true
+ cache: true
+ - name: ๐ Disable analytics
+ run: flutter --disable-analytics
+ - name: ๐ฆ Install dependencies
+ run: flutter pub get
+ - name: โ๏ธ Cache generated files
+ uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
+ with:
+ path: |
+ .dart_tool/
+ lib/gen/*.gen.dart
+ lib/features/**/*.g.dart
+ lib/features/**/*.freezed.dart
+ lib/utils/*.g.dart
+ lib/utils/*.freezed.dart
+ lib/app/*.gr.dart
+ lib/app/*.gm.dart
+ lib/l10n/app_localizations.dart
+ lib/l10n/app_localizations_*.dart
+ key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
+ - name: ๐ Generate files
+ run: |
+ flutter gen-l10n
+ dart run build_runner build -d
+ - name: ๐ง Build
+ run: |
+ flutter build ${{ matrix.target }} ${{ matrix.flutter-flags }}
+ # - name: โ๏ธ Upload build
+ # if: matrix.target == 'web'
+ # uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
+ # with:
+ # name: build-directory-${{ matrix.target }}-${{ steps.flutter.outputs.CHANNEL }}
+ # path: ./build
+ # if-no-files-found: error
+
+ lint:
+ name: Linting
+ needs: ["setup"]
+ timeout-minutes: 5
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ฆ Set up Flutter
+ id: flutter
+ uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2.16.0
+ with:
+ flutter-version-file: true
+ cache: true
+ - name: ๐ Disable analytics
+ run: flutter --disable-analytics
+ - name: ๐ฆ Install dependencies
+ run: flutter pub get
+ - name: โ๏ธ Cache generated files
+ uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
+ with:
+ path: |
+ .dart_tool/
+ lib/gen/*.gen.dart
+ lib/features/**/*.g.dart
+ lib/features/**/*.freezed.dart
+ lib/utils/*.g.dart
+ lib/utils/*.freezed.dart
+ lib/app/*.gr.dart
+ lib/app/*.gm.dart
+ lib/l10n/app_localizations.dart
+ lib/l10n/app_localizations_*.dart
+ key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
+ - name: ๐ Generate files
+ run: |
+ flutter gen-l10n
+ dart run build_runner build -d
+ - name: ๐ต๏ธ Analyze project source
+ run: flutter analyze --fatal-infos
+ - name: ๐ต๏ธ Run Custom Lint Rules
+ run: dart run custom_lint --fatal-infos
+
+ test:
+ name: Testing
+ needs: ["setup"]
+ timeout-minutes: 7
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ฆ Set up Flutter
+ id: flutter
+ uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2.16.0
+ with:
+ flutter-version-file: true
+ cache: true
+ - name: ๐ Disable analytics
+ run: flutter --disable-analytics
+ - name: ๐ฆ Install dependencies
+ run: flutter pub get
+ - name: โ๏ธ Cache generated files
+ uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
+ with:
+ path: |
+ .dart_tool/
+ lib/gen/*.gen.dart
+ lib/features/**/*.g.dart
+ lib/features/**/*.freezed.dart
+ lib/utils/*.g.dart
+ lib/utils/*.freezed.dart
+ lib/app/*.gr.dart
+ lib/app/*.gm.dart
+ lib/l10n/app_localizations.dart
+ lib/l10n/app_localizations_*.dart
+ key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
+ - name: ๐ Generate files
+ run: |
+ flutter gen-l10n
+ dart run build_runner build -d
+ - name: ๐งช Run tests
+ run: dart run very_good_cli:very_good test --coverage --test-randomize-ordering-seed random
+ - name: ๐ Check code coverage
+ uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # v3.0.0
+ with:
+ path: coverage/lcov.info
+ min_coverage: 10 # 100
+
+ format:
+ name: Formatting
+ needs: ["setup"]
+ timeout-minutes: 3
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ฆ Set up Flutter
+ id: flutter
+ uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2.16.0
+ with:
+ flutter-version-file: true
+ cache: true
+ - name: ๐ Disable analytics
+ run: flutter --disable-analytics
+ - name: โจ Verify formatting
+ run: dart format --output=none --set-exit-if-changed .
+
+ spell-check:
+ name: Check Spelling
+ needs: []
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git Checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+
+ - name: ๐ช Spell Check
+ uses: streetsidesoftware/cspell-action@807d7d92b7057593a2de102168506f298405339d # v6.2.0
+ with:
+ files: |
+ **/*.md
+ **/*.dart
+ **/*.yaml
+ **/*.toml
+ **/*.json
+ incremental_files_only: false
+
+ link-check:
+ name: Check Links
+ needs: []
+ timeout-minutes: 2
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ช Link check
+ uses: gaurav-nelson/github-action-markdown-link-check@d53a906aa6b22b8979d33bc86170567e619495ec # 1.0.15
+ with:
+ use-quiet-mode: "yes"
+ use-verbose-mode: "yes"
+ base-branch: "main"
+
+ markdownlint:
+ name: Lint Markdown
+ needs: []
+ timeout-minutes: 4
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git Checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ with:
+ submodules: recursive
+ clean: true
+ persist-credentials: false
+ set-safe-directory: true
+ - name: ๐ต๏ธ Markdown linting
+ uses: DavidAnson/markdownlint-cli2-action@510b996878fc0d1a46c8a04ec86b06dbfba09de7 # v16.0.0
+ id: markdownlint
+ with:
+ fix: true
+ globs: |
+ **/*.md
+ continue-on-error: true
diff --git a/.gitignore b/.gitignore
index 29a3a50..56dec33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# l10n
+lib/src/l10n/app_localizations*.dart
+
+# Testing
+test/.test_optimizer.dart
+
# Miscellaneous
*.class
*.log
@@ -10,26 +16,22 @@
.svn/
migrate_working_dir/
-# IntelliJ related
-*.iml
-*.ipr
-*.iws
-.idea/
-
-# 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/
-
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
+.packages
.pub-cache/
.pub/
/build/
+coverage/
+lib/gen/
+**/*.g.dart
+**/*.gr.dart
+**/*.gm.dart
+**/*.freezed.dart
# Symbolication related
app.*.symbols
@@ -41,3 +43,129 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
+
+
+# See https://www.dartlang.org/guides/libraries/private-files
+
+# 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*
+!.env.example
+
+# 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
+
+
+# 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/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+.idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+*.iml
+*.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
diff --git a/.idea/runConfigurations/main_dart.xml b/.idea/runConfigurations/main_dart.xml
new file mode 100644
index 0000000..aab7b5c
--- /dev/null
+++ b/.idea/runConfigurations/main_dart.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc
new file mode 100644
index 0000000..e95d9b8
--- /dev/null
+++ b/.markdownlint-cli2.jsonc
@@ -0,0 +1,6 @@
+{
+ "config": {
+ "line-length": false, // no one cares
+ "no-emphasis-as-heading": false // to many false positives
+ }
+}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..9896930
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,14 @@
+{
+ "recommendations": [
+ "dart-code.dart-code",
+ "dart-code.flutter",
+ "robert-brunhage.flutter-riverpod-snippets",
+ "lsaudon.l10nization",
+ "google.arb-editor",
+ "redhat.vscode-yaml",
+ "sndst00m.vscode-native-svg-preview",
+ "streetsidesoftware.code-spell-checker",
+ "streetsidesoftware.code-spell-checker-spanish",
+ "joshbolduc.commitlint"
+ ]
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..b83f07a
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch app",
+ "request": "launch",
+ "type": "dart",
+ "program": "lib/main.dart",
+ "flutterMode": "debug"
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..68ceac0
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,119 @@
+{
+ // Causes the debug view to automatically appear when a breakpoint is hit. This
+ // setting is global and not configurable per-language.
+ "debug.openDebug": "openOnDebugBreak",
+
+ // By default, VS Code will only switch to the Debug Console when you start
+ // debugging the first time in a session. This setting tells VS Code to always
+ // switch to the Debug Console when starting a session, so you can see the
+ // programs output.
+ "debug.internalConsoleOptions": "openOnSessionStart",
+
+ "[dart]": {
+ // Automatically format code on save and during typing of certain characters
+ // (like `;` and `}`).
+ "editor.formatOnSave": true,
+ "editor.formatOnType": true,
+
+ // Draw a guide line at 80 characters, where Dart's formatting will wrap code.
+ // "editor.rulers": [80],
+
+ // Disables built-in highlighting of words that match your selection. Without
+ // this, all instances of the selected text will be highlighted, interfering
+ // with Dart's ability to highlight only exact references to the selected variable.
+ "editor.selectionHighlight": false,
+
+ // By default, VS Code prevents code completion from popping open when in
+ // "snippet mode" (editing placeholders in inserted code). Setting this option
+ // to `false` stops that and allows completion to open as normal, as if you
+ // weren't in a snippet placeholder.
+ "editor.suggest.snippetsPreventQuickSuggestions": false,
+
+ // By default, VS Code will pre-select the most recently used item from code
+ // completion. This is usually not the most relevant item.
+ //
+ // "first" will always select top item
+ // "recentlyUsedByPrefix" will filter the recently used items based on the
+ // text immediately preceding where completion was invoked.
+ "editor.suggestSelection": "first",
+
+ // Allows pressing to complete snippets such as `for` even when the
+ // completion list is not visible.
+ "editor.tabCompletion": "onlySnippets",
+
+ // By default, VS Code will populate code completion with words found in the
+ // current file when a language service does not provide its own completions.
+ // This results in code completion suggesting words when editing comments and
+ // strings. This setting will prevent that.
+ "editor.wordBasedSuggestions": "off"
+ },
+ "explorer.fileNesting.enabled": true,
+ "explorer.fileNesting.patterns": {
+ "pubspec.yaml": ".metadata, analysis_options.yaml, pubspec.lock, build.yaml, dartdoc_options.yaml, l10n.yaml, pubspec_overrides.yaml, dart_test.yaml",
+ "README.*": "*.md",
+ "*.dart": "${capture}.*.dart, ${capture}_*.dart",
+ "cspell.json": ".markdownlint*, project_words.txt",
+ ".flutter-plugins": ".flutter-plugins-dependencies",
+ "untranslated.json": "*.log",
+ ".env": ".env.example",
+ "app.iml": "*.iml"
+ },
+ "yaml.schemas": {
+ "https://json.schemastore.org/github-issue-config.json": [
+ ".github/ISSUE_TEMPLATE/config.yml"
+ ],
+ "https://json.schemastore.org/dart-build": [
+ "build.yaml",
+ "*.build.yaml",
+ "build.*.yaml"
+ ]
+ },
+ "files.exclude": {
+ "**/.git": true,
+ "**/.svn": true,
+ "**/.hg": true,
+ "**/CVS": true,
+ "**/.DS_Store": true,
+ "**/Thumbs.db": true,
+ "**/.dart_tool": true
+ },
+ "l10nization.haveDescription": true,
+ "dart.renameFilesWithClasses": "prompt",
+ "dart.previewFlutterUiGuides": true,
+ "commitlint.config.extend.rules": {
+ "body-leading-blank": [1, "always"],
+ "body-max-line-length": [2, "always", 72],
+ "body-case": [1, "always", ["sentence-case"]],
+ "footer-leading-blank": [1, "always"],
+ "footer-max-line-length": [2, "always", 72],
+ "header-max-length": [2, "always", 50],
+ "scope-case": [2, "always", "lower-case"],
+ "subject-case": [
+ 2,
+ "never",
+ ["sentence-case", "start-case", "pascal-case", "upper-case"]
+ ],
+ "subject-empty": [2, "never"],
+ "subject-full-stop": [2, "never", "."],
+ "type-case": [2, "always", "lower-case"],
+ "type-empty": [2, "never"],
+ "type-enum": [
+ 2,
+ "always",
+ [
+ "feat",
+ "fix",
+ "docs",
+ "perf",
+ "refactor",
+ "build",
+ "ci",
+ "revert",
+ "style",
+ "test",
+ "chore"
+ ]
+ ]
+ },
+ "github-actions.workflows.pinned.workflows": [".github/workflows/dart.yaml"]
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..d1f6cbd
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,143 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "dart",
+ "command": "dart",
+ "cwd": ".",
+ "args": ["run", "build_runner", "${input:runtype}"],
+ "problemMatcher": ["$dart-build_runner"],
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "label": "Dart: run build_runner",
+ "detail": "Run a build_runner task.",
+ "runOptions": {
+ "runOn": "folderOpen"
+ },
+ "icon": {
+ "color": "terminal.ansiCyan",
+ "id": "gear"
+ },
+ "dependsOn": ["Flutter: gen-l10n"]
+ },
+ {
+ "type": "dart",
+ "command": "dart",
+ "cwd": ".",
+ "args": ["doc", "."],
+ "problemMatcher": [],
+ "group": "none",
+ "label": "Dart: doc",
+ "detail": "View the documentation.",
+ "icon": {
+ "color": "terminal.ansiGreen",
+ "id": "book"
+ }
+ },
+ {
+ "type": "flutter",
+ "command": "flutter",
+ "args": [
+ "build",
+ "${input:target}",
+ "--release",
+ ],
+ "problemMatcher": [],
+ "group": "build",
+ "label": "Flutter: build",
+ "detail": "Build a flutter app.",
+ "icon": {
+ "color": "terminal.ansiBlue",
+ "id": "gear"
+ }
+ },
+ {
+ "type": "flutter",
+ "command": "flutter",
+ "args": ["gen-l10n"],
+ "problemMatcher": [],
+ "group": "build",
+ "label": "Flutter: gen-l10n",
+ "detail": "Generate the localization files.",
+ "icon": {
+ "color": "terminal.ansiYellow",
+ "id": "comment-discussion"
+ }
+ },
+ {
+ "type": "flutter",
+ "command": "flutter",
+ "args": [
+ "build",
+ "${input:target}",
+ "--release",
+ ],
+ "problemMatcher": [],
+ "group": "build",
+ "label": "Flutter: build",
+ "detail": "Build a flutter app.",
+ "icon": {
+ "color": "terminal.ansiBlue",
+ "id": "gear"
+ }
+ },
+ {
+ "type": "dart",
+ "command": "dart",
+ "cwd": ".",
+ "args": [
+ "run",
+ "very_good_cli:very_good",
+ "test",
+ "--coverage",
+ "--test-randomize-ordering-seed",
+ "random"
+ ],
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "label": "Very Good Test",
+ "detail": "Run tests with the very_good_cli.",
+ "icon": {
+ "color": "terminal.ansiWhite",
+ "id": "beaker"
+ }
+ }
+ ],
+ "inputs": [
+ {
+ "id": "target",
+ "options": [
+ { "label": "Repository", "value": "arr" },
+ { "label": "Android APK", "value": "apk" },
+ { "label": "Android App Bundle", "value": "appbundle" },
+ { "label": "Flutter assets directory", "value": "bundle" },
+ { "label": "iOS", "value": "ios" },
+ { "label": ".xcframework (iOS)", "value": "ios-framework" },
+ { "label": "App Store Bundle", "value": "ipa" },
+ { "label": "macOS", "value": "macos" },
+ { "label": ".xcframework (macOS)", "value": "macos-framework" },
+ { "label": "Webapp bundle", "value": "web" },
+ { "label": "Windows", "value": "windows" }
+ ],
+ "type": "pickString",
+ "description": "the target to target",
+ "default": "web"
+ },
+ {
+ "id": "runtype",
+ "options": [
+ { "label": "run a build", "value": "build" },
+ { "label": "watch the filesystem, run many builds", "value": "watch" },
+ { "label": "clean up from old builds", "value": "clean" },
+ { "label": "verify the build.yaml", "value": "doctor" }
+ ],
+ "type": "pickString",
+ "description": "the type of build_runner run",
+ "default": "watch"
+ }
+ ]
+}
diff --git a/README.md b/README.md
index 2969a4d..cd6aa9c 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,11 @@
-# duly_noted
+# Duly Noted
-A new Flutter project.
+[![Dart][ci_dart_badge]][ci_dart_link]
+[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link]
-## Getting Started
+Better time management for busy people.
-This project is a starting point for a Flutter application that follows the
-[simple app state management
-tutorial](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple).
-
-For help getting started with Flutter development, view the
-[online documentation](https://flutter.dev/docs), which offers tutorials,
-samples, guidance on mobile development, and a full API reference.
-
-## Assets
-
-The `assets` directory houses images, fonts, and any other files you want to
-include with your application.
-
-The `assets/images` directory contains [resolution-aware
-images](https://flutter.dev/docs/development/ui/assets-and-images#resolution-aware).
-
-## Localization
-
-This project generates localized messages based on arb files found in
-the `lib/src/localization` directory.
-
-To support additional languages, please visit the tutorial on
-[Internationalizing Flutter
-apps](https://flutter.dev/docs/development/accessibility-and-localization/internationalization)
+[ci_dart_badge]: https://github.com/PHS-TSA/duly_noted/actions/workflows/ci.yaml/badge.svg?branch=main
+[ci_dart_link]: https://github.com/PHS-TSA/duly_noted/actions/workflows/ci.yaml
+[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg
+[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0d29021..5c1d820 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -7,7 +7,25 @@
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
-include: package:flutter_lints/flutter.yaml
+include: package:very_good_analysis/analysis_options.yaml
+
+analyzer:
+ exclude:
+ - "lib/gen/**"
+ - "lib/src/l10n/app_localizations*.dart"
+ - "build/**"
+ - "**/*.g.dart"
+ - "**/*.gr.dart"
+ - "**/*.gen.dart"
+ - "**/*.freezed.dart"
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+ errors:
+ close_sinks: error
+ plugins:
+ - custom_lint
linter:
# The lint rules applied to this project can be customized in the
@@ -21,8 +39,11 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
- # avoid_print: false # Uncomment to disable the `avoid_print` rule
- # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
-
+ prefer_relative_imports: true
+ always_use_package_imports: false
+ discarded_futures: true
+ lines_longer_than_80_chars: false
+ avoid_classes_with_only_static_members: true
+ one_member_abstracts: false
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
diff --git a/android/app/build.gradle b/android/app/build.gradle
index c5bb5f1..2b0008a 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -25,6 +25,7 @@ if (flutterVersionName == null) {
android {
namespace "org.psdr3.duly_noted"
compileSdk flutter.compileSdkVersion
+ compileSdkVersion 21
ndkVersion flutter.ndkVersion
compileOptions {
@@ -41,7 +42,6 @@ android {
}
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "org.psdr3.duly_noted"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0bb2a7f..29e0908 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
+ android:icon="@mipmap/launcher_icon">
+
diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png
new file mode 100644
index 0000000..54cf9c1
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png
new file mode 100644
index 0000000..5cdb723
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-night-v21/background.png b/android/app/src/main/res/drawable-night-v21/background.png
new file mode 100644
index 0000000..74d4117
Binary files /dev/null and b/android/app/src/main/res/drawable-night-v21/background.png differ
diff --git a/android/app/src/main/res/drawable-night-v21/launch_background.xml b/android/app/src/main/res/drawable-night-v21/launch_background.xml
new file mode 100644
index 0000000..3cc4948
--- /dev/null
+++ b/android/app/src/main/res/drawable-night-v21/launch_background.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+ -
+
+
+
diff --git a/android/app/src/main/res/drawable-night/background.png b/android/app/src/main/res/drawable-night/background.png
new file mode 100644
index 0000000..74d4117
Binary files /dev/null and b/android/app/src/main/res/drawable-night/background.png differ
diff --git a/android/app/src/main/res/drawable-night/launch_background.xml b/android/app/src/main/res/drawable-night/launch_background.xml
new file mode 100644
index 0000000..3cc4948
--- /dev/null
+++ b/android/app/src/main/res/drawable-night/launch_background.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+ -
+
+
+
diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png
new file mode 100644
index 0000000..f3967ff
Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
index f74085f..3cc4948 100644
--- a/android/app/src/main/res/drawable-v21/launch_background.xml
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -1,12 +1,9 @@
-
-
-
-
-
+ -
+
+
+ -
+
+
diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png
new file mode 100644
index 0000000..757c555
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png
new file mode 100644
index 0000000..68d99ee
Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png
new file mode 100644
index 0000000..cf2fda0
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png
new file mode 100644
index 0000000..f3967ff
Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 304732f..3cc4948 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -1,12 +1,9 @@
-
-
-
-
-
+ -
+
+
+ -
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png
new file mode 100644
index 0000000..0287dc7
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
new file mode 100644
index 0000000..c8b39bf
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
new file mode 100644
index 0000000..d07b1a4
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
new file mode 100644
index 0000000..bfe1117
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
new file mode 100644
index 0000000..7c1128f
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml
new file mode 100644
index 0000000..c846a66
--- /dev/null
+++ b/android/app/src/main/res/values-night-v31/styles.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
index 06952be..3c4a1fe 100644
--- a/android/app/src/main/res/values-night/styles.xml
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -5,6 +5,10 @@
- @drawable/launch_background
+ - false
+ - true
+ - true
+ - shortEdges
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..847e1be 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -5,6 +5,10 @@
- @drawable/launch_background
+ - false
+ - true
+ - true
+ - shortEdges
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- duly_noted
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+ function beginPreloading(manifestAssets) {
+ var assets = [
+ "flutter.js",
+ "main.dart.js",
+ "canvaskit/canvaskit.wasm",
+ "canvaskit/canvaskit.js",
+ ...additionalScripts,
+ ...manifestAssets,
+ ];
+ let totalAssets = assets.length + 1;
+ let loaded = 0;
+
+ const batchSize = 20;
+
+ async function reportProgress() {
+ loaded++;
+ const value = Math.floor((loaded / totalAssets) * 100) + "%";
+ progressIndicator.style.width = value;
+
+ if (assets.length == 0) {
+ dispatchAppLoad();
+ } else {
+ load(assets.shift());
+ }
+ }
+
+ function load(url) {
+ const req = new XMLHttpRequest();
+ req.onload = reportProgress;
+ req.open("get", url);
+ req.send();
+ }
+
+ function startBatch() {
+ const end = Math.min(batchSize, assets.length);
+ for (let i = 0; i < end; i++) {
+ load(assets.shift());
+ }
+ }
+
+ var scriptLoaded = false;
+ async function dispatchAppLoad() {
+ if (scriptLoaded) {
+ return;
+ }
+ scriptLoaded = true;
+
+ for (let i = 0; i < additionalScripts.length; i++) {
+ await injectScript(additionalScripts[i]);
+ }
+
+ await injectScript("flutter.js");
+
+ // Download main.dart.js
+ _flutter.loader.loadEntrypoint({
+ serviceWorker: {
+ serviceWorkerVersion: serviceWorkerVersion,
+ },
+ onEntrypointLoaded: function (engineInitializer) {
+ engineInitializer
+ .initializeEngine()
+ .then(async function (appRunner) {
+ window.addEventListener("flutter-first-frame", function () {
+ progressBar.remove();
+ document.body.classList.remove("loading-mode");
+ });
+
+ appRunner.runApp();
+ });
+ },
+ });
+ }
+
+ startBatch();
+ }
+
+ window.addEventListener("load", async function (ev) {
+ const response = await fetch("assets/AssetManifest.json");
+ const manifest = await response.json();
+ const assets = Object.values(manifest)
+ .map((list) => list.map((url) => "assets/" + url))
+ .reduce((arr, cur) => [...arr, ...cur]);
+
+ beginPreloading(assets);
+ });
+ }
+
+ run();
+
+