From 040f15a898657142c4bbc6f3c30b7a28897b06f0 Mon Sep 17 00:00:00 2001 From: vjrj Date: Tue, 7 Jul 2026 15:16:14 +0200 Subject: [PATCH] feat(block1): inventory walking skeleton + first quick-add slice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stand up the Tanemaki monorepo and the first end-to-end vertical slice of Block 1 (offline, encrypted inventory): add a seed → see it in a categorized, searchable list → it persists → reopen and it's still there. Architecture (state management like G1nkgo, adapted to Tane's reality): - flutter_bloc (Cubit-first), but the encrypted Drift DB is the single source of truth; cubits stream from repositories (no hydrated_bloc/Hive, which would write plaintext at rest). - get_it composition root; go_router; slang i18n (ES/EN, Weblate-friendly JSON). Workspace & core: - pub workspace: packages/commons_core (pure Dart) + apps/app_seeds (Flutter). - commons_core primitives: UUIDv7 IdGen, Hybrid Logical Clock, Quantity value type (+ plant-aware QuantityKind), IdentityService root-seed stub. Data & security: - Drift schemaVersion=1 with all 10 Block-1 tables + common CRDT columns (HLC updated_at, last_author, tombstones); Movement append-only. - SQLCipher via an injectable executor that refuses to open a plaintext DB; DB key + root seed in the OS keystore (separate secrets). - Exported drift_schema_v1.json + migration scaffold. Tests (near-TDD; nothing merges without tests): - commons_core units (24), Drift migration test, "no plaintext at rest" security guard (runs where SQLCipher is present, skips otherwise), repository, widget, full quick-add flow, file-reopen persistence, and a no-hardcoded-strings i18n guard. GitLab CI: format + analyze + test + coverage. Follow-on Block-1 stories (item detail/edit, species catalog, germination UI) and all of Block 2 remain out of scope. --- .gitlab-ci.yml | 54 + LICENSE | 674 +- analysis_options.yaml | 20 + apps/app_seeds/.gitignore | 45 + apps/app_seeds/.metadata | 36 + apps/app_seeds/README.md | 17 + apps/app_seeds/analysis_options.yaml | 28 + apps/app_seeds/android/.gitignore | 14 + apps/app_seeds/android/app/build.gradle.kts | 44 + .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 + .../kotlin/org/comunes/tane/MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + apps/app_seeds/android/build.gradle.kts | 24 + apps/app_seeds/android/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + apps/app_seeds/android/settings.gradle.kts | 26 + .../drift_schemas/drift_schema_v1.json | 1457 +++ apps/app_seeds/integration_test/app_test.dart | 50 + apps/app_seeds/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 24 + apps/app_seeds/ios/Flutter/Debug.xcconfig | 1 + apps/app_seeds/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 620 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 101 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + apps/app_seeds/ios/Runner/AppDelegate.swift | 16 + .../AppIcon.appiconset/Contents.json | 122 + .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + apps/app_seeds/ios/Runner/Info.plist | 70 + .../ios/Runner/Runner-Bridging-Header.h | 1 + apps/app_seeds/ios/Runner/SceneDelegate.swift | 6 + .../ios/RunnerTests/RunnerTests.swift | 12 + apps/app_seeds/lib/app.dart | 76 + .../lib/data/variety_repository.dart | 129 + apps/app_seeds/lib/db/database.dart | 38 + apps/app_seeds/lib/db/database.g.dart | 10194 ++++++++++++++++ apps/app_seeds/lib/db/encrypted_executor.dart | 61 + apps/app_seeds/lib/db/enums.dart | 27 + apps/app_seeds/lib/db/sync_columns.dart | 30 + apps/app_seeds/lib/db/tables.dart | 107 + apps/app_seeds/lib/di/injector.dart | 45 + apps/app_seeds/lib/i18n/en.i18n.json | 41 + apps/app_seeds/lib/i18n/es.i18n.json | 41 + apps/app_seeds/lib/i18n/strings.g.dart | 173 + apps/app_seeds/lib/i18n/strings_en.g.dart | 220 + apps/app_seeds/lib/i18n/strings_es.g.dart | 157 + apps/app_seeds/lib/main.dart | 15 + apps/app_seeds/lib/security/secret_store.dart | 27 + .../lib/security/secure_key_store.dart | 45 + apps/app_seeds/lib/state/inventory_cubit.dart | 62 + apps/app_seeds/lib/state/quick_add_cubit.dart | 97 + .../lib/ui/inventory_list_screen.dart | 128 + apps/app_seeds/lib/ui/quantity_kind_l10n.dart | 47 + apps/app_seeds/lib/ui/quick_add_sheet.dart | 184 + apps/app_seeds/linux/.gitignore | 1 + apps/app_seeds/linux/CMakeLists.txt | 128 + apps/app_seeds/linux/flutter/CMakeLists.txt | 88 + .../flutter/generated_plugin_registrant.cc | 27 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 28 + apps/app_seeds/linux/runner/CMakeLists.txt | 26 + apps/app_seeds/linux/runner/main.cc | 6 + apps/app_seeds/linux/runner/my_application.cc | 148 + apps/app_seeds/linux/runner/my_application.h | 21 + apps/app_seeds/pubspec.yaml | 62 + apps/app_seeds/slang.yaml | 14 + .../app_seeds/test/data/persistence_test.dart | 37 + .../test/data/variety_repository_test.dart | 76 + apps/app_seeds/test/db/migration_test.dart | 21 + apps/app_seeds/test/db/no_plaintext_test.dart | 80 + apps/app_seeds/test/db/schema/schema.dart | 21 + apps/app_seeds/test/db/schema/schema_v1.dart | 1380 +++ apps/app_seeds/test/flutter_test_config.dart | 23 + .../test/i18n/no_hardcoded_strings_test.dart | 30 + .../test/security/secure_key_store_test.dart | 41 + apps/app_seeds/test/support/test_support.dart | 56 + .../test/ui/inventory_list_screen_test.dart | 78 + .../test/ui/quick_add_flow_test.dart | 51 + packages/commons_core/.gitignore | 7 + packages/commons_core/CHANGELOG.md | 3 + packages/commons_core/README.md | 39 + packages/commons_core/analysis_options.yaml | 30 + packages/commons_core/lib/commons_core.dart | 11 + packages/commons_core/lib/src/clock/hlc.dart | 100 + .../lib/src/crypto/random_bytes.dart | 18 + .../lib/src/identity/identity_service.dart | 24 + packages/commons_core/lib/src/ids/id_gen.dart | 16 + .../commons_core/lib/src/value/quantity.dart | 67 + packages/commons_core/pubspec.yaml | 21 + .../commons_core/test/clock/hlc_test.dart | 91 + .../test/identity/identity_service_test.dart | 37 + .../commons_core/test/ids/id_gen_test.dart | 35 + .../test/value/quantity_test.dart | 47 + pubspec.lock | 1150 ++ pubspec.yaml | 12 + 131 files changed, 19855 insertions(+), 20 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 analysis_options.yaml create mode 100644 apps/app_seeds/.gitignore create mode 100644 apps/app_seeds/.metadata create mode 100644 apps/app_seeds/README.md create mode 100644 apps/app_seeds/analysis_options.yaml create mode 100644 apps/app_seeds/android/.gitignore create mode 100644 apps/app_seeds/android/app/build.gradle.kts create mode 100644 apps/app_seeds/android/app/src/debug/AndroidManifest.xml create mode 100644 apps/app_seeds/android/app/src/main/AndroidManifest.xml create mode 100644 apps/app_seeds/android/app/src/main/kotlin/org/comunes/tane/MainActivity.kt create mode 100644 apps/app_seeds/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 apps/app_seeds/android/app/src/main/res/drawable/launch_background.xml create mode 100644 apps/app_seeds/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 apps/app_seeds/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 apps/app_seeds/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 apps/app_seeds/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 apps/app_seeds/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 apps/app_seeds/android/app/src/main/res/values-night/styles.xml create mode 100644 apps/app_seeds/android/app/src/main/res/values/styles.xml create mode 100644 apps/app_seeds/android/app/src/profile/AndroidManifest.xml create mode 100644 apps/app_seeds/android/build.gradle.kts create mode 100644 apps/app_seeds/android/gradle.properties create mode 100644 apps/app_seeds/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 apps/app_seeds/android/settings.gradle.kts create mode 100644 apps/app_seeds/drift_schemas/drift_schema_v1.json create mode 100644 apps/app_seeds/integration_test/app_test.dart create mode 100644 apps/app_seeds/ios/.gitignore create mode 100644 apps/app_seeds/ios/Flutter/AppFrameworkInfo.plist create mode 100644 apps/app_seeds/ios/Flutter/Debug.xcconfig create mode 100644 apps/app_seeds/ios/Flutter/Release.xcconfig create mode 100644 apps/app_seeds/ios/Runner.xcodeproj/project.pbxproj create mode 100644 apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 apps/app_seeds/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 apps/app_seeds/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 apps/app_seeds/ios/Runner/AppDelegate.swift create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 apps/app_seeds/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 apps/app_seeds/ios/Runner/Base.lproj/Main.storyboard create mode 100644 apps/app_seeds/ios/Runner/Info.plist create mode 100644 apps/app_seeds/ios/Runner/Runner-Bridging-Header.h create mode 100644 apps/app_seeds/ios/Runner/SceneDelegate.swift create mode 100644 apps/app_seeds/ios/RunnerTests/RunnerTests.swift create mode 100644 apps/app_seeds/lib/app.dart create mode 100644 apps/app_seeds/lib/data/variety_repository.dart create mode 100644 apps/app_seeds/lib/db/database.dart create mode 100644 apps/app_seeds/lib/db/database.g.dart create mode 100644 apps/app_seeds/lib/db/encrypted_executor.dart create mode 100644 apps/app_seeds/lib/db/enums.dart create mode 100644 apps/app_seeds/lib/db/sync_columns.dart create mode 100644 apps/app_seeds/lib/db/tables.dart create mode 100644 apps/app_seeds/lib/di/injector.dart create mode 100644 apps/app_seeds/lib/i18n/en.i18n.json create mode 100644 apps/app_seeds/lib/i18n/es.i18n.json create mode 100644 apps/app_seeds/lib/i18n/strings.g.dart create mode 100644 apps/app_seeds/lib/i18n/strings_en.g.dart create mode 100644 apps/app_seeds/lib/i18n/strings_es.g.dart create mode 100644 apps/app_seeds/lib/main.dart create mode 100644 apps/app_seeds/lib/security/secret_store.dart create mode 100644 apps/app_seeds/lib/security/secure_key_store.dart create mode 100644 apps/app_seeds/lib/state/inventory_cubit.dart create mode 100644 apps/app_seeds/lib/state/quick_add_cubit.dart create mode 100644 apps/app_seeds/lib/ui/inventory_list_screen.dart create mode 100644 apps/app_seeds/lib/ui/quantity_kind_l10n.dart create mode 100644 apps/app_seeds/lib/ui/quick_add_sheet.dart create mode 100644 apps/app_seeds/linux/.gitignore create mode 100644 apps/app_seeds/linux/CMakeLists.txt create mode 100644 apps/app_seeds/linux/flutter/CMakeLists.txt create mode 100644 apps/app_seeds/linux/flutter/generated_plugin_registrant.cc create mode 100644 apps/app_seeds/linux/flutter/generated_plugin_registrant.h create mode 100644 apps/app_seeds/linux/flutter/generated_plugins.cmake create mode 100644 apps/app_seeds/linux/runner/CMakeLists.txt create mode 100644 apps/app_seeds/linux/runner/main.cc create mode 100644 apps/app_seeds/linux/runner/my_application.cc create mode 100644 apps/app_seeds/linux/runner/my_application.h create mode 100644 apps/app_seeds/pubspec.yaml create mode 100644 apps/app_seeds/slang.yaml create mode 100644 apps/app_seeds/test/data/persistence_test.dart create mode 100644 apps/app_seeds/test/data/variety_repository_test.dart create mode 100644 apps/app_seeds/test/db/migration_test.dart create mode 100644 apps/app_seeds/test/db/no_plaintext_test.dart create mode 100644 apps/app_seeds/test/db/schema/schema.dart create mode 100644 apps/app_seeds/test/db/schema/schema_v1.dart create mode 100644 apps/app_seeds/test/flutter_test_config.dart create mode 100644 apps/app_seeds/test/i18n/no_hardcoded_strings_test.dart create mode 100644 apps/app_seeds/test/security/secure_key_store_test.dart create mode 100644 apps/app_seeds/test/support/test_support.dart create mode 100644 apps/app_seeds/test/ui/inventory_list_screen_test.dart create mode 100644 apps/app_seeds/test/ui/quick_add_flow_test.dart create mode 100644 packages/commons_core/.gitignore create mode 100644 packages/commons_core/CHANGELOG.md create mode 100644 packages/commons_core/README.md create mode 100644 packages/commons_core/analysis_options.yaml create mode 100644 packages/commons_core/lib/commons_core.dart create mode 100644 packages/commons_core/lib/src/clock/hlc.dart create mode 100644 packages/commons_core/lib/src/crypto/random_bytes.dart create mode 100644 packages/commons_core/lib/src/identity/identity_service.dart create mode 100644 packages/commons_core/lib/src/ids/id_gen.dart create mode 100644 packages/commons_core/lib/src/value/quantity.dart create mode 100644 packages/commons_core/pubspec.yaml create mode 100644 packages/commons_core/test/clock/hlc_test.dart create mode 100644 packages/commons_core/test/identity/identity_service_test.dart create mode 100644 packages/commons_core/test/ids/id_gen_test.dart create mode 100644 packages/commons_core/test/value/quantity_test.dart create mode 100644 pubspec.lock create mode 100644 pubspec.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..beb193b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,54 @@ +# CI for Tanemaki. Mirrors the local verification gate (analyze + test + +# coverage) from docs/design/testing.md. Adapt to GitHub Actions if the +# canonical remote changes; the commands are the same. +# +# Uses the official Flutter Docker image. Pin the version to match the +# developer toolchain (Flutter 3.41.x / Dart 3.11.x). +image: ghcr.io/cirruslabs/flutter:3.41.9 + +stages: + - analyze + - test + +variables: + PUB_CACHE: "$CI_PROJECT_DIR/.pub-cache" + +cache: + key: "$CI_COMMIT_REF_SLUG" + paths: + - .pub-cache/ + +before_script: + # SQLCipher runtime lib so the "no plaintext at rest" security test actually + # runs (it skips where the library is absent). + - apt-get update -qq && apt-get install -y -qq libsqlcipher0 + - flutter --version + - flutter pub get + +analyze: + stage: analyze + script: + - dart format --output=none --set-exit-if-changed . + - flutter analyze + +test:commons_core: + stage: test + script: + - cd packages/commons_core + - dart test + +test:app_seeds: + stage: test + script: + - cd apps/app_seeds + # Generated sources (Drift, slang) must exist before analysis/tests. + - dart run build_runner build --delete-conflicting-outputs + - flutter test --coverage + coverage: '/lines\.*: \d+\.\d+\%/' + artifacts: + paths: + - apps/app_seeds/coverage/lcov.info + reports: + coverage_report: + coverage_format: cobertura + path: apps/app_seeds/coverage/cobertura.xml diff --git a/LICENSE b/LICENSE index edf520d..be3f7b2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,27 +1,661 @@ -Tanemaki — a local-first, decentralized app to manage and share traditional seeds. -Copyright (C) 2026 vjrj / Comunes + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. + Preamble -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. -SPDX-License-Identifier: AGPL-3.0-or-later + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. ---------------------------------------------------------------------------- -NOTE: This file currently holds the AGPL-3.0 copyright notice. Replace this -file with the full canonical license text before publishing the repository: + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - curl -o LICENSE https://www.gnu.org/licenses/agpl-3.0.txt + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. -(then re-add the copyright line above at the top if desired). Tracked as a -step in docs/design/first-sprint.md. ---------------------------------------------------------------------------- + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..950fd3f --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,20 @@ +# Shared analyzer config for the Tane workspace. +# Per-package files (packages/*/analysis_options.yaml, +# apps/*/analysis_options.yaml) include this and may add rules. +include: package:flutter_lints/flutter.yaml + +analyzer: + errors: + # Generated code must never fail the build. + invalid_annotation_target: ignore + exclude: + - "**/*.g.dart" + - "**/*.drift.dart" + - "apps/app_seeds/lib/i18n/strings.g.dart" + +linter: + rules: + # Enforce the "no hardcoded user-facing strings" rule at review time + # (full enforcement is a CI grep in test/; see docs/design/testing.md). + prefer_single_quotes: true + require_trailing_commas: true diff --git a/apps/app_seeds/.gitignore b/apps/app_seeds/.gitignore new file mode 100644 index 0000000..3820a95 --- /dev/null +++ b/apps/app_seeds/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +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-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/apps/app_seeds/.metadata b/apps/app_seeds/.metadata new file mode 100644 index 0000000..93f64e1 --- /dev/null +++ b/apps/app_seeds/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "00b0c91f06209d9e4a41f71b7a512d6eb3b9c694" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + - platform: android + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + - platform: ios + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + - platform: linux + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/apps/app_seeds/README.md b/apps/app_seeds/README.md new file mode 100644 index 0000000..459be74 --- /dev/null +++ b/apps/app_seeds/README.md @@ -0,0 +1,17 @@ +# tane + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) +- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/apps/app_seeds/analysis_options.yaml b/apps/app_seeds/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/apps/app_seeds/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# 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 + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// 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 + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/app_seeds/android/.gitignore b/apps/app_seeds/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/apps/app_seeds/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/apps/app_seeds/android/app/build.gradle.kts b/apps/app_seeds/android/app/build.gradle.kts new file mode 100644 index 0000000..9718a0a --- /dev/null +++ b/apps/app_seeds/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "org.comunes.tane" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "org.comunes.tane" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/apps/app_seeds/android/app/src/debug/AndroidManifest.xml b/apps/app_seeds/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/apps/app_seeds/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/apps/app_seeds/android/app/src/main/AndroidManifest.xml b/apps/app_seeds/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..738f046 --- /dev/null +++ b/apps/app_seeds/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app_seeds/android/app/src/main/kotlin/org/comunes/tane/MainActivity.kt b/apps/app_seeds/android/app/src/main/kotlin/org/comunes/tane/MainActivity.kt new file mode 100644 index 0000000..ff137d4 --- /dev/null +++ b/apps/app_seeds/android/app/src/main/kotlin/org/comunes/tane/MainActivity.kt @@ -0,0 +1,5 @@ +package org.comunes.tane + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/apps/app_seeds/android/app/src/main/res/drawable-v21/launch_background.xml b/apps/app_seeds/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/apps/app_seeds/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/apps/app_seeds/android/app/src/main/res/drawable/launch_background.xml b/apps/app_seeds/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/apps/app_seeds/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/apps/app_seeds/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/app_seeds/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/apps/app_seeds/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/app_seeds/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/apps/app_seeds/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/app_seeds/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/apps/app_seeds/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/app_seeds/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/apps/app_seeds/android/app/src/main/res/values-night/styles.xml b/apps/app_seeds/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/apps/app_seeds/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/apps/app_seeds/android/app/src/main/res/values/styles.xml b/apps/app_seeds/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/apps/app_seeds/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/apps/app_seeds/android/app/src/profile/AndroidManifest.xml b/apps/app_seeds/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/apps/app_seeds/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/apps/app_seeds/android/build.gradle.kts b/apps/app_seeds/android/build.gradle.kts new file mode 100644 index 0000000..dbee657 --- /dev/null +++ b/apps/app_seeds/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/apps/app_seeds/android/gradle.properties b/apps/app_seeds/android/gradle.properties new file mode 100644 index 0000000..fbee1d8 --- /dev/null +++ b/apps/app_seeds/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true diff --git a/apps/app_seeds/android/gradle/wrapper/gradle-wrapper.properties b/apps/app_seeds/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e4ef43f --- /dev/null +++ b/apps/app_seeds/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/apps/app_seeds/android/settings.gradle.kts b/apps/app_seeds/android/settings.gradle.kts new file mode 100644 index 0000000..ca7fe06 --- /dev/null +++ b/apps/app_seeds/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/apps/app_seeds/drift_schemas/drift_schema_v1.json b/apps/app_seeds/drift_schemas/drift_schema_v1.json new file mode 100644 index 0000000..80e0bae --- /dev/null +++ b/apps/app_seeds/drift_schemas/drift_schema_v1.json @@ -0,0 +1,1457 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.0" + }, + "options": { + "store_date_time_values_as_text": false + }, + "entities": [ + { + "id": 0, + "references": [], + "type": "table", + "data": { + "name": "varieties", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "label", + "getter_name": "label", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "species_id", + "getter_name": "speciesId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "cultivar_name", + "getter_name": "cultivarName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "category", + "getter_name": "category", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 1, + "references": [], + "type": "table", + "data": { + "name": "variety_vernacular_names", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "name", + "getter_name": "name", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "language", + "getter_name": "language", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "region", + "getter_name": "region", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "species", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "scientific_name", + "getter_name": "scientificName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "wikidata_qid", + "getter_name": "wikidataQid", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "gbif_key", + "getter_name": "gbifKey", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "family", + "getter_name": "family", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_bundled", + "getter_name": "isBundled", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_bundled\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_bundled\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 3, + "references": [], + "type": "table", + "data": { + "name": "species_common_names", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "species_id", + "getter_name": "speciesId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "name", + "getter_name": "name", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "language", + "getter_name": "language", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 4, + "references": [], + "type": "table", + "data": { + "name": "lots", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "harvest_year", + "getter_name": "harvestYear", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_kind", + "getter_name": "quantityKind", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_precise", + "getter_name": "quantityPrecise", + "moor_type": "double", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_label", + "getter_name": "quantityLabel", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "storage_location", + "getter_name": "storageLocation", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "offer_status", + "getter_name": "offerStatus", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'private\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(OfferStatus.values)", + "dart_type_name": "OfferStatus" + } + }, + { + "name": "seedbank_id", + "getter_name": "seedbankId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 5, + "references": [], + "type": "table", + "data": { + "name": "germination_tests", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "lot_id", + "getter_name": "lotId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "tested_on", + "getter_name": "testedOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sample_size", + "getter_name": "sampleSize", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "germinated_count", + "getter_name": "germinatedCount", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 6, + "references": [], + "type": "table", + "data": { + "name": "movements", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "lot_id", + "getter_name": "lotId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MovementType.values)", + "dart_type_name": "MovementType" + } + }, + { + "name": "occurred_on", + "getter_name": "occurredOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "counterparty_id", + "getter_name": "counterpartyId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_kind", + "getter_name": "quantityKind", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_precise", + "getter_name": "quantityPrecise", + "moor_type": "double", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_label", + "getter_name": "quantityLabel", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_movement_id", + "getter_name": "parentMovementId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "plantare_id", + "getter_name": "plantareId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 7, + "references": [], + "type": "table", + "data": { + "name": "parties", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "display_name", + "getter_name": "displayName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key", + "getter_name": "publicKey", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "kind", + "getter_name": "kind", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'person\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(PartyKind.values)", + "dart_type_name": "PartyKind" + } + }, + { + "name": "note", + "getter_name": "note", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "attachments", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_type", + "getter_name": "parentType", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(ParentType.values)", + "dart_type_name": "ParentType" + } + }, + { + "name": "parent_id", + "getter_name": "parentId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "kind", + "getter_name": "kind", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(AttachmentKind.values)", + "dart_type_name": "AttachmentKind" + } + }, + { + "name": "uri", + "getter_name": "uri", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "bytes", + "getter_name": "bytes", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mime_type", + "getter_name": "mimeType", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 9, + "references": [], + "type": "table", + "data": { + "name": "external_links", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_type", + "getter_name": "parentType", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(ParentType.values)", + "dart_type_name": "ParentType" + } + }, + { + "name": "parent_id", + "getter_name": "parentId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "url", + "getter_name": "url", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "title", + "getter_name": "title", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + } + ], + "fixed_sql": [ + { + "name": "varieties", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"varieties\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"label\" TEXT NOT NULL, \"species_id\" TEXT NULL, \"cultivar_name\" TEXT NULL, \"category\" TEXT NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "variety_vernacular_names", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"variety_vernacular_names\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"language\" TEXT NULL, \"region\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "species", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"species\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"scientific_name\" TEXT NOT NULL, \"wikidata_qid\" TEXT NULL, \"gbif_key\" INTEGER NULL, \"family\" TEXT NULL, \"is_bundled\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_bundled\" IN (0, 1)), PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "species_common_names", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"species_common_names\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"species_id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"language\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "lots", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"lots\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NOT NULL, \"harvest_year\" INTEGER NULL, \"quantity_kind\" TEXT NULL, \"quantity_precise\" REAL NULL, \"quantity_label\" TEXT NULL, \"storage_location\" TEXT NULL, \"offer_status\" TEXT NOT NULL DEFAULT 'private', \"seedbank_id\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "germination_tests", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"germination_tests\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"lot_id\" TEXT NOT NULL, \"tested_on\" INTEGER NULL, \"sample_size\" INTEGER NULL, \"germinated_count\" INTEGER NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "movements", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"movements\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"last_author\" TEXT NOT NULL, \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"lot_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"occurred_on\" INTEGER NULL, \"counterparty_id\" TEXT NULL, \"quantity_kind\" TEXT NULL, \"quantity_precise\" REAL NULL, \"quantity_label\" TEXT NULL, \"parent_movement_id\" TEXT NULL, \"plantare_id\" TEXT NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "parties", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"parties\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"display_name\" TEXT NOT NULL, \"public_key\" TEXT NULL, \"kind\" TEXT NOT NULL DEFAULT 'person', \"note\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "attachments", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"attachments\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"parent_type\" TEXT NOT NULL, \"parent_id\" TEXT NOT NULL, \"kind\" TEXT NOT NULL, \"uri\" TEXT NULL, \"bytes\" BLOB NULL, \"mime_type\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "external_links", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"external_links\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"parent_type\" TEXT NOT NULL, \"parent_id\" TEXT NOT NULL, \"url\" TEXT NOT NULL, \"title\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + } + ] +} \ No newline at end of file diff --git a/apps/app_seeds/integration_test/app_test.dart b/apps/app_seeds/integration_test/app_test.dart new file mode 100644 index 0000000..96f219c --- /dev/null +++ b/apps/app_seeds/integration_test/app_test.dart @@ -0,0 +1,50 @@ +import 'dart:io'; + +import 'package:commons_core/commons_core.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:tane/data/variety_repository.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/db/encrypted_executor.dart'; + +/// On-device end-to-end: a seed added to the *encrypted* database survives a +/// close and reopen. Runs where SQLCipher is available (device / CI with the +/// library); skips with a clear reason otherwise. +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('a seed persists in the encrypted DB across reopen', ( + tester, + ) async { + const keyHex = + '00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff'; + final dir = await Directory.systemTemp.createTemp('tane_e2e'); + addTearDown(() => dir.delete(recursive: true)); + final file = File(p.join(dir.path, 'inventory.sqlite')); + + var db = AppDatabase(openEncryptedExecutor(file, keyHex)); + try { + await VarietyRepository( + db, + idGen: IdGen(), + nodeId: 'n', + ).addQuickVariety(label: 'Persisted tomato'); + } on Object catch (e) { + markTestSkipped('SQLCipher unavailable: $e'); + await db.close(); + return; + } + await db.close(); + + db = AppDatabase(openEncryptedExecutor(file, keyHex)); + final items = await VarietyRepository( + db, + idGen: IdGen(), + nodeId: 'n', + ).watchInventory().first; + await db.close(); + + expect(items.map((i) => i.label), contains('Persisted tomato')); + }); +} diff --git a/apps/app_seeds/ios/.gitignore b/apps/app_seeds/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/apps/app_seeds/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.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/ephemeral/ +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 diff --git a/apps/app_seeds/ios/Flutter/AppFrameworkInfo.plist b/apps/app_seeds/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..391a902 --- /dev/null +++ b/apps/app_seeds/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/apps/app_seeds/ios/Flutter/Debug.xcconfig b/apps/app_seeds/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/apps/app_seeds/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/apps/app_seeds/ios/Flutter/Release.xcconfig b/apps/app_seeds/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/apps/app_seeds/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/apps/app_seeds/ios/Runner.xcodeproj/project.pbxproj b/apps/app_seeds/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3fd5390 --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,620 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.comunes.tane; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/apps/app_seeds/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/app_seeds/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app_seeds/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/app_seeds/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/apps/app_seeds/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/apps/app_seeds/ios/Runner/AppDelegate.swift b/apps/app_seeds/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..c30b367 --- /dev/null +++ b/apps/app_seeds/ios/Runner/AppDelegate.swift @@ -0,0 +1,16 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_xN#0001NP)t-s|Ns9~ z#rXRE|M&d=0au&!`~QyF`q}dRnBDt}*!qXo`c{v z{Djr|@Adh0(D_%#_&mM$D6{kE_x{oE{l@J5@%H*?%=t~i_`ufYOPkAEn!pfkr2$fs z652Tz0001XNklqeeKN4RM4i{jKqmiC$?+xN>3Apn^ z0QfuZLym_5b<*QdmkHjHlj811{If)dl(Z2K0A+ekGtrFJb?g|wt#k#pV-#A~bK=OT ts8>{%cPtyC${m|1#B1A6#u!Q;umknL1chzTM$P~L002ovPDHLkV1lTfnu!1a literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 zcmV;526g#~P){YQnis^a@{&-nmRmq)<&%Mztj67_#M}W?l>kYSliK<%xAp;0j{!}J0!o7b zE>q9${Lb$D&h7k=+4=!ek^n+`0zq>LL1O?lVyea53S5x`Nqqo2YyeuIrQrJj9XjOp z{;T5qbj3}&1vg1VK~#9!?b~^C5-}JC@Pyrv-6dSEqJqT}#j9#dJ@GzT@B8}x zU&J@bBI>f6w6en+CeI)3^kC*U?}X%OD8$Fd$H&LV$H&LV$H&LV#|K5~mLYf|VqzOc zkc7qL~0sOYuM{tG`rYEDV{DWY`Z8&)kW*hc2VkBuY+^Yx&92j&StN}Wp=LD zxoGxXw6f&8sB^u})h@b@z0RBeD`K7RMR9deyL(ZJu#39Z>rT)^>v}Khq8U-IbIvT> z?4pV9qGj=2)TNH3d)=De<+^w;>S7m_eFKTvzeaBeir45xY!^m!FmxnljbSS_3o=g( z->^wC9%qkR{kbGnW8MfFew_o9h3(r55Is`L$8KI@d+*%{=Nx+FXJ98L0PjFIu;rGnnfY zn1R5Qnp<{Jq0M1vX=X&F8gtLmcWv$1*M@4ZfF^9``()#hGTeKeP`1!iED ztNE(TN}M5}3Bbc*d=FIv`DNv&@|C6yYj{sSqUj5oo$#*0$7pu|Dd2TLI>t5%I zIa4Dvr(iayb+5x=j*Vum9&irk)xV1`t509lnPO0%skL8_1c#Xbamh(2@f?4yUI zhhuT5<#8RJhGz4%b$`PJwKPAudsm|at?u;*hGgnA zU1;9gnxVBC)wA(BsB`AW54N{|qmikJR*%x0c`{LGsSfa|NK61pYH(r-UQ4_JXd!Rsz)=k zL{GMc5{h138)fF5CzHEDM>+FqY)$pdN3}Ml+riTgJOLN0F*Vh?{9ESR{SVVg>*>=# zix;VJHPtvFFCRY$Ks*F;VX~%*r9F)W`PmPE9F!(&s#x07n2<}?S{(ygpXgX-&B&OM zONY&BRQ(#%0%jeQs?oJ4P!p*R98>qCy5p8w>_gpuh39NcOlp)(wOoz0sY-Qz55eB~ z7OC-fKBaD1sE3$l-6QgBJO!n?QOTza`!S_YK z_v-lm^7{VO^8Q@M_^8F)09Ki6%=s?2_5eupee(w1FB%aqSweusQ-T+CH0Xt{` zFjMvW{@C&TB)k25()nh~_yJ9coBRL(0oO@HK~z}7?bm5j;y@69;bvlHb2tf!$ReA~x{22wTq550 z?f?Hnw(;m3ip30;QzdV~7pi!wyMYhDtXW#cO7T>|f=bdFhu+F!zMZ2UFj;GUKX7tI z;hv3{q~!*pMj75WP_c}>6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FaF{8 z;u`Mw0ly(uE>*CgQYv{be6ab2LWhlaH1^iLIM{olnag$78^Fd}%dR7;JECQ+hmk|o z!u2&!3MqPfP5ChDSkFSH8F2WVOEf0(E_M(JL17G}Y+fg0_IuW%WQ zG(mG&u?|->YSdk0;8rc{yw2@2Z&GA}z{Wb91Ooz9VhA{b2DYE7RmG zjL}?eq#iX%3#k;JWMx_{^2nNax`xPhByFiDX+a7uTGU|otOvIAUy|dEKkXOm-`aWS z27pUzD{a)Ct<6p{{3)+lq@i`t@%>-wT4r?*S}k)58e09WZYP0{{R3FC5Sl00039P)t-s|Ns9~ z#rP?<_5oL$Q^olD{r_0T`27C={r>*`|Nj71npVa5OTzc(_WfbW_({R{p56NV{r*M2 z_xt?)2V0#0NsfV0u>{42ctGP(8vQj-Btk1n|O0ZD=YLwd&R{Ko41Gr9H= zY@z@@bOAMB5Ltl$E>bJJ{>JP30ZxkmI%?eW{k`b?Wy<&gOo;dS`~CR$Vwb@XWtR|N zi~t=w02?-0&j0TD{>bb6sNwsK*!p?V`RMQUl(*DVjk-9Cx+-z1KXab|Ka2oXhX5f% z`$|e!000AhNklrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`? zTG`AHia671e^vgmp!llKp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?hz91 z7p83F3%LVu9;S$tSI$C^%^yud1dfTM_6p2|+5Ejp$bd`GDvbR|xit>i!ZD&F>@CJrPmu*UjD&?DfZs=$@e3FQA(vNiU+$A*%a} z?`XcG2jDxJ_ZQ#Md`H{4Lpf6QBDp81_KWZ6Tk#yCy1)32zO#3<7>b`eT7UyYH1eGz z;O(rH$=QR*L%%ZcBpc=eGua?N55nD^K(8<#gl2+pN_j~b2MHs4#mcLmv%DkspS-3< zpI1F=^9siI0s-;IN_IrA;5xm~3?3!StX}pUv0vkxMaqm+zxrg7X7(I&*N~&dEd0kD z-FRV|g=|QuUsuh>-xCI}vD2imzYIOIdcCVV=$Bz@*u0+Bs<|L^)32nN*=wu3n%Ynw z@1|eLG>!8ruU1pFXUfb`j>(=Gy~?Rn4QJ-c3%3T|(Frd!bI`9u&zAnyFYTqlG#&J7 zAkD(jpw|oZLNiA>;>hgp1KX7-wxC~31II47gc zHcehD6Uxlf%+M^^uN5Wc*G%^;>D5qT{>=uxUhX%WJu^Z*(_Wq9y}npFO{Hhb>s6<9 zNi0pHXWFaVZnb)1+RS&F)xOv6&aeILcI)`k#0YE+?e)5&#r7J#c`3Z7x!LpTc01dx zrdC3{Z;joZ^KN&))zB_i)I9fWedoN>Zl-6_Iz+^G&*ak2jpF07*qoM6N<$f;w%0(f|Me literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/apps/app_seeds/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/apps/app_seeds/ios/Runner/Base.lproj/LaunchScreen.storyboard b/apps/app_seeds/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/apps/app_seeds/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app_seeds/ios/Runner/Base.lproj/Main.storyboard b/apps/app_seeds/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/apps/app_seeds/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app_seeds/ios/Runner/Info.plist b/apps/app_seeds/ios/Runner/Info.plist new file mode 100644 index 0000000..d731c37 --- /dev/null +++ b/apps/app_seeds/ios/Runner/Info.plist @@ -0,0 +1,70 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Tane + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tane + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/apps/app_seeds/ios/Runner/Runner-Bridging-Header.h b/apps/app_seeds/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/apps/app_seeds/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/apps/app_seeds/ios/Runner/SceneDelegate.swift b/apps/app_seeds/ios/Runner/SceneDelegate.swift new file mode 100644 index 0000000..b9ce8ea --- /dev/null +++ b/apps/app_seeds/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/apps/app_seeds/ios/RunnerTests/RunnerTests.swift b/apps/app_seeds/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/apps/app_seeds/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/apps/app_seeds/lib/app.dart b/apps/app_seeds/lib/app.dart new file mode 100644 index 0000000..0eb5c0e --- /dev/null +++ b/apps/app_seeds/lib/app.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:go_router/go_router.dart'; + +import 'data/variety_repository.dart'; +import 'i18n/strings.g.dart'; +import 'state/inventory_cubit.dart'; +import 'ui/inventory_list_screen.dart'; + +/// Root widget. Provides the repository + inventory cubit to the tree and wires +/// go_router. The list is `/`; `/variety/:id` is a placeholder detail route +/// (the full item screen is a follow-on story). +class TaneApp extends StatelessWidget { + TaneApp({required this.repository, super.key}) + : _router = _buildRouter(repository); + + final VarietyRepository repository; + final GoRouter _router; + + static GoRouter _buildRouter(VarietyRepository repository) { + return GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, state) => BlocProvider( + create: (_) => InventoryCubit(repository), + child: const InventoryListScreen(), + ), + ), + GoRoute( + path: '/variety/:id', + builder: (context, state) => + _VarietyDetailPlaceholder(id: state.pathParameters['id']!), + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + return RepositoryProvider.value( + value: repository, + child: MaterialApp.router( + onGenerateTitle: (context) => context.t.app.title, + debugShowCheckedModeBanner: false, + theme: ThemeData( + colorSchemeSeed: const Color(0xFF4C7A34), // seed-green + useMaterial3: true, + ), + locale: TranslationProvider.of(context).flutterLocale, + supportedLocales: AppLocaleUtils.supportedLocales, + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + routerConfig: _router, + ), + ); + } +} + +class _VarietyDetailPlaceholder extends StatelessWidget { + const _VarietyDetailPlaceholder({required this.id}); + + final String id; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center(child: Text(id)), + ); + } +} diff --git a/apps/app_seeds/lib/data/variety_repository.dart b/apps/app_seeds/lib/data/variety_repository.dart new file mode 100644 index 0000000..a0e2656 --- /dev/null +++ b/apps/app_seeds/lib/data/variety_repository.dart @@ -0,0 +1,129 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:drift/drift.dart'; +import 'package:equatable/equatable.dart'; + +import '../db/database.dart'; +import '../db/enums.dart'; + +/// A lightweight row for the inventory list (only what the list renders). +class VarietyListItem extends Equatable { + const VarietyListItem({required this.id, required this.label, this.category}); + + final String id; + final String label; + final String? category; + + @override + List get props => [id, label, category]; +} + +/// Reads and writes the inventory. The encrypted Drift DB is the single source +/// of truth; [watchInventory] exposes a reactive stream the UI subscribes to. +/// +/// Every write stamps the row with the local [Hlc] and [nodeId] so the CRDT +/// metadata is correct from day one, even though sync does not exist yet. +class VarietyRepository { + VarietyRepository( + this._db, { + required this.idGen, + required this.nodeId, + int Function()? nowMillis, + }) : _now = nowMillis ?? (() => DateTime.now().millisecondsSinceEpoch), + _clock = Hlc.zero(nodeId); + + final AppDatabase _db; + final IdGen idGen; + final String nodeId; + final int Function() _now; + Hlc _clock; + + /// Emits the non-deleted inventory, ordered by category then label. + Stream> watchInventory() { + final query = _db.select(_db.varieties) + ..where((v) => v.isDeleted.equals(false)) + ..orderBy([ + (v) => OrderingTerm(expression: v.category), + (v) => OrderingTerm(expression: v.label), + ]); + return query.watch().map( + (rows) => rows + .map( + (v) => + VarietyListItem(id: v.id, label: v.label, category: v.category), + ) + .toList(), + ); + } + + /// The 20-second quick-add: a [label] (required) plus an optional [category], + /// an optional [quantity] (creates a Lot) and an optional [photoBytes] + /// (stored as an encrypted BLOB Attachment). Returns the new Variety id. + Future addQuickVariety({ + required String label, + String? category, + Quantity? quantity, + Uint8List? photoBytes, + }) async { + final varietyId = idGen.newId(); + await _db.transaction(() async { + final (created, updated) = _stamp(); + await _db + .into(_db.varieties) + .insert( + VarietiesCompanion.insert( + id: varietyId, + label: label, + createdAt: created, + updatedAt: updated, + lastAuthor: nodeId, + category: Value(category), + ), + ); + + if (quantity != null) { + final (created, updated) = _stamp(); + await _db + .into(_db.lots) + .insert( + LotsCompanion.insert( + id: idGen.newId(), + varietyId: varietyId, + createdAt: created, + updatedAt: updated, + lastAuthor: nodeId, + quantityKind: Value(quantity.kind.name), + quantityPrecise: Value(quantity.precise), + quantityLabel: Value(quantity.label), + ), + ); + } + + if (photoBytes != null) { + final (created, updated) = _stamp(); + await _db + .into(_db.attachments) + .insert( + AttachmentsCompanion.insert( + id: idGen.newId(), + createdAt: created, + updatedAt: updated, + lastAuthor: nodeId, + parentType: ParentType.variety, + parentId: varietyId, + kind: AttachmentKind.photo, + bytes: Value(photoBytes), + mimeType: const Value('image/jpeg'), + ), + ); + } + }); + return varietyId; + } + + /// Advances the local clock and returns `(createdAtMillis, packedHlc)`. + (int, String) _stamp() { + final now = _now(); + _clock = _clock.localEvent(now); + return (now, _clock.pack()); + } +} diff --git a/apps/app_seeds/lib/db/database.dart b/apps/app_seeds/lib/db/database.dart new file mode 100644 index 0000000..7dbabb6 --- /dev/null +++ b/apps/app_seeds/lib/db/database.dart @@ -0,0 +1,38 @@ +import 'package:drift/drift.dart'; + +import 'enums.dart'; +import 'tables.dart'; + +part 'database.g.dart'; + +/// The encrypted local inventory database (SQLCipher via an injected executor). +/// +/// The executor is passed in so production wires SQLCipher while tests can use +/// an in-memory database — the schema and queries are identical either way. +@DriftDatabase( + tables: [ + Varieties, + VarietyVernacularNames, + Species, + SpeciesCommonNames, + Lots, + GerminationTests, + Movements, + Parties, + Attachments, + ExternalLinks, + ], +) +class AppDatabase extends _$AppDatabase { + AppDatabase(super.e); + + @override + int get schemaVersion => 1; + + @override + MigrationStrategy get migration => MigrationStrategy( + onCreate: (m) async => m.createAll(), + // Step-by-step upgrades (from1To2, …) are generated into + // schema_versions.dart when schemaVersion is bumped. See data-model §5. + ); +} diff --git a/apps/app_seeds/lib/db/database.g.dart b/apps/app_seeds/lib/db/database.g.dart new file mode 100644 index 0000000..dd9bd69 --- /dev/null +++ b/apps/app_seeds/lib/db/database.g.dart @@ -0,0 +1,10194 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'database.dart'; + +// ignore_for_file: type=lint +class $VarietiesTable extends Varieties + with TableInfo<$VarietiesTable, Variety> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $VarietiesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _labelMeta = const VerificationMeta('label'); + @override + late final GeneratedColumn label = GeneratedColumn( + 'label', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _speciesIdMeta = const VerificationMeta( + 'speciesId', + ); + @override + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _cultivarNameMeta = const VerificationMeta( + 'cultivarName', + ); + @override + late final GeneratedColumn cultivarName = GeneratedColumn( + 'cultivar_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _categoryMeta = const VerificationMeta( + 'category', + ); + @override + late final GeneratedColumn category = GeneratedColumn( + 'category', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _notesMeta = const VerificationMeta('notes'); + @override + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + label, + speciesId, + cultivarName, + category, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'varieties'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('label')) { + context.handle( + _labelMeta, + label.isAcceptableOrUnknown(data['label']!, _labelMeta), + ); + } else if (isInserting) { + context.missing(_labelMeta); + } + if (data.containsKey('species_id')) { + context.handle( + _speciesIdMeta, + speciesId.isAcceptableOrUnknown(data['species_id']!, _speciesIdMeta), + ); + } + if (data.containsKey('cultivar_name')) { + context.handle( + _cultivarNameMeta, + cultivarName.isAcceptableOrUnknown( + data['cultivar_name']!, + _cultivarNameMeta, + ), + ); + } + if (data.containsKey('category')) { + context.handle( + _categoryMeta, + category.isAcceptableOrUnknown(data['category']!, _categoryMeta), + ); + } + if (data.containsKey('notes')) { + context.handle( + _notesMeta, + notes.isAcceptableOrUnknown(data['notes']!, _notesMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Variety map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Variety( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + label: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}label'], + )!, + speciesId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}species_id'], + ), + cultivarName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}cultivar_name'], + ), + category: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}category'], + ), + notes: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}notes'], + ), + ); + } + + @override + $VarietiesTable createAlias(String alias) { + return $VarietiesTable(attachedDatabase, alias); + } +} + +class Variety extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String label; + final String? speciesId; + final String? cultivarName; + final String? category; + final String? notes; + const Variety({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.label, + this.speciesId, + this.cultivarName, + this.category, + this.notes, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['label'] = Variable(label); + if (!nullToAbsent || speciesId != null) { + map['species_id'] = Variable(speciesId); + } + if (!nullToAbsent || cultivarName != null) { + map['cultivar_name'] = Variable(cultivarName); + } + if (!nullToAbsent || category != null) { + map['category'] = Variable(category); + } + if (!nullToAbsent || notes != null) { + map['notes'] = Variable(notes); + } + return map; + } + + VarietiesCompanion toCompanion(bool nullToAbsent) { + return VarietiesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + label: Value(label), + speciesId: speciesId == null && nullToAbsent + ? const Value.absent() + : Value(speciesId), + cultivarName: cultivarName == null && nullToAbsent + ? const Value.absent() + : Value(cultivarName), + category: category == null && nullToAbsent + ? const Value.absent() + : Value(category), + notes: notes == null && nullToAbsent + ? const Value.absent() + : Value(notes), + ); + } + + factory Variety.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Variety( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + label: serializer.fromJson(json['label']), + speciesId: serializer.fromJson(json['speciesId']), + cultivarName: serializer.fromJson(json['cultivarName']), + category: serializer.fromJson(json['category']), + notes: serializer.fromJson(json['notes']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'label': serializer.toJson(label), + 'speciesId': serializer.toJson(speciesId), + 'cultivarName': serializer.toJson(cultivarName), + 'category': serializer.toJson(category), + 'notes': serializer.toJson(notes), + }; + } + + Variety copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? label, + Value speciesId = const Value.absent(), + Value cultivarName = const Value.absent(), + Value category = const Value.absent(), + Value notes = const Value.absent(), + }) => Variety( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + label: label ?? this.label, + speciesId: speciesId.present ? speciesId.value : this.speciesId, + cultivarName: cultivarName.present ? cultivarName.value : this.cultivarName, + category: category.present ? category.value : this.category, + notes: notes.present ? notes.value : this.notes, + ); + Variety copyWithCompanion(VarietiesCompanion data) { + return Variety( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + label: data.label.present ? data.label.value : this.label, + speciesId: data.speciesId.present ? data.speciesId.value : this.speciesId, + cultivarName: data.cultivarName.present + ? data.cultivarName.value + : this.cultivarName, + category: data.category.present ? data.category.value : this.category, + notes: data.notes.present ? data.notes.value : this.notes, + ); + } + + @override + String toString() { + return (StringBuffer('Variety(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('label: $label, ') + ..write('speciesId: $speciesId, ') + ..write('cultivarName: $cultivarName, ') + ..write('category: $category, ') + ..write('notes: $notes') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + label, + speciesId, + cultivarName, + category, + notes, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Variety && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.label == this.label && + other.speciesId == this.speciesId && + other.cultivarName == this.cultivarName && + other.category == this.category && + other.notes == this.notes); +} + +class VarietiesCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value label; + final Value speciesId; + final Value cultivarName; + final Value category; + final Value notes; + final Value rowid; + const VarietiesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.label = const Value.absent(), + this.speciesId = const Value.absent(), + this.cultivarName = const Value.absent(), + this.category = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }); + VarietiesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String label, + this.speciesId = const Value.absent(), + this.cultivarName = const Value.absent(), + this.category = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + label = Value(label); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? label, + Expression? speciesId, + Expression? cultivarName, + Expression? category, + Expression? notes, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (label != null) 'label': label, + if (speciesId != null) 'species_id': speciesId, + if (cultivarName != null) 'cultivar_name': cultivarName, + if (category != null) 'category': category, + if (notes != null) 'notes': notes, + if (rowid != null) 'rowid': rowid, + }); + } + + VarietiesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? label, + Value? speciesId, + Value? cultivarName, + Value? category, + Value? notes, + Value? rowid, + }) { + return VarietiesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + label: label ?? this.label, + speciesId: speciesId ?? this.speciesId, + cultivarName: cultivarName ?? this.cultivarName, + category: category ?? this.category, + notes: notes ?? this.notes, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (label.present) { + map['label'] = Variable(label.value); + } + if (speciesId.present) { + map['species_id'] = Variable(speciesId.value); + } + if (cultivarName.present) { + map['cultivar_name'] = Variable(cultivarName.value); + } + if (category.present) { + map['category'] = Variable(category.value); + } + if (notes.present) { + map['notes'] = Variable(notes.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VarietiesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('label: $label, ') + ..write('speciesId: $speciesId, ') + ..write('cultivarName: $cultivarName, ') + ..write('category: $category, ') + ..write('notes: $notes, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $VarietyVernacularNamesTable extends VarietyVernacularNames + with TableInfo<$VarietyVernacularNamesTable, VarietyVernacularName> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $VarietyVernacularNamesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _varietyIdMeta = const VerificationMeta( + 'varietyId', + ); + @override + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _languageMeta = const VerificationMeta( + 'language', + ); + @override + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _regionMeta = const VerificationMeta('region'); + @override + late final GeneratedColumn region = GeneratedColumn( + 'region', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + name, + language, + region, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'variety_vernacular_names'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('variety_id')) { + context.handle( + _varietyIdMeta, + varietyId.isAcceptableOrUnknown(data['variety_id']!, _varietyIdMeta), + ); + } else if (isInserting) { + context.missing(_varietyIdMeta); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('language')) { + context.handle( + _languageMeta, + language.isAcceptableOrUnknown(data['language']!, _languageMeta), + ); + } + if (data.containsKey('region')) { + context.handle( + _regionMeta, + region.isAcceptableOrUnknown(data['region']!, _regionMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + VarietyVernacularName map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VarietyVernacularName( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + varietyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}variety_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + language: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}language'], + ), + region: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}region'], + ), + ); + } + + @override + $VarietyVernacularNamesTable createAlias(String alias) { + return $VarietyVernacularNamesTable(attachedDatabase, alias); + } +} + +class VarietyVernacularName extends DataClass + implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String varietyId; + final String name; + final String? language; + final String? region; + const VarietyVernacularName({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.varietyId, + required this.name, + this.language, + this.region, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['variety_id'] = Variable(varietyId); + map['name'] = Variable(name); + if (!nullToAbsent || language != null) { + map['language'] = Variable(language); + } + if (!nullToAbsent || region != null) { + map['region'] = Variable(region); + } + return map; + } + + VarietyVernacularNamesCompanion toCompanion(bool nullToAbsent) { + return VarietyVernacularNamesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + varietyId: Value(varietyId), + name: Value(name), + language: language == null && nullToAbsent + ? const Value.absent() + : Value(language), + region: region == null && nullToAbsent + ? const Value.absent() + : Value(region), + ); + } + + factory VarietyVernacularName.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VarietyVernacularName( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + varietyId: serializer.fromJson(json['varietyId']), + name: serializer.fromJson(json['name']), + language: serializer.fromJson(json['language']), + region: serializer.fromJson(json['region']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'varietyId': serializer.toJson(varietyId), + 'name': serializer.toJson(name), + 'language': serializer.toJson(language), + 'region': serializer.toJson(region), + }; + } + + VarietyVernacularName copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? varietyId, + String? name, + Value language = const Value.absent(), + Value region = const Value.absent(), + }) => VarietyVernacularName( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId ?? this.varietyId, + name: name ?? this.name, + language: language.present ? language.value : this.language, + region: region.present ? region.value : this.region, + ); + VarietyVernacularName copyWithCompanion( + VarietyVernacularNamesCompanion data, + ) { + return VarietyVernacularName( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + varietyId: data.varietyId.present ? data.varietyId.value : this.varietyId, + name: data.name.present ? data.name.value : this.name, + language: data.language.present ? data.language.value : this.language, + region: data.region.present ? data.region.value : this.region, + ); + } + + @override + String toString() { + return (StringBuffer('VarietyVernacularName(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('name: $name, ') + ..write('language: $language, ') + ..write('region: $region') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + name, + language, + region, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VarietyVernacularName && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.varietyId == this.varietyId && + other.name == this.name && + other.language == this.language && + other.region == this.region); +} + +class VarietyVernacularNamesCompanion + extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value varietyId; + final Value name; + final Value language; + final Value region; + final Value rowid; + const VarietyVernacularNamesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.varietyId = const Value.absent(), + this.name = const Value.absent(), + this.language = const Value.absent(), + this.region = const Value.absent(), + this.rowid = const Value.absent(), + }); + VarietyVernacularNamesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String varietyId, + required String name, + this.language = const Value.absent(), + this.region = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + varietyId = Value(varietyId), + name = Value(name); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? varietyId, + Expression? name, + Expression? language, + Expression? region, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (varietyId != null) 'variety_id': varietyId, + if (name != null) 'name': name, + if (language != null) 'language': language, + if (region != null) 'region': region, + if (rowid != null) 'rowid': rowid, + }); + } + + VarietyVernacularNamesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? varietyId, + Value? name, + Value? language, + Value? region, + Value? rowid, + }) { + return VarietyVernacularNamesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId ?? this.varietyId, + name: name ?? this.name, + language: language ?? this.language, + region: region ?? this.region, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (varietyId.present) { + map['variety_id'] = Variable(varietyId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (language.present) { + map['language'] = Variable(language.value); + } + if (region.present) { + map['region'] = Variable(region.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VarietyVernacularNamesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('name: $name, ') + ..write('language: $language, ') + ..write('region: $region, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $SpeciesTable extends Species with TableInfo<$SpeciesTable, Specy> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $SpeciesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _scientificNameMeta = const VerificationMeta( + 'scientificName', + ); + @override + late final GeneratedColumn scientificName = GeneratedColumn( + 'scientific_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _wikidataQidMeta = const VerificationMeta( + 'wikidataQid', + ); + @override + late final GeneratedColumn wikidataQid = GeneratedColumn( + 'wikidata_qid', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _gbifKeyMeta = const VerificationMeta( + 'gbifKey', + ); + @override + late final GeneratedColumn gbifKey = GeneratedColumn( + 'gbif_key', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _familyMeta = const VerificationMeta('family'); + @override + late final GeneratedColumn family = GeneratedColumn( + 'family', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _isBundledMeta = const VerificationMeta( + 'isBundled', + ); + @override + late final GeneratedColumn isBundled = GeneratedColumn( + 'is_bundled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_bundled" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + scientificName, + wikidataQid, + gbifKey, + family, + isBundled, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('scientific_name')) { + context.handle( + _scientificNameMeta, + scientificName.isAcceptableOrUnknown( + data['scientific_name']!, + _scientificNameMeta, + ), + ); + } else if (isInserting) { + context.missing(_scientificNameMeta); + } + if (data.containsKey('wikidata_qid')) { + context.handle( + _wikidataQidMeta, + wikidataQid.isAcceptableOrUnknown( + data['wikidata_qid']!, + _wikidataQidMeta, + ), + ); + } + if (data.containsKey('gbif_key')) { + context.handle( + _gbifKeyMeta, + gbifKey.isAcceptableOrUnknown(data['gbif_key']!, _gbifKeyMeta), + ); + } + if (data.containsKey('family')) { + context.handle( + _familyMeta, + family.isAcceptableOrUnknown(data['family']!, _familyMeta), + ); + } + if (data.containsKey('is_bundled')) { + context.handle( + _isBundledMeta, + isBundled.isAcceptableOrUnknown(data['is_bundled']!, _isBundledMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Specy map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Specy( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + scientificName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}scientific_name'], + )!, + wikidataQid: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}wikidata_qid'], + ), + gbifKey: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}gbif_key'], + ), + family: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}family'], + ), + isBundled: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_bundled'], + )!, + ); + } + + @override + $SpeciesTable createAlias(String alias) { + return $SpeciesTable(attachedDatabase, alias); + } +} + +class Specy extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String scientificName; + final String? wikidataQid; + final int? gbifKey; + final String? family; + final bool isBundled; + const Specy({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.scientificName, + this.wikidataQid, + this.gbifKey, + this.family, + required this.isBundled, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['scientific_name'] = Variable(scientificName); + if (!nullToAbsent || wikidataQid != null) { + map['wikidata_qid'] = Variable(wikidataQid); + } + if (!nullToAbsent || gbifKey != null) { + map['gbif_key'] = Variable(gbifKey); + } + if (!nullToAbsent || family != null) { + map['family'] = Variable(family); + } + map['is_bundled'] = Variable(isBundled); + return map; + } + + SpeciesCompanion toCompanion(bool nullToAbsent) { + return SpeciesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + scientificName: Value(scientificName), + wikidataQid: wikidataQid == null && nullToAbsent + ? const Value.absent() + : Value(wikidataQid), + gbifKey: gbifKey == null && nullToAbsent + ? const Value.absent() + : Value(gbifKey), + family: family == null && nullToAbsent + ? const Value.absent() + : Value(family), + isBundled: Value(isBundled), + ); + } + + factory Specy.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Specy( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + scientificName: serializer.fromJson(json['scientificName']), + wikidataQid: serializer.fromJson(json['wikidataQid']), + gbifKey: serializer.fromJson(json['gbifKey']), + family: serializer.fromJson(json['family']), + isBundled: serializer.fromJson(json['isBundled']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'scientificName': serializer.toJson(scientificName), + 'wikidataQid': serializer.toJson(wikidataQid), + 'gbifKey': serializer.toJson(gbifKey), + 'family': serializer.toJson(family), + 'isBundled': serializer.toJson(isBundled), + }; + } + + Specy copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? scientificName, + Value wikidataQid = const Value.absent(), + Value gbifKey = const Value.absent(), + Value family = const Value.absent(), + bool? isBundled, + }) => Specy( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + scientificName: scientificName ?? this.scientificName, + wikidataQid: wikidataQid.present ? wikidataQid.value : this.wikidataQid, + gbifKey: gbifKey.present ? gbifKey.value : this.gbifKey, + family: family.present ? family.value : this.family, + isBundled: isBundled ?? this.isBundled, + ); + Specy copyWithCompanion(SpeciesCompanion data) { + return Specy( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + scientificName: data.scientificName.present + ? data.scientificName.value + : this.scientificName, + wikidataQid: data.wikidataQid.present + ? data.wikidataQid.value + : this.wikidataQid, + gbifKey: data.gbifKey.present ? data.gbifKey.value : this.gbifKey, + family: data.family.present ? data.family.value : this.family, + isBundled: data.isBundled.present ? data.isBundled.value : this.isBundled, + ); + } + + @override + String toString() { + return (StringBuffer('Specy(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('scientificName: $scientificName, ') + ..write('wikidataQid: $wikidataQid, ') + ..write('gbifKey: $gbifKey, ') + ..write('family: $family, ') + ..write('isBundled: $isBundled') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + scientificName, + wikidataQid, + gbifKey, + family, + isBundled, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Specy && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.scientificName == this.scientificName && + other.wikidataQid == this.wikidataQid && + other.gbifKey == this.gbifKey && + other.family == this.family && + other.isBundled == this.isBundled); +} + +class SpeciesCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value scientificName; + final Value wikidataQid; + final Value gbifKey; + final Value family; + final Value isBundled; + final Value rowid; + const SpeciesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.scientificName = const Value.absent(), + this.wikidataQid = const Value.absent(), + this.gbifKey = const Value.absent(), + this.family = const Value.absent(), + this.isBundled = const Value.absent(), + this.rowid = const Value.absent(), + }); + SpeciesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String scientificName, + this.wikidataQid = const Value.absent(), + this.gbifKey = const Value.absent(), + this.family = const Value.absent(), + this.isBundled = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + scientificName = Value(scientificName); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? scientificName, + Expression? wikidataQid, + Expression? gbifKey, + Expression? family, + Expression? isBundled, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (scientificName != null) 'scientific_name': scientificName, + if (wikidataQid != null) 'wikidata_qid': wikidataQid, + if (gbifKey != null) 'gbif_key': gbifKey, + if (family != null) 'family': family, + if (isBundled != null) 'is_bundled': isBundled, + if (rowid != null) 'rowid': rowid, + }); + } + + SpeciesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? scientificName, + Value? wikidataQid, + Value? gbifKey, + Value? family, + Value? isBundled, + Value? rowid, + }) { + return SpeciesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + scientificName: scientificName ?? this.scientificName, + wikidataQid: wikidataQid ?? this.wikidataQid, + gbifKey: gbifKey ?? this.gbifKey, + family: family ?? this.family, + isBundled: isBundled ?? this.isBundled, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (scientificName.present) { + map['scientific_name'] = Variable(scientificName.value); + } + if (wikidataQid.present) { + map['wikidata_qid'] = Variable(wikidataQid.value); + } + if (gbifKey.present) { + map['gbif_key'] = Variable(gbifKey.value); + } + if (family.present) { + map['family'] = Variable(family.value); + } + if (isBundled.present) { + map['is_bundled'] = Variable(isBundled.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SpeciesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('scientificName: $scientificName, ') + ..write('wikidataQid: $wikidataQid, ') + ..write('gbifKey: $gbifKey, ') + ..write('family: $family, ') + ..write('isBundled: $isBundled, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $SpeciesCommonNamesTable extends SpeciesCommonNames + with TableInfo<$SpeciesCommonNamesTable, SpeciesCommonName> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $SpeciesCommonNamesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _speciesIdMeta = const VerificationMeta( + 'speciesId', + ); + @override + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _languageMeta = const VerificationMeta( + 'language', + ); + @override + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + speciesId, + name, + language, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species_common_names'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('species_id')) { + context.handle( + _speciesIdMeta, + speciesId.isAcceptableOrUnknown(data['species_id']!, _speciesIdMeta), + ); + } else if (isInserting) { + context.missing(_speciesIdMeta); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('language')) { + context.handle( + _languageMeta, + language.isAcceptableOrUnknown(data['language']!, _languageMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + SpeciesCommonName map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SpeciesCommonName( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + speciesId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}species_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + language: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}language'], + ), + ); + } + + @override + $SpeciesCommonNamesTable createAlias(String alias) { + return $SpeciesCommonNamesTable(attachedDatabase, alias); + } +} + +class SpeciesCommonName extends DataClass + implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String speciesId; + final String name; + final String? language; + const SpeciesCommonName({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.speciesId, + required this.name, + this.language, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['species_id'] = Variable(speciesId); + map['name'] = Variable(name); + if (!nullToAbsent || language != null) { + map['language'] = Variable(language); + } + return map; + } + + SpeciesCommonNamesCompanion toCompanion(bool nullToAbsent) { + return SpeciesCommonNamesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + speciesId: Value(speciesId), + name: Value(name), + language: language == null && nullToAbsent + ? const Value.absent() + : Value(language), + ); + } + + factory SpeciesCommonName.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SpeciesCommonName( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + speciesId: serializer.fromJson(json['speciesId']), + name: serializer.fromJson(json['name']), + language: serializer.fromJson(json['language']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'speciesId': serializer.toJson(speciesId), + 'name': serializer.toJson(name), + 'language': serializer.toJson(language), + }; + } + + SpeciesCommonName copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? speciesId, + String? name, + Value language = const Value.absent(), + }) => SpeciesCommonName( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + speciesId: speciesId ?? this.speciesId, + name: name ?? this.name, + language: language.present ? language.value : this.language, + ); + SpeciesCommonName copyWithCompanion(SpeciesCommonNamesCompanion data) { + return SpeciesCommonName( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + speciesId: data.speciesId.present ? data.speciesId.value : this.speciesId, + name: data.name.present ? data.name.value : this.name, + language: data.language.present ? data.language.value : this.language, + ); + } + + @override + String toString() { + return (StringBuffer('SpeciesCommonName(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('speciesId: $speciesId, ') + ..write('name: $name, ') + ..write('language: $language') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + speciesId, + name, + language, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SpeciesCommonName && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.speciesId == this.speciesId && + other.name == this.name && + other.language == this.language); +} + +class SpeciesCommonNamesCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value speciesId; + final Value name; + final Value language; + final Value rowid; + const SpeciesCommonNamesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.speciesId = const Value.absent(), + this.name = const Value.absent(), + this.language = const Value.absent(), + this.rowid = const Value.absent(), + }); + SpeciesCommonNamesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String speciesId, + required String name, + this.language = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + speciesId = Value(speciesId), + name = Value(name); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? speciesId, + Expression? name, + Expression? language, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (speciesId != null) 'species_id': speciesId, + if (name != null) 'name': name, + if (language != null) 'language': language, + if (rowid != null) 'rowid': rowid, + }); + } + + SpeciesCommonNamesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? speciesId, + Value? name, + Value? language, + Value? rowid, + }) { + return SpeciesCommonNamesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + speciesId: speciesId ?? this.speciesId, + name: name ?? this.name, + language: language ?? this.language, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (speciesId.present) { + map['species_id'] = Variable(speciesId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (language.present) { + map['language'] = Variable(language.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SpeciesCommonNamesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('speciesId: $speciesId, ') + ..write('name: $name, ') + ..write('language: $language, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $LotsTable extends Lots with TableInfo<$LotsTable, Lot> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $LotsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _varietyIdMeta = const VerificationMeta( + 'varietyId', + ); + @override + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _harvestYearMeta = const VerificationMeta( + 'harvestYear', + ); + @override + late final GeneratedColumn harvestYear = GeneratedColumn( + 'harvest_year', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityKindMeta = const VerificationMeta( + 'quantityKind', + ); + @override + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityPreciseMeta = const VerificationMeta( + 'quantityPrecise', + ); + @override + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityLabelMeta = const VerificationMeta( + 'quantityLabel', + ); + @override + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _storageLocationMeta = const VerificationMeta( + 'storageLocation', + ); + @override + late final GeneratedColumn storageLocation = GeneratedColumn( + 'storage_location', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + late final GeneratedColumnWithTypeConverter offerStatus = + GeneratedColumn( + 'offer_status', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const Constant('private'), + ).withConverter($LotsTable.$converterofferStatus); + static const VerificationMeta _seedbankIdMeta = const VerificationMeta( + 'seedbankId', + ); + @override + late final GeneratedColumn seedbankId = GeneratedColumn( + 'seedbank_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + harvestYear, + quantityKind, + quantityPrecise, + quantityLabel, + storageLocation, + offerStatus, + seedbankId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'lots'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('variety_id')) { + context.handle( + _varietyIdMeta, + varietyId.isAcceptableOrUnknown(data['variety_id']!, _varietyIdMeta), + ); + } else if (isInserting) { + context.missing(_varietyIdMeta); + } + if (data.containsKey('harvest_year')) { + context.handle( + _harvestYearMeta, + harvestYear.isAcceptableOrUnknown( + data['harvest_year']!, + _harvestYearMeta, + ), + ); + } + if (data.containsKey('quantity_kind')) { + context.handle( + _quantityKindMeta, + quantityKind.isAcceptableOrUnknown( + data['quantity_kind']!, + _quantityKindMeta, + ), + ); + } + if (data.containsKey('quantity_precise')) { + context.handle( + _quantityPreciseMeta, + quantityPrecise.isAcceptableOrUnknown( + data['quantity_precise']!, + _quantityPreciseMeta, + ), + ); + } + if (data.containsKey('quantity_label')) { + context.handle( + _quantityLabelMeta, + quantityLabel.isAcceptableOrUnknown( + data['quantity_label']!, + _quantityLabelMeta, + ), + ); + } + if (data.containsKey('storage_location')) { + context.handle( + _storageLocationMeta, + storageLocation.isAcceptableOrUnknown( + data['storage_location']!, + _storageLocationMeta, + ), + ); + } + if (data.containsKey('seedbank_id')) { + context.handle( + _seedbankIdMeta, + seedbankId.isAcceptableOrUnknown(data['seedbank_id']!, _seedbankIdMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Lot map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Lot( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + varietyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}variety_id'], + )!, + harvestYear: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}harvest_year'], + ), + quantityKind: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quantity_kind'], + ), + quantityPrecise: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}quantity_precise'], + ), + quantityLabel: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quantity_label'], + ), + storageLocation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}storage_location'], + ), + offerStatus: $LotsTable.$converterofferStatus.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}offer_status'], + )!, + ), + seedbankId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}seedbank_id'], + ), + ); + } + + @override + $LotsTable createAlias(String alias) { + return $LotsTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $converterofferStatus = + const EnumNameConverter(OfferStatus.values); +} + +class Lot extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String varietyId; + final int? harvestYear; + final String? quantityKind; + final double? quantityPrecise; + final String? quantityLabel; + final String? storageLocation; + final OfferStatus offerStatus; + final String? seedbankId; + const Lot({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.varietyId, + this.harvestYear, + this.quantityKind, + this.quantityPrecise, + this.quantityLabel, + this.storageLocation, + required this.offerStatus, + this.seedbankId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['variety_id'] = Variable(varietyId); + if (!nullToAbsent || harvestYear != null) { + map['harvest_year'] = Variable(harvestYear); + } + if (!nullToAbsent || quantityKind != null) { + map['quantity_kind'] = Variable(quantityKind); + } + if (!nullToAbsent || quantityPrecise != null) { + map['quantity_precise'] = Variable(quantityPrecise); + } + if (!nullToAbsent || quantityLabel != null) { + map['quantity_label'] = Variable(quantityLabel); + } + if (!nullToAbsent || storageLocation != null) { + map['storage_location'] = Variable(storageLocation); + } + { + map['offer_status'] = Variable( + $LotsTable.$converterofferStatus.toSql(offerStatus), + ); + } + if (!nullToAbsent || seedbankId != null) { + map['seedbank_id'] = Variable(seedbankId); + } + return map; + } + + LotsCompanion toCompanion(bool nullToAbsent) { + return LotsCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + varietyId: Value(varietyId), + harvestYear: harvestYear == null && nullToAbsent + ? const Value.absent() + : Value(harvestYear), + quantityKind: quantityKind == null && nullToAbsent + ? const Value.absent() + : Value(quantityKind), + quantityPrecise: quantityPrecise == null && nullToAbsent + ? const Value.absent() + : Value(quantityPrecise), + quantityLabel: quantityLabel == null && nullToAbsent + ? const Value.absent() + : Value(quantityLabel), + storageLocation: storageLocation == null && nullToAbsent + ? const Value.absent() + : Value(storageLocation), + offerStatus: Value(offerStatus), + seedbankId: seedbankId == null && nullToAbsent + ? const Value.absent() + : Value(seedbankId), + ); + } + + factory Lot.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Lot( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + varietyId: serializer.fromJson(json['varietyId']), + harvestYear: serializer.fromJson(json['harvestYear']), + quantityKind: serializer.fromJson(json['quantityKind']), + quantityPrecise: serializer.fromJson(json['quantityPrecise']), + quantityLabel: serializer.fromJson(json['quantityLabel']), + storageLocation: serializer.fromJson(json['storageLocation']), + offerStatus: $LotsTable.$converterofferStatus.fromJson( + serializer.fromJson(json['offerStatus']), + ), + seedbankId: serializer.fromJson(json['seedbankId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'varietyId': serializer.toJson(varietyId), + 'harvestYear': serializer.toJson(harvestYear), + 'quantityKind': serializer.toJson(quantityKind), + 'quantityPrecise': serializer.toJson(quantityPrecise), + 'quantityLabel': serializer.toJson(quantityLabel), + 'storageLocation': serializer.toJson(storageLocation), + 'offerStatus': serializer.toJson( + $LotsTable.$converterofferStatus.toJson(offerStatus), + ), + 'seedbankId': serializer.toJson(seedbankId), + }; + } + + Lot copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? varietyId, + Value harvestYear = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value storageLocation = const Value.absent(), + OfferStatus? offerStatus, + Value seedbankId = const Value.absent(), + }) => Lot( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId ?? this.varietyId, + harvestYear: harvestYear.present ? harvestYear.value : this.harvestYear, + quantityKind: quantityKind.present ? quantityKind.value : this.quantityKind, + quantityPrecise: quantityPrecise.present + ? quantityPrecise.value + : this.quantityPrecise, + quantityLabel: quantityLabel.present + ? quantityLabel.value + : this.quantityLabel, + storageLocation: storageLocation.present + ? storageLocation.value + : this.storageLocation, + offerStatus: offerStatus ?? this.offerStatus, + seedbankId: seedbankId.present ? seedbankId.value : this.seedbankId, + ); + Lot copyWithCompanion(LotsCompanion data) { + return Lot( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + varietyId: data.varietyId.present ? data.varietyId.value : this.varietyId, + harvestYear: data.harvestYear.present + ? data.harvestYear.value + : this.harvestYear, + quantityKind: data.quantityKind.present + ? data.quantityKind.value + : this.quantityKind, + quantityPrecise: data.quantityPrecise.present + ? data.quantityPrecise.value + : this.quantityPrecise, + quantityLabel: data.quantityLabel.present + ? data.quantityLabel.value + : this.quantityLabel, + storageLocation: data.storageLocation.present + ? data.storageLocation.value + : this.storageLocation, + offerStatus: data.offerStatus.present + ? data.offerStatus.value + : this.offerStatus, + seedbankId: data.seedbankId.present + ? data.seedbankId.value + : this.seedbankId, + ); + } + + @override + String toString() { + return (StringBuffer('Lot(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('harvestYear: $harvestYear, ') + ..write('quantityKind: $quantityKind, ') + ..write('quantityPrecise: $quantityPrecise, ') + ..write('quantityLabel: $quantityLabel, ') + ..write('storageLocation: $storageLocation, ') + ..write('offerStatus: $offerStatus, ') + ..write('seedbankId: $seedbankId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + harvestYear, + quantityKind, + quantityPrecise, + quantityLabel, + storageLocation, + offerStatus, + seedbankId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Lot && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.varietyId == this.varietyId && + other.harvestYear == this.harvestYear && + other.quantityKind == this.quantityKind && + other.quantityPrecise == this.quantityPrecise && + other.quantityLabel == this.quantityLabel && + other.storageLocation == this.storageLocation && + other.offerStatus == this.offerStatus && + other.seedbankId == this.seedbankId); +} + +class LotsCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value varietyId; + final Value harvestYear; + final Value quantityKind; + final Value quantityPrecise; + final Value quantityLabel; + final Value storageLocation; + final Value offerStatus; + final Value seedbankId; + final Value rowid; + const LotsCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.varietyId = const Value.absent(), + this.harvestYear = const Value.absent(), + this.quantityKind = const Value.absent(), + this.quantityPrecise = const Value.absent(), + this.quantityLabel = const Value.absent(), + this.storageLocation = const Value.absent(), + this.offerStatus = const Value.absent(), + this.seedbankId = const Value.absent(), + this.rowid = const Value.absent(), + }); + LotsCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String varietyId, + this.harvestYear = const Value.absent(), + this.quantityKind = const Value.absent(), + this.quantityPrecise = const Value.absent(), + this.quantityLabel = const Value.absent(), + this.storageLocation = const Value.absent(), + this.offerStatus = const Value.absent(), + this.seedbankId = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + varietyId = Value(varietyId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? varietyId, + Expression? harvestYear, + Expression? quantityKind, + Expression? quantityPrecise, + Expression? quantityLabel, + Expression? storageLocation, + Expression? offerStatus, + Expression? seedbankId, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (varietyId != null) 'variety_id': varietyId, + if (harvestYear != null) 'harvest_year': harvestYear, + if (quantityKind != null) 'quantity_kind': quantityKind, + if (quantityPrecise != null) 'quantity_precise': quantityPrecise, + if (quantityLabel != null) 'quantity_label': quantityLabel, + if (storageLocation != null) 'storage_location': storageLocation, + if (offerStatus != null) 'offer_status': offerStatus, + if (seedbankId != null) 'seedbank_id': seedbankId, + if (rowid != null) 'rowid': rowid, + }); + } + + LotsCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? varietyId, + Value? harvestYear, + Value? quantityKind, + Value? quantityPrecise, + Value? quantityLabel, + Value? storageLocation, + Value? offerStatus, + Value? seedbankId, + Value? rowid, + }) { + return LotsCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId ?? this.varietyId, + harvestYear: harvestYear ?? this.harvestYear, + quantityKind: quantityKind ?? this.quantityKind, + quantityPrecise: quantityPrecise ?? this.quantityPrecise, + quantityLabel: quantityLabel ?? this.quantityLabel, + storageLocation: storageLocation ?? this.storageLocation, + offerStatus: offerStatus ?? this.offerStatus, + seedbankId: seedbankId ?? this.seedbankId, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (varietyId.present) { + map['variety_id'] = Variable(varietyId.value); + } + if (harvestYear.present) { + map['harvest_year'] = Variable(harvestYear.value); + } + if (quantityKind.present) { + map['quantity_kind'] = Variable(quantityKind.value); + } + if (quantityPrecise.present) { + map['quantity_precise'] = Variable(quantityPrecise.value); + } + if (quantityLabel.present) { + map['quantity_label'] = Variable(quantityLabel.value); + } + if (storageLocation.present) { + map['storage_location'] = Variable(storageLocation.value); + } + if (offerStatus.present) { + map['offer_status'] = Variable( + $LotsTable.$converterofferStatus.toSql(offerStatus.value), + ); + } + if (seedbankId.present) { + map['seedbank_id'] = Variable(seedbankId.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LotsCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('harvestYear: $harvestYear, ') + ..write('quantityKind: $quantityKind, ') + ..write('quantityPrecise: $quantityPrecise, ') + ..write('quantityLabel: $quantityLabel, ') + ..write('storageLocation: $storageLocation, ') + ..write('offerStatus: $offerStatus, ') + ..write('seedbankId: $seedbankId, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $GerminationTestsTable extends GerminationTests + with TableInfo<$GerminationTestsTable, GerminationTest> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $GerminationTestsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _lotIdMeta = const VerificationMeta('lotId'); + @override + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _testedOnMeta = const VerificationMeta( + 'testedOn', + ); + @override + late final GeneratedColumn testedOn = GeneratedColumn( + 'tested_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _sampleSizeMeta = const VerificationMeta( + 'sampleSize', + ); + @override + late final GeneratedColumn sampleSize = GeneratedColumn( + 'sample_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _germinatedCountMeta = const VerificationMeta( + 'germinatedCount', + ); + @override + late final GeneratedColumn germinatedCount = GeneratedColumn( + 'germinated_count', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _notesMeta = const VerificationMeta('notes'); + @override + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + lotId, + testedOn, + sampleSize, + germinatedCount, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'germination_tests'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('lot_id')) { + context.handle( + _lotIdMeta, + lotId.isAcceptableOrUnknown(data['lot_id']!, _lotIdMeta), + ); + } else if (isInserting) { + context.missing(_lotIdMeta); + } + if (data.containsKey('tested_on')) { + context.handle( + _testedOnMeta, + testedOn.isAcceptableOrUnknown(data['tested_on']!, _testedOnMeta), + ); + } + if (data.containsKey('sample_size')) { + context.handle( + _sampleSizeMeta, + sampleSize.isAcceptableOrUnknown(data['sample_size']!, _sampleSizeMeta), + ); + } + if (data.containsKey('germinated_count')) { + context.handle( + _germinatedCountMeta, + germinatedCount.isAcceptableOrUnknown( + data['germinated_count']!, + _germinatedCountMeta, + ), + ); + } + if (data.containsKey('notes')) { + context.handle( + _notesMeta, + notes.isAcceptableOrUnknown(data['notes']!, _notesMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + GerminationTest map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GerminationTest( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + lotId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lot_id'], + )!, + testedOn: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}tested_on'], + ), + sampleSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sample_size'], + ), + germinatedCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}germinated_count'], + ), + notes: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}notes'], + ), + ); + } + + @override + $GerminationTestsTable createAlias(String alias) { + return $GerminationTestsTable(attachedDatabase, alias); + } +} + +class GerminationTest extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String lotId; + final int? testedOn; + final int? sampleSize; + final int? germinatedCount; + final String? notes; + const GerminationTest({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.lotId, + this.testedOn, + this.sampleSize, + this.germinatedCount, + this.notes, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['lot_id'] = Variable(lotId); + if (!nullToAbsent || testedOn != null) { + map['tested_on'] = Variable(testedOn); + } + if (!nullToAbsent || sampleSize != null) { + map['sample_size'] = Variable(sampleSize); + } + if (!nullToAbsent || germinatedCount != null) { + map['germinated_count'] = Variable(germinatedCount); + } + if (!nullToAbsent || notes != null) { + map['notes'] = Variable(notes); + } + return map; + } + + GerminationTestsCompanion toCompanion(bool nullToAbsent) { + return GerminationTestsCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + lotId: Value(lotId), + testedOn: testedOn == null && nullToAbsent + ? const Value.absent() + : Value(testedOn), + sampleSize: sampleSize == null && nullToAbsent + ? const Value.absent() + : Value(sampleSize), + germinatedCount: germinatedCount == null && nullToAbsent + ? const Value.absent() + : Value(germinatedCount), + notes: notes == null && nullToAbsent + ? const Value.absent() + : Value(notes), + ); + } + + factory GerminationTest.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GerminationTest( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + lotId: serializer.fromJson(json['lotId']), + testedOn: serializer.fromJson(json['testedOn']), + sampleSize: serializer.fromJson(json['sampleSize']), + germinatedCount: serializer.fromJson(json['germinatedCount']), + notes: serializer.fromJson(json['notes']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'lotId': serializer.toJson(lotId), + 'testedOn': serializer.toJson(testedOn), + 'sampleSize': serializer.toJson(sampleSize), + 'germinatedCount': serializer.toJson(germinatedCount), + 'notes': serializer.toJson(notes), + }; + } + + GerminationTest copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? lotId, + Value testedOn = const Value.absent(), + Value sampleSize = const Value.absent(), + Value germinatedCount = const Value.absent(), + Value notes = const Value.absent(), + }) => GerminationTest( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + lotId: lotId ?? this.lotId, + testedOn: testedOn.present ? testedOn.value : this.testedOn, + sampleSize: sampleSize.present ? sampleSize.value : this.sampleSize, + germinatedCount: germinatedCount.present + ? germinatedCount.value + : this.germinatedCount, + notes: notes.present ? notes.value : this.notes, + ); + GerminationTest copyWithCompanion(GerminationTestsCompanion data) { + return GerminationTest( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + lotId: data.lotId.present ? data.lotId.value : this.lotId, + testedOn: data.testedOn.present ? data.testedOn.value : this.testedOn, + sampleSize: data.sampleSize.present + ? data.sampleSize.value + : this.sampleSize, + germinatedCount: data.germinatedCount.present + ? data.germinatedCount.value + : this.germinatedCount, + notes: data.notes.present ? data.notes.value : this.notes, + ); + } + + @override + String toString() { + return (StringBuffer('GerminationTest(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('lotId: $lotId, ') + ..write('testedOn: $testedOn, ') + ..write('sampleSize: $sampleSize, ') + ..write('germinatedCount: $germinatedCount, ') + ..write('notes: $notes') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + lotId, + testedOn, + sampleSize, + germinatedCount, + notes, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GerminationTest && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.lotId == this.lotId && + other.testedOn == this.testedOn && + other.sampleSize == this.sampleSize && + other.germinatedCount == this.germinatedCount && + other.notes == this.notes); +} + +class GerminationTestsCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value lotId; + final Value testedOn; + final Value sampleSize; + final Value germinatedCount; + final Value notes; + final Value rowid; + const GerminationTestsCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.lotId = const Value.absent(), + this.testedOn = const Value.absent(), + this.sampleSize = const Value.absent(), + this.germinatedCount = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }); + GerminationTestsCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String lotId, + this.testedOn = const Value.absent(), + this.sampleSize = const Value.absent(), + this.germinatedCount = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + lotId = Value(lotId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? lotId, + Expression? testedOn, + Expression? sampleSize, + Expression? germinatedCount, + Expression? notes, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (lotId != null) 'lot_id': lotId, + if (testedOn != null) 'tested_on': testedOn, + if (sampleSize != null) 'sample_size': sampleSize, + if (germinatedCount != null) 'germinated_count': germinatedCount, + if (notes != null) 'notes': notes, + if (rowid != null) 'rowid': rowid, + }); + } + + GerminationTestsCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? lotId, + Value? testedOn, + Value? sampleSize, + Value? germinatedCount, + Value? notes, + Value? rowid, + }) { + return GerminationTestsCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + lotId: lotId ?? this.lotId, + testedOn: testedOn ?? this.testedOn, + sampleSize: sampleSize ?? this.sampleSize, + germinatedCount: germinatedCount ?? this.germinatedCount, + notes: notes ?? this.notes, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (lotId.present) { + map['lot_id'] = Variable(lotId.value); + } + if (testedOn.present) { + map['tested_on'] = Variable(testedOn.value); + } + if (sampleSize.present) { + map['sample_size'] = Variable(sampleSize.value); + } + if (germinatedCount.present) { + map['germinated_count'] = Variable(germinatedCount.value); + } + if (notes.present) { + map['notes'] = Variable(notes.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GerminationTestsCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('lotId: $lotId, ') + ..write('testedOn: $testedOn, ') + ..write('sampleSize: $sampleSize, ') + ..write('germinatedCount: $germinatedCount, ') + ..write('notes: $notes, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $MovementsTable extends Movements + with TableInfo<$MovementsTable, Movement> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $MovementsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _lotIdMeta = const VerificationMeta('lotId'); + @override + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + late final GeneratedColumnWithTypeConverter type = + GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($MovementsTable.$convertertype); + static const VerificationMeta _occurredOnMeta = const VerificationMeta( + 'occurredOn', + ); + @override + late final GeneratedColumn occurredOn = GeneratedColumn( + 'occurred_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _counterpartyIdMeta = const VerificationMeta( + 'counterpartyId', + ); + @override + late final GeneratedColumn counterpartyId = GeneratedColumn( + 'counterparty_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityKindMeta = const VerificationMeta( + 'quantityKind', + ); + @override + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityPreciseMeta = const VerificationMeta( + 'quantityPrecise', + ); + @override + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + static const VerificationMeta _quantityLabelMeta = const VerificationMeta( + 'quantityLabel', + ); + @override + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _parentMovementIdMeta = const VerificationMeta( + 'parentMovementId', + ); + @override + late final GeneratedColumn parentMovementId = GeneratedColumn( + 'parent_movement_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _plantareIdMeta = const VerificationMeta( + 'plantareId', + ); + @override + late final GeneratedColumn plantareId = GeneratedColumn( + 'plantare_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _notesMeta = const VerificationMeta('notes'); + @override + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + lastAuthor, + schemaRowVersion, + lotId, + type, + occurredOn, + counterpartyId, + quantityKind, + quantityPrecise, + quantityLabel, + parentMovementId, + plantareId, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'movements'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('lot_id')) { + context.handle( + _lotIdMeta, + lotId.isAcceptableOrUnknown(data['lot_id']!, _lotIdMeta), + ); + } else if (isInserting) { + context.missing(_lotIdMeta); + } + if (data.containsKey('occurred_on')) { + context.handle( + _occurredOnMeta, + occurredOn.isAcceptableOrUnknown(data['occurred_on']!, _occurredOnMeta), + ); + } + if (data.containsKey('counterparty_id')) { + context.handle( + _counterpartyIdMeta, + counterpartyId.isAcceptableOrUnknown( + data['counterparty_id']!, + _counterpartyIdMeta, + ), + ); + } + if (data.containsKey('quantity_kind')) { + context.handle( + _quantityKindMeta, + quantityKind.isAcceptableOrUnknown( + data['quantity_kind']!, + _quantityKindMeta, + ), + ); + } + if (data.containsKey('quantity_precise')) { + context.handle( + _quantityPreciseMeta, + quantityPrecise.isAcceptableOrUnknown( + data['quantity_precise']!, + _quantityPreciseMeta, + ), + ); + } + if (data.containsKey('quantity_label')) { + context.handle( + _quantityLabelMeta, + quantityLabel.isAcceptableOrUnknown( + data['quantity_label']!, + _quantityLabelMeta, + ), + ); + } + if (data.containsKey('parent_movement_id')) { + context.handle( + _parentMovementIdMeta, + parentMovementId.isAcceptableOrUnknown( + data['parent_movement_id']!, + _parentMovementIdMeta, + ), + ); + } + if (data.containsKey('plantare_id')) { + context.handle( + _plantareIdMeta, + plantareId.isAcceptableOrUnknown(data['plantare_id']!, _plantareIdMeta), + ); + } + if (data.containsKey('notes')) { + context.handle( + _notesMeta, + notes.isAcceptableOrUnknown(data['notes']!, _notesMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Movement map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Movement( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + lotId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lot_id'], + )!, + type: $MovementsTable.$convertertype.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ), + occurredOn: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}occurred_on'], + ), + counterpartyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}counterparty_id'], + ), + quantityKind: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quantity_kind'], + ), + quantityPrecise: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}quantity_precise'], + ), + quantityLabel: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quantity_label'], + ), + parentMovementId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}parent_movement_id'], + ), + plantareId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}plantare_id'], + ), + notes: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}notes'], + ), + ); + } + + @override + $MovementsTable createAlias(String alias) { + return $MovementsTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $convertertype = + const EnumNameConverter(MovementType.values); +} + +class Movement extends DataClass implements Insertable { + final String id; + final int createdAt; + final String lastAuthor; + final int schemaRowVersion; + final String lotId; + final MovementType type; + final int? occurredOn; + final String? counterpartyId; + final String? quantityKind; + final double? quantityPrecise; + final String? quantityLabel; + final String? parentMovementId; + final String? plantareId; + final String? notes; + const Movement({ + required this.id, + required this.createdAt, + required this.lastAuthor, + required this.schemaRowVersion, + required this.lotId, + required this.type, + this.occurredOn, + this.counterpartyId, + this.quantityKind, + this.quantityPrecise, + this.quantityLabel, + this.parentMovementId, + this.plantareId, + this.notes, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['last_author'] = Variable(lastAuthor); + map['schema_row_version'] = Variable(schemaRowVersion); + map['lot_id'] = Variable(lotId); + { + map['type'] = Variable( + $MovementsTable.$convertertype.toSql(type), + ); + } + if (!nullToAbsent || occurredOn != null) { + map['occurred_on'] = Variable(occurredOn); + } + if (!nullToAbsent || counterpartyId != null) { + map['counterparty_id'] = Variable(counterpartyId); + } + if (!nullToAbsent || quantityKind != null) { + map['quantity_kind'] = Variable(quantityKind); + } + if (!nullToAbsent || quantityPrecise != null) { + map['quantity_precise'] = Variable(quantityPrecise); + } + if (!nullToAbsent || quantityLabel != null) { + map['quantity_label'] = Variable(quantityLabel); + } + if (!nullToAbsent || parentMovementId != null) { + map['parent_movement_id'] = Variable(parentMovementId); + } + if (!nullToAbsent || plantareId != null) { + map['plantare_id'] = Variable(plantareId); + } + if (!nullToAbsent || notes != null) { + map['notes'] = Variable(notes); + } + return map; + } + + MovementsCompanion toCompanion(bool nullToAbsent) { + return MovementsCompanion( + id: Value(id), + createdAt: Value(createdAt), + lastAuthor: Value(lastAuthor), + schemaRowVersion: Value(schemaRowVersion), + lotId: Value(lotId), + type: Value(type), + occurredOn: occurredOn == null && nullToAbsent + ? const Value.absent() + : Value(occurredOn), + counterpartyId: counterpartyId == null && nullToAbsent + ? const Value.absent() + : Value(counterpartyId), + quantityKind: quantityKind == null && nullToAbsent + ? const Value.absent() + : Value(quantityKind), + quantityPrecise: quantityPrecise == null && nullToAbsent + ? const Value.absent() + : Value(quantityPrecise), + quantityLabel: quantityLabel == null && nullToAbsent + ? const Value.absent() + : Value(quantityLabel), + parentMovementId: parentMovementId == null && nullToAbsent + ? const Value.absent() + : Value(parentMovementId), + plantareId: plantareId == null && nullToAbsent + ? const Value.absent() + : Value(plantareId), + notes: notes == null && nullToAbsent + ? const Value.absent() + : Value(notes), + ); + } + + factory Movement.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Movement( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + lotId: serializer.fromJson(json['lotId']), + type: $MovementsTable.$convertertype.fromJson( + serializer.fromJson(json['type']), + ), + occurredOn: serializer.fromJson(json['occurredOn']), + counterpartyId: serializer.fromJson(json['counterpartyId']), + quantityKind: serializer.fromJson(json['quantityKind']), + quantityPrecise: serializer.fromJson(json['quantityPrecise']), + quantityLabel: serializer.fromJson(json['quantityLabel']), + parentMovementId: serializer.fromJson(json['parentMovementId']), + plantareId: serializer.fromJson(json['plantareId']), + notes: serializer.fromJson(json['notes']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'lotId': serializer.toJson(lotId), + 'type': serializer.toJson( + $MovementsTable.$convertertype.toJson(type), + ), + 'occurredOn': serializer.toJson(occurredOn), + 'counterpartyId': serializer.toJson(counterpartyId), + 'quantityKind': serializer.toJson(quantityKind), + 'quantityPrecise': serializer.toJson(quantityPrecise), + 'quantityLabel': serializer.toJson(quantityLabel), + 'parentMovementId': serializer.toJson(parentMovementId), + 'plantareId': serializer.toJson(plantareId), + 'notes': serializer.toJson(notes), + }; + } + + Movement copyWith({ + String? id, + int? createdAt, + String? lastAuthor, + int? schemaRowVersion, + String? lotId, + MovementType? type, + Value occurredOn = const Value.absent(), + Value counterpartyId = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value parentMovementId = const Value.absent(), + Value plantareId = const Value.absent(), + Value notes = const Value.absent(), + }) => Movement( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + lotId: lotId ?? this.lotId, + type: type ?? this.type, + occurredOn: occurredOn.present ? occurredOn.value : this.occurredOn, + counterpartyId: counterpartyId.present + ? counterpartyId.value + : this.counterpartyId, + quantityKind: quantityKind.present ? quantityKind.value : this.quantityKind, + quantityPrecise: quantityPrecise.present + ? quantityPrecise.value + : this.quantityPrecise, + quantityLabel: quantityLabel.present + ? quantityLabel.value + : this.quantityLabel, + parentMovementId: parentMovementId.present + ? parentMovementId.value + : this.parentMovementId, + plantareId: plantareId.present ? plantareId.value : this.plantareId, + notes: notes.present ? notes.value : this.notes, + ); + Movement copyWithCompanion(MovementsCompanion data) { + return Movement( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + lotId: data.lotId.present ? data.lotId.value : this.lotId, + type: data.type.present ? data.type.value : this.type, + occurredOn: data.occurredOn.present + ? data.occurredOn.value + : this.occurredOn, + counterpartyId: data.counterpartyId.present + ? data.counterpartyId.value + : this.counterpartyId, + quantityKind: data.quantityKind.present + ? data.quantityKind.value + : this.quantityKind, + quantityPrecise: data.quantityPrecise.present + ? data.quantityPrecise.value + : this.quantityPrecise, + quantityLabel: data.quantityLabel.present + ? data.quantityLabel.value + : this.quantityLabel, + parentMovementId: data.parentMovementId.present + ? data.parentMovementId.value + : this.parentMovementId, + plantareId: data.plantareId.present + ? data.plantareId.value + : this.plantareId, + notes: data.notes.present ? data.notes.value : this.notes, + ); + } + + @override + String toString() { + return (StringBuffer('Movement(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('lotId: $lotId, ') + ..write('type: $type, ') + ..write('occurredOn: $occurredOn, ') + ..write('counterpartyId: $counterpartyId, ') + ..write('quantityKind: $quantityKind, ') + ..write('quantityPrecise: $quantityPrecise, ') + ..write('quantityLabel: $quantityLabel, ') + ..write('parentMovementId: $parentMovementId, ') + ..write('plantareId: $plantareId, ') + ..write('notes: $notes') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + lastAuthor, + schemaRowVersion, + lotId, + type, + occurredOn, + counterpartyId, + quantityKind, + quantityPrecise, + quantityLabel, + parentMovementId, + plantareId, + notes, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Movement && + other.id == this.id && + other.createdAt == this.createdAt && + other.lastAuthor == this.lastAuthor && + other.schemaRowVersion == this.schemaRowVersion && + other.lotId == this.lotId && + other.type == this.type && + other.occurredOn == this.occurredOn && + other.counterpartyId == this.counterpartyId && + other.quantityKind == this.quantityKind && + other.quantityPrecise == this.quantityPrecise && + other.quantityLabel == this.quantityLabel && + other.parentMovementId == this.parentMovementId && + other.plantareId == this.plantareId && + other.notes == this.notes); +} + +class MovementsCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value lastAuthor; + final Value schemaRowVersion; + final Value lotId; + final Value type; + final Value occurredOn; + final Value counterpartyId; + final Value quantityKind; + final Value quantityPrecise; + final Value quantityLabel; + final Value parentMovementId; + final Value plantareId; + final Value notes; + final Value rowid; + const MovementsCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.lotId = const Value.absent(), + this.type = const Value.absent(), + this.occurredOn = const Value.absent(), + this.counterpartyId = const Value.absent(), + this.quantityKind = const Value.absent(), + this.quantityPrecise = const Value.absent(), + this.quantityLabel = const Value.absent(), + this.parentMovementId = const Value.absent(), + this.plantareId = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }); + MovementsCompanion.insert({ + required String id, + required int createdAt, + required String lastAuthor, + this.schemaRowVersion = const Value.absent(), + required String lotId, + required MovementType type, + this.occurredOn = const Value.absent(), + this.counterpartyId = const Value.absent(), + this.quantityKind = const Value.absent(), + this.quantityPrecise = const Value.absent(), + this.quantityLabel = const Value.absent(), + this.parentMovementId = const Value.absent(), + this.plantareId = const Value.absent(), + this.notes = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + lastAuthor = Value(lastAuthor), + lotId = Value(lotId), + type = Value(type); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? lastAuthor, + Expression? schemaRowVersion, + Expression? lotId, + Expression? type, + Expression? occurredOn, + Expression? counterpartyId, + Expression? quantityKind, + Expression? quantityPrecise, + Expression? quantityLabel, + Expression? parentMovementId, + Expression? plantareId, + Expression? notes, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (lotId != null) 'lot_id': lotId, + if (type != null) 'type': type, + if (occurredOn != null) 'occurred_on': occurredOn, + if (counterpartyId != null) 'counterparty_id': counterpartyId, + if (quantityKind != null) 'quantity_kind': quantityKind, + if (quantityPrecise != null) 'quantity_precise': quantityPrecise, + if (quantityLabel != null) 'quantity_label': quantityLabel, + if (parentMovementId != null) 'parent_movement_id': parentMovementId, + if (plantareId != null) 'plantare_id': plantareId, + if (notes != null) 'notes': notes, + if (rowid != null) 'rowid': rowid, + }); + } + + MovementsCompanion copyWith({ + Value? id, + Value? createdAt, + Value? lastAuthor, + Value? schemaRowVersion, + Value? lotId, + Value? type, + Value? occurredOn, + Value? counterpartyId, + Value? quantityKind, + Value? quantityPrecise, + Value? quantityLabel, + Value? parentMovementId, + Value? plantareId, + Value? notes, + Value? rowid, + }) { + return MovementsCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + lotId: lotId ?? this.lotId, + type: type ?? this.type, + occurredOn: occurredOn ?? this.occurredOn, + counterpartyId: counterpartyId ?? this.counterpartyId, + quantityKind: quantityKind ?? this.quantityKind, + quantityPrecise: quantityPrecise ?? this.quantityPrecise, + quantityLabel: quantityLabel ?? this.quantityLabel, + parentMovementId: parentMovementId ?? this.parentMovementId, + plantareId: plantareId ?? this.plantareId, + notes: notes ?? this.notes, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (lotId.present) { + map['lot_id'] = Variable(lotId.value); + } + if (type.present) { + map['type'] = Variable( + $MovementsTable.$convertertype.toSql(type.value), + ); + } + if (occurredOn.present) { + map['occurred_on'] = Variable(occurredOn.value); + } + if (counterpartyId.present) { + map['counterparty_id'] = Variable(counterpartyId.value); + } + if (quantityKind.present) { + map['quantity_kind'] = Variable(quantityKind.value); + } + if (quantityPrecise.present) { + map['quantity_precise'] = Variable(quantityPrecise.value); + } + if (quantityLabel.present) { + map['quantity_label'] = Variable(quantityLabel.value); + } + if (parentMovementId.present) { + map['parent_movement_id'] = Variable(parentMovementId.value); + } + if (plantareId.present) { + map['plantare_id'] = Variable(plantareId.value); + } + if (notes.present) { + map['notes'] = Variable(notes.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MovementsCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('lotId: $lotId, ') + ..write('type: $type, ') + ..write('occurredOn: $occurredOn, ') + ..write('counterpartyId: $counterpartyId, ') + ..write('quantityKind: $quantityKind, ') + ..write('quantityPrecise: $quantityPrecise, ') + ..write('quantityLabel: $quantityLabel, ') + ..write('parentMovementId: $parentMovementId, ') + ..write('plantareId: $plantareId, ') + ..write('notes: $notes, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $PartiesTable extends Parties with TableInfo<$PartiesTable, Party> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PartiesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _displayNameMeta = const VerificationMeta( + 'displayName', + ); + @override + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _publicKeyMeta = const VerificationMeta( + 'publicKey', + ); + @override + late final GeneratedColumn publicKey = GeneratedColumn( + 'public_key', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + late final GeneratedColumnWithTypeConverter kind = + GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const Constant('person'), + ).withConverter($PartiesTable.$converterkind); + static const VerificationMeta _noteMeta = const VerificationMeta('note'); + @override + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + displayName, + publicKey, + kind, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'parties'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('display_name')) { + context.handle( + _displayNameMeta, + displayName.isAcceptableOrUnknown( + data['display_name']!, + _displayNameMeta, + ), + ); + } else if (isInserting) { + context.missing(_displayNameMeta); + } + if (data.containsKey('public_key')) { + context.handle( + _publicKeyMeta, + publicKey.isAcceptableOrUnknown(data['public_key']!, _publicKeyMeta), + ); + } + if (data.containsKey('note')) { + context.handle( + _noteMeta, + note.isAcceptableOrUnknown(data['note']!, _noteMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Party map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Party( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + displayName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}display_name'], + )!, + publicKey: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}public_key'], + ), + kind: $PartiesTable.$converterkind.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}kind'], + )!, + ), + note: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}note'], + ), + ); + } + + @override + $PartiesTable createAlias(String alias) { + return $PartiesTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $converterkind = + const EnumNameConverter(PartyKind.values); +} + +class Party extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final String displayName; + final String? publicKey; + final PartyKind kind; + final String? note; + const Party({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.displayName, + this.publicKey, + required this.kind, + this.note, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + map['display_name'] = Variable(displayName); + if (!nullToAbsent || publicKey != null) { + map['public_key'] = Variable(publicKey); + } + { + map['kind'] = Variable($PartiesTable.$converterkind.toSql(kind)); + } + if (!nullToAbsent || note != null) { + map['note'] = Variable(note); + } + return map; + } + + PartiesCompanion toCompanion(bool nullToAbsent) { + return PartiesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + displayName: Value(displayName), + publicKey: publicKey == null && nullToAbsent + ? const Value.absent() + : Value(publicKey), + kind: Value(kind), + note: note == null && nullToAbsent ? const Value.absent() : Value(note), + ); + } + + factory Party.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Party( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + displayName: serializer.fromJson(json['displayName']), + publicKey: serializer.fromJson(json['publicKey']), + kind: $PartiesTable.$converterkind.fromJson( + serializer.fromJson(json['kind']), + ), + note: serializer.fromJson(json['note']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'displayName': serializer.toJson(displayName), + 'publicKey': serializer.toJson(publicKey), + 'kind': serializer.toJson( + $PartiesTable.$converterkind.toJson(kind), + ), + 'note': serializer.toJson(note), + }; + } + + Party copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + String? displayName, + Value publicKey = const Value.absent(), + PartyKind? kind, + Value note = const Value.absent(), + }) => Party( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + displayName: displayName ?? this.displayName, + publicKey: publicKey.present ? publicKey.value : this.publicKey, + kind: kind ?? this.kind, + note: note.present ? note.value : this.note, + ); + Party copyWithCompanion(PartiesCompanion data) { + return Party( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + displayName: data.displayName.present + ? data.displayName.value + : this.displayName, + publicKey: data.publicKey.present ? data.publicKey.value : this.publicKey, + kind: data.kind.present ? data.kind.value : this.kind, + note: data.note.present ? data.note.value : this.note, + ); + } + + @override + String toString() { + return (StringBuffer('Party(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('displayName: $displayName, ') + ..write('publicKey: $publicKey, ') + ..write('kind: $kind, ') + ..write('note: $note') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + displayName, + publicKey, + kind, + note, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Party && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.displayName == this.displayName && + other.publicKey == this.publicKey && + other.kind == this.kind && + other.note == this.note); +} + +class PartiesCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value displayName; + final Value publicKey; + final Value kind; + final Value note; + final Value rowid; + const PartiesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.displayName = const Value.absent(), + this.publicKey = const Value.absent(), + this.kind = const Value.absent(), + this.note = const Value.absent(), + this.rowid = const Value.absent(), + }); + PartiesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required String displayName, + this.publicKey = const Value.absent(), + this.kind = const Value.absent(), + this.note = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + displayName = Value(displayName); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? displayName, + Expression? publicKey, + Expression? kind, + Expression? note, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (displayName != null) 'display_name': displayName, + if (publicKey != null) 'public_key': publicKey, + if (kind != null) 'kind': kind, + if (note != null) 'note': note, + if (rowid != null) 'rowid': rowid, + }); + } + + PartiesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? displayName, + Value? publicKey, + Value? kind, + Value? note, + Value? rowid, + }) { + return PartiesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + displayName: displayName ?? this.displayName, + publicKey: publicKey ?? this.publicKey, + kind: kind ?? this.kind, + note: note ?? this.note, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (displayName.present) { + map['display_name'] = Variable(displayName.value); + } + if (publicKey.present) { + map['public_key'] = Variable(publicKey.value); + } + if (kind.present) { + map['kind'] = Variable( + $PartiesTable.$converterkind.toSql(kind.value), + ); + } + if (note.present) { + map['note'] = Variable(note.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PartiesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('displayName: $displayName, ') + ..write('publicKey: $publicKey, ') + ..write('kind: $kind, ') + ..write('note: $note, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $AttachmentsTable extends Attachments + with TableInfo<$AttachmentsTable, Attachment> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AttachmentsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + @override + late final GeneratedColumnWithTypeConverter parentType = + GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($AttachmentsTable.$converterparentType); + static const VerificationMeta _parentIdMeta = const VerificationMeta( + 'parentId', + ); + @override + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + late final GeneratedColumnWithTypeConverter kind = + GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($AttachmentsTable.$converterkind); + static const VerificationMeta _uriMeta = const VerificationMeta('uri'); + @override + late final GeneratedColumn uri = GeneratedColumn( + 'uri', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _bytesMeta = const VerificationMeta('bytes'); + @override + late final GeneratedColumn bytes = GeneratedColumn( + 'bytes', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + ); + static const VerificationMeta _mimeTypeMeta = const VerificationMeta( + 'mimeType', + ); + @override + late final GeneratedColumn mimeType = GeneratedColumn( + 'mime_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + kind, + uri, + bytes, + mimeType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'attachments'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('parent_id')) { + context.handle( + _parentIdMeta, + parentId.isAcceptableOrUnknown(data['parent_id']!, _parentIdMeta), + ); + } else if (isInserting) { + context.missing(_parentIdMeta); + } + if (data.containsKey('uri')) { + context.handle( + _uriMeta, + uri.isAcceptableOrUnknown(data['uri']!, _uriMeta), + ); + } + if (data.containsKey('bytes')) { + context.handle( + _bytesMeta, + bytes.isAcceptableOrUnknown(data['bytes']!, _bytesMeta), + ); + } + if (data.containsKey('mime_type')) { + context.handle( + _mimeTypeMeta, + mimeType.isAcceptableOrUnknown(data['mime_type']!, _mimeTypeMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Attachment map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Attachment( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + parentType: $AttachmentsTable.$converterparentType.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}parent_type'], + )!, + ), + parentId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}parent_id'], + )!, + kind: $AttachmentsTable.$converterkind.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}kind'], + )!, + ), + uri: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}uri'], + ), + bytes: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}bytes'], + ), + mimeType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}mime_type'], + ), + ); + } + + @override + $AttachmentsTable createAlias(String alias) { + return $AttachmentsTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $converterparentType = + const EnumNameConverter(ParentType.values); + static JsonTypeConverter2 $converterkind = + const EnumNameConverter(AttachmentKind.values); +} + +class Attachment extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final ParentType parentType; + final String parentId; + final AttachmentKind kind; + final String? uri; + final Uint8List? bytes; + final String? mimeType; + const Attachment({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.parentType, + required this.parentId, + required this.kind, + this.uri, + this.bytes, + this.mimeType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + { + map['parent_type'] = Variable( + $AttachmentsTable.$converterparentType.toSql(parentType), + ); + } + map['parent_id'] = Variable(parentId); + { + map['kind'] = Variable( + $AttachmentsTable.$converterkind.toSql(kind), + ); + } + if (!nullToAbsent || uri != null) { + map['uri'] = Variable(uri); + } + if (!nullToAbsent || bytes != null) { + map['bytes'] = Variable(bytes); + } + if (!nullToAbsent || mimeType != null) { + map['mime_type'] = Variable(mimeType); + } + return map; + } + + AttachmentsCompanion toCompanion(bool nullToAbsent) { + return AttachmentsCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + parentType: Value(parentType), + parentId: Value(parentId), + kind: Value(kind), + uri: uri == null && nullToAbsent ? const Value.absent() : Value(uri), + bytes: bytes == null && nullToAbsent + ? const Value.absent() + : Value(bytes), + mimeType: mimeType == null && nullToAbsent + ? const Value.absent() + : Value(mimeType), + ); + } + + factory Attachment.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Attachment( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + parentType: $AttachmentsTable.$converterparentType.fromJson( + serializer.fromJson(json['parentType']), + ), + parentId: serializer.fromJson(json['parentId']), + kind: $AttachmentsTable.$converterkind.fromJson( + serializer.fromJson(json['kind']), + ), + uri: serializer.fromJson(json['uri']), + bytes: serializer.fromJson(json['bytes']), + mimeType: serializer.fromJson(json['mimeType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'parentType': serializer.toJson( + $AttachmentsTable.$converterparentType.toJson(parentType), + ), + 'parentId': serializer.toJson(parentId), + 'kind': serializer.toJson( + $AttachmentsTable.$converterkind.toJson(kind), + ), + 'uri': serializer.toJson(uri), + 'bytes': serializer.toJson(bytes), + 'mimeType': serializer.toJson(mimeType), + }; + } + + Attachment copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + ParentType? parentType, + String? parentId, + AttachmentKind? kind, + Value uri = const Value.absent(), + Value bytes = const Value.absent(), + Value mimeType = const Value.absent(), + }) => Attachment( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + parentType: parentType ?? this.parentType, + parentId: parentId ?? this.parentId, + kind: kind ?? this.kind, + uri: uri.present ? uri.value : this.uri, + bytes: bytes.present ? bytes.value : this.bytes, + mimeType: mimeType.present ? mimeType.value : this.mimeType, + ); + Attachment copyWithCompanion(AttachmentsCompanion data) { + return Attachment( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + parentType: data.parentType.present + ? data.parentType.value + : this.parentType, + parentId: data.parentId.present ? data.parentId.value : this.parentId, + kind: data.kind.present ? data.kind.value : this.kind, + uri: data.uri.present ? data.uri.value : this.uri, + bytes: data.bytes.present ? data.bytes.value : this.bytes, + mimeType: data.mimeType.present ? data.mimeType.value : this.mimeType, + ); + } + + @override + String toString() { + return (StringBuffer('Attachment(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('parentType: $parentType, ') + ..write('parentId: $parentId, ') + ..write('kind: $kind, ') + ..write('uri: $uri, ') + ..write('bytes: $bytes, ') + ..write('mimeType: $mimeType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + kind, + uri, + $driftBlobEquality.hash(bytes), + mimeType, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Attachment && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.parentType == this.parentType && + other.parentId == this.parentId && + other.kind == this.kind && + other.uri == this.uri && + $driftBlobEquality.equals(other.bytes, this.bytes) && + other.mimeType == this.mimeType); +} + +class AttachmentsCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value parentType; + final Value parentId; + final Value kind; + final Value uri; + final Value bytes; + final Value mimeType; + final Value rowid; + const AttachmentsCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.parentType = const Value.absent(), + this.parentId = const Value.absent(), + this.kind = const Value.absent(), + this.uri = const Value.absent(), + this.bytes = const Value.absent(), + this.mimeType = const Value.absent(), + this.rowid = const Value.absent(), + }); + AttachmentsCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required ParentType parentType, + required String parentId, + required AttachmentKind kind, + this.uri = const Value.absent(), + this.bytes = const Value.absent(), + this.mimeType = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + parentType = Value(parentType), + parentId = Value(parentId), + kind = Value(kind); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? parentType, + Expression? parentId, + Expression? kind, + Expression? uri, + Expression? bytes, + Expression? mimeType, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (parentType != null) 'parent_type': parentType, + if (parentId != null) 'parent_id': parentId, + if (kind != null) 'kind': kind, + if (uri != null) 'uri': uri, + if (bytes != null) 'bytes': bytes, + if (mimeType != null) 'mime_type': mimeType, + if (rowid != null) 'rowid': rowid, + }); + } + + AttachmentsCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? parentType, + Value? parentId, + Value? kind, + Value? uri, + Value? bytes, + Value? mimeType, + Value? rowid, + }) { + return AttachmentsCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + parentType: parentType ?? this.parentType, + parentId: parentId ?? this.parentId, + kind: kind ?? this.kind, + uri: uri ?? this.uri, + bytes: bytes ?? this.bytes, + mimeType: mimeType ?? this.mimeType, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (parentType.present) { + map['parent_type'] = Variable( + $AttachmentsTable.$converterparentType.toSql(parentType.value), + ); + } + if (parentId.present) { + map['parent_id'] = Variable(parentId.value); + } + if (kind.present) { + map['kind'] = Variable( + $AttachmentsTable.$converterkind.toSql(kind.value), + ); + } + if (uri.present) { + map['uri'] = Variable(uri.value); + } + if (bytes.present) { + map['bytes'] = Variable(bytes.value); + } + if (mimeType.present) { + map['mime_type'] = Variable(mimeType.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AttachmentsCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('parentType: $parentType, ') + ..write('parentId: $parentId, ') + ..write('kind: $kind, ') + ..write('uri: $uri, ') + ..write('bytes: $bytes, ') + ..write('mimeType: $mimeType, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $ExternalLinksTable extends ExternalLinks + with TableInfo<$ExternalLinksTable, ExternalLink> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $ExternalLinksTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + @override + late final GeneratedColumnWithTypeConverter parentType = + GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($ExternalLinksTable.$converterparentType); + static const VerificationMeta _parentIdMeta = const VerificationMeta( + 'parentId', + ); + @override + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _urlMeta = const VerificationMeta('url'); + @override + late final GeneratedColumn url = GeneratedColumn( + 'url', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _titleMeta = const VerificationMeta('title'); + @override + late final GeneratedColumn title = GeneratedColumn( + 'title', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + url, + title, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'external_links'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('parent_id')) { + context.handle( + _parentIdMeta, + parentId.isAcceptableOrUnknown(data['parent_id']!, _parentIdMeta), + ); + } else if (isInserting) { + context.missing(_parentIdMeta); + } + if (data.containsKey('url')) { + context.handle( + _urlMeta, + url.isAcceptableOrUnknown(data['url']!, _urlMeta), + ); + } else if (isInserting) { + context.missing(_urlMeta); + } + if (data.containsKey('title')) { + context.handle( + _titleMeta, + title.isAcceptableOrUnknown(data['title']!, _titleMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + ExternalLink map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ExternalLink( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + parentType: $ExternalLinksTable.$converterparentType.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}parent_type'], + )!, + ), + parentId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}parent_id'], + )!, + url: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}url'], + )!, + title: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}title'], + ), + ); + } + + @override + $ExternalLinksTable createAlias(String alias) { + return $ExternalLinksTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $converterparentType = + const EnumNameConverter(ParentType.values); +} + +class ExternalLink extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + final ParentType parentType; + final String parentId; + final String url; + final String? title; + const ExternalLink({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + required this.parentType, + required this.parentId, + required this.url, + this.title, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + { + map['parent_type'] = Variable( + $ExternalLinksTable.$converterparentType.toSql(parentType), + ); + } + map['parent_id'] = Variable(parentId); + map['url'] = Variable(url); + if (!nullToAbsent || title != null) { + map['title'] = Variable(title); + } + return map; + } + + ExternalLinksCompanion toCompanion(bool nullToAbsent) { + return ExternalLinksCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + parentType: Value(parentType), + parentId: Value(parentId), + url: Value(url), + title: title == null && nullToAbsent + ? const Value.absent() + : Value(title), + ); + } + + factory ExternalLink.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ExternalLink( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + parentType: $ExternalLinksTable.$converterparentType.fromJson( + serializer.fromJson(json['parentType']), + ), + parentId: serializer.fromJson(json['parentId']), + url: serializer.fromJson(json['url']), + title: serializer.fromJson(json['title']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'parentType': serializer.toJson( + $ExternalLinksTable.$converterparentType.toJson(parentType), + ), + 'parentId': serializer.toJson(parentId), + 'url': serializer.toJson(url), + 'title': serializer.toJson(title), + }; + } + + ExternalLink copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + ParentType? parentType, + String? parentId, + String? url, + Value title = const Value.absent(), + }) => ExternalLink( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + parentType: parentType ?? this.parentType, + parentId: parentId ?? this.parentId, + url: url ?? this.url, + title: title.present ? title.value : this.title, + ); + ExternalLink copyWithCompanion(ExternalLinksCompanion data) { + return ExternalLink( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + parentType: data.parentType.present + ? data.parentType.value + : this.parentType, + parentId: data.parentId.present ? data.parentId.value : this.parentId, + url: data.url.present ? data.url.value : this.url, + title: data.title.present ? data.title.value : this.title, + ); + } + + @override + String toString() { + return (StringBuffer('ExternalLink(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('parentType: $parentType, ') + ..write('parentId: $parentId, ') + ..write('url: $url, ') + ..write('title: $title') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + url, + title, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ExternalLink && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.parentType == this.parentType && + other.parentId == this.parentId && + other.url == this.url && + other.title == this.title); +} + +class ExternalLinksCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value parentType; + final Value parentId; + final Value url; + final Value title; + final Value rowid; + const ExternalLinksCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.parentType = const Value.absent(), + this.parentId = const Value.absent(), + this.url = const Value.absent(), + this.title = const Value.absent(), + this.rowid = const Value.absent(), + }); + ExternalLinksCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + required ParentType parentType, + required String parentId, + required String url, + this.title = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + parentType = Value(parentType), + parentId = Value(parentId), + url = Value(url); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? parentType, + Expression? parentId, + Expression? url, + Expression? title, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (parentType != null) 'parent_type': parentType, + if (parentId != null) 'parent_id': parentId, + if (url != null) 'url': url, + if (title != null) 'title': title, + if (rowid != null) 'rowid': rowid, + }); + } + + ExternalLinksCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? parentType, + Value? parentId, + Value? url, + Value? title, + Value? rowid, + }) { + return ExternalLinksCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + parentType: parentType ?? this.parentType, + parentId: parentId ?? this.parentId, + url: url ?? this.url, + title: title ?? this.title, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (parentType.present) { + map['parent_type'] = Variable( + $ExternalLinksTable.$converterparentType.toSql(parentType.value), + ); + } + if (parentId.present) { + map['parent_id'] = Variable(parentId.value); + } + if (url.present) { + map['url'] = Variable(url.value); + } + if (title.present) { + map['title'] = Variable(title.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ExternalLinksCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('parentType: $parentType, ') + ..write('parentId: $parentId, ') + ..write('url: $url, ') + ..write('title: $title, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +abstract class _$AppDatabase extends GeneratedDatabase { + _$AppDatabase(QueryExecutor e) : super(e); + $AppDatabaseManager get managers => $AppDatabaseManager(this); + late final $VarietiesTable varieties = $VarietiesTable(this); + late final $VarietyVernacularNamesTable varietyVernacularNames = + $VarietyVernacularNamesTable(this); + late final $SpeciesTable species = $SpeciesTable(this); + late final $SpeciesCommonNamesTable speciesCommonNames = + $SpeciesCommonNamesTable(this); + late final $LotsTable lots = $LotsTable(this); + late final $GerminationTestsTable germinationTests = $GerminationTestsTable( + this, + ); + late final $MovementsTable movements = $MovementsTable(this); + late final $PartiesTable parties = $PartiesTable(this); + late final $AttachmentsTable attachments = $AttachmentsTable(this); + late final $ExternalLinksTable externalLinks = $ExternalLinksTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + varieties, + varietyVernacularNames, + species, + speciesCommonNames, + lots, + germinationTests, + movements, + parties, + attachments, + externalLinks, + ]; +} + +typedef $$VarietiesTableCreateCompanionBuilder = + VarietiesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String label, + Value speciesId, + Value cultivarName, + Value category, + Value notes, + Value rowid, + }); +typedef $$VarietiesTableUpdateCompanionBuilder = + VarietiesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value label, + Value speciesId, + Value cultivarName, + Value category, + Value notes, + Value rowid, + }); + +class $$VarietiesTableFilterComposer + extends Composer<_$AppDatabase, $VarietiesTable> { + $$VarietiesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get label => $composableBuilder( + column: $table.label, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get speciesId => $composableBuilder( + column: $table.speciesId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get cultivarName => $composableBuilder( + column: $table.cultivarName, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get category => $composableBuilder( + column: $table.category, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnFilters(column), + ); +} + +class $$VarietiesTableOrderingComposer + extends Composer<_$AppDatabase, $VarietiesTable> { + $$VarietiesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get label => $composableBuilder( + column: $table.label, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get speciesId => $composableBuilder( + column: $table.speciesId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get cultivarName => $composableBuilder( + column: $table.cultivarName, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get category => $composableBuilder( + column: $table.category, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$VarietiesTableAnnotationComposer + extends Composer<_$AppDatabase, $VarietiesTable> { + $$VarietiesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get label => + $composableBuilder(column: $table.label, builder: (column) => column); + + GeneratedColumn get speciesId => + $composableBuilder(column: $table.speciesId, builder: (column) => column); + + GeneratedColumn get cultivarName => $composableBuilder( + column: $table.cultivarName, + builder: (column) => column, + ); + + GeneratedColumn get category => + $composableBuilder(column: $table.category, builder: (column) => column); + + GeneratedColumn get notes => + $composableBuilder(column: $table.notes, builder: (column) => column); +} + +class $$VarietiesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $VarietiesTable, + Variety, + $$VarietiesTableFilterComposer, + $$VarietiesTableOrderingComposer, + $$VarietiesTableAnnotationComposer, + $$VarietiesTableCreateCompanionBuilder, + $$VarietiesTableUpdateCompanionBuilder, + (Variety, BaseReferences<_$AppDatabase, $VarietiesTable, Variety>), + Variety, + PrefetchHooks Function() + > { + $$VarietiesTableTableManager(_$AppDatabase db, $VarietiesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$VarietiesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$VarietiesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$VarietiesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value label = const Value.absent(), + Value speciesId = const Value.absent(), + Value cultivarName = const Value.absent(), + Value category = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => VarietiesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + label: label, + speciesId: speciesId, + cultivarName: cultivarName, + category: category, + notes: notes, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String label, + Value speciesId = const Value.absent(), + Value cultivarName = const Value.absent(), + Value category = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => VarietiesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + label: label, + speciesId: speciesId, + cultivarName: cultivarName, + category: category, + notes: notes, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$VarietiesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $VarietiesTable, + Variety, + $$VarietiesTableFilterComposer, + $$VarietiesTableOrderingComposer, + $$VarietiesTableAnnotationComposer, + $$VarietiesTableCreateCompanionBuilder, + $$VarietiesTableUpdateCompanionBuilder, + (Variety, BaseReferences<_$AppDatabase, $VarietiesTable, Variety>), + Variety, + PrefetchHooks Function() + >; +typedef $$VarietyVernacularNamesTableCreateCompanionBuilder = + VarietyVernacularNamesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String varietyId, + required String name, + Value language, + Value region, + Value rowid, + }); +typedef $$VarietyVernacularNamesTableUpdateCompanionBuilder = + VarietyVernacularNamesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value varietyId, + Value name, + Value language, + Value region, + Value rowid, + }); + +class $$VarietyVernacularNamesTableFilterComposer + extends Composer<_$AppDatabase, $VarietyVernacularNamesTable> { + $$VarietyVernacularNamesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get language => $composableBuilder( + column: $table.language, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get region => $composableBuilder( + column: $table.region, + builder: (column) => ColumnFilters(column), + ); +} + +class $$VarietyVernacularNamesTableOrderingComposer + extends Composer<_$AppDatabase, $VarietyVernacularNamesTable> { + $$VarietyVernacularNamesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get language => $composableBuilder( + column: $table.language, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get region => $composableBuilder( + column: $table.region, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$VarietyVernacularNamesTableAnnotationComposer + extends Composer<_$AppDatabase, $VarietyVernacularNamesTable> { + $$VarietyVernacularNamesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get varietyId => + $composableBuilder(column: $table.varietyId, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get language => + $composableBuilder(column: $table.language, builder: (column) => column); + + GeneratedColumn get region => + $composableBuilder(column: $table.region, builder: (column) => column); +} + +class $$VarietyVernacularNamesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $VarietyVernacularNamesTable, + VarietyVernacularName, + $$VarietyVernacularNamesTableFilterComposer, + $$VarietyVernacularNamesTableOrderingComposer, + $$VarietyVernacularNamesTableAnnotationComposer, + $$VarietyVernacularNamesTableCreateCompanionBuilder, + $$VarietyVernacularNamesTableUpdateCompanionBuilder, + ( + VarietyVernacularName, + BaseReferences< + _$AppDatabase, + $VarietyVernacularNamesTable, + VarietyVernacularName + >, + ), + VarietyVernacularName, + PrefetchHooks Function() + > { + $$VarietyVernacularNamesTableTableManager( + _$AppDatabase db, + $VarietyVernacularNamesTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$VarietyVernacularNamesTableFilterComposer( + $db: db, + $table: table, + ), + createOrderingComposer: () => + $$VarietyVernacularNamesTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$VarietyVernacularNamesTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value varietyId = const Value.absent(), + Value name = const Value.absent(), + Value language = const Value.absent(), + Value region = const Value.absent(), + Value rowid = const Value.absent(), + }) => VarietyVernacularNamesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + name: name, + language: language, + region: region, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String varietyId, + required String name, + Value language = const Value.absent(), + Value region = const Value.absent(), + Value rowid = const Value.absent(), + }) => VarietyVernacularNamesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + name: name, + language: language, + region: region, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$VarietyVernacularNamesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $VarietyVernacularNamesTable, + VarietyVernacularName, + $$VarietyVernacularNamesTableFilterComposer, + $$VarietyVernacularNamesTableOrderingComposer, + $$VarietyVernacularNamesTableAnnotationComposer, + $$VarietyVernacularNamesTableCreateCompanionBuilder, + $$VarietyVernacularNamesTableUpdateCompanionBuilder, + ( + VarietyVernacularName, + BaseReferences< + _$AppDatabase, + $VarietyVernacularNamesTable, + VarietyVernacularName + >, + ), + VarietyVernacularName, + PrefetchHooks Function() + >; +typedef $$SpeciesTableCreateCompanionBuilder = + SpeciesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String scientificName, + Value wikidataQid, + Value gbifKey, + Value family, + Value isBundled, + Value rowid, + }); +typedef $$SpeciesTableUpdateCompanionBuilder = + SpeciesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value scientificName, + Value wikidataQid, + Value gbifKey, + Value family, + Value isBundled, + Value rowid, + }); + +class $$SpeciesTableFilterComposer + extends Composer<_$AppDatabase, $SpeciesTable> { + $$SpeciesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get scientificName => $composableBuilder( + column: $table.scientificName, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get wikidataQid => $composableBuilder( + column: $table.wikidataQid, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get gbifKey => $composableBuilder( + column: $table.gbifKey, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get family => $composableBuilder( + column: $table.family, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isBundled => $composableBuilder( + column: $table.isBundled, + builder: (column) => ColumnFilters(column), + ); +} + +class $$SpeciesTableOrderingComposer + extends Composer<_$AppDatabase, $SpeciesTable> { + $$SpeciesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get scientificName => $composableBuilder( + column: $table.scientificName, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get wikidataQid => $composableBuilder( + column: $table.wikidataQid, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get gbifKey => $composableBuilder( + column: $table.gbifKey, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get family => $composableBuilder( + column: $table.family, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isBundled => $composableBuilder( + column: $table.isBundled, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$SpeciesTableAnnotationComposer + extends Composer<_$AppDatabase, $SpeciesTable> { + $$SpeciesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get scientificName => $composableBuilder( + column: $table.scientificName, + builder: (column) => column, + ); + + GeneratedColumn get wikidataQid => $composableBuilder( + column: $table.wikidataQid, + builder: (column) => column, + ); + + GeneratedColumn get gbifKey => + $composableBuilder(column: $table.gbifKey, builder: (column) => column); + + GeneratedColumn get family => + $composableBuilder(column: $table.family, builder: (column) => column); + + GeneratedColumn get isBundled => + $composableBuilder(column: $table.isBundled, builder: (column) => column); +} + +class $$SpeciesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $SpeciesTable, + Specy, + $$SpeciesTableFilterComposer, + $$SpeciesTableOrderingComposer, + $$SpeciesTableAnnotationComposer, + $$SpeciesTableCreateCompanionBuilder, + $$SpeciesTableUpdateCompanionBuilder, + (Specy, BaseReferences<_$AppDatabase, $SpeciesTable, Specy>), + Specy, + PrefetchHooks Function() + > { + $$SpeciesTableTableManager(_$AppDatabase db, $SpeciesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$SpeciesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$SpeciesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$SpeciesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value scientificName = const Value.absent(), + Value wikidataQid = const Value.absent(), + Value gbifKey = const Value.absent(), + Value family = const Value.absent(), + Value isBundled = const Value.absent(), + Value rowid = const Value.absent(), + }) => SpeciesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + scientificName: scientificName, + wikidataQid: wikidataQid, + gbifKey: gbifKey, + family: family, + isBundled: isBundled, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String scientificName, + Value wikidataQid = const Value.absent(), + Value gbifKey = const Value.absent(), + Value family = const Value.absent(), + Value isBundled = const Value.absent(), + Value rowid = const Value.absent(), + }) => SpeciesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + scientificName: scientificName, + wikidataQid: wikidataQid, + gbifKey: gbifKey, + family: family, + isBundled: isBundled, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$SpeciesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $SpeciesTable, + Specy, + $$SpeciesTableFilterComposer, + $$SpeciesTableOrderingComposer, + $$SpeciesTableAnnotationComposer, + $$SpeciesTableCreateCompanionBuilder, + $$SpeciesTableUpdateCompanionBuilder, + (Specy, BaseReferences<_$AppDatabase, $SpeciesTable, Specy>), + Specy, + PrefetchHooks Function() + >; +typedef $$SpeciesCommonNamesTableCreateCompanionBuilder = + SpeciesCommonNamesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String speciesId, + required String name, + Value language, + Value rowid, + }); +typedef $$SpeciesCommonNamesTableUpdateCompanionBuilder = + SpeciesCommonNamesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value speciesId, + Value name, + Value language, + Value rowid, + }); + +class $$SpeciesCommonNamesTableFilterComposer + extends Composer<_$AppDatabase, $SpeciesCommonNamesTable> { + $$SpeciesCommonNamesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get speciesId => $composableBuilder( + column: $table.speciesId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get language => $composableBuilder( + column: $table.language, + builder: (column) => ColumnFilters(column), + ); +} + +class $$SpeciesCommonNamesTableOrderingComposer + extends Composer<_$AppDatabase, $SpeciesCommonNamesTable> { + $$SpeciesCommonNamesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get speciesId => $composableBuilder( + column: $table.speciesId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get language => $composableBuilder( + column: $table.language, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$SpeciesCommonNamesTableAnnotationComposer + extends Composer<_$AppDatabase, $SpeciesCommonNamesTable> { + $$SpeciesCommonNamesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get speciesId => + $composableBuilder(column: $table.speciesId, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get language => + $composableBuilder(column: $table.language, builder: (column) => column); +} + +class $$SpeciesCommonNamesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $SpeciesCommonNamesTable, + SpeciesCommonName, + $$SpeciesCommonNamesTableFilterComposer, + $$SpeciesCommonNamesTableOrderingComposer, + $$SpeciesCommonNamesTableAnnotationComposer, + $$SpeciesCommonNamesTableCreateCompanionBuilder, + $$SpeciesCommonNamesTableUpdateCompanionBuilder, + ( + SpeciesCommonName, + BaseReferences< + _$AppDatabase, + $SpeciesCommonNamesTable, + SpeciesCommonName + >, + ), + SpeciesCommonName, + PrefetchHooks Function() + > { + $$SpeciesCommonNamesTableTableManager( + _$AppDatabase db, + $SpeciesCommonNamesTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$SpeciesCommonNamesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$SpeciesCommonNamesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$SpeciesCommonNamesTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value speciesId = const Value.absent(), + Value name = const Value.absent(), + Value language = const Value.absent(), + Value rowid = const Value.absent(), + }) => SpeciesCommonNamesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + speciesId: speciesId, + name: name, + language: language, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String speciesId, + required String name, + Value language = const Value.absent(), + Value rowid = const Value.absent(), + }) => SpeciesCommonNamesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + speciesId: speciesId, + name: name, + language: language, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$SpeciesCommonNamesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $SpeciesCommonNamesTable, + SpeciesCommonName, + $$SpeciesCommonNamesTableFilterComposer, + $$SpeciesCommonNamesTableOrderingComposer, + $$SpeciesCommonNamesTableAnnotationComposer, + $$SpeciesCommonNamesTableCreateCompanionBuilder, + $$SpeciesCommonNamesTableUpdateCompanionBuilder, + ( + SpeciesCommonName, + BaseReferences< + _$AppDatabase, + $SpeciesCommonNamesTable, + SpeciesCommonName + >, + ), + SpeciesCommonName, + PrefetchHooks Function() + >; +typedef $$LotsTableCreateCompanionBuilder = + LotsCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String varietyId, + Value harvestYear, + Value quantityKind, + Value quantityPrecise, + Value quantityLabel, + Value storageLocation, + Value offerStatus, + Value seedbankId, + Value rowid, + }); +typedef $$LotsTableUpdateCompanionBuilder = + LotsCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value varietyId, + Value harvestYear, + Value quantityKind, + Value quantityPrecise, + Value quantityLabel, + Value storageLocation, + Value offerStatus, + Value seedbankId, + Value rowid, + }); + +class $$LotsTableFilterComposer extends Composer<_$AppDatabase, $LotsTable> { + $$LotsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get harvestYear => $composableBuilder( + column: $table.harvestYear, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get storageLocation => $composableBuilder( + column: $table.storageLocation, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters + get offerStatus => $composableBuilder( + column: $table.offerStatus, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get seedbankId => $composableBuilder( + column: $table.seedbankId, + builder: (column) => ColumnFilters(column), + ); +} + +class $$LotsTableOrderingComposer extends Composer<_$AppDatabase, $LotsTable> { + $$LotsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get harvestYear => $composableBuilder( + column: $table.harvestYear, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get storageLocation => $composableBuilder( + column: $table.storageLocation, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get offerStatus => $composableBuilder( + column: $table.offerStatus, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get seedbankId => $composableBuilder( + column: $table.seedbankId, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$LotsTableAnnotationComposer + extends Composer<_$AppDatabase, $LotsTable> { + $$LotsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get varietyId => + $composableBuilder(column: $table.varietyId, builder: (column) => column); + + GeneratedColumn get harvestYear => $composableBuilder( + column: $table.harvestYear, + builder: (column) => column, + ); + + GeneratedColumn get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => column, + ); + + GeneratedColumn get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => column, + ); + + GeneratedColumn get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => column, + ); + + GeneratedColumn get storageLocation => $composableBuilder( + column: $table.storageLocation, + builder: (column) => column, + ); + + GeneratedColumnWithTypeConverter get offerStatus => + $composableBuilder( + column: $table.offerStatus, + builder: (column) => column, + ); + + GeneratedColumn get seedbankId => $composableBuilder( + column: $table.seedbankId, + builder: (column) => column, + ); +} + +class $$LotsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $LotsTable, + Lot, + $$LotsTableFilterComposer, + $$LotsTableOrderingComposer, + $$LotsTableAnnotationComposer, + $$LotsTableCreateCompanionBuilder, + $$LotsTableUpdateCompanionBuilder, + (Lot, BaseReferences<_$AppDatabase, $LotsTable, Lot>), + Lot, + PrefetchHooks Function() + > { + $$LotsTableTableManager(_$AppDatabase db, $LotsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$LotsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$LotsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$LotsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value varietyId = const Value.absent(), + Value harvestYear = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value storageLocation = const Value.absent(), + Value offerStatus = const Value.absent(), + Value seedbankId = const Value.absent(), + Value rowid = const Value.absent(), + }) => LotsCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + harvestYear: harvestYear, + quantityKind: quantityKind, + quantityPrecise: quantityPrecise, + quantityLabel: quantityLabel, + storageLocation: storageLocation, + offerStatus: offerStatus, + seedbankId: seedbankId, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String varietyId, + Value harvestYear = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value storageLocation = const Value.absent(), + Value offerStatus = const Value.absent(), + Value seedbankId = const Value.absent(), + Value rowid = const Value.absent(), + }) => LotsCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + harvestYear: harvestYear, + quantityKind: quantityKind, + quantityPrecise: quantityPrecise, + quantityLabel: quantityLabel, + storageLocation: storageLocation, + offerStatus: offerStatus, + seedbankId: seedbankId, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$LotsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $LotsTable, + Lot, + $$LotsTableFilterComposer, + $$LotsTableOrderingComposer, + $$LotsTableAnnotationComposer, + $$LotsTableCreateCompanionBuilder, + $$LotsTableUpdateCompanionBuilder, + (Lot, BaseReferences<_$AppDatabase, $LotsTable, Lot>), + Lot, + PrefetchHooks Function() + >; +typedef $$GerminationTestsTableCreateCompanionBuilder = + GerminationTestsCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String lotId, + Value testedOn, + Value sampleSize, + Value germinatedCount, + Value notes, + Value rowid, + }); +typedef $$GerminationTestsTableUpdateCompanionBuilder = + GerminationTestsCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value lotId, + Value testedOn, + Value sampleSize, + Value germinatedCount, + Value notes, + Value rowid, + }); + +class $$GerminationTestsTableFilterComposer + extends Composer<_$AppDatabase, $GerminationTestsTable> { + $$GerminationTestsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lotId => $composableBuilder( + column: $table.lotId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get testedOn => $composableBuilder( + column: $table.testedOn, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sampleSize => $composableBuilder( + column: $table.sampleSize, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get germinatedCount => $composableBuilder( + column: $table.germinatedCount, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnFilters(column), + ); +} + +class $$GerminationTestsTableOrderingComposer + extends Composer<_$AppDatabase, $GerminationTestsTable> { + $$GerminationTestsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lotId => $composableBuilder( + column: $table.lotId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get testedOn => $composableBuilder( + column: $table.testedOn, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sampleSize => $composableBuilder( + column: $table.sampleSize, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get germinatedCount => $composableBuilder( + column: $table.germinatedCount, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$GerminationTestsTableAnnotationComposer + extends Composer<_$AppDatabase, $GerminationTestsTable> { + $$GerminationTestsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get lotId => + $composableBuilder(column: $table.lotId, builder: (column) => column); + + GeneratedColumn get testedOn => + $composableBuilder(column: $table.testedOn, builder: (column) => column); + + GeneratedColumn get sampleSize => $composableBuilder( + column: $table.sampleSize, + builder: (column) => column, + ); + + GeneratedColumn get germinatedCount => $composableBuilder( + column: $table.germinatedCount, + builder: (column) => column, + ); + + GeneratedColumn get notes => + $composableBuilder(column: $table.notes, builder: (column) => column); +} + +class $$GerminationTestsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $GerminationTestsTable, + GerminationTest, + $$GerminationTestsTableFilterComposer, + $$GerminationTestsTableOrderingComposer, + $$GerminationTestsTableAnnotationComposer, + $$GerminationTestsTableCreateCompanionBuilder, + $$GerminationTestsTableUpdateCompanionBuilder, + ( + GerminationTest, + BaseReferences< + _$AppDatabase, + $GerminationTestsTable, + GerminationTest + >, + ), + GerminationTest, + PrefetchHooks Function() + > { + $$GerminationTestsTableTableManager( + _$AppDatabase db, + $GerminationTestsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$GerminationTestsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$GerminationTestsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$GerminationTestsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value lotId = const Value.absent(), + Value testedOn = const Value.absent(), + Value sampleSize = const Value.absent(), + Value germinatedCount = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => GerminationTestsCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + lotId: lotId, + testedOn: testedOn, + sampleSize: sampleSize, + germinatedCount: germinatedCount, + notes: notes, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String lotId, + Value testedOn = const Value.absent(), + Value sampleSize = const Value.absent(), + Value germinatedCount = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => GerminationTestsCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + lotId: lotId, + testedOn: testedOn, + sampleSize: sampleSize, + germinatedCount: germinatedCount, + notes: notes, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$GerminationTestsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $GerminationTestsTable, + GerminationTest, + $$GerminationTestsTableFilterComposer, + $$GerminationTestsTableOrderingComposer, + $$GerminationTestsTableAnnotationComposer, + $$GerminationTestsTableCreateCompanionBuilder, + $$GerminationTestsTableUpdateCompanionBuilder, + ( + GerminationTest, + BaseReferences<_$AppDatabase, $GerminationTestsTable, GerminationTest>, + ), + GerminationTest, + PrefetchHooks Function() + >; +typedef $$MovementsTableCreateCompanionBuilder = + MovementsCompanion Function({ + required String id, + required int createdAt, + required String lastAuthor, + Value schemaRowVersion, + required String lotId, + required MovementType type, + Value occurredOn, + Value counterpartyId, + Value quantityKind, + Value quantityPrecise, + Value quantityLabel, + Value parentMovementId, + Value plantareId, + Value notes, + Value rowid, + }); +typedef $$MovementsTableUpdateCompanionBuilder = + MovementsCompanion Function({ + Value id, + Value createdAt, + Value lastAuthor, + Value schemaRowVersion, + Value lotId, + Value type, + Value occurredOn, + Value counterpartyId, + Value quantityKind, + Value quantityPrecise, + Value quantityLabel, + Value parentMovementId, + Value plantareId, + Value notes, + Value rowid, + }); + +class $$MovementsTableFilterComposer + extends Composer<_$AppDatabase, $MovementsTable> { + $$MovementsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lotId => $composableBuilder( + column: $table.lotId, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters get type => + $composableBuilder( + column: $table.type, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get occurredOn => $composableBuilder( + column: $table.occurredOn, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get counterpartyId => $composableBuilder( + column: $table.counterpartyId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get parentMovementId => $composableBuilder( + column: $table.parentMovementId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get plantareId => $composableBuilder( + column: $table.plantareId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnFilters(column), + ); +} + +class $$MovementsTableOrderingComposer + extends Composer<_$AppDatabase, $MovementsTable> { + $$MovementsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lotId => $composableBuilder( + column: $table.lotId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get occurredOn => $composableBuilder( + column: $table.occurredOn, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get counterpartyId => $composableBuilder( + column: $table.counterpartyId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get parentMovementId => $composableBuilder( + column: $table.parentMovementId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get plantareId => $composableBuilder( + column: $table.plantareId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$MovementsTableAnnotationComposer + extends Composer<_$AppDatabase, $MovementsTable> { + $$MovementsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get lotId => + $composableBuilder(column: $table.lotId, builder: (column) => column); + + GeneratedColumnWithTypeConverter get type => + $composableBuilder(column: $table.type, builder: (column) => column); + + GeneratedColumn get occurredOn => $composableBuilder( + column: $table.occurredOn, + builder: (column) => column, + ); + + GeneratedColumn get counterpartyId => $composableBuilder( + column: $table.counterpartyId, + builder: (column) => column, + ); + + GeneratedColumn get quantityKind => $composableBuilder( + column: $table.quantityKind, + builder: (column) => column, + ); + + GeneratedColumn get quantityPrecise => $composableBuilder( + column: $table.quantityPrecise, + builder: (column) => column, + ); + + GeneratedColumn get quantityLabel => $composableBuilder( + column: $table.quantityLabel, + builder: (column) => column, + ); + + GeneratedColumn get parentMovementId => $composableBuilder( + column: $table.parentMovementId, + builder: (column) => column, + ); + + GeneratedColumn get plantareId => $composableBuilder( + column: $table.plantareId, + builder: (column) => column, + ); + + GeneratedColumn get notes => + $composableBuilder(column: $table.notes, builder: (column) => column); +} + +class $$MovementsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $MovementsTable, + Movement, + $$MovementsTableFilterComposer, + $$MovementsTableOrderingComposer, + $$MovementsTableAnnotationComposer, + $$MovementsTableCreateCompanionBuilder, + $$MovementsTableUpdateCompanionBuilder, + (Movement, BaseReferences<_$AppDatabase, $MovementsTable, Movement>), + Movement, + PrefetchHooks Function() + > { + $$MovementsTableTableManager(_$AppDatabase db, $MovementsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$MovementsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$MovementsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$MovementsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value lotId = const Value.absent(), + Value type = const Value.absent(), + Value occurredOn = const Value.absent(), + Value counterpartyId = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value parentMovementId = const Value.absent(), + Value plantareId = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => MovementsCompanion( + id: id, + createdAt: createdAt, + lastAuthor: lastAuthor, + schemaRowVersion: schemaRowVersion, + lotId: lotId, + type: type, + occurredOn: occurredOn, + counterpartyId: counterpartyId, + quantityKind: quantityKind, + quantityPrecise: quantityPrecise, + quantityLabel: quantityLabel, + parentMovementId: parentMovementId, + plantareId: plantareId, + notes: notes, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String lastAuthor, + Value schemaRowVersion = const Value.absent(), + required String lotId, + required MovementType type, + Value occurredOn = const Value.absent(), + Value counterpartyId = const Value.absent(), + Value quantityKind = const Value.absent(), + Value quantityPrecise = const Value.absent(), + Value quantityLabel = const Value.absent(), + Value parentMovementId = const Value.absent(), + Value plantareId = const Value.absent(), + Value notes = const Value.absent(), + Value rowid = const Value.absent(), + }) => MovementsCompanion.insert( + id: id, + createdAt: createdAt, + lastAuthor: lastAuthor, + schemaRowVersion: schemaRowVersion, + lotId: lotId, + type: type, + occurredOn: occurredOn, + counterpartyId: counterpartyId, + quantityKind: quantityKind, + quantityPrecise: quantityPrecise, + quantityLabel: quantityLabel, + parentMovementId: parentMovementId, + plantareId: plantareId, + notes: notes, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$MovementsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $MovementsTable, + Movement, + $$MovementsTableFilterComposer, + $$MovementsTableOrderingComposer, + $$MovementsTableAnnotationComposer, + $$MovementsTableCreateCompanionBuilder, + $$MovementsTableUpdateCompanionBuilder, + (Movement, BaseReferences<_$AppDatabase, $MovementsTable, Movement>), + Movement, + PrefetchHooks Function() + >; +typedef $$PartiesTableCreateCompanionBuilder = + PartiesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required String displayName, + Value publicKey, + Value kind, + Value note, + Value rowid, + }); +typedef $$PartiesTableUpdateCompanionBuilder = + PartiesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value displayName, + Value publicKey, + Value kind, + Value note, + Value rowid, + }); + +class $$PartiesTableFilterComposer + extends Composer<_$AppDatabase, $PartiesTable> { + $$PartiesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get displayName => $composableBuilder( + column: $table.displayName, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get publicKey => $composableBuilder( + column: $table.publicKey, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters get kind => + $composableBuilder( + column: $table.kind, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get note => $composableBuilder( + column: $table.note, + builder: (column) => ColumnFilters(column), + ); +} + +class $$PartiesTableOrderingComposer + extends Composer<_$AppDatabase, $PartiesTable> { + $$PartiesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get displayName => $composableBuilder( + column: $table.displayName, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get publicKey => $composableBuilder( + column: $table.publicKey, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get kind => $composableBuilder( + column: $table.kind, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get note => $composableBuilder( + column: $table.note, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$PartiesTableAnnotationComposer + extends Composer<_$AppDatabase, $PartiesTable> { + $$PartiesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get displayName => $composableBuilder( + column: $table.displayName, + builder: (column) => column, + ); + + GeneratedColumn get publicKey => + $composableBuilder(column: $table.publicKey, builder: (column) => column); + + GeneratedColumnWithTypeConverter get kind => + $composableBuilder(column: $table.kind, builder: (column) => column); + + GeneratedColumn get note => + $composableBuilder(column: $table.note, builder: (column) => column); +} + +class $$PartiesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $PartiesTable, + Party, + $$PartiesTableFilterComposer, + $$PartiesTableOrderingComposer, + $$PartiesTableAnnotationComposer, + $$PartiesTableCreateCompanionBuilder, + $$PartiesTableUpdateCompanionBuilder, + (Party, BaseReferences<_$AppDatabase, $PartiesTable, Party>), + Party, + PrefetchHooks Function() + > { + $$PartiesTableTableManager(_$AppDatabase db, $PartiesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$PartiesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$PartiesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$PartiesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value displayName = const Value.absent(), + Value publicKey = const Value.absent(), + Value kind = const Value.absent(), + Value note = const Value.absent(), + Value rowid = const Value.absent(), + }) => PartiesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + displayName: displayName, + publicKey: publicKey, + kind: kind, + note: note, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required String displayName, + Value publicKey = const Value.absent(), + Value kind = const Value.absent(), + Value note = const Value.absent(), + Value rowid = const Value.absent(), + }) => PartiesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + displayName: displayName, + publicKey: publicKey, + kind: kind, + note: note, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$PartiesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $PartiesTable, + Party, + $$PartiesTableFilterComposer, + $$PartiesTableOrderingComposer, + $$PartiesTableAnnotationComposer, + $$PartiesTableCreateCompanionBuilder, + $$PartiesTableUpdateCompanionBuilder, + (Party, BaseReferences<_$AppDatabase, $PartiesTable, Party>), + Party, + PrefetchHooks Function() + >; +typedef $$AttachmentsTableCreateCompanionBuilder = + AttachmentsCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required ParentType parentType, + required String parentId, + required AttachmentKind kind, + Value uri, + Value bytes, + Value mimeType, + Value rowid, + }); +typedef $$AttachmentsTableUpdateCompanionBuilder = + AttachmentsCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value parentType, + Value parentId, + Value kind, + Value uri, + Value bytes, + Value mimeType, + Value rowid, + }); + +class $$AttachmentsTableFilterComposer + extends Composer<_$AppDatabase, $AttachmentsTable> { + $$AttachmentsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters + get parentType => $composableBuilder( + column: $table.parentType, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get parentId => $composableBuilder( + column: $table.parentId, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters + get kind => $composableBuilder( + column: $table.kind, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get uri => $composableBuilder( + column: $table.uri, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get bytes => $composableBuilder( + column: $table.bytes, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get mimeType => $composableBuilder( + column: $table.mimeType, + builder: (column) => ColumnFilters(column), + ); +} + +class $$AttachmentsTableOrderingComposer + extends Composer<_$AppDatabase, $AttachmentsTable> { + $$AttachmentsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get parentType => $composableBuilder( + column: $table.parentType, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get parentId => $composableBuilder( + column: $table.parentId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get kind => $composableBuilder( + column: $table.kind, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get uri => $composableBuilder( + column: $table.uri, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get bytes => $composableBuilder( + column: $table.bytes, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get mimeType => $composableBuilder( + column: $table.mimeType, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$AttachmentsTableAnnotationComposer + extends Composer<_$AppDatabase, $AttachmentsTable> { + $$AttachmentsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumnWithTypeConverter get parentType => + $composableBuilder( + column: $table.parentType, + builder: (column) => column, + ); + + GeneratedColumn get parentId => + $composableBuilder(column: $table.parentId, builder: (column) => column); + + GeneratedColumnWithTypeConverter get kind => + $composableBuilder(column: $table.kind, builder: (column) => column); + + GeneratedColumn get uri => + $composableBuilder(column: $table.uri, builder: (column) => column); + + GeneratedColumn get bytes => + $composableBuilder(column: $table.bytes, builder: (column) => column); + + GeneratedColumn get mimeType => + $composableBuilder(column: $table.mimeType, builder: (column) => column); +} + +class $$AttachmentsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $AttachmentsTable, + Attachment, + $$AttachmentsTableFilterComposer, + $$AttachmentsTableOrderingComposer, + $$AttachmentsTableAnnotationComposer, + $$AttachmentsTableCreateCompanionBuilder, + $$AttachmentsTableUpdateCompanionBuilder, + ( + Attachment, + BaseReferences<_$AppDatabase, $AttachmentsTable, Attachment>, + ), + Attachment, + PrefetchHooks Function() + > { + $$AttachmentsTableTableManager(_$AppDatabase db, $AttachmentsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$AttachmentsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$AttachmentsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$AttachmentsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value parentType = const Value.absent(), + Value parentId = const Value.absent(), + Value kind = const Value.absent(), + Value uri = const Value.absent(), + Value bytes = const Value.absent(), + Value mimeType = const Value.absent(), + Value rowid = const Value.absent(), + }) => AttachmentsCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + parentType: parentType, + parentId: parentId, + kind: kind, + uri: uri, + bytes: bytes, + mimeType: mimeType, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required ParentType parentType, + required String parentId, + required AttachmentKind kind, + Value uri = const Value.absent(), + Value bytes = const Value.absent(), + Value mimeType = const Value.absent(), + Value rowid = const Value.absent(), + }) => AttachmentsCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + parentType: parentType, + parentId: parentId, + kind: kind, + uri: uri, + bytes: bytes, + mimeType: mimeType, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$AttachmentsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $AttachmentsTable, + Attachment, + $$AttachmentsTableFilterComposer, + $$AttachmentsTableOrderingComposer, + $$AttachmentsTableAnnotationComposer, + $$AttachmentsTableCreateCompanionBuilder, + $$AttachmentsTableUpdateCompanionBuilder, + ( + Attachment, + BaseReferences<_$AppDatabase, $AttachmentsTable, Attachment>, + ), + Attachment, + PrefetchHooks Function() + >; +typedef $$ExternalLinksTableCreateCompanionBuilder = + ExternalLinksCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + required ParentType parentType, + required String parentId, + required String url, + Value title, + Value rowid, + }); +typedef $$ExternalLinksTableUpdateCompanionBuilder = + ExternalLinksCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value parentType, + Value parentId, + Value url, + Value title, + Value rowid, + }); + +class $$ExternalLinksTableFilterComposer + extends Composer<_$AppDatabase, $ExternalLinksTable> { + $$ExternalLinksTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters + get parentType => $composableBuilder( + column: $table.parentType, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get parentId => $composableBuilder( + column: $table.parentId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get url => $composableBuilder( + column: $table.url, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get title => $composableBuilder( + column: $table.title, + builder: (column) => ColumnFilters(column), + ); +} + +class $$ExternalLinksTableOrderingComposer + extends Composer<_$AppDatabase, $ExternalLinksTable> { + $$ExternalLinksTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get parentType => $composableBuilder( + column: $table.parentType, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get parentId => $composableBuilder( + column: $table.parentId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get url => $composableBuilder( + column: $table.url, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get title => $composableBuilder( + column: $table.title, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$ExternalLinksTableAnnotationComposer + extends Composer<_$AppDatabase, $ExternalLinksTable> { + $$ExternalLinksTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumnWithTypeConverter get parentType => + $composableBuilder( + column: $table.parentType, + builder: (column) => column, + ); + + GeneratedColumn get parentId => + $composableBuilder(column: $table.parentId, builder: (column) => column); + + GeneratedColumn get url => + $composableBuilder(column: $table.url, builder: (column) => column); + + GeneratedColumn get title => + $composableBuilder(column: $table.title, builder: (column) => column); +} + +class $$ExternalLinksTableTableManager + extends + RootTableManager< + _$AppDatabase, + $ExternalLinksTable, + ExternalLink, + $$ExternalLinksTableFilterComposer, + $$ExternalLinksTableOrderingComposer, + $$ExternalLinksTableAnnotationComposer, + $$ExternalLinksTableCreateCompanionBuilder, + $$ExternalLinksTableUpdateCompanionBuilder, + ( + ExternalLink, + BaseReferences<_$AppDatabase, $ExternalLinksTable, ExternalLink>, + ), + ExternalLink, + PrefetchHooks Function() + > { + $$ExternalLinksTableTableManager(_$AppDatabase db, $ExternalLinksTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$ExternalLinksTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$ExternalLinksTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$ExternalLinksTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value parentType = const Value.absent(), + Value parentId = const Value.absent(), + Value url = const Value.absent(), + Value title = const Value.absent(), + Value rowid = const Value.absent(), + }) => ExternalLinksCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + parentType: parentType, + parentId: parentId, + url: url, + title: title, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + required ParentType parentType, + required String parentId, + required String url, + Value title = const Value.absent(), + Value rowid = const Value.absent(), + }) => ExternalLinksCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + parentType: parentType, + parentId: parentId, + url: url, + title: title, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$ExternalLinksTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $ExternalLinksTable, + ExternalLink, + $$ExternalLinksTableFilterComposer, + $$ExternalLinksTableOrderingComposer, + $$ExternalLinksTableAnnotationComposer, + $$ExternalLinksTableCreateCompanionBuilder, + $$ExternalLinksTableUpdateCompanionBuilder, + ( + ExternalLink, + BaseReferences<_$AppDatabase, $ExternalLinksTable, ExternalLink>, + ), + ExternalLink, + PrefetchHooks Function() + >; + +class $AppDatabaseManager { + final _$AppDatabase _db; + $AppDatabaseManager(this._db); + $$VarietiesTableTableManager get varieties => + $$VarietiesTableTableManager(_db, _db.varieties); + $$VarietyVernacularNamesTableTableManager get varietyVernacularNames => + $$VarietyVernacularNamesTableTableManager( + _db, + _db.varietyVernacularNames, + ); + $$SpeciesTableTableManager get species => + $$SpeciesTableTableManager(_db, _db.species); + $$SpeciesCommonNamesTableTableManager get speciesCommonNames => + $$SpeciesCommonNamesTableTableManager(_db, _db.speciesCommonNames); + $$LotsTableTableManager get lots => $$LotsTableTableManager(_db, _db.lots); + $$GerminationTestsTableTableManager get germinationTests => + $$GerminationTestsTableTableManager(_db, _db.germinationTests); + $$MovementsTableTableManager get movements => + $$MovementsTableTableManager(_db, _db.movements); + $$PartiesTableTableManager get parties => + $$PartiesTableTableManager(_db, _db.parties); + $$AttachmentsTableTableManager get attachments => + $$AttachmentsTableTableManager(_db, _db.attachments); + $$ExternalLinksTableTableManager get externalLinks => + $$ExternalLinksTableTableManager(_db, _db.externalLinks); +} diff --git a/apps/app_seeds/lib/db/encrypted_executor.dart b/apps/app_seeds/lib/db/encrypted_executor.dart new file mode 100644 index 0000000..b882973 --- /dev/null +++ b/apps/app_seeds/lib/db/encrypted_executor.dart @@ -0,0 +1,61 @@ +import 'dart:ffi'; +import 'dart:io'; + +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart'; +import 'package:sqlite3/open.dart'; +import 'package:sqlite3/sqlite3.dart'; + +/// Routes package:sqlite3 to the **SQLCipher** build instead of plain SQLite. +/// +/// - Android: the bundled SQLCipher `.so` (from sqlcipher_flutter_libs). +/// - Linux: the system `libsqlcipher.so` (dev machines / CI install it). +/// - iOS & macOS: SQLCipher is linked into the app binary — no override needed. +void useSqlCipher() { + open + ..overrideFor(OperatingSystem.android, openCipherOnAndroid) + ..overrideFor(OperatingSystem.linux, _openLinuxCipher); +} + +DynamicLibrary _openLinuxCipher() { + // The dev package ships `libsqlcipher.so`; the runtime package only the + // versioned `libsqlcipher.so.0`. Accept either. + try { + return DynamicLibrary.open('libsqlcipher.so'); + } on ArgumentError { + return DynamicLibrary.open('libsqlcipher.so.0'); + } +} + +/// Opens [file] as an encrypted database using the raw 256-bit [keyHex]. +/// +/// Verifies SQLCipher is actually linked (`PRAGMA cipher_version`) and refuses +/// to fall back to plaintext — enforcing "no plaintext at rest, ever". +QueryExecutor openEncryptedExecutor(File file, String keyHex) { + return LazyDatabase(() async { + if (Platform.isAndroid) { + await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions(); + } + return NativeDatabase.createInBackground( + file, + isolateSetup: useSqlCipher, + setup: (db) => applyKeyAndVerify(db, keyHex), + ); + }); +} + +/// Applies the SQLCipher key to [db] and asserts encryption is active. +/// +/// `x'…'` passes the key as raw bytes, skipping the KDF (our key is already a +/// random 256-bit value from the OS keystore). Exposed for the security test. +void applyKeyAndVerify(Database db, String keyHex) { + db.execute('PRAGMA key = "x\'$keyHex\'";'); + final cipher = db.select('PRAGMA cipher_version;'); + if (cipher.isEmpty) { + throw StateError( + 'SQLCipher is not linked: PRAGMA cipher_version is empty. Encryption at ' + 'rest is mandatory — refusing to open a plaintext database.', + ); + } +} diff --git a/apps/app_seeds/lib/db/enums.dart b/apps/app_seeds/lib/db/enums.dart new file mode 100644 index 0000000..38780a4 --- /dev/null +++ b/apps/app_seeds/lib/db/enums.dart @@ -0,0 +1,27 @@ +// Domain enums stored by **name** (never by index) via Drift `textEnum`, so +// the stored keys are stable across migrations. Per data-model §5.2, values +// may only be appended, never renumbered or reused; when sync arrives, readers +// must tolerate unknown values (map to a safe default). No sync yet in Block 1. + +/// Per-lot visibility (data-model §2.3). Used by the future sharing layer. +enum OfferStatus { private, shared, exchange, sell } + +/// Append-only event kinds on a Lot (data-model §2.4). +enum MovementType { + received, + given, + sown, + harvested, + germinationTest, + split, + discarded, +} + +/// A counterparty is a person or a collective (data-model §2.5). +enum PartyKind { person, collective } + +/// Attachment media kind (data-model §2.1). +enum AttachmentKind { photo, doc } + +/// Polymorphic parent of an Attachment / ExternalLink. +enum ParentType { variety, lot, movement } diff --git a/apps/app_seeds/lib/db/sync_columns.dart b/apps/app_seeds/lib/db/sync_columns.dart new file mode 100644 index 0000000..c85d019 --- /dev/null +++ b/apps/app_seeds/lib/db/sync_columns.dart @@ -0,0 +1,30 @@ +import 'package:drift/drift.dart'; + +/// Common columns on every *mutable* row (data-model §1). Carries the metadata +/// needed to merge across devices later (CRDT), even before sync exists. +/// +/// `updatedAt` stores a packed [Hlc] string; `isDeleted` is a tombstone — +/// rows are never physically deleted, so they can merge correctly. +mixin SyncColumns on Table { + TextColumn get id => text()(); + IntColumn get createdAt => integer()(); + TextColumn get updatedAt => text()(); // packed HLC + TextColumn get lastAuthor => text()(); // public key / device id + BoolColumn get isDeleted => boolean().withDefault(const Constant(false))(); + IntColumn get schemaRowVersion => integer().withDefault(const Constant(1))(); + + @override + Set get primaryKey => {id}; +} + +/// Common columns on *append-only* rows (only `Movement` for now). Immutable +/// events: no `updatedAt`/`isDeleted` — a correction is a new compensating row. +mixin AppendOnlyColumns on Table { + TextColumn get id => text()(); + IntColumn get createdAt => integer()(); + TextColumn get lastAuthor => text()(); + IntColumn get schemaRowVersion => integer().withDefault(const Constant(1))(); + + @override + Set get primaryKey => {id}; +} diff --git a/apps/app_seeds/lib/db/tables.dart b/apps/app_seeds/lib/db/tables.dart new file mode 100644 index 0000000..da3c054 --- /dev/null +++ b/apps/app_seeds/lib/db/tables.dart @@ -0,0 +1,107 @@ +import 'package:drift/drift.dart'; + +import 'enums.dart'; +import 'sync_columns.dart'; + +/// The identity/accession — one row per distinct thing in the inventory. +/// Only [label] is mandatory (progressive disclosure). +class Varieties extends Table with SyncColumns { + TextColumn get label => text()(); + TextColumn get speciesId => text().nullable()(); // → Species + TextColumn get cultivarName => text().nullable()(); + TextColumn get category => + text().nullable()(); // free text, prefilled from family + TextColumn get notes => text().nullable()(); +} + +/// The multiple common names of a Variety (separate table so concurrent adds +/// merge as a set). +class VarietyVernacularNames extends Table with SyncColumns { + TextColumn get varietyId => text()(); + TextColumn get name => text()(); + TextColumn get language => text().nullable()(); + TextColumn get region => text().nullable()(); +} + +/// Bundled, mostly read-only name catalog (Wikidata CC0 + GBIF CC-BY). +class Species extends Table with SyncColumns { + TextColumn get scientificName => text()(); + TextColumn get wikidataQid => text().nullable()(); + IntColumn get gbifKey => integer().nullable()(); + TextColumn get family => text().nullable()(); + BoolColumn get isBundled => boolean().withDefault(const Constant(false))(); +} + +/// Localized common names for the catalog (bundled). +class SpeciesCommonNames extends Table with SyncColumns { + TextColumn get speciesId => text()(); + TextColumn get name => text()(); + TextColumn get language => text().nullable()(); +} + +/// A homogeneous batch held for a Variety — its own year and its own unit. +/// Quantity (commons_core value type) is flattened into columns here. +class Lots extends Table with SyncColumns { + TextColumn get varietyId => text()(); + IntColumn get harvestYear => integer().nullable()(); + TextColumn get quantityKind => text().nullable()(); // QuantityKind.name + RealColumn get quantityPrecise => real().nullable()(); + TextColumn get quantityLabel => text().nullable()(); + TextColumn get storageLocation => text().nullable()(); + TextColumn get offerStatus => + textEnum().withDefault(const Constant('private'))(); + TextColumn get seedbankId => text().nullable()(); +} + +/// Optional germination history for a Lot; percent is derived in code. +class GerminationTests extends Table with SyncColumns { + TextColumn get lotId => text()(); + IntColumn get testedOn => integer().nullable()(); // date, ms since epoch + IntColumn get sampleSize => integer().nullable()(); + IntColumn get germinatedCount => integer().nullable()(); + TextColumn get notes => text().nullable()(); +} + +/// The append-only event log on a Lot — history + provenance DAG. +class Movements extends Table with AppendOnlyColumns { + TextColumn get lotId => text()(); + TextColumn get type => textEnum()(); + IntColumn get occurredOn => integer().nullable()(); // date, ms since epoch + TextColumn get counterpartyId => text().nullable()(); // → Party + TextColumn get quantityKind => text().nullable()(); + RealColumn get quantityPrecise => real().nullable()(); + TextColumn get quantityLabel => text().nullable()(); + TextColumn get parentMovementId => text().nullable()(); // provenance DAG + TextColumn get plantareId => text().nullable()(); // reserved (social layer) + TextColumn get notes => text().nullable()(); +} + +/// A person or collective you exchange with. +class Parties extends Table with SyncColumns { + TextColumn get displayName => text()(); + TextColumn get publicKey => text().nullable()(); + TextColumn get kind => + textEnum().withDefault(const Constant('person'))(); + TextColumn get note => text().nullable()(); +} + +/// Photos/docs. Polymorphic parent. Photo bytes are stored in-DB (encrypted at +/// rest by SQLCipher) via [bytes]; external files use [uri]. Storing bytes here +/// keeps the "no plaintext at rest" rule for photos in Block 1; an external +/// encrypted file store is a later optimization. +class Attachments extends Table with SyncColumns { + TextColumn get parentType => textEnum()(); + TextColumn get parentId => text()(); + TextColumn get kind => textEnum()(); + TextColumn get uri => text().nullable()(); + BlobColumn get bytes => blob().nullable()(); + TextColumn get mimeType => text().nullable()(); +} + +/// Any pasted URL (Wikipedia, forum…). Polymorphic parent. +class ExternalLinks extends Table with SyncColumns { + TextColumn get parentType => textEnum()(); + TextColumn get parentId => text()(); + TextColumn get url => text()(); + TextColumn get title => text().nullable()(); +} diff --git a/apps/app_seeds/lib/di/injector.dart b/apps/app_seeds/lib/di/injector.dart new file mode 100644 index 0000000..a03ef8c --- /dev/null +++ b/apps/app_seeds/lib/di/injector.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:commons_core/commons_core.dart'; +import 'package:get_it/get_it.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; + +import '../data/variety_repository.dart'; +import '../db/database.dart'; +import '../db/encrypted_executor.dart'; +import '../security/secret_store.dart'; +import '../security/secure_key_store.dart'; + +/// The app's service locator. Kept to the composition root — widgets get their +/// repositories from here (or via BlocProvider), never by reaching into it deep +/// in the tree. +final GetIt getIt = GetIt.instance; + +/// Wires the encrypted DB, keystore and repositories. Call once from `main` +/// before `runApp`; the DB key must exist before the DB opens. +Future configureDependencies() async { + final keyStore = SecureKeyStore(store: FlutterSecretStore()); + final dbKeyHex = await keyStore.databaseKeyHex(); + final rootSeedHex = await keyStore.rootSeedHex(); + + final database = AppDatabase( + openEncryptedExecutor(await _databaseFile(), dbKeyHex), + ); + + // Until real key derivation lands, the node/author id is a stable per-install + // slice of the root seed. It becomes the user's public key in the social layer. + final nodeId = rootSeedHex.substring(0, 16); + + getIt + ..registerSingleton(keyStore) + ..registerSingleton(database) + ..registerSingleton( + VarietyRepository(database, idGen: IdGen(), nodeId: nodeId), + ); +} + +Future _databaseFile() async { + final dir = await getApplicationDocumentsDirectory(); + return File(p.join(dir.path, 'tane_inventory.sqlite')); +} diff --git a/apps/app_seeds/lib/i18n/en.i18n.json b/apps/app_seeds/lib/i18n/en.i18n.json new file mode 100644 index 0000000..14b3f9f --- /dev/null +++ b/apps/app_seeds/lib/i18n/en.i18n.json @@ -0,0 +1,41 @@ +{ + "app": { + "title": "Tanemaki" + }, + "inventory": { + "title": "Inventory", + "searchHint": "Search seeds", + "empty": "No seeds yet. Tap + to add your first.", + "uncategorized": "Uncategorized" + }, + "quickAdd": { + "title": "Add a seed", + "labelField": "Name", + "labelRequired": "Give it a name", + "addPhoto": "Add photo", + "quantity": "How much?", + "more": "Add more…", + "save": "Save", + "cancel": "Cancel" + }, + "quantityKind": { + "aFew": "a few", + "some": "some", + "plenty": "plenty", + "handful": "a handful", + "pinch": "a pinch", + "jar": "a jar", + "packet": "a packet", + "cob": "a cob", + "head": "a head", + "pod": "a pod", + "ear": "an ear", + "fruit": "a fruit", + "bulb": "a bulb", + "tuber": "a tuber", + "seedHead": "a seed head", + "bunch": "a bunch", + "grams": "grams", + "count": "count" + } +} diff --git a/apps/app_seeds/lib/i18n/es.i18n.json b/apps/app_seeds/lib/i18n/es.i18n.json new file mode 100644 index 0000000..5197803 --- /dev/null +++ b/apps/app_seeds/lib/i18n/es.i18n.json @@ -0,0 +1,41 @@ +{ + "app": { + "title": "Tanemaki" + }, + "inventory": { + "title": "Inventario", + "searchHint": "Buscar semillas", + "empty": "Aún no hay semillas. Toca + para añadir la primera.", + "uncategorized": "Sin categoría" + }, + "quickAdd": { + "title": "Añadir una semilla", + "labelField": "Nombre", + "labelRequired": "Ponle un nombre", + "addPhoto": "Añadir foto", + "quantity": "¿Cuánta?", + "more": "Añadir más…", + "save": "Guardar", + "cancel": "Cancelar" + }, + "quantityKind": { + "aFew": "unas pocas", + "some": "algunas", + "plenty": "muchas", + "handful": "un puñado", + "pinch": "una pizca", + "jar": "un tarro", + "packet": "un sobre", + "cob": "una mazorca", + "head": "una cabezuela", + "pod": "una vaina", + "ear": "una espiga", + "fruit": "un fruto", + "bulb": "un bulbo", + "tuber": "un tubérculo", + "seedHead": "una cabeza de semillas", + "bunch": "un manojo", + "grams": "gramos", + "count": "unidades" + } +} diff --git a/apps/app_seeds/lib/i18n/strings.g.dart b/apps/app_seeds/lib/i18n/strings.g.dart new file mode 100644 index 0000000..9e225f8 --- /dev/null +++ b/apps/app_seeds/lib/i18n/strings.g.dart @@ -0,0 +1,173 @@ +/// Generated file. Do not edit. +/// +/// Source: lib/i18n +/// To regenerate, run: `dart run slang` +/// +/// Locales: 2 +/// Strings: 62 (31 per locale) +/// +/// Built on 2026-07-07 at 13:12 UTC + +// coverage:ignore-file +// ignore_for_file: type=lint, unused_import +// dart format off + +import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; +import 'package:slang/generated.dart'; +import 'package:slang_flutter/slang_flutter.dart'; +export 'package:slang_flutter/slang_flutter.dart'; + +import 'strings_es.g.dart' as l_es; +part 'strings_en.g.dart'; + +/// Supported locales. +/// +/// Usage: +/// - LocaleSettings.setLocale(AppLocale.en) // set locale +/// - Locale locale = AppLocale.en.flutterLocale // get flutter locale from enum +/// - if (LocaleSettings.currentLocale == AppLocale.en) // locale check +enum AppLocale with BaseAppLocale { + en(languageCode: 'en'), + es(languageCode: 'es'); + + const AppLocale({ + required this.languageCode, + this.scriptCode, // ignore: unused_element, unused_element_parameter + this.countryCode, // ignore: unused_element, unused_element_parameter + }); + + @override final String languageCode; + @override final String? scriptCode; + @override final String? countryCode; + + @override + Future build({ + Map? overrides, + PluralResolver? cardinalResolver, + PluralResolver? ordinalResolver, + }) async { + return buildSync( + overrides: overrides, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); + } + + @override + Translations buildSync({ + Map? overrides, + PluralResolver? cardinalResolver, + PluralResolver? ordinalResolver, + }) { + switch (this) { + case AppLocale.en: + return TranslationsEn( + overrides: overrides, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); + case AppLocale.es: + return l_es.TranslationsEs( + overrides: overrides, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); + } + } + + /// Gets current instance managed by [LocaleSettings]. + Translations get translations => LocaleSettings.instance.getTranslations(this); +} + +/// Method A: Simple +/// +/// No rebuild after locale change. +/// Translation happens during initialization of the widget (call of t). +/// Configurable via 'translate_var'. +/// +/// Usage: +/// String a = t.someKey.anotherKey; +/// String b = t['someKey.anotherKey']; // Only for edge cases! +Translations get t => LocaleSettings.instance.currentTranslations; + +/// Method B: Advanced +/// +/// All widgets using this method will trigger a rebuild when locale changes. +/// Use this if you have e.g. a settings page where the user can select the locale during runtime. +/// +/// Step 1: +/// wrap your App with +/// TranslationProvider( +/// child: MyApp() +/// ); +/// +/// Step 2: +/// final t = Translations.of(context); // Get t variable. +/// String a = t.someKey.anotherKey; // Use t variable. +/// String b = t['someKey.anotherKey']; // Only for edge cases! +class TranslationProvider extends BaseTranslationProvider { + TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance); + + static InheritedLocaleData of(BuildContext context) => InheritedLocaleData.of(context); +} + +/// Method B shorthand via [BuildContext] extension method. +/// Configurable via 'translate_var'. +/// +/// Usage (e.g. in a widget's build method): +/// context.t.someKey.anotherKey +extension BuildContextTranslationsExtension on BuildContext { + Translations get t => TranslationProvider.of(this).translations; +} + +/// Manages all translation instances and the current locale +class LocaleSettings extends BaseFlutterLocaleSettings { + LocaleSettings._() : super( + utils: AppLocaleUtils.instance, + lazy: false, + ); + + static final instance = LocaleSettings._(); + + // static aliases (checkout base methods for documentation) + static AppLocale get currentLocale => instance.currentLocale; + static Stream getLocaleStream() => instance.getLocaleStream(); + static Future setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale); + static Future setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale); + static Future useDeviceLocale() => instance.useDeviceLocale(); + static Future setPluralResolver({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolver( + language: language, + locale: locale, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); + + // synchronous versions + static AppLocale setLocaleSync(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocaleSync(locale, listenToDeviceLocale: listenToDeviceLocale); + static AppLocale setLocaleRawSync(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRawSync(rawLocale, listenToDeviceLocale: listenToDeviceLocale); + static AppLocale useDeviceLocaleSync() => instance.useDeviceLocaleSync(); + static void setPluralResolverSync({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolverSync( + language: language, + locale: locale, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); +} + +/// Provides utility functions without any side effects. +class AppLocaleUtils extends BaseAppLocaleUtils { + AppLocaleUtils._() : super( + baseLocale: AppLocale.en, + locales: AppLocale.values, + ); + + static final instance = AppLocaleUtils._(); + + // static aliases (checkout base methods for documentation) + static AppLocale parse(String rawLocale) => instance.parse(rawLocale); + static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode); + static AppLocale findDeviceLocale() => instance.findDeviceLocale(); + static List get supportedLocales => instance.supportedLocales; + static List get supportedLocalesRaw => instance.supportedLocalesRaw; +} diff --git a/apps/app_seeds/lib/i18n/strings_en.g.dart b/apps/app_seeds/lib/i18n/strings_en.g.dart new file mode 100644 index 0000000..ed1891f --- /dev/null +++ b/apps/app_seeds/lib/i18n/strings_en.g.dart @@ -0,0 +1,220 @@ +/// +/// Generated file. Do not edit. +/// +// coverage:ignore-file +// ignore_for_file: type=lint, unused_import +// dart format off + +part of 'strings.g.dart'; + +// Path: +typedef TranslationsEn = Translations; // ignore: unused_element +class Translations with BaseTranslations { + /// Returns the current translations of the given [context]. + /// + /// Usage: + /// final t = Translations.of(context); + static Translations of(BuildContext context) => InheritedLocaleData.of(context).translations; + + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + Translations({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver, TranslationMetadata? meta}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = meta ?? TranslationMetadata( + locale: AppLocale.en, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ) { + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + dynamic operator[](String key) => $meta.getTranslation(key); + + late final Translations _root = this; // ignore: unused_field + + Translations $copyWith({TranslationMetadata? meta}) => Translations(meta: meta ?? this.$meta); + + // Translations + late final Translations$app$en app = Translations$app$en.internal(_root); + late final Translations$inventory$en inventory = Translations$inventory$en.internal(_root); + late final Translations$quickAdd$en quickAdd = Translations$quickAdd$en.internal(_root); + late final Translations$quantityKind$en quantityKind = Translations$quantityKind$en.internal(_root); +} + +// Path: app +class Translations$app$en { + Translations$app$en.internal(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Tanemaki' + String get title => 'Tanemaki'; +} + +// Path: inventory +class Translations$inventory$en { + Translations$inventory$en.internal(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Inventory' + String get title => 'Inventory'; + + /// en: 'Search seeds' + String get searchHint => 'Search seeds'; + + /// en: 'No seeds yet. Tap + to add your first.' + String get empty => 'No seeds yet. Tap + to add your first.'; + + /// en: 'Uncategorized' + String get uncategorized => 'Uncategorized'; +} + +// Path: quickAdd +class Translations$quickAdd$en { + Translations$quickAdd$en.internal(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Add a seed' + String get title => 'Add a seed'; + + /// en: 'Name' + String get labelField => 'Name'; + + /// en: 'Give it a name' + String get labelRequired => 'Give it a name'; + + /// en: 'Add photo' + String get addPhoto => 'Add photo'; + + /// en: 'How much?' + String get quantity => 'How much?'; + + /// en: 'Add more…' + String get more => 'Add more…'; + + /// en: 'Save' + String get save => 'Save'; + + /// en: 'Cancel' + String get cancel => 'Cancel'; +} + +// Path: quantityKind +class Translations$quantityKind$en { + Translations$quantityKind$en.internal(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'a few' + String get aFew => 'a few'; + + /// en: 'some' + String get some => 'some'; + + /// en: 'plenty' + String get plenty => 'plenty'; + + /// en: 'a handful' + String get handful => 'a handful'; + + /// en: 'a pinch' + String get pinch => 'a pinch'; + + /// en: 'a jar' + String get jar => 'a jar'; + + /// en: 'a packet' + String get packet => 'a packet'; + + /// en: 'a cob' + String get cob => 'a cob'; + + /// en: 'a head' + String get head => 'a head'; + + /// en: 'a pod' + String get pod => 'a pod'; + + /// en: 'an ear' + String get ear => 'an ear'; + + /// en: 'a fruit' + String get fruit => 'a fruit'; + + /// en: 'a bulb' + String get bulb => 'a bulb'; + + /// en: 'a tuber' + String get tuber => 'a tuber'; + + /// en: 'a seed head' + String get seedHead => 'a seed head'; + + /// en: 'a bunch' + String get bunch => 'a bunch'; + + /// en: 'grams' + String get grams => 'grams'; + + /// en: 'count' + String get count => 'count'; +} + +/// The flat map containing all translations for locale . +/// Only for edge cases! For simple maps, use the map function of this library. +/// +/// The Dart AOT compiler has issues with very large switch statements, +/// so the map is split into smaller functions (512 entries each). +extension on Translations { + dynamic _flatMapFunction(String path) { + return switch (path) { + 'app.title' => 'Tanemaki', + 'inventory.title' => 'Inventory', + 'inventory.searchHint' => 'Search seeds', + 'inventory.empty' => 'No seeds yet. Tap + to add your first.', + 'inventory.uncategorized' => 'Uncategorized', + 'quickAdd.title' => 'Add a seed', + 'quickAdd.labelField' => 'Name', + 'quickAdd.labelRequired' => 'Give it a name', + 'quickAdd.addPhoto' => 'Add photo', + 'quickAdd.quantity' => 'How much?', + 'quickAdd.more' => 'Add more…', + 'quickAdd.save' => 'Save', + 'quickAdd.cancel' => 'Cancel', + 'quantityKind.aFew' => 'a few', + 'quantityKind.some' => 'some', + 'quantityKind.plenty' => 'plenty', + 'quantityKind.handful' => 'a handful', + 'quantityKind.pinch' => 'a pinch', + 'quantityKind.jar' => 'a jar', + 'quantityKind.packet' => 'a packet', + 'quantityKind.cob' => 'a cob', + 'quantityKind.head' => 'a head', + 'quantityKind.pod' => 'a pod', + 'quantityKind.ear' => 'an ear', + 'quantityKind.fruit' => 'a fruit', + 'quantityKind.bulb' => 'a bulb', + 'quantityKind.tuber' => 'a tuber', + 'quantityKind.seedHead' => 'a seed head', + 'quantityKind.bunch' => 'a bunch', + 'quantityKind.grams' => 'grams', + 'quantityKind.count' => 'count', + _ => null, + }; + } +} diff --git a/apps/app_seeds/lib/i18n/strings_es.g.dart b/apps/app_seeds/lib/i18n/strings_es.g.dart new file mode 100644 index 0000000..f2e0dfe --- /dev/null +++ b/apps/app_seeds/lib/i18n/strings_es.g.dart @@ -0,0 +1,157 @@ +/// +/// Generated file. Do not edit. +/// +// coverage:ignore-file +// ignore_for_file: type=lint, unused_import +// dart format off + +import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; +import 'package:slang/generated.dart'; +import 'strings.g.dart'; + +// Path: +class TranslationsEs extends Translations with BaseTranslations { + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + TranslationsEs({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver, TranslationMetadata? meta}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = meta ?? TranslationMetadata( + locale: AppLocale.es, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ), + super(cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver) { + super.$meta.setFlatMapFunction($meta.getTranslation); // copy base translations to super.$meta + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + @override dynamic operator[](String key) => $meta.getTranslation(key) ?? super.$meta.getTranslation(key); + + late final TranslationsEs _root = this; // ignore: unused_field + + @override + TranslationsEs $copyWith({TranslationMetadata? meta}) => TranslationsEs(meta: meta ?? this.$meta); + + // Translations + @override late final _Translations$app$es app = _Translations$app$es._(_root); + @override late final _Translations$inventory$es inventory = _Translations$inventory$es._(_root); + @override late final _Translations$quickAdd$es quickAdd = _Translations$quickAdd$es._(_root); + @override late final _Translations$quantityKind$es quantityKind = _Translations$quantityKind$es._(_root); +} + +// Path: app +class _Translations$app$es extends Translations$app$en { + _Translations$app$es._(TranslationsEs root) : this._root = root, super.internal(root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Tanemaki'; +} + +// Path: inventory +class _Translations$inventory$es extends Translations$inventory$en { + _Translations$inventory$es._(TranslationsEs root) : this._root = root, super.internal(root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Inventario'; + @override String get searchHint => 'Buscar semillas'; + @override String get empty => 'Aún no hay semillas. Toca + para añadir la primera.'; + @override String get uncategorized => 'Sin categoría'; +} + +// Path: quickAdd +class _Translations$quickAdd$es extends Translations$quickAdd$en { + _Translations$quickAdd$es._(TranslationsEs root) : this._root = root, super.internal(root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Añadir una semilla'; + @override String get labelField => 'Nombre'; + @override String get labelRequired => 'Ponle un nombre'; + @override String get addPhoto => 'Añadir foto'; + @override String get quantity => '¿Cuánta?'; + @override String get more => 'Añadir más…'; + @override String get save => 'Guardar'; + @override String get cancel => 'Cancelar'; +} + +// Path: quantityKind +class _Translations$quantityKind$es extends Translations$quantityKind$en { + _Translations$quantityKind$es._(TranslationsEs root) : this._root = root, super.internal(root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get aFew => 'unas pocas'; + @override String get some => 'algunas'; + @override String get plenty => 'muchas'; + @override String get handful => 'un puñado'; + @override String get pinch => 'una pizca'; + @override String get jar => 'un tarro'; + @override String get packet => 'un sobre'; + @override String get cob => 'una mazorca'; + @override String get head => 'una cabezuela'; + @override String get pod => 'una vaina'; + @override String get ear => 'una espiga'; + @override String get fruit => 'un fruto'; + @override String get bulb => 'un bulbo'; + @override String get tuber => 'un tubérculo'; + @override String get seedHead => 'una cabeza de semillas'; + @override String get bunch => 'un manojo'; + @override String get grams => 'gramos'; + @override String get count => 'unidades'; +} + +/// The flat map containing all translations for locale . +/// Only for edge cases! For simple maps, use the map function of this library. +/// +/// The Dart AOT compiler has issues with very large switch statements, +/// so the map is split into smaller functions (512 entries each). +extension on TranslationsEs { + dynamic _flatMapFunction(String path) { + return switch (path) { + 'app.title' => 'Tanemaki', + 'inventory.title' => 'Inventario', + 'inventory.searchHint' => 'Buscar semillas', + 'inventory.empty' => 'Aún no hay semillas. Toca + para añadir la primera.', + 'inventory.uncategorized' => 'Sin categoría', + 'quickAdd.title' => 'Añadir una semilla', + 'quickAdd.labelField' => 'Nombre', + 'quickAdd.labelRequired' => 'Ponle un nombre', + 'quickAdd.addPhoto' => 'Añadir foto', + 'quickAdd.quantity' => '¿Cuánta?', + 'quickAdd.more' => 'Añadir más…', + 'quickAdd.save' => 'Guardar', + 'quickAdd.cancel' => 'Cancelar', + 'quantityKind.aFew' => 'unas pocas', + 'quantityKind.some' => 'algunas', + 'quantityKind.plenty' => 'muchas', + 'quantityKind.handful' => 'un puñado', + 'quantityKind.pinch' => 'una pizca', + 'quantityKind.jar' => 'un tarro', + 'quantityKind.packet' => 'un sobre', + 'quantityKind.cob' => 'una mazorca', + 'quantityKind.head' => 'una cabezuela', + 'quantityKind.pod' => 'una vaina', + 'quantityKind.ear' => 'una espiga', + 'quantityKind.fruit' => 'un fruto', + 'quantityKind.bulb' => 'un bulbo', + 'quantityKind.tuber' => 'un tubérculo', + 'quantityKind.seedHead' => 'una cabeza de semillas', + 'quantityKind.bunch' => 'un manojo', + 'quantityKind.grams' => 'gramos', + 'quantityKind.count' => 'unidades', + _ => null, + }; + } +} diff --git a/apps/app_seeds/lib/main.dart b/apps/app_seeds/lib/main.dart new file mode 100644 index 0000000..b2db26c --- /dev/null +++ b/apps/app_seeds/lib/main.dart @@ -0,0 +1,15 @@ +import 'package:flutter/widgets.dart'; + +import 'app.dart'; +import 'data/variety_repository.dart'; +import 'di/injector.dart'; +import 'i18n/strings.g.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + LocaleSettings.useDeviceLocaleSync(); + await configureDependencies(); + runApp( + TranslationProvider(child: TaneApp(repository: getIt())), + ); +} diff --git a/apps/app_seeds/lib/security/secret_store.dart b/apps/app_seeds/lib/security/secret_store.dart new file mode 100644 index 0000000..5ae48f3 --- /dev/null +++ b/apps/app_seeds/lib/security/secret_store.dart @@ -0,0 +1,27 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +/// Minimal secret key/value store, backed by the OS keystore in production and +/// trivially fakeable in tests. Keeps [SecureKeyStore] free of plugin calls. +abstract class SecretStore { + Future read(String key); + Future write(String key, String value); +} + +/// OS-keystore-backed implementation (Android Keystore / iOS Keychain / etc.). +class FlutterSecretStore implements SecretStore { + FlutterSecretStore([FlutterSecureStorage? storage]) + : _storage = + storage ?? + const FlutterSecureStorage( + aOptions: AndroidOptions(encryptedSharedPreferences: true), + ); + + final FlutterSecureStorage _storage; + + @override + Future read(String key) => _storage.read(key: key); + + @override + Future write(String key, String value) => + _storage.write(key: key, value: value); +} diff --git a/apps/app_seeds/lib/security/secure_key_store.dart b/apps/app_seeds/lib/security/secure_key_store.dart new file mode 100644 index 0000000..5499285 --- /dev/null +++ b/apps/app_seeds/lib/security/secure_key_store.dart @@ -0,0 +1,45 @@ +import 'package:commons_core/commons_core.dart'; + +import 'secret_store.dart'; + +/// Owns the app's secrets in the OS keystore and creates them on first run: +/// +/// - the **DB key**: a random 256-bit symmetric key for SQLCipher (NOT derived +/// from any user password — see CLAUDE.md identity section); +/// - the **root seed**: the Duniter/Ğ1-style identity seed (stub for now). +/// +/// Both are stored as lowercase hex strings. +class SecureKeyStore { + SecureKeyStore({required SecretStore store, IdentityService? identity}) + : _store = store, + _identity = identity ?? IdentityService(); + + final SecretStore _store; + final IdentityService _identity; + + static const dbKeyName = 'tane.db_key'; + static const rootSeedName = 'tane.root_seed'; + static const _dbKeyLengthBytes = 32; + + /// The SQLCipher database key as hex, created and persisted on first access. + Future databaseKeyHex() => + _readOrCreate(dbKeyName, () => randomBytes(_dbKeyLengthBytes)); + + /// The root identity seed as hex, created and persisted on first access. + Future rootSeedHex() => + _readOrCreate(rootSeedName, _identity.generateRootSeed); + + Future _readOrCreate( + String key, + List Function() generate, + ) async { + final existing = await _store.read(key); + if (existing != null) return existing; + final hex = _toHex(generate()); + await _store.write(key, hex); + return hex; + } + + static String _toHex(List bytes) => + bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); +} diff --git a/apps/app_seeds/lib/state/inventory_cubit.dart b/apps/app_seeds/lib/state/inventory_cubit.dart new file mode 100644 index 0000000..725307f --- /dev/null +++ b/apps/app_seeds/lib/state/inventory_cubit.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../data/variety_repository.dart'; + +/// Inventory list state: all items from the DB plus the current search query. +/// [visibleItems] applies the query; grouping by category is done in the UI. +class InventoryState extends Equatable { + const InventoryState({ + this.items = const [], + this.query = '', + this.loading = true, + }); + + final List items; + final String query; + final bool loading; + + List get visibleItems { + if (query.trim().isEmpty) return items; + final q = query.toLowerCase(); + return items.where((i) => i.label.toLowerCase().contains(q)).toList(); + } + + InventoryState copyWith({ + List? items, + String? query, + bool? loading, + }) { + return InventoryState( + items: items ?? this.items, + query: query ?? this.query, + loading: loading ?? this.loading, + ); + } + + @override + List get props => [items, query, loading]; +} + +/// Subscribes to the repository's reactive inventory stream. The list updates +/// automatically after a quick-add — no manual refresh. +class InventoryCubit extends Cubit { + InventoryCubit(this._repo) : super(const InventoryState()) { + _sub = _repo.watchInventory().listen( + (items) => emit(state.copyWith(items: items, loading: false)), + ); + } + + final VarietyRepository _repo; + late final StreamSubscription> _sub; + + void search(String query) => emit(state.copyWith(query: query)); + + @override + Future close() async { + await _sub.cancel(); + return super.close(); + } +} diff --git a/apps/app_seeds/lib/state/quick_add_cubit.dart b/apps/app_seeds/lib/state/quick_add_cubit.dart new file mode 100644 index 0000000..2681318 --- /dev/null +++ b/apps/app_seeds/lib/state/quick_add_cubit.dart @@ -0,0 +1,97 @@ +import 'dart:typed_data'; + +import 'package:commons_core/commons_core.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../data/variety_repository.dart'; + +/// Form state for the quick-add sheet. Only [label] is required; everything +/// else is progressive disclosure behind [expanded]. +class QuickAddState extends Equatable { + const QuickAddState({ + this.label = '', + this.quantityKind, + this.photoBytes, + this.expanded = false, + this.submitting = false, + this.submitted = false, + this.showLabelError = false, + }); + + final String label; + final QuantityKind? quantityKind; + final Uint8List? photoBytes; + final bool expanded; + final bool submitting; + final bool submitted; + final bool showLabelError; + + bool get hasValidLabel => label.trim().isNotEmpty; + + QuickAddState copyWith({ + String? label, + QuantityKind? quantityKind, + Uint8List? photoBytes, + bool? expanded, + bool? submitting, + bool? submitted, + bool? showLabelError, + }) { + return QuickAddState( + label: label ?? this.label, + quantityKind: quantityKind ?? this.quantityKind, + photoBytes: photoBytes ?? this.photoBytes, + expanded: expanded ?? this.expanded, + submitting: submitting ?? this.submitting, + submitted: submitted ?? this.submitted, + showLabelError: showLabelError ?? this.showLabelError, + ); + } + + @override + List get props => [ + label, + quantityKind, + photoBytes, + expanded, + submitting, + submitted, + showLabelError, + ]; +} + +/// Drives the 20-second quick-add flow and persists via [VarietyRepository]. +class QuickAddCubit extends Cubit { + QuickAddCubit(this._repo) : super(const QuickAddState()); + + final VarietyRepository _repo; + + void labelChanged(String value) => + emit(state.copyWith(label: value, showLabelError: false)); + + void selectQuantity(QuantityKind kind) => + emit(state.copyWith(quantityKind: kind)); + + void photoPicked(Uint8List bytes) => emit(state.copyWith(photoBytes: bytes)); + + void toggleExpanded() => emit(state.copyWith(expanded: !state.expanded)); + + /// Validates and saves. No-op (sets [showLabelError]) if the label is empty. + Future submit() async { + if (!state.hasValidLabel) { + emit(state.copyWith(showLabelError: true)); + return; + } + if (state.submitting) return; + emit(state.copyWith(submitting: true)); + await _repo.addQuickVariety( + label: state.label.trim(), + quantity: state.quantityKind == null + ? null + : Quantity(kind: state.quantityKind!), + photoBytes: state.photoBytes, + ); + emit(state.copyWith(submitting: false, submitted: true)); + } +} diff --git a/apps/app_seeds/lib/ui/inventory_list_screen.dart b/apps/app_seeds/lib/ui/inventory_list_screen.dart new file mode 100644 index 0000000..86c26d2 --- /dev/null +++ b/apps/app_seeds/lib/ui/inventory_list_screen.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../data/variety_repository.dart'; +import '../i18n/strings.g.dart'; +import '../state/inventory_cubit.dart'; +import 'quick_add_sheet.dart'; + +/// The inventory home: a searchable list of seeds grouped by category, with a +/// quick-add FAB. Driven by [InventoryCubit] over the encrypted DB stream. +class InventoryListScreen extends StatelessWidget { + const InventoryListScreen({super.key}); + + @override + Widget build(BuildContext context) { + final t = context.t; + return Scaffold( + appBar: AppBar(title: Text(t.inventory.title)), + floatingActionButton: FloatingActionButton( + key: const Key('inventory.addFab'), + tooltip: t.quickAdd.title, + onPressed: () => showQuickAddSheet( + context, + repository: context.read(), + ), + child: const Icon(Icons.add), + ), + body: BlocBuilder( + builder: (context, state) { + if (state.loading) { + return const Center(child: CircularProgressIndicator()); + } + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(12), + child: TextField( + key: const Key('inventory.search'), + decoration: InputDecoration( + hintText: t.inventory.searchHint, + prefixIcon: const Icon(Icons.search), + border: const OutlineInputBorder(), + ), + onChanged: context.read().search, + ), + ), + Expanded(child: _InventoryBody(items: state.visibleItems)), + ], + ); + }, + ), + ); + } +} + +class _InventoryBody extends StatelessWidget { + const _InventoryBody({required this.items}); + + final List items; + + @override + Widget build(BuildContext context) { + final t = context.t; + if (items.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: Text( + t.inventory.empty, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge, + ), + ), + ); + } + + // Items arrive ordered by category then label; insert a header whenever the + // category changes. + final rows = []; + String? currentCategory; + for (final item in items) { + final category = item.category ?? t.inventory.uncategorized; + if (category != currentCategory) { + currentCategory = category; + rows.add(_CategoryHeader(title: category)); + } + rows.add(_VarietyTile(item: item)); + } + return ListView(children: rows); + } +} + +class _CategoryHeader extends StatelessWidget { + const _CategoryHeader({required this.title}); + + final String title; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 4), + child: Text( + title, + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } +} + +class _VarietyTile extends StatelessWidget { + const _VarietyTile({required this.item}); + + final VarietyListItem item; + + @override + Widget build(BuildContext context) { + final trimmed = item.label.trim(); + final initial = trimmed.isEmpty + ? '?' + : trimmed.substring(0, 1).toUpperCase(); + return ListTile( + leading: CircleAvatar(child: Text(initial)), + title: Text(item.label), + ); + } +} diff --git a/apps/app_seeds/lib/ui/quantity_kind_l10n.dart b/apps/app_seeds/lib/ui/quantity_kind_l10n.dart new file mode 100644 index 0000000..4389297 --- /dev/null +++ b/apps/app_seeds/lib/ui/quantity_kind_l10n.dart @@ -0,0 +1,47 @@ +import 'package:commons_core/commons_core.dart'; + +import '../i18n/strings.g.dart'; + +/// Localized display label for a [QuantityKind]. The enum name is the stable +/// storage key; the label is always resolved through i18n (never hardcoded). +String quantityKindLabel(Translations t, QuantityKind kind) { + final q = t.quantityKind; + switch (kind) { + case QuantityKind.aFew: + return q.aFew; + case QuantityKind.some: + return q.some; + case QuantityKind.plenty: + return q.plenty; + case QuantityKind.handful: + return q.handful; + case QuantityKind.pinch: + return q.pinch; + case QuantityKind.jar: + return q.jar; + case QuantityKind.packet: + return q.packet; + case QuantityKind.cob: + return q.cob; + case QuantityKind.head: + return q.head; + case QuantityKind.pod: + return q.pod; + case QuantityKind.ear: + return q.ear; + case QuantityKind.fruit: + return q.fruit; + case QuantityKind.bulb: + return q.bulb; + case QuantityKind.tuber: + return q.tuber; + case QuantityKind.seedHead: + return q.seedHead; + case QuantityKind.bunch: + return q.bunch; + case QuantityKind.grams: + return q.grams; + case QuantityKind.count: + return q.count; + } +} diff --git a/apps/app_seeds/lib/ui/quick_add_sheet.dart b/apps/app_seeds/lib/ui/quick_add_sheet.dart new file mode 100644 index 0000000..405d2ef --- /dev/null +++ b/apps/app_seeds/lib/ui/quick_add_sheet.dart @@ -0,0 +1,184 @@ +import 'dart:typed_data'; + +import 'package:commons_core/commons_core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:image_picker/image_picker.dart'; + +import '../data/variety_repository.dart'; +import '../i18n/strings.g.dart'; +import '../state/quick_add_cubit.dart'; +import 'quantity_kind_l10n.dart'; + +/// Picks a photo and returns its bytes (or null if cancelled). Injected so +/// widget tests can supply a fake instead of the camera plugin. +typedef PhotoPicker = Future Function(); + +/// A short, high-frequency subset of quantity units shown up front to keep the +/// add flow fast; the rest live behind "Add more…". +const _quickKinds = [ + QuantityKind.aFew, + QuantityKind.handful, + QuantityKind.packet, + QuantityKind.pod, + QuantityKind.cob, + QuantityKind.grams, +]; + +Future showQuickAddSheet( + BuildContext context, { + required VarietyRepository repository, + PhotoPicker? photoPicker, +}) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (_) => BlocProvider( + create: (_) => QuickAddCubit(repository), + child: QuickAddSheet(photoPicker: photoPicker ?? _cameraPhotoPicker), + ), + ); +} + +Future _cameraPhotoPicker() async { + final file = await ImagePicker().pickImage( + source: ImageSource.camera, + maxWidth: 1280, + imageQuality: 80, + ); + return file?.readAsBytes(); +} + +class QuickAddSheet extends StatelessWidget { + const QuickAddSheet({required this.photoPicker, super.key}); + + final PhotoPicker photoPicker; + + @override + Widget build(BuildContext context) { + final t = context.t; + return BlocConsumer( + listenWhen: (prev, curr) => !prev.submitted && curr.submitted, + listener: (context, state) => Navigator.of(context).pop(), + builder: (context, state) { + final cubit = context.read(); + return Padding( + padding: EdgeInsets.only( + left: 16, + right: 16, + top: 16, + bottom: MediaQuery.of(context).viewInsets.bottom + 16, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + t.quickAdd.title, + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(height: 12), + TextField( + key: const Key('quickAdd.labelField'), + autofocus: true, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + labelText: t.quickAdd.labelField, + errorText: state.showLabelError + ? t.quickAdd.labelRequired + : null, + border: const OutlineInputBorder(), + ), + onChanged: cubit.labelChanged, + onSubmitted: (_) => cubit.submit(), + ), + const SizedBox(height: 16), + Text( + t.quickAdd.quantity, + style: Theme.of(context).textTheme.labelLarge, + ), + const SizedBox(height: 8), + Wrap( + spacing: 8, + children: [ + for (final kind in _quickKinds) + ChoiceChip( + label: Text(quantityKindLabel(t, kind)), + selected: state.quantityKind == kind, + onSelected: (_) => cubit.selectQuantity(kind), + ), + ], + ), + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: cubit.toggleExpanded, + icon: Icon( + state.expanded ? Icons.expand_less : Icons.expand_more, + ), + label: Text(t.quickAdd.more), + ), + ), + if (state.expanded) _MoreSection(photoPicker: photoPicker), + const SizedBox(height: 8), + Row( + children: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(t.quickAdd.cancel), + ), + const Spacer(), + FilledButton( + key: const Key('quickAdd.save'), + onPressed: state.submitting ? null : cubit.submit, + child: Text(t.quickAdd.save), + ), + ], + ), + ], + ), + ); + }, + ); + } +} + +class _MoreSection extends StatelessWidget { + const _MoreSection({required this.photoPicker}); + + final PhotoPicker photoPicker; + + @override + Widget build(BuildContext context) { + final t = context.t; + final state = context.watch().state; + final cubit = context.read(); + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 8), + if (state.photoBytes != null) + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.memory( + state.photoBytes!, + height: 120, + fit: BoxFit.cover, + ), + ), + Align( + alignment: Alignment.centerLeft, + child: OutlinedButton.icon( + onPressed: () async { + final bytes = await photoPicker(); + if (bytes != null) cubit.photoPicked(bytes); + }, + icon: const Icon(Icons.photo_camera_outlined), + label: Text(t.quickAdd.addPhoto), + ), + ), + ], + ); + } +} diff --git a/apps/app_seeds/linux/.gitignore b/apps/app_seeds/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/apps/app_seeds/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/apps/app_seeds/linux/CMakeLists.txt b/apps/app_seeds/linux/CMakeLists.txt new file mode 100644 index 0000000..b6f238d --- /dev/null +++ b/apps/app_seeds/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "tane") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "org.comunes.tane") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/apps/app_seeds/linux/flutter/CMakeLists.txt b/apps/app_seeds/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/apps/app_seeds/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/apps/app_seeds/linux/flutter/generated_plugin_registrant.cc b/apps/app_seeds/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..5c58be9 --- /dev/null +++ b/apps/app_seeds/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,27 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) sqlcipher_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); + sqlite3_flutter_libs_plugin_register_with_registrar(sqlcipher_flutter_libs_registrar); + g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); + sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); +} diff --git a/apps/app_seeds/linux/flutter/generated_plugin_registrant.h b/apps/app_seeds/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/apps/app_seeds/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/app_seeds/linux/flutter/generated_plugins.cmake b/apps/app_seeds/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..e3fa138 --- /dev/null +++ b/apps/app_seeds/linux/flutter/generated_plugins.cmake @@ -0,0 +1,28 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + flutter_secure_storage_linux + sqlcipher_flutter_libs + sqlite3_flutter_libs +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/app_seeds/linux/runner/CMakeLists.txt b/apps/app_seeds/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/apps/app_seeds/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/apps/app_seeds/linux/runner/main.cc b/apps/app_seeds/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/apps/app_seeds/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/apps/app_seeds/linux/runner/my_application.cc b/apps/app_seeds/linux/runner/my_application.cc new file mode 100644 index 0000000..68e8b57 --- /dev/null +++ b/apps/app_seeds/linux/runner/my_application.cc @@ -0,0 +1,148 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "tane"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "tane"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); +} diff --git a/apps/app_seeds/linux/runner/my_application.h b/apps/app_seeds/linux/runner/my_application.h new file mode 100644 index 0000000..db16367 --- /dev/null +++ b/apps/app_seeds/linux/runner/my_application.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/apps/app_seeds/pubspec.yaml b/apps/app_seeds/pubspec.yaml new file mode 100644 index 0000000..e46f378 --- /dev/null +++ b/apps/app_seeds/pubspec.yaml @@ -0,0 +1,62 @@ +name: tane +description: "Tanemaki — local-first, encrypted, decentralized traditional-seed inventory." +publish_to: 'none' +version: 0.1.0+1 + +environment: + sdk: ^3.11.5 + +resolution: workspace + +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + + commons_core: + path: ../../packages/commons_core + + # State management (Cubit-first). Drift streams are the source of truth. + flutter_bloc: ^9.1.1 + equatable: ^2.0.5 + + # Encrypted local database. + drift: ^2.28.0 + drift_flutter: ^0.2.4 + sqlite3: ^2.7.5 + sqlcipher_flutter_libs: ^0.6.5 + + # Dependency injection composition root. + get_it: ^8.0.3 + + # i18n (Weblate-friendly JSON per locale). + slang: ^4.7.0 + slang_flutter: ^4.7.0 + + # Secure key storage (OS keystore). + flutter_secure_storage: ^9.2.4 + + # Routing + media + paths. + go_router: ^14.6.2 + image_picker: ^1.1.2 + path: ^1.9.0 + path_provider: ^2.1.5 + + cupertino_icons: ^1.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + + flutter_lints: ^6.0.0 + build_runner: ^2.4.13 + drift_dev: ^2.28.0 + slang_build_runner: ^4.7.0 + mocktail: ^1.0.4 + +flutter: + uses-material-design: true + # Seed strings for slang live under lib/i18n (not a Flutter asset; compiled). diff --git a/apps/app_seeds/slang.yaml b/apps/app_seeds/slang.yaml new file mode 100644 index 0000000..6f6331d --- /dev/null +++ b/apps/app_seeds/slang.yaml @@ -0,0 +1,14 @@ +# slang i18n config. JSON-per-locale keeps files Weblate-friendly (nested JSON). +base_locale: en +input_directory: lib/i18n +input_file_pattern: .i18n.json +output_directory: lib/i18n +output_file_name: strings.g.dart +translate_var: t +enum_name: AppLocale +class_name: Translations +# Missing keys in a non-base locale fall back to the base locale at runtime. +fallback_strategy: base_locale +# Compile all locales in (not deferred), so setLocaleSync / useDeviceLocaleSync +# work for every locale — needed for a small app and for widget tests. +lazy: false diff --git a/apps/app_seeds/test/data/persistence_test.dart b/apps/app_seeds/test/data/persistence_test.dart new file mode 100644 index 0000000..c8c7bd6 --- /dev/null +++ b/apps/app_seeds/test/data/persistence_test.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import 'package:commons_core/commons_core.dart'; +import 'package:drift/native.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:tane/data/variety_repository.dart'; +import 'package:tane/db/database.dart'; + +/// Proves the "reopen and it's still there" half of the sprint's definition of +/// done at the persistence layer, on a real on-disk file (unencrypted here so +/// it runs on any host — encryption at rest is covered by no_plaintext_test). +void main() { + test('a seed survives closing and reopening the database file', () async { + final dir = await Directory.systemTemp.createTemp('tane_persist'); + addTearDown(() => dir.delete(recursive: true)); + final file = File(p.join(dir.path, 'inventory.sqlite')); + + var db = AppDatabase(NativeDatabase(file)); + await VarietyRepository( + db, + idGen: IdGen(), + nodeId: 'n', + ).addQuickVariety(label: 'Persisted tomato'); + await db.close(); + + db = AppDatabase(NativeDatabase(file)); + final items = await VarietyRepository( + db, + idGen: IdGen(), + nodeId: 'n', + ).watchInventory().first; + await db.close(); + + expect(items.map((i) => i.label), ['Persisted tomato']); + }); +} diff --git a/apps/app_seeds/test/data/variety_repository_test.dart b/apps/app_seeds/test/data/variety_repository_test.dart new file mode 100644 index 0000000..3fc2375 --- /dev/null +++ b/apps/app_seeds/test/data/variety_repository_test.dart @@ -0,0 +1,76 @@ +import 'dart:typed_data'; + +import 'package:commons_core/commons_core.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/data/variety_repository.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/db/enums.dart'; + +import '../support/test_support.dart'; + +void main() { + late AppDatabase db; + late VarietyRepository repo; + + setUp(() { + db = newTestDatabase(); + repo = newTestRepository(db); + }); + tearDown(() => db.close()); + + test( + 'addQuickVariety persists a variety that appears in the stream', + () async { + await repo.addQuickVariety( + label: 'Grandma tomato', + category: 'Solanaceae', + ); + final items = await repo.watchInventory().first; + expect(items.single.label, 'Grandma tomato'); + expect(items.single.category, 'Solanaceae'); + }, + ); + + test( + 'a quantity creates a Lot and a photo creates an encrypted-BLOB Attachment', + () async { + final id = await repo.addQuickVariety( + label: 'Maize', + quantity: const Quantity(kind: QuantityKind.cob), + photoBytes: Uint8List.fromList([1, 2, 3]), + ); + + final lot = await db.select(db.lots).getSingle(); + expect(lot.varietyId, id); + expect(lot.quantityKind, 'cob'); + + final attachment = await db.select(db.attachments).getSingle(); + expect(attachment.parentType, ParentType.variety); + expect(attachment.parentId, id); + expect(attachment.kind, AttachmentKind.photo); + expect(attachment.bytes, [1, 2, 3]); + }, + ); + + test( + 'stream is ordered by category then label and excludes soft-deleted rows', + () async { + await repo.addQuickVariety(label: 'Bean', category: 'Fabaceae'); + await repo.addQuickVariety(label: 'Apple', category: 'Rosaceae'); + await repo.addQuickVariety(label: 'Almond', category: 'Rosaceae'); + + final items = await repo.watchInventory().first; + expect(items.map((i) => i.label), ['Bean', 'Almond', 'Apple']); + }, + ); + + test('writes stamp a monotonic HLC into updated_at', () async { + await repo.addQuickVariety(label: 'First'); + await repo.addQuickVariety(label: 'Second'); + final rows = await db.select(db.varieties).get(); + final stamps = rows.map((r) => r.updatedAt).toList()..sort(); + // Distinct, parseable, ordered HLC stamps. + expect(stamps.toSet().length, 2); + expect(() => stamps.map(Hlc.parse).toList(), returnsNormally); + }); +} diff --git a/apps/app_seeds/test/db/migration_test.dart b/apps/app_seeds/test/db/migration_test.dart new file mode 100644 index 0000000..fec0993 --- /dev/null +++ b/apps/app_seeds/test/db/migration_test.dart @@ -0,0 +1,21 @@ +import 'package:drift_dev/api/migrations_native.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/db/database.dart'; + +import 'schema/schema.dart'; + +void main() { + late SchemaVerifier verifier; + + setUpAll(() { + verifier = SchemaVerifier(GeneratedHelper()); + }); + + test('freshly created database matches the exported schema v1', () async { + // Guards that `createAll` stays in sync with drift_schemas/drift_schema_v1.json. + final schema = await verifier.schemaAt(1); + final db = AppDatabase(schema.newConnection()); + await verifier.migrateAndValidate(db, 1); + await db.close(); + }); +} diff --git a/apps/app_seeds/test/db/no_plaintext_test.dart b/apps/app_seeds/test/db/no_plaintext_test.dart new file mode 100644 index 0000000..d8144a0 --- /dev/null +++ b/apps/app_seeds/test/db/no_plaintext_test.dart @@ -0,0 +1,80 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:tane/db/database.dart'; +import 'package:tane/db/encrypted_executor.dart'; + +/// Security regression guard for "no plaintext at rest, ever" (CLAUDE.md). +/// +/// Writes a Variety whose label is a unique sentinel, then reads the raw +/// database file bytes and asserts the sentinel does NOT appear — proving +/// SQLCipher actually encrypted the data. +/// +/// Requires a real SQLCipher library. On a host without it (no +/// `libsqlcipher.so`), the test is skipped with a clear reason; CI installs +/// SQLCipher so the guard runs there. It also runs on-device via integration +/// tests. +void main() { + test('sentinel label is absent from the raw encrypted DB file', () async { + const sentinel = 'GRANDMA_TOMATO_SENTINEL_9f3a1c'; + const keyHex = + '00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff'; + + final dir = await Directory.systemTemp.createTemp('tane_enc_test'); + final file = File(p.join(dir.path, 'inventory.sqlite')); + addTearDown(() => dir.delete(recursive: true)); + + final db = AppDatabase(openEncryptedExecutor(file, keyHex)); + try { + await db + .into(db.varieties) + .insert( + VarietiesCompanion.insert( + id: 'sentinel-row', + label: sentinel, + createdAt: 0, + updatedAt: '0', + lastAuthor: 'test', + ), + ); + } on Object catch (e) { + // SQLCipher not available in this environment (e.g. dev host without + // libsqlcipher). Skip rather than pass silently. + markTestSkipped('SQLCipher unavailable, cannot verify encryption: $e'); + await db.close(); + return; + } + await db.close(); + + final bytes = await file.readAsBytes(); + expect( + _containsAscii(bytes, sentinel), + isFalse, + reason: 'Label leaked as plaintext — SQLCipher encryption is not active.', + ); + // Sanity: a real SQLCipher file does not start with the plain-SQLite header. + expect( + _containsAscii(bytes.sublist(0, 16), 'SQLite format 3'), + isFalse, + reason: 'File has a plaintext SQLite header — not encrypted.', + ); + }); +} + +bool _containsAscii(Uint8List haystack, String needle) { + final n = needle.codeUnits; + if (n.isEmpty || haystack.length < n.length) return false; + for (var i = 0; i <= haystack.length - n.length; i++) { + var match = true; + for (var j = 0; j < n.length; j++) { + if (haystack[i + j] != n[j]) { + match = false; + break; + } + } + if (match) return true; + } + return false; +} diff --git a/apps/app_seeds/test/db/schema/schema.dart b/apps/app_seeds/test/db/schema/schema.dart new file mode 100644 index 0000000..8869e40 --- /dev/null +++ b/apps/app_seeds/test/db/schema/schema.dart @@ -0,0 +1,21 @@ +// dart format width=80 +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +import 'package:drift/drift.dart'; +import 'package:drift/internal/migrations.dart'; +import 'schema_v1.dart' as v1; + +class GeneratedHelper implements SchemaInstantiationHelper { + @override + GeneratedDatabase databaseForVersion(QueryExecutor db, int version) { + switch (version) { + case 1: + return v1.DatabaseAtV1(db); + default: + throw MissingSchemaException(version, versions); + } + } + + static const versions = const [1]; +} diff --git a/apps/app_seeds/test/db/schema/schema_v1.dart b/apps/app_seeds/test/db/schema/schema_v1.dart new file mode 100644 index 0000000..94bce71 --- /dev/null +++ b/apps/app_seeds/test/db/schema/schema_v1.dart @@ -0,0 +1,1380 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +import 'package:drift/drift.dart'; + +class Varieties extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Varieties(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn label = GeneratedColumn( + 'label', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn cultivarName = GeneratedColumn( + 'cultivar_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn category = GeneratedColumn( + 'category', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + label, + speciesId, + cultivarName, + category, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'varieties'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Varieties createAlias(String alias) { + return Varieties(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class VarietyVernacularNames extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VarietyVernacularNames(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn region = GeneratedColumn( + 'region', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + name, + language, + region, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'variety_vernacular_names'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + VarietyVernacularNames createAlias(String alias) { + return VarietyVernacularNames(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Species extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Species(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn scientificName = GeneratedColumn( + 'scientific_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn wikidataQid = GeneratedColumn( + 'wikidata_qid', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn gbifKey = GeneratedColumn( + 'gbif_key', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn family = GeneratedColumn( + 'family', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isBundled = GeneratedColumn( + 'is_bundled', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_bundled IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + scientificName, + wikidataQid, + gbifKey, + family, + isBundled, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Species createAlias(String alias) { + return Species(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class SpeciesCommonNames extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SpeciesCommonNames(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + speciesId, + name, + language, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species_common_names'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + SpeciesCommonNames createAlias(String alias) { + return SpeciesCommonNames(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Lots extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Lots(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn harvestYear = GeneratedColumn( + 'harvest_year', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storageLocation = GeneratedColumn( + 'storage_location', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn offerStatus = GeneratedColumn( + 'offer_status', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'private\'', + defaultValue: const CustomExpression('\'private\''), + ); + late final GeneratedColumn seedbankId = GeneratedColumn( + 'seedbank_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + harvestYear, + quantityKind, + quantityPrecise, + quantityLabel, + storageLocation, + offerStatus, + seedbankId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'lots'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Lots createAlias(String alias) { + return Lots(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class GerminationTests extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GerminationTests(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn testedOn = GeneratedColumn( + 'tested_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn sampleSize = GeneratedColumn( + 'sample_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn germinatedCount = GeneratedColumn( + 'germinated_count', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + lotId, + testedOn, + sampleSize, + germinatedCount, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'germination_tests'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + GerminationTests createAlias(String alias) { + return GerminationTests(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Movements extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Movements(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn occurredOn = GeneratedColumn( + 'occurred_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn counterpartyId = GeneratedColumn( + 'counterparty_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn parentMovementId = GeneratedColumn( + 'parent_movement_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn plantareId = GeneratedColumn( + 'plantare_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + lastAuthor, + schemaRowVersion, + lotId, + type, + occurredOn, + counterpartyId, + quantityKind, + quantityPrecise, + quantityLabel, + parentMovementId, + plantareId, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'movements'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Movements createAlias(String alias) { + return Movements(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Parties extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Parties(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKey = GeneratedColumn( + 'public_key', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn kind = GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'person\'', + defaultValue: const CustomExpression('\'person\''), + ); + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + displayName, + publicKey, + kind, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'parties'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Parties createAlias(String alias) { + return Parties(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Attachments extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Attachments(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn parentType = GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn kind = GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uri = GeneratedColumn( + 'uri', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn bytes = + GeneratedColumn( + 'bytes', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mimeType = GeneratedColumn( + 'mime_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + kind, + uri, + bytes, + mimeType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'attachments'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Attachments createAlias(String alias) { + return Attachments(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class ExternalLinks extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ExternalLinks(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn parentType = GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn url = GeneratedColumn( + 'url', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn title = GeneratedColumn( + 'title', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + url, + title, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'external_links'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + ExternalLinks createAlias(String alias) { + return ExternalLinks(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class DatabaseAtV1 extends GeneratedDatabase { + DatabaseAtV1(QueryExecutor e) : super(e); + late final Varieties varieties = Varieties(this); + late final VarietyVernacularNames varietyVernacularNames = + VarietyVernacularNames(this); + late final Species species = Species(this); + late final SpeciesCommonNames speciesCommonNames = SpeciesCommonNames(this); + late final Lots lots = Lots(this); + late final GerminationTests germinationTests = GerminationTests(this); + late final Movements movements = Movements(this); + late final Parties parties = Parties(this); + late final Attachments attachments = Attachments(this); + late final ExternalLinks externalLinks = ExternalLinks(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + varieties, + varietyVernacularNames, + species, + speciesCommonNames, + lots, + germinationTests, + movements, + parties, + attachments, + externalLinks, + ]; + @override + int get schemaVersion => 1; +} diff --git a/apps/app_seeds/test/flutter_test_config.dart b/apps/app_seeds/test/flutter_test_config.dart new file mode 100644 index 0000000..4bd3fde --- /dev/null +++ b/apps/app_seeds/test/flutter_test_config.dart @@ -0,0 +1,23 @@ +import 'dart:async'; +import 'dart:ffi'; +import 'dart:io'; + +import 'package:sqlite3/open.dart'; + +/// Host test setup: point package:sqlite3 at the system SQLite so in-memory +/// Drift databases (migration/widget tests) load on Linux CI/dev machines, +/// where only `libsqlite3.so.0` may be present. The encrypted executor +/// overrides its own isolate to SQLCipher separately, so this does not affect +/// the on-disk encryption tests. +Future testExecutable(FutureOr Function() testMain) async { + if (Platform.isLinux) { + open.overrideFor(OperatingSystem.linux, () { + try { + return DynamicLibrary.open('libsqlite3.so'); + } on ArgumentError { + return DynamicLibrary.open('libsqlite3.so.0'); + } + }); + } + await testMain(); +} diff --git a/apps/app_seeds/test/i18n/no_hardcoded_strings_test.dart b/apps/app_seeds/test/i18n/no_hardcoded_strings_test.dart new file mode 100644 index 0000000..73d05cd --- /dev/null +++ b/apps/app_seeds/test/i18n/no_hardcoded_strings_test.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; + +/// Enforces the golden rule "user-facing strings are NEVER hardcoded". Scans +/// lib/ for `Text('literal')` / `Text("literal")` with an alphabetic literal — +/// all UI text must come from slang (`t.…`). Variables like `Text(item.label)` +/// and symbols like `Text('?')` are allowed. +void main() { + test('no hardcoded Text() string literals in lib/', () { + final textLiteral = RegExp('''Text\\(\\s*['"][A-Za-z]'''); + final offenders = []; + + for (final entity in Directory('lib').listSync(recursive: true)) { + if (entity is! File || !entity.path.endsWith('.dart')) continue; + if (entity.path.contains('/i18n/') || entity.path.endsWith('.g.dart')) { + continue; // generated / translation sources + } + if (textLiteral.hasMatch(entity.readAsStringSync())) { + offenders.add(entity.path); + } + } + + expect( + offenders, + isEmpty, + reason: 'Hardcoded Text() literals found (use t.…): $offenders', + ); + }); +} diff --git a/apps/app_seeds/test/security/secure_key_store_test.dart b/apps/app_seeds/test/security/secure_key_store_test.dart new file mode 100644 index 0000000..c5e6a7f --- /dev/null +++ b/apps/app_seeds/test/security/secure_key_store_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/security/secret_store.dart'; +import 'package:tane/security/secure_key_store.dart'; + +class InMemorySecretStore implements SecretStore { + final Map _values = {}; + int writeCount = 0; + + @override + Future read(String key) async => _values[key]; + + @override + Future write(String key, String value) async { + _values[key] = value; + writeCount++; + } +} + +void main() { + group('SecureKeyStore', () { + test('creates a 256-bit (64 hex char) db key on first run', () async { + final keys = SecureKeyStore(store: InMemorySecretStore()); + final key = await keys.databaseKeyHex(); + expect(key, matches(RegExp(r'^[0-9a-f]{64}$'))); + }); + + test('reuses the same db key across calls (created once)', () async { + final store = InMemorySecretStore(); + final keys = SecureKeyStore(store: store); + final first = await keys.databaseKeyHex(); + final second = await keys.databaseKeyHex(); + expect(second, first); + expect(store.writeCount, 1); + }); + + test('db key and root seed are independent secrets', () async { + final keys = SecureKeyStore(store: InMemorySecretStore()); + expect(await keys.databaseKeyHex(), isNot(await keys.rootSeedHex())); + }); + }); +} diff --git a/apps/app_seeds/test/support/test_support.dart b/apps/app_seeds/test/support/test_support.dart new file mode 100644 index 0000000..e3fe7ee --- /dev/null +++ b/apps/app_seeds/test/support/test_support.dart @@ -0,0 +1,56 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:drift/native.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/data/variety_repository.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/i18n/strings.g.dart'; +import 'package:tane/state/inventory_cubit.dart'; + +/// A fresh in-memory database for host tests (unencrypted; encryption is +/// verified separately in the SQLCipher-only security test). +AppDatabase newTestDatabase() => AppDatabase(NativeDatabase.memory()); + +/// Unmounts the widget tree *inside* the test and drains the zero-duration +/// timer Drift schedules when its stream subscription is cancelled. Without +/// this, flutter_test reports "a Timer is still pending after disposal". Call +/// at the end of any widget test that mounts an [InventoryCubit]. +Future disposeTree(WidgetTester tester) async { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(const Duration(milliseconds: 10)); +} + +VarietyRepository newTestRepository( + AppDatabase db, { + String nodeId = 'test-node', +}) => VarietyRepository(db, idGen: IdGen(), nodeId: nodeId); + +/// Wraps [child] with the providers a screen expects (repository, inventory +/// cubit) plus i18n and Material localizations, pinned to [locale]. +Widget wrapScreen({ + required VarietyRepository repository, + required Widget child, + AppLocale locale = AppLocale.en, +}) { + LocaleSettings.setLocaleSync(locale); + return TranslationProvider( + child: RepositoryProvider.value( + value: repository, + child: BlocProvider( + create: (_) => InventoryCubit(repository), + child: MaterialApp( + locale: locale.flutterLocale, + supportedLocales: AppLocaleUtils.supportedLocales, + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + home: child, + ), + ), + ), + ); +} diff --git a/apps/app_seeds/test/ui/inventory_list_screen_test.dart b/apps/app_seeds/test/ui/inventory_list_screen_test.dart new file mode 100644 index 0000000..19e662e --- /dev/null +++ b/apps/app_seeds/test/ui/inventory_list_screen_test.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/i18n/strings.g.dart'; +import 'package:tane/ui/inventory_list_screen.dart'; + +import '../support/test_support.dart'; + +void main() { + late AppDatabase db; + + setUp(() => db = newTestDatabase()); + tearDown(() => db.close()); + + testWidgets('shows the empty state when there are no seeds', (tester) async { + final repo = newTestRepository(db); + await tester.pumpWidget( + wrapScreen(repository: repo, child: const InventoryListScreen()), + ); + await tester.pumpAndSettle(); + + expect(find.text('No seeds yet. Tap + to add your first.'), findsOneWidget); + await disposeTree(tester); + }); + + testWidgets( + 'renders seeds from the repository grouped under their category', + (tester) async { + final repo = newTestRepository(db); + await repo.addQuickVariety( + label: 'Grandma tomato', + category: 'Solanaceae', + ); + + await tester.pumpWidget( + wrapScreen(repository: repo, child: const InventoryListScreen()), + ); + await tester.pumpAndSettle(); + + expect(find.text('Grandma tomato'), findsOneWidget); + expect(find.text('Solanaceae'), findsOneWidget); // category header + await disposeTree(tester); + }, + ); + + testWidgets('search filters the visible list', (tester) async { + final repo = newTestRepository(db); + await repo.addQuickVariety(label: 'Tomato'); + await repo.addQuickVariety(label: 'Bean'); + + await tester.pumpWidget( + wrapScreen(repository: repo, child: const InventoryListScreen()), + ); + await tester.pumpAndSettle(); + + await tester.enterText(find.byKey(const Key('inventory.search')), 'bea'); + await tester.pumpAndSettle(); + + expect(find.text('Bean'), findsOneWidget); + expect(find.text('Tomato'), findsNothing); + await disposeTree(tester); + }); + + testWidgets('renders in Spanish when the locale is es', (tester) async { + final repo = newTestRepository(db); + await tester.pumpWidget( + wrapScreen( + repository: repo, + child: const InventoryListScreen(), + locale: AppLocale.es, + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('Inventario'), findsOneWidget); + await disposeTree(tester); + }); +} diff --git a/apps/app_seeds/test/ui/quick_add_flow_test.dart b/apps/app_seeds/test/ui/quick_add_flow_test.dart new file mode 100644 index 0000000..3fbd422 --- /dev/null +++ b/apps/app_seeds/test/ui/quick_add_flow_test.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/app.dart'; +import 'package:tane/i18n/strings.g.dart'; + +import '../support/test_support.dart'; + +void main() { + testWidgets( + 'quick-add: empty label errors; filling it saves and lists the seed', + (tester) async { + LocaleSettings.setLocaleSync(AppLocale.en); + final db = newTestDatabase(); + addTearDown(db.close); + final repo = newTestRepository(db); + + await tester.pumpWidget( + TranslationProvider(child: TaneApp(repository: repo)), + ); + await tester.pumpAndSettle(); + + // Starts empty. + expect( + find.text('No seeds yet. Tap + to add your first.'), + findsOneWidget, + ); + + // Open the quick-add sheet. + await tester.tap(find.byKey(const Key('inventory.addFab'))); + await tester.pumpAndSettle(); + + // Saving with an empty label surfaces the validation message. + await tester.tap(find.byKey(const Key('quickAdd.save'))); + await tester.pumpAndSettle(); + expect(find.text('Give it a name'), findsOneWidget); + + // Enter a name and save. + await tester.enterText( + find.byKey(const Key('quickAdd.labelField')), + 'Grandma tomato', + ); + await tester.tap(find.byKey(const Key('quickAdd.save'))); + await tester.pumpAndSettle(); + + // Sheet closed and the seed shows in the list. + expect(find.byKey(const Key('quickAdd.labelField')), findsNothing); + expect(find.text('Grandma tomato'), findsOneWidget); + await disposeTree(tester); + }, + ); +} diff --git a/packages/commons_core/.gitignore b/packages/commons_core/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/commons_core/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/commons_core/CHANGELOG.md b/packages/commons_core/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/commons_core/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/commons_core/README.md b/packages/commons_core/README.md new file mode 100644 index 0000000..8831761 --- /dev/null +++ b/packages/commons_core/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/commons_core/analysis_options.yaml b/packages/commons_core/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/commons_core/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/commons_core/lib/commons_core.dart b/packages/commons_core/lib/commons_core.dart new file mode 100644 index 0000000..9dd406c --- /dev/null +++ b/packages/commons_core/lib/commons_core.dart @@ -0,0 +1,11 @@ +/// Generic local-first commons engine primitives. +/// +/// Pure Dart, Flutter-free. Holds only what is surely shared across apps built +/// on the engine (ids, clocks, value types, identity). No seed-specific code. +library; + +export 'src/clock/hlc.dart'; +export 'src/crypto/random_bytes.dart'; +export 'src/identity/identity_service.dart'; +export 'src/ids/id_gen.dart'; +export 'src/value/quantity.dart'; diff --git a/packages/commons_core/lib/src/clock/hlc.dart b/packages/commons_core/lib/src/clock/hlc.dart new file mode 100644 index 0000000..d80208a --- /dev/null +++ b/packages/commons_core/lib/src/clock/hlc.dart @@ -0,0 +1,100 @@ +import 'package:equatable/equatable.dart'; + +/// A Hybrid Logical Clock timestamp (Kulkarni et al.). +/// +/// Combines a physical wall-clock component ([millis]) with a monotonic +/// [counter] and a [nodeId] tiebreaker. It is the `updated_at` stamp on every +/// mutable row and drives last-writer-wins merges across devices, staying +/// monotonic even when the wall clock jumps backwards. +/// +/// [pack] produces a fixed-width, lexicographically-sortable string so it can +/// be stored in a `TEXT` column and ordered with a plain SQL `ORDER BY`. +class Hlc extends Equatable implements Comparable { + const Hlc({ + required this.millis, + required this.counter, + required this.nodeId, + }); + + /// The initial clock for [nodeId], before any event. + const Hlc.zero(String nodeId) : this(millis: 0, counter: 0, nodeId: nodeId); + + /// Physical time in milliseconds since the Unix epoch. + final int millis; + + /// Logical counter, bumped when two events share the same [millis]. + final int counter; + + /// Stable identifier of the node/device that issued this stamp. + final String nodeId; + + static const _millisDigits = 15; // good until year ~5138 + static const _counterDigits = 5; // 99999 events within one millisecond + + /// Issues the next local timestamp given the current wall clock [wallMillis]. + /// + /// Monotonic: if the wall clock is behind our last stamp, we keep our + /// [millis] and bump the [counter] instead of moving time backwards. + Hlc localEvent(int wallMillis) { + final newMillis = millis > wallMillis ? millis : wallMillis; + final newCounter = newMillis == millis ? counter + 1 : 0; + return Hlc(millis: newMillis, counter: newCounter, nodeId: nodeId); + } + + /// Merges an incoming [remote] stamp with the current wall clock, producing + /// the next local timestamp (used when receiving a peer's write). + Hlc receiveEvent(Hlc remote, int wallMillis) { + final newMillis = [ + millis, + remote.millis, + wallMillis, + ].reduce((a, b) => a > b ? a : b); + final int newCounter; + if (newMillis == millis && newMillis == remote.millis) { + newCounter = (counter > remote.counter ? counter : remote.counter) + 1; + } else if (newMillis == millis) { + newCounter = counter + 1; + } else if (newMillis == remote.millis) { + newCounter = remote.counter + 1; + } else { + newCounter = 0; + } + return Hlc(millis: newMillis, counter: newCounter, nodeId: nodeId); + } + + /// A fixed-width, lexicographically-sortable encoding: `millis:counter:node`. + String pack() { + final m = millis.toString().padLeft(_millisDigits, '0'); + final c = counter.toString().padLeft(_counterDigits, '0'); + return '$m:$c:$nodeId'; + } + + /// Parses a string produced by [pack]. + factory Hlc.parse(String packed) { + final parts = packed.split(':'); + if (parts.length < 3) { + throw FormatException('Not a packed HLC: "$packed"'); + } + return Hlc( + millis: int.parse(parts[0]), + counter: int.parse(parts[1]), + // nodeId may itself contain ':', so re-join the remainder. + nodeId: parts.sublist(2).join(':'), + ); + } + + @override + int compareTo(Hlc other) { + final byMillis = millis.compareTo(other.millis); + if (byMillis != 0) return byMillis; + final byCounter = counter.compareTo(other.counter); + if (byCounter != 0) return byCounter; + return nodeId.compareTo(other.nodeId); + } + + @override + String toString() => pack(); + + @override + List get props => [millis, counter, nodeId]; +} diff --git a/packages/commons_core/lib/src/crypto/random_bytes.dart b/packages/commons_core/lib/src/crypto/random_bytes.dart new file mode 100644 index 0000000..aa5ba62 --- /dev/null +++ b/packages/commons_core/lib/src/crypto/random_bytes.dart @@ -0,0 +1,18 @@ +import 'dart:math'; +import 'dart:typed_data'; + +/// Returns [length] cryptographically-random bytes. +/// +/// Defaults to [Random.secure]. A seeded [Random] may be injected in tests for +/// reproducibility — never do that in production code, as it is not secure. +Uint8List randomBytes(int length, {Random? random}) { + if (length < 0) { + throw ArgumentError.value(length, 'length', 'must be non-negative'); + } + final rng = random ?? Random.secure(); + final out = Uint8List(length); + for (var i = 0; i < length; i++) { + out[i] = rng.nextInt(256); + } + return out; +} diff --git a/packages/commons_core/lib/src/identity/identity_service.dart b/packages/commons_core/lib/src/identity/identity_service.dart new file mode 100644 index 0000000..3064923 --- /dev/null +++ b/packages/commons_core/lib/src/identity/identity_service.dart @@ -0,0 +1,24 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import '../crypto/random_bytes.dart'; + +/// Creates the user's root identity secret. +/// +/// One identity == one Duniter/Ğ1-style root seed. From it the app will later +/// *derive* a secp256k1 subkey for Nostr transport and expose a printable +/// recovery QR. This service only produces the seed bytes; derivation and +/// backup are separate, later stories (see docs/design/backup-and-recovery.md). +class IdentityService { + IdentityService({Random? random}) : _random = random; + + /// Injected only in tests (seeded, reproducible). Production uses a CSPRNG. + final Random? _random; + + /// Length of the root seed in bytes (256-bit). + static const int rootSeedLengthBytes = 32; + + /// Generates a fresh root seed — the ONE secret the user backs up. + Uint8List generateRootSeed() => + randomBytes(rootSeedLengthBytes, random: _random); +} diff --git a/packages/commons_core/lib/src/ids/id_gen.dart b/packages/commons_core/lib/src/ids/id_gen.dart new file mode 100644 index 0000000..7d27264 --- /dev/null +++ b/packages/commons_core/lib/src/ids/id_gen.dart @@ -0,0 +1,16 @@ +import 'package:uuid/uuid.dart'; + +/// Generates client-side, time-sortable row identifiers (UUIDv7). +/// +/// Every mutable row in the model is keyed by a client-generated UUIDv7 — +/// never an auto-increment (which would collide across peers). UUIDv7 embeds a +/// millisecond timestamp in its most-significant bits, so lexical order +/// approximates creation order, which suits CRDT sync and time-ordered queries. +class IdGen { + IdGen({Uuid? uuid}) : _uuid = uuid ?? const Uuid(); + + final Uuid _uuid; + + /// A fresh UUIDv7 string, e.g. `018f1a2b-...-7...-...`. + String newId() => _uuid.v7(); +} diff --git a/packages/commons_core/lib/src/value/quantity.dart b/packages/commons_core/lib/src/value/quantity.dart new file mode 100644 index 0000000..b97eac6 --- /dev/null +++ b/packages/commons_core/lib/src/value/quantity.dart @@ -0,0 +1,67 @@ +import 'package:equatable/equatable.dart'; + +/// Coarse groups used by the UI to suggest relevant [QuantityKind]s for a +/// species/family. Purely presentational — never forces a choice. +enum QuantityGroup { informal, plantForm, precise } + +/// A stable, extensible, i18n vocabulary for *rough, human* seed amounts. +/// +/// Values go deliberately beyond kitchen measures: seeds are counted in the +/// forms the plant gives them (a cob, a pod, a flower head…). The display label +/// is localized from [name] — so the enum name is the stable storage key and +/// must never be renumbered or reused (see data-model §5 migration rules). +enum QuantityKind { + // Informal / generic + aFew(QuantityGroup.informal), + some(QuantityGroup.informal), + plenty(QuantityGroup.informal), + handful(QuantityGroup.informal), + pinch(QuantityGroup.informal), + jar(QuantityGroup.informal), + packet(QuantityGroup.informal), + // Plant-form natural units + cob(QuantityGroup.plantForm), + head(QuantityGroup.plantForm), + pod(QuantityGroup.plantForm), + ear(QuantityGroup.plantForm), + fruit(QuantityGroup.plantForm), + bulb(QuantityGroup.plantForm), + tuber(QuantityGroup.plantForm), + seedHead(QuantityGroup.plantForm), + bunch(QuantityGroup.plantForm), + // Precise + grams(QuantityGroup.precise), + count(QuantityGroup.precise); + + const QuantityKind(this.group); + + final QuantityGroup group; +} + +/// A quantity held or moved: a qualitative [kind], plus an optional [precise] +/// amount (grams / seed count) and an optional free-text [label] for rough +/// amounts no [kind] captures. Shared value type used by both Lot and Movement. +class Quantity extends Equatable { + const Quantity({required this.kind, this.precise, this.label}); + + final QuantityKind kind; + + /// Optional precise amount, meaningful for [QuantityGroup.precise] kinds. + final double? precise; + + /// Optional free text ("half a jam jar") when no [kind] fits well. + final String? label; + + bool get isPrecise => precise != null; + + Quantity copyWith({QuantityKind? kind, double? precise, String? label}) { + return Quantity( + kind: kind ?? this.kind, + precise: precise ?? this.precise, + label: label ?? this.label, + ); + } + + @override + List get props => [kind, precise, label]; +} diff --git a/packages/commons_core/pubspec.yaml b/packages/commons_core/pubspec.yaml new file mode 100644 index 0000000..6c0de5b --- /dev/null +++ b/packages/commons_core/pubspec.yaml @@ -0,0 +1,21 @@ +name: commons_core +description: >- + Generic local-first commons engine primitives (identity, clocks, value types). + Pure Dart, Flutter-free. No seed-specific code. See + ../../docs/design/core-domain-boundary.md. +version: 0.1.0 +publish_to: none + +environment: + sdk: ^3.11.5 + +resolution: workspace + +dependencies: + uuid: ^4.5.0 + equatable: ^2.0.5 + meta: ^1.15.0 + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.6 diff --git a/packages/commons_core/test/clock/hlc_test.dart b/packages/commons_core/test/clock/hlc_test.dart new file mode 100644 index 0000000..43c78de --- /dev/null +++ b/packages/commons_core/test/clock/hlc_test.dart @@ -0,0 +1,91 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:test/test.dart'; + +void main() { + group('Hlc', () { + test('round-trips through pack/parse', () { + const h = Hlc(millis: 1720000000000, counter: 7, nodeId: 'node-a'); + expect(Hlc.parse(h.pack()), h); + }); + + test('parse tolerates a nodeId containing colons', () { + const h = Hlc(millis: 42, counter: 1, nodeId: 'a:b:c'); + expect(Hlc.parse(h.pack()), h); + }); + + test('packed form sorts lexically in timestamp order', () { + const older = Hlc(millis: 100, counter: 9, nodeId: 'z'); + const newer = Hlc(millis: 200, counter: 0, nodeId: 'a'); + expect(older.pack().compareTo(newer.pack()), lessThan(0)); + }); + + test('packed counter breaks ties within the same millisecond', () { + const a = Hlc(millis: 100, counter: 1, nodeId: 'n'); + const b = Hlc(millis: 100, counter: 2, nodeId: 'n'); + expect(a.pack().compareTo(b.pack()), lessThan(0)); + }); + + group('localEvent', () { + test( + 'advances millis and resets counter when wall clock moves forward', + () { + const clock = Hlc(millis: 100, counter: 4, nodeId: 'n'); + final next = clock.localEvent(200); + expect(next.millis, 200); + expect(next.counter, 0); + }, + ); + + test('bumps counter when wall clock is unchanged', () { + const clock = Hlc(millis: 100, counter: 4, nodeId: 'n'); + final next = clock.localEvent(100); + expect(next.millis, 100); + expect(next.counter, 5); + }); + + test('stays monotonic when the wall clock runs backwards', () { + const clock = Hlc(millis: 100, counter: 4, nodeId: 'n'); + final next = clock.localEvent(50); // clock skew + expect(next.millis, 100); + expect(next.counter, 5); + expect(next.compareTo(clock), greaterThan(0)); + }); + }); + + group('receiveEvent', () { + test('takes the max millis and bumps beyond both counters on a tie', () { + const local = Hlc(millis: 100, counter: 2, nodeId: 'local'); + const remote = Hlc(millis: 100, counter: 5, nodeId: 'remote'); + final merged = local.receiveEvent(remote, 100); + expect(merged.millis, 100); + expect(merged.counter, 6); + expect(merged.nodeId, 'local'); // identity stays local + }); + + test('adopts a remote future timestamp and continues its counter', () { + const local = Hlc(millis: 100, counter: 2, nodeId: 'local'); + const remote = Hlc(millis: 300, counter: 1, nodeId: 'remote'); + final merged = local.receiveEvent(remote, 120); + expect(merged.millis, 300); + expect(merged.counter, 2); + }); + + test('resets counter when the wall clock leads everything', () { + const local = Hlc(millis: 100, counter: 2, nodeId: 'local'); + const remote = Hlc(millis: 150, counter: 9, nodeId: 'remote'); + final merged = local.receiveEvent(remote, 400); + expect(merged.millis, 400); + expect(merged.counter, 0); + }); + }); + + test('compareTo orders by millis, then counter, then nodeId', () { + const a = Hlc(millis: 1, counter: 0, nodeId: 'a'); + const b = Hlc(millis: 1, counter: 0, nodeId: 'b'); + const c = Hlc(millis: 1, counter: 1, nodeId: 'a'); + const d = Hlc(millis: 2, counter: 0, nodeId: 'a'); + final sorted = [d, c, b, a]..sort(); + expect(sorted, [a, b, c, d]); + }); + }); +} diff --git a/packages/commons_core/test/identity/identity_service_test.dart b/packages/commons_core/test/identity/identity_service_test.dart new file mode 100644 index 0000000..9208486 --- /dev/null +++ b/packages/commons_core/test/identity/identity_service_test.dart @@ -0,0 +1,37 @@ +import 'dart:math'; + +import 'package:commons_core/commons_core.dart'; +import 'package:test/test.dart'; + +void main() { + group('IdentityService', () { + test('generates a 32-byte root seed', () { + final seed = IdentityService().generateRootSeed(); + expect(seed.length, IdentityService.rootSeedLengthBytes); + expect(seed.length, 32); + }); + + test('two seeds from a secure RNG differ', () { + final service = IdentityService(); + expect(service.generateRootSeed(), isNot(service.generateRootSeed())); + }); + + test('is reproducible with an injected seeded RNG (test-only)', () { + // `equals` does element-wise comparison on the byte lists. + final s1 = IdentityService(random: Random(1)).generateRootSeed(); + final s2 = IdentityService(random: Random(1)).generateRootSeed(); + expect(s1, equals(s2)); + }); + }); + + group('randomBytes', () { + test('returns the requested length', () { + expect(randomBytes(16).length, 16); + expect(randomBytes(0).length, 0); + }); + + test('rejects negative lengths', () { + expect(() => randomBytes(-1), throwsArgumentError); + }); + }); +} diff --git a/packages/commons_core/test/ids/id_gen_test.dart b/packages/commons_core/test/ids/id_gen_test.dart new file mode 100644 index 0000000..fffea6d --- /dev/null +++ b/packages/commons_core/test/ids/id_gen_test.dart @@ -0,0 +1,35 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:test/test.dart'; + +void main() { + group('IdGen', () { + final idGen = IdGen(); + + test('produces well-formed UUIDv7 strings', () { + final id = idGen.newId(); + // 8-4-4-4-12 hex groups. + expect( + id, + matches( + RegExp( + r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', + ), + ), + ); + // Version nibble is 7. + expect(id.split('-')[2][0], '7'); + }); + + test('never collides across many calls', () { + final ids = List.generate(5000, (_) => idGen.newId()); + expect(ids.toSet().length, ids.length); + }); + + test('is time-sortable: later ids sort after earlier ones', () async { + final earlier = idGen.newId(); + await Future.delayed(const Duration(milliseconds: 3)); + final later = idGen.newId(); + expect(earlier.compareTo(later), lessThan(0)); + }); + }); +} diff --git a/packages/commons_core/test/value/quantity_test.dart b/packages/commons_core/test/value/quantity_test.dart new file mode 100644 index 0000000..cf261b1 --- /dev/null +++ b/packages/commons_core/test/value/quantity_test.dart @@ -0,0 +1,47 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:test/test.dart'; + +void main() { + group('Quantity', () { + test('value equality ignores object identity', () { + const a = Quantity(kind: QuantityKind.pod, precise: 12, label: 'a bag'); + const b = Quantity(kind: QuantityKind.pod, precise: 12, label: 'a bag'); + expect(a, b); + expect(a.hashCode, b.hashCode); + }); + + test('isPrecise reflects the presence of a precise amount', () { + expect( + const Quantity(kind: QuantityKind.grams, precise: 5).isPrecise, + isTrue, + ); + expect(const Quantity(kind: QuantityKind.aFew).isPrecise, isFalse); + }); + + test('copyWith overrides only the given fields', () { + const q = Quantity(kind: QuantityKind.cob, precise: 2); + final q2 = q.copyWith(kind: QuantityKind.ear); + expect(q2.kind, QuantityKind.ear); + expect(q2.precise, 2); + }); + }); + + group('QuantityKind', () { + test('enum names are stable storage keys', () { + // Guards against accidental renames — these strings live in the DB. + expect(QuantityKind.pod.name, 'pod'); + expect(QuantityKind.cob.name, 'cob'); + expect(QuantityKind.head.name, 'head'); + expect(QuantityKind.packet.name, 'packet'); + expect(QuantityKind.handful.name, 'handful'); + expect(QuantityKind.grams.name, 'grams'); + expect(QuantityKind.count.name, 'count'); + }); + + test('every kind belongs to a group', () { + for (final kind in QuantityKind.values) { + expect(QuantityGroup.values, contains(kind.group)); + } + }); + }); +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..e8847f4 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1150 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d" + url: "https://pub.dev" + source: hosted + version: "93.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b + url: "https://pub.dev" + source: hosted + version: "10.0.1" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + bloc: + dependency: transitive + description: + name: bloc + sha256: e03b235924e4f509c27b5d6b2f949200e0a91149a9818b4f65eeb56662b75413 + url: "https://pub.dev" + source: hosted + version: "9.2.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10 + url: "https://pub.dev" + source: hosted + version: "4.0.6" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + url: "https://pub.dev" + source: hosted + version: "4.1.1" + build_runner: + dependency: transitive + description: + name: build_runner + sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6" + url: "https://pub.dev" + source: hosted + version: "2.15.0" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56" + url: "https://pub.dev" + source: hosted + version: "8.12.6" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d" + url: "https://pub.dev" + source: hosted + version: "1.15.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "92c9c43c383bfa1c32079d3bc492d55d6d4318044b7b47edaff8971cbb555c51" + url: "https://pub.dev" + source: hosted + version: "0.3.5+4" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cupertino_icons: + dependency: transitive + description: + name: cupertino_icons + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2" + url: "https://pub.dev" + source: hosted + version: "3.1.7" + drift: + dependency: transitive + description: + name: drift + sha256: "970cd188fddb111b26ea6a9b07a62bf5c2432d74147b8122c67044ae3b97e99e" + url: "https://pub.dev" + source: hosted + version: "2.31.0" + drift_dev: + dependency: transitive + description: + name: drift_dev + sha256: "917184b2fb867b70a548a83bf0d36268423b38d39968c06cce4905683da49587" + url: "https://pub.dev" + source: hosted + version: "2.31.0" + drift_flutter: + dependency: transitive + description: + name: drift_flutter + sha256: c07120854742a0cae2f7501a0da02493addde550db6641d284983c08762e60a7 + url: "https://pub.dev" + source: hosted + version: "0.2.8" + equatable: + dependency: transitive + description: + name: equatable + sha256: "3bce007a596ff8b3119c45d68aaef631272537c03d30e5d4534dd24bf4c5eaa2" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + url: "https://pub.dev" + source: hosted + version: "0.9.3+5" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: transitive + description: + name: flutter_bloc + sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38 + url: "https://pub.dev" + source: hosted + version: "9.1.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: transitive + description: + name: flutter_lints + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" + url: "https://pub.dev" + source: hosted + version: "2.0.35" + flutter_secure_storage: + dependency: transitive + description: + name: flutter_secure_storage + sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" + url: "https://pub.dev" + source: hosted + version: "9.2.4" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247" + url: "https://pub.dev" + source: hosted + version: "3.1.3" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + flutter_test: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + get_it: + dependency: transitive + description: + name: get_it + sha256: ae78de7c3f2304b8d81f2bb6e320833e5e81de942188542328f074978cc0efa9 + url: "https://pub.dev" + source: hosted + version: "8.3.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + go_router: + dependency: transitive + description: + name: go_router + sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 + url: "https://pub.dev" + source: hosted + version: "14.8.1" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image_picker: + dependency: transitive + description: + name: image_picker + sha256: d8402284df184bc05f4a2210c6c23983b0720f4cd87cbd05c5390a78af602667 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: d5b3e1774af29c9ab00103afb0d4614070f924d2e0057ac867ec98800114793f + url: "https://pub.dev" + source: hosted + version: "0.8.13+17" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + url: "https://pub.dev" + source: hosted + version: "0.8.13+6" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.dev" + source: hosted + version: "0.2.2" + integration_test: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" + url: "https://pub.dev" + source: hosted + version: "4.12.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" + source: hosted + version: "0.12.19" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mocktail: + dependency: transitive + description: + name: mocktail + sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: a7f4874f987173da295a61c181b8ee71dab59b332a486b391babf26a1b884825 + url: "https://pub.dev" + source: hosted + version: "2.1.6" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: "58c2005f147315b11e9b4a7bc889cd5203e250cba8e3f012dae259b4972b5c16" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "484838772624c3a4b94f1e44a3e19897fee738f2d5c4ce448443b0417f7c9dda" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + process: + dependency: transitive + description: + name: process + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + serial_csv: + dependency: transitive + description: + name: serial_csv + sha256: "2d62bb70cb3ce7251383fc86ea9aae1298ab1e57af6ef4e93b6a9751c5c268dd" + url: "https://pub.dev" + source: hosted + version: "0.5.2" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + slang: + dependency: transitive + description: + name: slang + sha256: "76dbf1f8e87ed1c417026e93a57512f6b6b597104ce72eed99b24a3ed08f0ba2" + url: "https://pub.dev" + source: hosted + version: "4.18.0" + slang_build_runner: + dependency: transitive + description: + name: slang_build_runner + sha256: e24f5ab540c2078db20a1e3292b9bae11ef4ed07bef1c235ae000b0a6113267e + url: "https://pub.dev" + source: hosted + version: "4.18.0" + slang_flutter: + dependency: transitive + description: + name: slang_flutter + sha256: "7523a9389b44210eabcfd58412d9131f284b9b3c22d731614f0016e9582ee996" + url: "https://pub.dev" + source: hosted + version: "4.18.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02 + url: "https://pub.dev" + source: hosted + version: "4.2.3" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + sqlcipher_flutter_libs: + dependency: transitive + description: + name: sqlcipher_flutter_libs + sha256: dd1fcc74d5baf3c36ad53e2652b2d06c9f8747494a3ccde0076e88b159dfe622 + url: "https://pub.dev" + source: hosted + version: "0.6.8" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" + url: "https://pub.dev" + source: hosted + version: "2.9.4" + sqlite3_flutter_libs: + dependency: transitive + description: + name: sqlite3_flutter_libs + sha256: eeb9e3a45207649076b808f8a5a74d68770d0b7f26ccef6d5f43106eee5375ad + url: "https://pub.dev" + source: hosted + version: "0.5.42" + sqlparser: + dependency: transitive + description: + name: sqlparser + sha256: "337e9997f7141ffdd054259128553c348635fa318f7ca492f07a4ab76f850d19" + url: "https://pub.dev" + source: hosted + version: "0.43.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: transitive + description: + name: test + sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" + url: "https://pub.dev" + source: hosted + version: "1.30.0" + test_api: + dependency: transitive + description: + name: test_api + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + test_core: + dependency: transitive + description: + name: test_core + sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" + url: "https://pub.dev" + source: hosted + version: "0.6.16" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.dev" + source: hosted + version: "15.2.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.11.5 <4.0.0" + flutter: ">=3.38.4" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..1476cb9 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,12 @@ +# Pub workspace root for Tanemaki (Tane). +# Members share a single lockfile and .dart_tool. See CLAUDE.md and +# docs/design/core-domain-boundary.md for the package boundary rules. +name: tane_workspace +publish_to: none + +environment: + sdk: ^3.11.5 + +workspace: + - packages/commons_core + - apps/app_seeds