commit 9df372ebb7b8e701f3493a055ef5613b91478d07 Author: alexis Date: Sat Jul 11 18:10:09 2026 +0200 init: ynab_lite Flutter project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3820a95 --- /dev/null +++ b/.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/.metadata b/.metadata new file mode 100644 index 0000000..235bfb1 --- /dev/null +++ b/.metadata @@ -0,0 +1,30 @@ +# 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: "ee80f08bbf97172ec030b8751ceab557177a34a6" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6 + base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6 + - platform: android + create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6 + base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6 + + # 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/README.md b/README.md new file mode 100644 index 0000000..1f8688b --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# ynab_lite + +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/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/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/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/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/android/app/build.gradle.kts b/android/app/build.gradle.kts new file mode 100644 index 0000000..02b9eaa --- /dev/null +++ b/android/app/build.gradle.kts @@ -0,0 +1,45 @@ +plugins { + id("com.android.application") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.ynab.ynab_lite" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.ynab.ynab_lite" + // 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") + } + } +} + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + +flutter { + source = "../.." +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a94609c --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/ynab/ynab_lite/MainActivity.kt b/android/app/src/main/kotlin/com/ynab/ynab_lite/MainActivity.kt new file mode 100644 index 0000000..a7cc929 --- /dev/null +++ b/android/app/src/main/kotlin/com/ynab/ynab_lite/MainActivity.kt @@ -0,0 +1,5 @@ +package com.ynab.ynab_lite + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..dbee657 --- /dev/null +++ b/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/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..e96108c --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,6 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +# This newDsl flag was added by the Flutter template +android.newDsl=false +# This builtInKotlin flag was added by the Flutter template +android.builtInKotlin=false diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2d428bf --- /dev/null +++ b/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-9.1.0-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts new file mode 100644 index 0000000..c21f0c5 --- /dev/null +++ b/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 "9.0.1" apply false + id("org.jetbrains.kotlin.android") version "2.3.20" apply false +} + +include(":app") diff --git a/lib/app.dart b/lib/app.dart new file mode 100644 index 0000000..858da9d --- /dev/null +++ b/lib/app.dart @@ -0,0 +1,218 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'theme/app_theme.dart'; +import 'screens/dashboard_screen.dart'; +import 'screens/budget_screen.dart'; +import 'screens/accounts_screen.dart'; +import 'screens/transactions_screen.dart'; + +final _selectedIndexProvider = StateProvider((ref) => 0); + +class YnabApp extends ConsumerStatefulWidget { + const YnabApp({super.key}); + + @override + ConsumerState createState() => _YnabAppState(); +} + +class _YnabAppState extends ConsumerState { + late final List _screens; + late final List<_NavItem> _navItems; + + @override + void initState() { + super.initState(); + _screens = const [ + DashboardScreen(), + BudgetScreen(), + AccountsScreen(), + TransactionsScreen(), + ]; + _navItems = const [ + _NavItem(icon: Icons.dashboard_outlined, selectedIcon: Icons.dashboard, label: 'Tableau de bord'), + _NavItem(icon: Icons.pie_chart_outline, selectedIcon: Icons.pie_chart, label: 'Budget'), + _NavItem(icon: Icons.account_balance_outlined, selectedIcon: Icons.account_balance, label: 'Comptes'), + _NavItem(icon: Icons.receipt_long_outlined, selectedIcon: Icons.receipt_long, label: 'Transactions'), + ]; + } + + @override + Widget build(BuildContext context) { + final selectedIndex = ref.watch(_selectedIndexProvider); + + return Scaffold( + backgroundColor: kSurfaceBg, + body: SafeArea( + child: Row( + children: [ + // ── Side Navigation ── + Container( + width: 72, + decoration: BoxDecoration( + color: kSurfaceCard, + border: Border( + right: BorderSide(color: kDivider, width: 1), + ), + ), + child: Column( + children: [ + const SizedBox(height: 20), + // App logo / icon + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: kGreenAccent.withAlpha(30), + borderRadius: BorderRadius.circular(12), + ), + child: const Center( + child: Icon(Icons.currency_bitcoin, color: kGreenAccent, size: 22), + ), + ), + const SizedBox(height: 8), + Text( + 'YNAB\nLite', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 9, + color: kGreenAccent, + fontWeight: FontWeight.w700, + height: 1.2, + ), + ), + const SizedBox(height: 28), + // Navigation items + ...List.generate(_navItems.length, (i) { + final item = _navItems[i]; + final active = i == selectedIndex; + return _NavRailItem( + icon: active ? item.selectedIcon : item.icon, + label: item.label, + active: active, + onTap: () => ref.read(_selectedIndexProvider.notifier).state = i, + ); + }), + const Spacer(), + // Settings at bottom + _NavRailItem( + icon: Icons.settings_outlined, + selectedIcon: Icons.settings, + label: 'Paramètres', + active: false, + onTap: () {}, + ), + const SizedBox(height: 20), + ], + ), + ), + // ── Main Content ── + Expanded( + child: Column( + children: [ + // Header + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + decoration: BoxDecoration( + color: kSurfaceBg, + border: Border( + bottom: BorderSide(color: kDivider, width: 0.5), + ), + ), + child: Row( + children: [ + Text( + _navItems[selectedIndex].label, + style: const TextStyle( + color: kTextPrimary, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + const Spacer(), + IconButton( + icon: const Icon(Icons.add, color: kGreenAccent), + onPressed: () {}, + tooltip: 'Ajouter une transaction', + ), + IconButton( + icon: const Icon(Icons.search, color: kTextSecondary), + onPressed: () {}, + tooltip: 'Rechercher', + ), + ], + ), + ), + // Content + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + child: _screens[selectedIndex], + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} + +class _NavItem { + final IconData icon; + final IconData selectedIcon; + final String label; + const _NavItem({required this.icon, required this.selectedIcon, required this.label}); +} + +class _NavRailItem extends StatelessWidget { + final IconData icon; + final IconData? selectedIcon; + final String label; + final bool active; + final VoidCallback onTap; + + const _NavRailItem({ + required this.icon, + this.selectedIcon, + required this.label, + required this.active, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Tooltip( + message: label, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + width: 56, + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: active ? kGreenAccent.withAlpha(20) : null, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 22, + color: active ? kGreenAccent : kTextSecondary, + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/data/db.dart b/lib/data/db.dart new file mode 100644 index 0000000..183b659 --- /dev/null +++ b/lib/data/db.dart @@ -0,0 +1,87 @@ +import 'package:drift/drift.dart'; +import 'package:drift_flutter/drift_flutter.dart'; +import 'tables.dart'; + +part 'db.g.dart'; + +@DriftDatabase( + tables: [ + Accounts, + CategoryGroups, + Categories, + Transactions, + Budgets, + ], +) +class AppDatabase extends _$AppDatabase { + AppDatabase() : super(_openConnection()); + + static QueryExecutor _openConnection() { + return driftDatabase(name: 'ynab_lite'); + } + + @override + int get schemaVersion => 1; + + // ── Seed ────────────────────────────────────────────────────────────────── + Future seedIfEmpty() async { + final count = await select(accounts).get().then((r) => r.length); + if (count > 0) return; + + // default category groups + final groups = [ + CategoryGroupsCompanion.insert(name: 'Logement & Charges Fixes', sortOrder: const Value(1)), + CategoryGroupsCompanion.insert(name: 'Alimentation', sortOrder: const Value(2)), + CategoryGroupsCompanion.insert(name: 'Transport', sortOrder: const Value(3)), + CategoryGroupsCompanion.insert(name: 'Loisirs & Divertissements', sortOrder: const Value(4)), + CategoryGroupsCompanion.insert(name: 'Épargne & Objectifs', sortOrder: const Value(5)), + ]; + for (final g in groups) { + await into(categoryGroups).insert(g); + } + + // categories + final cats = [ + (group: 1, name: 'Loyer', icon: 'home'), + (group: 1, name: 'Électricité', icon: 'bolt'), + (group: 1, name: 'Eau', icon: 'water_drop'), + (group: 1, name: 'Assurance habitation', icon: 'shield'), + (group: 2, name: 'Courses', icon: 'shopping_cart'), + (group: 2, name: 'Restaurants', icon: 'restaurant'), + (group: 3, name: 'Essence', icon: 'local_gas_station'), + (group: 3, name: 'Transports en commun', icon: 'directions_bus'), + (group: 4, name: 'Streaming', icon: 'tv'), + (group: 4, name: 'Sorties', icon: 'celebration'), + (group: 5, name: 'Épargne d\'urgence', icon: 'savings'), + (group: 5, name: 'Vacances', icon: 'flight'), + ]; + for (int i = 0; i < cats.length; i++) { + await into(categories).insert(CategoriesCompanion.insert( + name: cats[i].name, + groupId: cats[i].group, + icon: Value(cats[i].icon), + sortOrder: Value(i + 1), + )); + } + + // default account + await into(accounts).insert(AccountsCompanion.insert( + name: 'Compte courant', + type: 'checking', + balance: const Value(2500.0), + sortOrder: const Value(1), + )); + await into(accounts).insert(AccountsCompanion.insert( + name: 'Livret A', + type: 'savings', + balance: const Value(5000.0), + sortOrder: const Value(2), + )); + await into(accounts).insert(AccountsCompanion.insert( + name: 'Espèces', + type: 'cash', + balance: const Value(120.0), + sortOrder: const Value(3), + )); + } +} diff --git a/lib/data/db.g.dart b/lib/data/db.g.dart new file mode 100644 index 0000000..fee2f2d --- /dev/null +++ b/lib/data/db.g.dart @@ -0,0 +1,3874 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'db.dart'; + +// ignore_for_file: type=lint +class $AccountsTable extends Accounts with TableInfo<$AccountsTable, Account> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AccountsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _typeMeta = const VerificationMeta('type'); + @override + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _balanceMeta = const VerificationMeta( + 'balance', + ); + @override + late final GeneratedColumn balance = GeneratedColumn( + 'balance', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(0.0), + ); + static const VerificationMeta _isClosedMeta = const VerificationMeta( + 'isClosed', + ); + @override + late final GeneratedColumn isClosed = GeneratedColumn( + 'is_closed', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_closed" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _sortOrderMeta = const VerificationMeta( + 'sortOrder', + ); + @override + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + @override + List get $columns => [ + id, + name, + type, + balance, + isClosed, + sortOrder, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'accounts'; + @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)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('type')) { + context.handle( + _typeMeta, + type.isAcceptableOrUnknown(data['type']!, _typeMeta), + ); + } else if (isInserting) { + context.missing(_typeMeta); + } + if (data.containsKey('balance')) { + context.handle( + _balanceMeta, + balance.isAcceptableOrUnknown(data['balance']!, _balanceMeta), + ); + } + if (data.containsKey('is_closed')) { + context.handle( + _isClosedMeta, + isClosed.isAcceptableOrUnknown(data['is_closed']!, _isClosedMeta), + ); + } + if (data.containsKey('sort_order')) { + context.handle( + _sortOrderMeta, + sortOrder.isAcceptableOrUnknown(data['sort_order']!, _sortOrderMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Account map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Account( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + balance: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}balance'], + )!, + isClosed: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_closed'], + )!, + sortOrder: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sort_order'], + )!, + ); + } + + @override + $AccountsTable createAlias(String alias) { + return $AccountsTable(attachedDatabase, alias); + } +} + +class Account extends DataClass implements Insertable { + final int id; + final String name; + final String type; + final double balance; + final bool isClosed; + final int sortOrder; + const Account({ + required this.id, + required this.name, + required this.type, + required this.balance, + required this.isClosed, + required this.sortOrder, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['type'] = Variable(type); + map['balance'] = Variable(balance); + map['is_closed'] = Variable(isClosed); + map['sort_order'] = Variable(sortOrder); + return map; + } + + AccountsCompanion toCompanion(bool nullToAbsent) { + return AccountsCompanion( + id: Value(id), + name: Value(name), + type: Value(type), + balance: Value(balance), + isClosed: Value(isClosed), + sortOrder: Value(sortOrder), + ); + } + + factory Account.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Account( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + balance: serializer.fromJson(json['balance']), + isClosed: serializer.fromJson(json['isClosed']), + sortOrder: serializer.fromJson(json['sortOrder']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'balance': serializer.toJson(balance), + 'isClosed': serializer.toJson(isClosed), + 'sortOrder': serializer.toJson(sortOrder), + }; + } + + Account copyWith({ + int? id, + String? name, + String? type, + double? balance, + bool? isClosed, + int? sortOrder, + }) => Account( + id: id ?? this.id, + name: name ?? this.name, + type: type ?? this.type, + balance: balance ?? this.balance, + isClosed: isClosed ?? this.isClosed, + sortOrder: sortOrder ?? this.sortOrder, + ); + Account copyWithCompanion(AccountsCompanion data) { + return Account( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + balance: data.balance.present ? data.balance.value : this.balance, + isClosed: data.isClosed.present ? data.isClosed.value : this.isClosed, + sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder, + ); + } + + @override + String toString() { + return (StringBuffer('Account(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('balance: $balance, ') + ..write('isClosed: $isClosed, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, type, balance, isClosed, sortOrder); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Account && + other.id == this.id && + other.name == this.name && + other.type == this.type && + other.balance == this.balance && + other.isClosed == this.isClosed && + other.sortOrder == this.sortOrder); +} + +class AccountsCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value type; + final Value balance; + final Value isClosed; + final Value sortOrder; + const AccountsCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.type = const Value.absent(), + this.balance = const Value.absent(), + this.isClosed = const Value.absent(), + this.sortOrder = const Value.absent(), + }); + AccountsCompanion.insert({ + this.id = const Value.absent(), + required String name, + required String type, + this.balance = const Value.absent(), + this.isClosed = const Value.absent(), + this.sortOrder = const Value.absent(), + }) : name = Value(name), + type = Value(type); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? type, + Expression? balance, + Expression? isClosed, + Expression? sortOrder, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (type != null) 'type': type, + if (balance != null) 'balance': balance, + if (isClosed != null) 'is_closed': isClosed, + if (sortOrder != null) 'sort_order': sortOrder, + }); + } + + AccountsCompanion copyWith({ + Value? id, + Value? name, + Value? type, + Value? balance, + Value? isClosed, + Value? sortOrder, + }) { + return AccountsCompanion( + id: id ?? this.id, + name: name ?? this.name, + type: type ?? this.type, + balance: balance ?? this.balance, + isClosed: isClosed ?? this.isClosed, + sortOrder: sortOrder ?? this.sortOrder, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (balance.present) { + map['balance'] = Variable(balance.value); + } + if (isClosed.present) { + map['is_closed'] = Variable(isClosed.value); + } + if (sortOrder.present) { + map['sort_order'] = Variable(sortOrder.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AccountsCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('balance: $balance, ') + ..write('isClosed: $isClosed, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } +} + +class $CategoryGroupsTable extends CategoryGroups + with TableInfo<$CategoryGroupsTable, CategoryGroup> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $CategoryGroupsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _sortOrderMeta = const VerificationMeta( + 'sortOrder', + ); + @override + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + @override + List get $columns => [id, name, sortOrder]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'category_groups'; + @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)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('sort_order')) { + context.handle( + _sortOrderMeta, + sortOrder.isAcceptableOrUnknown(data['sort_order']!, _sortOrderMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + CategoryGroup map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return CategoryGroup( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + sortOrder: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sort_order'], + )!, + ); + } + + @override + $CategoryGroupsTable createAlias(String alias) { + return $CategoryGroupsTable(attachedDatabase, alias); + } +} + +class CategoryGroup extends DataClass implements Insertable { + final int id; + final String name; + final int sortOrder; + const CategoryGroup({ + required this.id, + required this.name, + required this.sortOrder, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['sort_order'] = Variable(sortOrder); + return map; + } + + CategoryGroupsCompanion toCompanion(bool nullToAbsent) { + return CategoryGroupsCompanion( + id: Value(id), + name: Value(name), + sortOrder: Value(sortOrder), + ); + } + + factory CategoryGroup.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return CategoryGroup( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + sortOrder: serializer.fromJson(json['sortOrder']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'sortOrder': serializer.toJson(sortOrder), + }; + } + + CategoryGroup copyWith({int? id, String? name, int? sortOrder}) => + CategoryGroup( + id: id ?? this.id, + name: name ?? this.name, + sortOrder: sortOrder ?? this.sortOrder, + ); + CategoryGroup copyWithCompanion(CategoryGroupsCompanion data) { + return CategoryGroup( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder, + ); + } + + @override + String toString() { + return (StringBuffer('CategoryGroup(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, sortOrder); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is CategoryGroup && + other.id == this.id && + other.name == this.name && + other.sortOrder == this.sortOrder); +} + +class CategoryGroupsCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value sortOrder; + const CategoryGroupsCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.sortOrder = const Value.absent(), + }); + CategoryGroupsCompanion.insert({ + this.id = const Value.absent(), + required String name, + this.sortOrder = const Value.absent(), + }) : name = Value(name); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? sortOrder, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (sortOrder != null) 'sort_order': sortOrder, + }); + } + + CategoryGroupsCompanion copyWith({ + Value? id, + Value? name, + Value? sortOrder, + }) { + return CategoryGroupsCompanion( + id: id ?? this.id, + name: name ?? this.name, + sortOrder: sortOrder ?? this.sortOrder, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (sortOrder.present) { + map['sort_order'] = Variable(sortOrder.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('CategoryGroupsCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } +} + +class $CategoriesTable extends Categories + with TableInfo<$CategoriesTable, Category> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $CategoriesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _groupIdMeta = const VerificationMeta( + 'groupId', + ); + @override + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES category_groups (id)', + ), + ); + static const VerificationMeta _budgetedMeta = const VerificationMeta( + 'budgeted', + ); + @override + late final GeneratedColumn budgeted = GeneratedColumn( + 'budgeted', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(0.0), + ); + static const VerificationMeta _sortOrderMeta = const VerificationMeta( + 'sortOrder', + ); + @override + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + static const VerificationMeta _iconMeta = const VerificationMeta('icon'); + @override + late final GeneratedColumn icon = GeneratedColumn( + 'icon', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + name, + groupId, + budgeted, + sortOrder, + icon, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'categories'; + @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)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('group_id')) { + context.handle( + _groupIdMeta, + groupId.isAcceptableOrUnknown(data['group_id']!, _groupIdMeta), + ); + } else if (isInserting) { + context.missing(_groupIdMeta); + } + if (data.containsKey('budgeted')) { + context.handle( + _budgetedMeta, + budgeted.isAcceptableOrUnknown(data['budgeted']!, _budgetedMeta), + ); + } + if (data.containsKey('sort_order')) { + context.handle( + _sortOrderMeta, + sortOrder.isAcceptableOrUnknown(data['sort_order']!, _sortOrderMeta), + ); + } + if (data.containsKey('icon')) { + context.handle( + _iconMeta, + icon.isAcceptableOrUnknown(data['icon']!, _iconMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Category map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Category( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}group_id'], + )!, + budgeted: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}budgeted'], + )!, + sortOrder: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sort_order'], + )!, + icon: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}icon'], + ), + ); + } + + @override + $CategoriesTable createAlias(String alias) { + return $CategoriesTable(attachedDatabase, alias); + } +} + +class Category extends DataClass implements Insertable { + final int id; + final String name; + final int groupId; + final double budgeted; + final int sortOrder; + final String? icon; + const Category({ + required this.id, + required this.name, + required this.groupId, + required this.budgeted, + required this.sortOrder, + this.icon, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['group_id'] = Variable(groupId); + map['budgeted'] = Variable(budgeted); + map['sort_order'] = Variable(sortOrder); + if (!nullToAbsent || icon != null) { + map['icon'] = Variable(icon); + } + return map; + } + + CategoriesCompanion toCompanion(bool nullToAbsent) { + return CategoriesCompanion( + id: Value(id), + name: Value(name), + groupId: Value(groupId), + budgeted: Value(budgeted), + sortOrder: Value(sortOrder), + icon: icon == null && nullToAbsent ? const Value.absent() : Value(icon), + ); + } + + factory Category.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Category( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + groupId: serializer.fromJson(json['groupId']), + budgeted: serializer.fromJson(json['budgeted']), + sortOrder: serializer.fromJson(json['sortOrder']), + icon: serializer.fromJson(json['icon']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'groupId': serializer.toJson(groupId), + 'budgeted': serializer.toJson(budgeted), + 'sortOrder': serializer.toJson(sortOrder), + 'icon': serializer.toJson(icon), + }; + } + + Category copyWith({ + int? id, + String? name, + int? groupId, + double? budgeted, + int? sortOrder, + Value icon = const Value.absent(), + }) => Category( + id: id ?? this.id, + name: name ?? this.name, + groupId: groupId ?? this.groupId, + budgeted: budgeted ?? this.budgeted, + sortOrder: sortOrder ?? this.sortOrder, + icon: icon.present ? icon.value : this.icon, + ); + Category copyWithCompanion(CategoriesCompanion data) { + return Category( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + budgeted: data.budgeted.present ? data.budgeted.value : this.budgeted, + sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder, + icon: data.icon.present ? data.icon.value : this.icon, + ); + } + + @override + String toString() { + return (StringBuffer('Category(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('groupId: $groupId, ') + ..write('budgeted: $budgeted, ') + ..write('sortOrder: $sortOrder, ') + ..write('icon: $icon') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, groupId, budgeted, sortOrder, icon); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Category && + other.id == this.id && + other.name == this.name && + other.groupId == this.groupId && + other.budgeted == this.budgeted && + other.sortOrder == this.sortOrder && + other.icon == this.icon); +} + +class CategoriesCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value groupId; + final Value budgeted; + final Value sortOrder; + final Value icon; + const CategoriesCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.groupId = const Value.absent(), + this.budgeted = const Value.absent(), + this.sortOrder = const Value.absent(), + this.icon = const Value.absent(), + }); + CategoriesCompanion.insert({ + this.id = const Value.absent(), + required String name, + required int groupId, + this.budgeted = const Value.absent(), + this.sortOrder = const Value.absent(), + this.icon = const Value.absent(), + }) : name = Value(name), + groupId = Value(groupId); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? groupId, + Expression? budgeted, + Expression? sortOrder, + Expression? icon, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (groupId != null) 'group_id': groupId, + if (budgeted != null) 'budgeted': budgeted, + if (sortOrder != null) 'sort_order': sortOrder, + if (icon != null) 'icon': icon, + }); + } + + CategoriesCompanion copyWith({ + Value? id, + Value? name, + Value? groupId, + Value? budgeted, + Value? sortOrder, + Value? icon, + }) { + return CategoriesCompanion( + id: id ?? this.id, + name: name ?? this.name, + groupId: groupId ?? this.groupId, + budgeted: budgeted ?? this.budgeted, + sortOrder: sortOrder ?? this.sortOrder, + icon: icon ?? this.icon, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (budgeted.present) { + map['budgeted'] = Variable(budgeted.value); + } + if (sortOrder.present) { + map['sort_order'] = Variable(sortOrder.value); + } + if (icon.present) { + map['icon'] = Variable(icon.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('CategoriesCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('groupId: $groupId, ') + ..write('budgeted: $budgeted, ') + ..write('sortOrder: $sortOrder, ') + ..write('icon: $icon') + ..write(')')) + .toString(); + } +} + +class $TransactionsTable extends Transactions + with TableInfo<$TransactionsTable, Transaction> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $TransactionsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _accountIdMeta = const VerificationMeta( + 'accountId', + ); + @override + late final GeneratedColumn accountId = GeneratedColumn( + 'account_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES accounts (id)', + ), + ); + static const VerificationMeta _categoryIdMeta = const VerificationMeta( + 'categoryId', + ); + @override + late final GeneratedColumn categoryId = GeneratedColumn( + 'category_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES categories (id)', + ), + ); + static const VerificationMeta _payeeMeta = const VerificationMeta('payee'); + @override + late final GeneratedColumn payee = GeneratedColumn( + 'payee', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _notesMeta = const VerificationMeta('notes'); + @override + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _amountMeta = const VerificationMeta('amount'); + @override + late final GeneratedColumn amount = GeneratedColumn( + 'amount', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: true, + ); + static const VerificationMeta _dateMeta = const VerificationMeta('date'); + @override + late final GeneratedColumn date = GeneratedColumn( + 'date', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + static const VerificationMeta _clearedMeta = const VerificationMeta( + 'cleared', + ); + @override + late final GeneratedColumn cleared = GeneratedColumn( + 'cleared', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("cleared" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _sortOrderMeta = const VerificationMeta( + 'sortOrder', + ); + @override + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + @override + List get $columns => [ + id, + accountId, + categoryId, + payee, + notes, + amount, + date, + cleared, + sortOrder, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'transactions'; + @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)); + } + if (data.containsKey('account_id')) { + context.handle( + _accountIdMeta, + accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta), + ); + } else if (isInserting) { + context.missing(_accountIdMeta); + } + if (data.containsKey('category_id')) { + context.handle( + _categoryIdMeta, + categoryId.isAcceptableOrUnknown(data['category_id']!, _categoryIdMeta), + ); + } + if (data.containsKey('payee')) { + context.handle( + _payeeMeta, + payee.isAcceptableOrUnknown(data['payee']!, _payeeMeta), + ); + } else if (isInserting) { + context.missing(_payeeMeta); + } + if (data.containsKey('notes')) { + context.handle( + _notesMeta, + notes.isAcceptableOrUnknown(data['notes']!, _notesMeta), + ); + } + if (data.containsKey('amount')) { + context.handle( + _amountMeta, + amount.isAcceptableOrUnknown(data['amount']!, _amountMeta), + ); + } else if (isInserting) { + context.missing(_amountMeta); + } + if (data.containsKey('date')) { + context.handle( + _dateMeta, + date.isAcceptableOrUnknown(data['date']!, _dateMeta), + ); + } else if (isInserting) { + context.missing(_dateMeta); + } + if (data.containsKey('cleared')) { + context.handle( + _clearedMeta, + cleared.isAcceptableOrUnknown(data['cleared']!, _clearedMeta), + ); + } + if (data.containsKey('sort_order')) { + context.handle( + _sortOrderMeta, + sortOrder.isAcceptableOrUnknown(data['sort_order']!, _sortOrderMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Transaction map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Transaction( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + accountId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}account_id'], + )!, + categoryId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}category_id'], + ), + payee: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}payee'], + )!, + notes: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}notes'], + ), + amount: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}amount'], + )!, + date: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}date'], + )!, + cleared: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}cleared'], + )!, + sortOrder: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sort_order'], + )!, + ); + } + + @override + $TransactionsTable createAlias(String alias) { + return $TransactionsTable(attachedDatabase, alias); + } +} + +class Transaction extends DataClass implements Insertable { + final int id; + final int accountId; + final int? categoryId; + final String payee; + final String? notes; + final double amount; + final DateTime date; + final bool cleared; + final int sortOrder; + const Transaction({ + required this.id, + required this.accountId, + this.categoryId, + required this.payee, + this.notes, + required this.amount, + required this.date, + required this.cleared, + required this.sortOrder, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['account_id'] = Variable(accountId); + if (!nullToAbsent || categoryId != null) { + map['category_id'] = Variable(categoryId); + } + map['payee'] = Variable(payee); + if (!nullToAbsent || notes != null) { + map['notes'] = Variable(notes); + } + map['amount'] = Variable(amount); + map['date'] = Variable(date); + map['cleared'] = Variable(cleared); + map['sort_order'] = Variable(sortOrder); + return map; + } + + TransactionsCompanion toCompanion(bool nullToAbsent) { + return TransactionsCompanion( + id: Value(id), + accountId: Value(accountId), + categoryId: categoryId == null && nullToAbsent + ? const Value.absent() + : Value(categoryId), + payee: Value(payee), + notes: notes == null && nullToAbsent + ? const Value.absent() + : Value(notes), + amount: Value(amount), + date: Value(date), + cleared: Value(cleared), + sortOrder: Value(sortOrder), + ); + } + + factory Transaction.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Transaction( + id: serializer.fromJson(json['id']), + accountId: serializer.fromJson(json['accountId']), + categoryId: serializer.fromJson(json['categoryId']), + payee: serializer.fromJson(json['payee']), + notes: serializer.fromJson(json['notes']), + amount: serializer.fromJson(json['amount']), + date: serializer.fromJson(json['date']), + cleared: serializer.fromJson(json['cleared']), + sortOrder: serializer.fromJson(json['sortOrder']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'accountId': serializer.toJson(accountId), + 'categoryId': serializer.toJson(categoryId), + 'payee': serializer.toJson(payee), + 'notes': serializer.toJson(notes), + 'amount': serializer.toJson(amount), + 'date': serializer.toJson(date), + 'cleared': serializer.toJson(cleared), + 'sortOrder': serializer.toJson(sortOrder), + }; + } + + Transaction copyWith({ + int? id, + int? accountId, + Value categoryId = const Value.absent(), + String? payee, + Value notes = const Value.absent(), + double? amount, + DateTime? date, + bool? cleared, + int? sortOrder, + }) => Transaction( + id: id ?? this.id, + accountId: accountId ?? this.accountId, + categoryId: categoryId.present ? categoryId.value : this.categoryId, + payee: payee ?? this.payee, + notes: notes.present ? notes.value : this.notes, + amount: amount ?? this.amount, + date: date ?? this.date, + cleared: cleared ?? this.cleared, + sortOrder: sortOrder ?? this.sortOrder, + ); + Transaction copyWithCompanion(TransactionsCompanion data) { + return Transaction( + id: data.id.present ? data.id.value : this.id, + accountId: data.accountId.present ? data.accountId.value : this.accountId, + categoryId: data.categoryId.present + ? data.categoryId.value + : this.categoryId, + payee: data.payee.present ? data.payee.value : this.payee, + notes: data.notes.present ? data.notes.value : this.notes, + amount: data.amount.present ? data.amount.value : this.amount, + date: data.date.present ? data.date.value : this.date, + cleared: data.cleared.present ? data.cleared.value : this.cleared, + sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder, + ); + } + + @override + String toString() { + return (StringBuffer('Transaction(') + ..write('id: $id, ') + ..write('accountId: $accountId, ') + ..write('categoryId: $categoryId, ') + ..write('payee: $payee, ') + ..write('notes: $notes, ') + ..write('amount: $amount, ') + ..write('date: $date, ') + ..write('cleared: $cleared, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + accountId, + categoryId, + payee, + notes, + amount, + date, + cleared, + sortOrder, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Transaction && + other.id == this.id && + other.accountId == this.accountId && + other.categoryId == this.categoryId && + other.payee == this.payee && + other.notes == this.notes && + other.amount == this.amount && + other.date == this.date && + other.cleared == this.cleared && + other.sortOrder == this.sortOrder); +} + +class TransactionsCompanion extends UpdateCompanion { + final Value id; + final Value accountId; + final Value categoryId; + final Value payee; + final Value notes; + final Value amount; + final Value date; + final Value cleared; + final Value sortOrder; + const TransactionsCompanion({ + this.id = const Value.absent(), + this.accountId = const Value.absent(), + this.categoryId = const Value.absent(), + this.payee = const Value.absent(), + this.notes = const Value.absent(), + this.amount = const Value.absent(), + this.date = const Value.absent(), + this.cleared = const Value.absent(), + this.sortOrder = const Value.absent(), + }); + TransactionsCompanion.insert({ + this.id = const Value.absent(), + required int accountId, + this.categoryId = const Value.absent(), + required String payee, + this.notes = const Value.absent(), + required double amount, + required DateTime date, + this.cleared = const Value.absent(), + this.sortOrder = const Value.absent(), + }) : accountId = Value(accountId), + payee = Value(payee), + amount = Value(amount), + date = Value(date); + static Insertable custom({ + Expression? id, + Expression? accountId, + Expression? categoryId, + Expression? payee, + Expression? notes, + Expression? amount, + Expression? date, + Expression? cleared, + Expression? sortOrder, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (accountId != null) 'account_id': accountId, + if (categoryId != null) 'category_id': categoryId, + if (payee != null) 'payee': payee, + if (notes != null) 'notes': notes, + if (amount != null) 'amount': amount, + if (date != null) 'date': date, + if (cleared != null) 'cleared': cleared, + if (sortOrder != null) 'sort_order': sortOrder, + }); + } + + TransactionsCompanion copyWith({ + Value? id, + Value? accountId, + Value? categoryId, + Value? payee, + Value? notes, + Value? amount, + Value? date, + Value? cleared, + Value? sortOrder, + }) { + return TransactionsCompanion( + id: id ?? this.id, + accountId: accountId ?? this.accountId, + categoryId: categoryId ?? this.categoryId, + payee: payee ?? this.payee, + notes: notes ?? this.notes, + amount: amount ?? this.amount, + date: date ?? this.date, + cleared: cleared ?? this.cleared, + sortOrder: sortOrder ?? this.sortOrder, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (accountId.present) { + map['account_id'] = Variable(accountId.value); + } + if (categoryId.present) { + map['category_id'] = Variable(categoryId.value); + } + if (payee.present) { + map['payee'] = Variable(payee.value); + } + if (notes.present) { + map['notes'] = Variable(notes.value); + } + if (amount.present) { + map['amount'] = Variable(amount.value); + } + if (date.present) { + map['date'] = Variable(date.value); + } + if (cleared.present) { + map['cleared'] = Variable(cleared.value); + } + if (sortOrder.present) { + map['sort_order'] = Variable(sortOrder.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('TransactionsCompanion(') + ..write('id: $id, ') + ..write('accountId: $accountId, ') + ..write('categoryId: $categoryId, ') + ..write('payee: $payee, ') + ..write('notes: $notes, ') + ..write('amount: $amount, ') + ..write('date: $date, ') + ..write('cleared: $cleared, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } +} + +class $BudgetsTable extends Budgets with TableInfo<$BudgetsTable, Budget> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $BudgetsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _categoryIdMeta = const VerificationMeta( + 'categoryId', + ); + @override + late final GeneratedColumn categoryId = GeneratedColumn( + 'category_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES categories (id)', + ), + ); + static const VerificationMeta _monthMeta = const VerificationMeta('month'); + @override + late final GeneratedColumn month = GeneratedColumn( + 'month', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _budgetedMeta = const VerificationMeta( + 'budgeted', + ); + @override + late final GeneratedColumn budgeted = GeneratedColumn( + 'budgeted', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(0.0), + ); + static const VerificationMeta _sortOrderMeta = const VerificationMeta( + 'sortOrder', + ); + @override + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + @override + List get $columns => [ + id, + categoryId, + month, + budgeted, + sortOrder, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'budgets'; + @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)); + } + if (data.containsKey('category_id')) { + context.handle( + _categoryIdMeta, + categoryId.isAcceptableOrUnknown(data['category_id']!, _categoryIdMeta), + ); + } else if (isInserting) { + context.missing(_categoryIdMeta); + } + if (data.containsKey('month')) { + context.handle( + _monthMeta, + month.isAcceptableOrUnknown(data['month']!, _monthMeta), + ); + } else if (isInserting) { + context.missing(_monthMeta); + } + if (data.containsKey('budgeted')) { + context.handle( + _budgetedMeta, + budgeted.isAcceptableOrUnknown(data['budgeted']!, _budgetedMeta), + ); + } + if (data.containsKey('sort_order')) { + context.handle( + _sortOrderMeta, + sortOrder.isAcceptableOrUnknown(data['sort_order']!, _sortOrderMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Budget map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Budget( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + categoryId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}category_id'], + )!, + month: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}month'], + )!, + budgeted: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}budgeted'], + )!, + sortOrder: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sort_order'], + )!, + ); + } + + @override + $BudgetsTable createAlias(String alias) { + return $BudgetsTable(attachedDatabase, alias); + } +} + +class Budget extends DataClass implements Insertable { + final int id; + final int categoryId; + final String month; + final double budgeted; + final int sortOrder; + const Budget({ + required this.id, + required this.categoryId, + required this.month, + required this.budgeted, + required this.sortOrder, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['category_id'] = Variable(categoryId); + map['month'] = Variable(month); + map['budgeted'] = Variable(budgeted); + map['sort_order'] = Variable(sortOrder); + return map; + } + + BudgetsCompanion toCompanion(bool nullToAbsent) { + return BudgetsCompanion( + id: Value(id), + categoryId: Value(categoryId), + month: Value(month), + budgeted: Value(budgeted), + sortOrder: Value(sortOrder), + ); + } + + factory Budget.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Budget( + id: serializer.fromJson(json['id']), + categoryId: serializer.fromJson(json['categoryId']), + month: serializer.fromJson(json['month']), + budgeted: serializer.fromJson(json['budgeted']), + sortOrder: serializer.fromJson(json['sortOrder']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'categoryId': serializer.toJson(categoryId), + 'month': serializer.toJson(month), + 'budgeted': serializer.toJson(budgeted), + 'sortOrder': serializer.toJson(sortOrder), + }; + } + + Budget copyWith({ + int? id, + int? categoryId, + String? month, + double? budgeted, + int? sortOrder, + }) => Budget( + id: id ?? this.id, + categoryId: categoryId ?? this.categoryId, + month: month ?? this.month, + budgeted: budgeted ?? this.budgeted, + sortOrder: sortOrder ?? this.sortOrder, + ); + Budget copyWithCompanion(BudgetsCompanion data) { + return Budget( + id: data.id.present ? data.id.value : this.id, + categoryId: data.categoryId.present + ? data.categoryId.value + : this.categoryId, + month: data.month.present ? data.month.value : this.month, + budgeted: data.budgeted.present ? data.budgeted.value : this.budgeted, + sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder, + ); + } + + @override + String toString() { + return (StringBuffer('Budget(') + ..write('id: $id, ') + ..write('categoryId: $categoryId, ') + ..write('month: $month, ') + ..write('budgeted: $budgeted, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, categoryId, month, budgeted, sortOrder); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Budget && + other.id == this.id && + other.categoryId == this.categoryId && + other.month == this.month && + other.budgeted == this.budgeted && + other.sortOrder == this.sortOrder); +} + +class BudgetsCompanion extends UpdateCompanion { + final Value id; + final Value categoryId; + final Value month; + final Value budgeted; + final Value sortOrder; + const BudgetsCompanion({ + this.id = const Value.absent(), + this.categoryId = const Value.absent(), + this.month = const Value.absent(), + this.budgeted = const Value.absent(), + this.sortOrder = const Value.absent(), + }); + BudgetsCompanion.insert({ + this.id = const Value.absent(), + required int categoryId, + required String month, + this.budgeted = const Value.absent(), + this.sortOrder = const Value.absent(), + }) : categoryId = Value(categoryId), + month = Value(month); + static Insertable custom({ + Expression? id, + Expression? categoryId, + Expression? month, + Expression? budgeted, + Expression? sortOrder, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (categoryId != null) 'category_id': categoryId, + if (month != null) 'month': month, + if (budgeted != null) 'budgeted': budgeted, + if (sortOrder != null) 'sort_order': sortOrder, + }); + } + + BudgetsCompanion copyWith({ + Value? id, + Value? categoryId, + Value? month, + Value? budgeted, + Value? sortOrder, + }) { + return BudgetsCompanion( + id: id ?? this.id, + categoryId: categoryId ?? this.categoryId, + month: month ?? this.month, + budgeted: budgeted ?? this.budgeted, + sortOrder: sortOrder ?? this.sortOrder, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (categoryId.present) { + map['category_id'] = Variable(categoryId.value); + } + if (month.present) { + map['month'] = Variable(month.value); + } + if (budgeted.present) { + map['budgeted'] = Variable(budgeted.value); + } + if (sortOrder.present) { + map['sort_order'] = Variable(sortOrder.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('BudgetsCompanion(') + ..write('id: $id, ') + ..write('categoryId: $categoryId, ') + ..write('month: $month, ') + ..write('budgeted: $budgeted, ') + ..write('sortOrder: $sortOrder') + ..write(')')) + .toString(); + } +} + +abstract class _$AppDatabase extends GeneratedDatabase { + _$AppDatabase(QueryExecutor e) : super(e); + $AppDatabaseManager get managers => $AppDatabaseManager(this); + late final $AccountsTable accounts = $AccountsTable(this); + late final $CategoryGroupsTable categoryGroups = $CategoryGroupsTable(this); + late final $CategoriesTable categories = $CategoriesTable(this); + late final $TransactionsTable transactions = $TransactionsTable(this); + late final $BudgetsTable budgets = $BudgetsTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + accounts, + categoryGroups, + categories, + transactions, + budgets, + ]; +} + +typedef $$AccountsTableCreateCompanionBuilder = + AccountsCompanion Function({ + Value id, + required String name, + required String type, + Value balance, + Value isClosed, + Value sortOrder, + }); +typedef $$AccountsTableUpdateCompanionBuilder = + AccountsCompanion Function({ + Value id, + Value name, + Value type, + Value balance, + Value isClosed, + Value sortOrder, + }); + +final class $$AccountsTableReferences + extends BaseReferences<_$AppDatabase, $AccountsTable, Account> { + $$AccountsTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static MultiTypedResultKey<$TransactionsTable, List> + _transactionsRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.transactions, + aliasName: $_aliasNameGenerator(db.accounts.id, db.transactions.accountId), + ); + + $$TransactionsTableProcessedTableManager get transactionsRefs { + final manager = $$TransactionsTableTableManager( + $_db, + $_db.transactions, + ).filter((f) => f.accountId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_transactionsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$AccountsTableFilterComposer + extends Composer<_$AppDatabase, $AccountsTable> { + $$AccountsTableFilterComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get balance => $composableBuilder( + column: $table.balance, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isClosed => $composableBuilder( + column: $table.isClosed, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnFilters(column), + ); + + Expression transactionsRefs( + Expression Function($$TransactionsTableFilterComposer f) f, + ) { + final $$TransactionsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.transactions, + getReferencedColumn: (t) => t.accountId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$TransactionsTableFilterComposer( + $db: $db, + $table: $db.transactions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$AccountsTableOrderingComposer + extends Composer<_$AppDatabase, $AccountsTable> { + $$AccountsTableOrderingComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get balance => $composableBuilder( + column: $table.balance, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isClosed => $composableBuilder( + column: $table.isClosed, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$AccountsTableAnnotationComposer + extends Composer<_$AppDatabase, $AccountsTable> { + $$AccountsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get type => + $composableBuilder(column: $table.type, builder: (column) => column); + + GeneratedColumn get balance => + $composableBuilder(column: $table.balance, builder: (column) => column); + + GeneratedColumn get isClosed => + $composableBuilder(column: $table.isClosed, builder: (column) => column); + + GeneratedColumn get sortOrder => + $composableBuilder(column: $table.sortOrder, builder: (column) => column); + + Expression transactionsRefs( + Expression Function($$TransactionsTableAnnotationComposer a) f, + ) { + final $$TransactionsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.transactions, + getReferencedColumn: (t) => t.accountId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$TransactionsTableAnnotationComposer( + $db: $db, + $table: $db.transactions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$AccountsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $AccountsTable, + Account, + $$AccountsTableFilterComposer, + $$AccountsTableOrderingComposer, + $$AccountsTableAnnotationComposer, + $$AccountsTableCreateCompanionBuilder, + $$AccountsTableUpdateCompanionBuilder, + (Account, $$AccountsTableReferences), + Account, + PrefetchHooks Function({bool transactionsRefs}) + > { + $$AccountsTableTableManager(_$AppDatabase db, $AccountsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$AccountsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$AccountsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$AccountsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value name = const Value.absent(), + Value type = const Value.absent(), + Value balance = const Value.absent(), + Value isClosed = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => AccountsCompanion( + id: id, + name: name, + type: type, + balance: balance, + isClosed: isClosed, + sortOrder: sortOrder, + ), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required String name, + required String type, + Value balance = const Value.absent(), + Value isClosed = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => AccountsCompanion.insert( + id: id, + name: name, + type: type, + balance: balance, + isClosed: isClosed, + sortOrder: sortOrder, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$AccountsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({transactionsRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [if (transactionsRefs) db.transactions], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (transactionsRefs) + await $_getPrefetchedData< + Account, + $AccountsTable, + Transaction + >( + currentTable: table, + referencedTable: $$AccountsTableReferences + ._transactionsRefsTable(db), + managerFromTypedResult: (p0) => $$AccountsTableReferences( + db, + table, + p0, + ).transactionsRefs, + referencedItemsForCurrentItem: (item, referencedItems) => + referencedItems.where((e) => e.accountId == item.id), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$AccountsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $AccountsTable, + Account, + $$AccountsTableFilterComposer, + $$AccountsTableOrderingComposer, + $$AccountsTableAnnotationComposer, + $$AccountsTableCreateCompanionBuilder, + $$AccountsTableUpdateCompanionBuilder, + (Account, $$AccountsTableReferences), + Account, + PrefetchHooks Function({bool transactionsRefs}) + >; +typedef $$CategoryGroupsTableCreateCompanionBuilder = + CategoryGroupsCompanion Function({ + Value id, + required String name, + Value sortOrder, + }); +typedef $$CategoryGroupsTableUpdateCompanionBuilder = + CategoryGroupsCompanion Function({ + Value id, + Value name, + Value sortOrder, + }); + +final class $$CategoryGroupsTableReferences + extends BaseReferences<_$AppDatabase, $CategoryGroupsTable, CategoryGroup> { + $$CategoryGroupsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static MultiTypedResultKey<$CategoriesTable, List> + _categoriesRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.categories, + aliasName: $_aliasNameGenerator( + db.categoryGroups.id, + db.categories.groupId, + ), + ); + + $$CategoriesTableProcessedTableManager get categoriesRefs { + final manager = $$CategoriesTableTableManager( + $_db, + $_db.categories, + ).filter((f) => f.groupId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_categoriesRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$CategoryGroupsTableFilterComposer + extends Composer<_$AppDatabase, $CategoryGroupsTable> { + $$CategoryGroupsTableFilterComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnFilters(column), + ); + + Expression categoriesRefs( + Expression Function($$CategoriesTableFilterComposer f) f, + ) { + final $$CategoriesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.groupId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableFilterComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$CategoryGroupsTableOrderingComposer + extends Composer<_$AppDatabase, $CategoryGroupsTable> { + $$CategoryGroupsTableOrderingComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$CategoryGroupsTableAnnotationComposer + extends Composer<_$AppDatabase, $CategoryGroupsTable> { + $$CategoryGroupsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get sortOrder => + $composableBuilder(column: $table.sortOrder, builder: (column) => column); + + Expression categoriesRefs( + Expression Function($$CategoriesTableAnnotationComposer a) f, + ) { + final $$CategoriesTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.groupId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableAnnotationComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$CategoryGroupsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $CategoryGroupsTable, + CategoryGroup, + $$CategoryGroupsTableFilterComposer, + $$CategoryGroupsTableOrderingComposer, + $$CategoryGroupsTableAnnotationComposer, + $$CategoryGroupsTableCreateCompanionBuilder, + $$CategoryGroupsTableUpdateCompanionBuilder, + (CategoryGroup, $$CategoryGroupsTableReferences), + CategoryGroup, + PrefetchHooks Function({bool categoriesRefs}) + > { + $$CategoryGroupsTableTableManager( + _$AppDatabase db, + $CategoryGroupsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$CategoryGroupsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$CategoryGroupsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$CategoryGroupsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value name = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => CategoryGroupsCompanion( + id: id, + name: name, + sortOrder: sortOrder, + ), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required String name, + Value sortOrder = const Value.absent(), + }) => CategoryGroupsCompanion.insert( + id: id, + name: name, + sortOrder: sortOrder, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$CategoryGroupsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({categoriesRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [if (categoriesRefs) db.categories], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (categoriesRefs) + await $_getPrefetchedData< + CategoryGroup, + $CategoryGroupsTable, + Category + >( + currentTable: table, + referencedTable: $$CategoryGroupsTableReferences + ._categoriesRefsTable(db), + managerFromTypedResult: (p0) => + $$CategoryGroupsTableReferences( + db, + table, + p0, + ).categoriesRefs, + referencedItemsForCurrentItem: (item, referencedItems) => + referencedItems.where((e) => e.groupId == item.id), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$CategoryGroupsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $CategoryGroupsTable, + CategoryGroup, + $$CategoryGroupsTableFilterComposer, + $$CategoryGroupsTableOrderingComposer, + $$CategoryGroupsTableAnnotationComposer, + $$CategoryGroupsTableCreateCompanionBuilder, + $$CategoryGroupsTableUpdateCompanionBuilder, + (CategoryGroup, $$CategoryGroupsTableReferences), + CategoryGroup, + PrefetchHooks Function({bool categoriesRefs}) + >; +typedef $$CategoriesTableCreateCompanionBuilder = + CategoriesCompanion Function({ + Value id, + required String name, + required int groupId, + Value budgeted, + Value sortOrder, + Value icon, + }); +typedef $$CategoriesTableUpdateCompanionBuilder = + CategoriesCompanion Function({ + Value id, + Value name, + Value groupId, + Value budgeted, + Value sortOrder, + Value icon, + }); + +final class $$CategoriesTableReferences + extends BaseReferences<_$AppDatabase, $CategoriesTable, Category> { + $$CategoriesTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static $CategoryGroupsTable _groupIdTable(_$AppDatabase db) => + db.categoryGroups.createAlias( + $_aliasNameGenerator(db.categories.groupId, db.categoryGroups.id), + ); + + $$CategoryGroupsTableProcessedTableManager get groupId { + final $_column = $_itemColumn('group_id')!; + + final manager = $$CategoryGroupsTableTableManager( + $_db, + $_db.categoryGroups, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_groupIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static MultiTypedResultKey<$TransactionsTable, List> + _transactionsRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.transactions, + aliasName: $_aliasNameGenerator( + db.categories.id, + db.transactions.categoryId, + ), + ); + + $$TransactionsTableProcessedTableManager get transactionsRefs { + final manager = $$TransactionsTableTableManager( + $_db, + $_db.transactions, + ).filter((f) => f.categoryId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_transactionsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey<$BudgetsTable, List> _budgetsRefsTable( + _$AppDatabase db, + ) => MultiTypedResultKey.fromTable( + db.budgets, + aliasName: $_aliasNameGenerator(db.categories.id, db.budgets.categoryId), + ); + + $$BudgetsTableProcessedTableManager get budgetsRefs { + final manager = $$BudgetsTableTableManager( + $_db, + $_db.budgets, + ).filter((f) => f.categoryId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_budgetsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$CategoriesTableFilterComposer + extends Composer<_$AppDatabase, $CategoriesTable> { + $$CategoriesTableFilterComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get budgeted => $composableBuilder( + column: $table.budgeted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get icon => $composableBuilder( + column: $table.icon, + builder: (column) => ColumnFilters(column), + ); + + $$CategoryGroupsTableFilterComposer get groupId { + final $$CategoryGroupsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.categoryGroups, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoryGroupsTableFilterComposer( + $db: $db, + $table: $db.categoryGroups, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + Expression transactionsRefs( + Expression Function($$TransactionsTableFilterComposer f) f, + ) { + final $$TransactionsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.transactions, + getReferencedColumn: (t) => t.categoryId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$TransactionsTableFilterComposer( + $db: $db, + $table: $db.transactions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression budgetsRefs( + Expression Function($$BudgetsTableFilterComposer f) f, + ) { + final $$BudgetsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.budgets, + getReferencedColumn: (t) => t.categoryId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$BudgetsTableFilterComposer( + $db: $db, + $table: $db.budgets, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$CategoriesTableOrderingComposer + extends Composer<_$AppDatabase, $CategoriesTable> { + $$CategoriesTableOrderingComposer({ + 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 name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get budgeted => $composableBuilder( + column: $table.budgeted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get icon => $composableBuilder( + column: $table.icon, + builder: (column) => ColumnOrderings(column), + ); + + $$CategoryGroupsTableOrderingComposer get groupId { + final $$CategoryGroupsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.categoryGroups, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoryGroupsTableOrderingComposer( + $db: $db, + $table: $db.categoryGroups, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$CategoriesTableAnnotationComposer + extends Composer<_$AppDatabase, $CategoriesTable> { + $$CategoriesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get budgeted => + $composableBuilder(column: $table.budgeted, builder: (column) => column); + + GeneratedColumn get sortOrder => + $composableBuilder(column: $table.sortOrder, builder: (column) => column); + + GeneratedColumn get icon => + $composableBuilder(column: $table.icon, builder: (column) => column); + + $$CategoryGroupsTableAnnotationComposer get groupId { + final $$CategoryGroupsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.categoryGroups, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoryGroupsTableAnnotationComposer( + $db: $db, + $table: $db.categoryGroups, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + Expression transactionsRefs( + Expression Function($$TransactionsTableAnnotationComposer a) f, + ) { + final $$TransactionsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.transactions, + getReferencedColumn: (t) => t.categoryId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$TransactionsTableAnnotationComposer( + $db: $db, + $table: $db.transactions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression budgetsRefs( + Expression Function($$BudgetsTableAnnotationComposer a) f, + ) { + final $$BudgetsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.budgets, + getReferencedColumn: (t) => t.categoryId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$BudgetsTableAnnotationComposer( + $db: $db, + $table: $db.budgets, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$CategoriesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $CategoriesTable, + Category, + $$CategoriesTableFilterComposer, + $$CategoriesTableOrderingComposer, + $$CategoriesTableAnnotationComposer, + $$CategoriesTableCreateCompanionBuilder, + $$CategoriesTableUpdateCompanionBuilder, + (Category, $$CategoriesTableReferences), + Category, + PrefetchHooks Function({ + bool groupId, + bool transactionsRefs, + bool budgetsRefs, + }) + > { + $$CategoriesTableTableManager(_$AppDatabase db, $CategoriesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$CategoriesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$CategoriesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$CategoriesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value name = const Value.absent(), + Value groupId = const Value.absent(), + Value budgeted = const Value.absent(), + Value sortOrder = const Value.absent(), + Value icon = const Value.absent(), + }) => CategoriesCompanion( + id: id, + name: name, + groupId: groupId, + budgeted: budgeted, + sortOrder: sortOrder, + icon: icon, + ), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required String name, + required int groupId, + Value budgeted = const Value.absent(), + Value sortOrder = const Value.absent(), + Value icon = const Value.absent(), + }) => CategoriesCompanion.insert( + id: id, + name: name, + groupId: groupId, + budgeted: budgeted, + sortOrder: sortOrder, + icon: icon, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$CategoriesTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: + ({ + groupId = false, + transactionsRefs = false, + budgetsRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (transactionsRefs) db.transactions, + if (budgetsRefs) db.budgets, + ], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (groupId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.groupId, + referencedTable: $$CategoriesTableReferences + ._groupIdTable(db), + referencedColumn: + $$CategoriesTableReferences + ._groupIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return [ + if (transactionsRefs) + await $_getPrefetchedData< + Category, + $CategoriesTable, + Transaction + >( + currentTable: table, + referencedTable: $$CategoriesTableReferences + ._transactionsRefsTable(db), + managerFromTypedResult: (p0) => + $$CategoriesTableReferences( + db, + table, + p0, + ).transactionsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.categoryId == item.id, + ), + typedResults: items, + ), + if (budgetsRefs) + await $_getPrefetchedData< + Category, + $CategoriesTable, + Budget + >( + currentTable: table, + referencedTable: $$CategoriesTableReferences + ._budgetsRefsTable(db), + managerFromTypedResult: (p0) => + $$CategoriesTableReferences( + db, + table, + p0, + ).budgetsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.categoryId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$CategoriesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $CategoriesTable, + Category, + $$CategoriesTableFilterComposer, + $$CategoriesTableOrderingComposer, + $$CategoriesTableAnnotationComposer, + $$CategoriesTableCreateCompanionBuilder, + $$CategoriesTableUpdateCompanionBuilder, + (Category, $$CategoriesTableReferences), + Category, + PrefetchHooks Function({ + bool groupId, + bool transactionsRefs, + bool budgetsRefs, + }) + >; +typedef $$TransactionsTableCreateCompanionBuilder = + TransactionsCompanion Function({ + Value id, + required int accountId, + Value categoryId, + required String payee, + Value notes, + required double amount, + required DateTime date, + Value cleared, + Value sortOrder, + }); +typedef $$TransactionsTableUpdateCompanionBuilder = + TransactionsCompanion Function({ + Value id, + Value accountId, + Value categoryId, + Value payee, + Value notes, + Value amount, + Value date, + Value cleared, + Value sortOrder, + }); + +final class $$TransactionsTableReferences + extends BaseReferences<_$AppDatabase, $TransactionsTable, Transaction> { + $$TransactionsTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static $AccountsTable _accountIdTable(_$AppDatabase db) => + db.accounts.createAlias( + $_aliasNameGenerator(db.transactions.accountId, db.accounts.id), + ); + + $$AccountsTableProcessedTableManager get accountId { + final $_column = $_itemColumn('account_id')!; + + final manager = $$AccountsTableTableManager( + $_db, + $_db.accounts, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_accountIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static $CategoriesTable _categoryIdTable(_$AppDatabase db) => + db.categories.createAlias( + $_aliasNameGenerator(db.transactions.categoryId, db.categories.id), + ); + + $$CategoriesTableProcessedTableManager? get categoryId { + final $_column = $_itemColumn('category_id'); + if ($_column == null) return null; + final manager = $$CategoriesTableTableManager( + $_db, + $_db.categories, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_categoryIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$TransactionsTableFilterComposer + extends Composer<_$AppDatabase, $TransactionsTable> { + $$TransactionsTableFilterComposer({ + 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 payee => $composableBuilder( + column: $table.payee, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get amount => $composableBuilder( + column: $table.amount, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get date => $composableBuilder( + column: $table.date, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get cleared => $composableBuilder( + column: $table.cleared, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnFilters(column), + ); + + $$AccountsTableFilterComposer get accountId { + final $$AccountsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.accountId, + referencedTable: $db.accounts, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$AccountsTableFilterComposer( + $db: $db, + $table: $db.accounts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$CategoriesTableFilterComposer get categoryId { + final $$CategoriesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableFilterComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$TransactionsTableOrderingComposer + extends Composer<_$AppDatabase, $TransactionsTable> { + $$TransactionsTableOrderingComposer({ + 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 payee => $composableBuilder( + column: $table.payee, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get notes => $composableBuilder( + column: $table.notes, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get amount => $composableBuilder( + column: $table.amount, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get date => $composableBuilder( + column: $table.date, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get cleared => $composableBuilder( + column: $table.cleared, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnOrderings(column), + ); + + $$AccountsTableOrderingComposer get accountId { + final $$AccountsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.accountId, + referencedTable: $db.accounts, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$AccountsTableOrderingComposer( + $db: $db, + $table: $db.accounts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$CategoriesTableOrderingComposer get categoryId { + final $$CategoriesTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableOrderingComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$TransactionsTableAnnotationComposer + extends Composer<_$AppDatabase, $TransactionsTable> { + $$TransactionsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get payee => + $composableBuilder(column: $table.payee, builder: (column) => column); + + GeneratedColumn get notes => + $composableBuilder(column: $table.notes, builder: (column) => column); + + GeneratedColumn get amount => + $composableBuilder(column: $table.amount, builder: (column) => column); + + GeneratedColumn get date => + $composableBuilder(column: $table.date, builder: (column) => column); + + GeneratedColumn get cleared => + $composableBuilder(column: $table.cleared, builder: (column) => column); + + GeneratedColumn get sortOrder => + $composableBuilder(column: $table.sortOrder, builder: (column) => column); + + $$AccountsTableAnnotationComposer get accountId { + final $$AccountsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.accountId, + referencedTable: $db.accounts, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$AccountsTableAnnotationComposer( + $db: $db, + $table: $db.accounts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$CategoriesTableAnnotationComposer get categoryId { + final $$CategoriesTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableAnnotationComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$TransactionsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $TransactionsTable, + Transaction, + $$TransactionsTableFilterComposer, + $$TransactionsTableOrderingComposer, + $$TransactionsTableAnnotationComposer, + $$TransactionsTableCreateCompanionBuilder, + $$TransactionsTableUpdateCompanionBuilder, + (Transaction, $$TransactionsTableReferences), + Transaction, + PrefetchHooks Function({bool accountId, bool categoryId}) + > { + $$TransactionsTableTableManager(_$AppDatabase db, $TransactionsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$TransactionsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$TransactionsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$TransactionsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value accountId = const Value.absent(), + Value categoryId = const Value.absent(), + Value payee = const Value.absent(), + Value notes = const Value.absent(), + Value amount = const Value.absent(), + Value date = const Value.absent(), + Value cleared = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => TransactionsCompanion( + id: id, + accountId: accountId, + categoryId: categoryId, + payee: payee, + notes: notes, + amount: amount, + date: date, + cleared: cleared, + sortOrder: sortOrder, + ), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required int accountId, + Value categoryId = const Value.absent(), + required String payee, + Value notes = const Value.absent(), + required double amount, + required DateTime date, + Value cleared = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => TransactionsCompanion.insert( + id: id, + accountId: accountId, + categoryId: categoryId, + payee: payee, + notes: notes, + amount: amount, + date: date, + cleared: cleared, + sortOrder: sortOrder, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$TransactionsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({accountId = false, categoryId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (accountId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.accountId, + referencedTable: $$TransactionsTableReferences + ._accountIdTable(db), + referencedColumn: $$TransactionsTableReferences + ._accountIdTable(db) + .id, + ) + as T; + } + if (categoryId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.categoryId, + referencedTable: $$TransactionsTableReferences + ._categoryIdTable(db), + referencedColumn: $$TransactionsTableReferences + ._categoryIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$TransactionsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $TransactionsTable, + Transaction, + $$TransactionsTableFilterComposer, + $$TransactionsTableOrderingComposer, + $$TransactionsTableAnnotationComposer, + $$TransactionsTableCreateCompanionBuilder, + $$TransactionsTableUpdateCompanionBuilder, + (Transaction, $$TransactionsTableReferences), + Transaction, + PrefetchHooks Function({bool accountId, bool categoryId}) + >; +typedef $$BudgetsTableCreateCompanionBuilder = + BudgetsCompanion Function({ + Value id, + required int categoryId, + required String month, + Value budgeted, + Value sortOrder, + }); +typedef $$BudgetsTableUpdateCompanionBuilder = + BudgetsCompanion Function({ + Value id, + Value categoryId, + Value month, + Value budgeted, + Value sortOrder, + }); + +final class $$BudgetsTableReferences + extends BaseReferences<_$AppDatabase, $BudgetsTable, Budget> { + $$BudgetsTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static $CategoriesTable _categoryIdTable(_$AppDatabase db) => + db.categories.createAlias( + $_aliasNameGenerator(db.budgets.categoryId, db.categories.id), + ); + + $$CategoriesTableProcessedTableManager get categoryId { + final $_column = $_itemColumn('category_id')!; + + final manager = $$CategoriesTableTableManager( + $_db, + $_db.categories, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_categoryIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$BudgetsTableFilterComposer + extends Composer<_$AppDatabase, $BudgetsTable> { + $$BudgetsTableFilterComposer({ + 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 month => $composableBuilder( + column: $table.month, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get budgeted => $composableBuilder( + column: $table.budgeted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnFilters(column), + ); + + $$CategoriesTableFilterComposer get categoryId { + final $$CategoriesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableFilterComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$BudgetsTableOrderingComposer + extends Composer<_$AppDatabase, $BudgetsTable> { + $$BudgetsTableOrderingComposer({ + 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 month => $composableBuilder( + column: $table.month, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get budgeted => $composableBuilder( + column: $table.budgeted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get sortOrder => $composableBuilder( + column: $table.sortOrder, + builder: (column) => ColumnOrderings(column), + ); + + $$CategoriesTableOrderingComposer get categoryId { + final $$CategoriesTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableOrderingComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$BudgetsTableAnnotationComposer + extends Composer<_$AppDatabase, $BudgetsTable> { + $$BudgetsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get month => + $composableBuilder(column: $table.month, builder: (column) => column); + + GeneratedColumn get budgeted => + $composableBuilder(column: $table.budgeted, builder: (column) => column); + + GeneratedColumn get sortOrder => + $composableBuilder(column: $table.sortOrder, builder: (column) => column); + + $$CategoriesTableAnnotationComposer get categoryId { + final $$CategoriesTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.categoryId, + referencedTable: $db.categories, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$CategoriesTableAnnotationComposer( + $db: $db, + $table: $db.categories, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$BudgetsTableTableManager + extends + RootTableManager< + _$AppDatabase, + $BudgetsTable, + Budget, + $$BudgetsTableFilterComposer, + $$BudgetsTableOrderingComposer, + $$BudgetsTableAnnotationComposer, + $$BudgetsTableCreateCompanionBuilder, + $$BudgetsTableUpdateCompanionBuilder, + (Budget, $$BudgetsTableReferences), + Budget, + PrefetchHooks Function({bool categoryId}) + > { + $$BudgetsTableTableManager(_$AppDatabase db, $BudgetsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$BudgetsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$BudgetsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$BudgetsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value categoryId = const Value.absent(), + Value month = const Value.absent(), + Value budgeted = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => BudgetsCompanion( + id: id, + categoryId: categoryId, + month: month, + budgeted: budgeted, + sortOrder: sortOrder, + ), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required int categoryId, + required String month, + Value budgeted = const Value.absent(), + Value sortOrder = const Value.absent(), + }) => BudgetsCompanion.insert( + id: id, + categoryId: categoryId, + month: month, + budgeted: budgeted, + sortOrder: sortOrder, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$BudgetsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({categoryId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (categoryId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.categoryId, + referencedTable: $$BudgetsTableReferences + ._categoryIdTable(db), + referencedColumn: $$BudgetsTableReferences + ._categoryIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$BudgetsTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $BudgetsTable, + Budget, + $$BudgetsTableFilterComposer, + $$BudgetsTableOrderingComposer, + $$BudgetsTableAnnotationComposer, + $$BudgetsTableCreateCompanionBuilder, + $$BudgetsTableUpdateCompanionBuilder, + (Budget, $$BudgetsTableReferences), + Budget, + PrefetchHooks Function({bool categoryId}) + >; + +class $AppDatabaseManager { + final _$AppDatabase _db; + $AppDatabaseManager(this._db); + $$AccountsTableTableManager get accounts => + $$AccountsTableTableManager(_db, _db.accounts); + $$CategoryGroupsTableTableManager get categoryGroups => + $$CategoryGroupsTableTableManager(_db, _db.categoryGroups); + $$CategoriesTableTableManager get categories => + $$CategoriesTableTableManager(_db, _db.categories); + $$TransactionsTableTableManager get transactions => + $$TransactionsTableTableManager(_db, _db.transactions); + $$BudgetsTableTableManager get budgets => + $$BudgetsTableTableManager(_db, _db.budgets); +} diff --git a/lib/data/tables.dart b/lib/data/tables.dart new file mode 100644 index 0000000..22fedc1 --- /dev/null +++ b/lib/data/tables.dart @@ -0,0 +1,47 @@ +import 'package:drift/drift.dart'; + +// ── Tables ──────────────────────────────────────────────────────────────────── + +class Accounts extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + TextColumn get type => text()(); // checking, savings, credit, cash + RealColumn get balance => real().withDefault(const Constant(0.0))(); + BoolColumn get isClosed => boolean().withDefault(const Constant(false))(); + IntColumn get sortOrder => integer().withDefault(const Constant(0))(); +} + +class CategoryGroups extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + IntColumn get sortOrder => integer().withDefault(const Constant(0))(); +} + +class Categories extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + IntColumn get groupId => integer().references(CategoryGroups, #id)(); + RealColumn get budgeted => real().withDefault(const Constant(0.0))(); + IntColumn get sortOrder => integer().withDefault(const Constant(0))(); + TextColumn get icon => text().nullable()(); +} + +class Transactions extends Table { + IntColumn get id => integer().autoIncrement()(); + IntColumn get accountId => integer().references(Accounts, #id)(); + IntColumn get categoryId => integer().references(Categories, #id).nullable()(); + TextColumn get payee => text()(); + TextColumn get notes => text().nullable()(); + RealColumn get amount => real()(); // positive = income, negative = expense + DateTimeColumn get date => dateTime()(); + BoolColumn get cleared => boolean().withDefault(const Constant(false))(); + IntColumn get sortOrder => integer().withDefault(const Constant(0))(); +} + +class Budgets extends Table { + IntColumn get id => integer().autoIncrement()(); + IntColumn get categoryId => integer().references(Categories, #id)(); + TextColumn get month => text()(); // "2026-07" + RealColumn get budgeted => real().withDefault(const Constant(0.0))(); + IntColumn get sortOrder => integer().withDefault(const Constant(0))(); +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..69c72da --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'app.dart'; +import 'theme/app_theme.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + runApp( + const ProviderScope( + child: YnabLiteApp(), + ), + ); +} + +class YnabLiteApp extends StatelessWidget { + const YnabLiteApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'YNAB Lite', + debugShowCheckedModeBanner: false, + theme: ynabDarkTheme, + home: const YnabApp(), + ); + } +} diff --git a/lib/providers/db_provider.dart b/lib/providers/db_provider.dart new file mode 100644 index 0000000..9f20e08 --- /dev/null +++ b/lib/providers/db_provider.dart @@ -0,0 +1,107 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:drift/drift.dart'; +import '../data/db.dart'; +export '../data/db.dart' show Account, CategoryGroup, Category, Transaction, Budget; + +// Singleton DB provider +final dbProvider = Provider((ref) { + final db = AppDatabase(); + ref.onDispose(() => db.close()); + db.seedIfEmpty(); + return db; +}); + +// ── Accounts ──────────────────────────────────────────────────────────── +final accountsProvider = StreamProvider>((ref) { + final db = ref.watch(dbProvider); + return db.select(db.accounts).watch(); +}); + +final openAccountsProvider = Provider>((ref) { + final accounts = ref.watch(accountsProvider).valueOrNull ?? []; + return accounts.where((a) => !a.isClosed).toList(); +}); + +final totalBalanceProvider = Provider((ref) { + final accounts = ref.watch(openAccountsProvider); + return accounts.fold(0.0, (sum, a) => sum + a.balance); +}); + +// ── Category Groups ───────────────────────────────────────────────────── +final categoryGroupsProvider = StreamProvider>((ref) { + final db = ref.watch(dbProvider); + return (db.select(db.categoryGroups) + ..orderBy([(g) => OrderingTerm(expression: g.sortOrder)])) + .watch(); +}); + +// ── Categories ────────────────────────────────────────────────────────── +final categoriesProvider = StreamProvider>((ref) { + final db = ref.watch(dbProvider); + return (db.select(db.categories) + ..orderBy([(c) => OrderingTerm(expression: c.sortOrder)])) + .watch(); +}); + +final categoriesByGroupProvider = Provider>>((ref) { + final cats = ref.watch(categoriesProvider).valueOrNull ?? []; + final map = >{}; + for (final c in cats) { + map.putIfAbsent(c.groupId, () => []).add(c); + } + return map; +}); + +// ── Transactions ──────────────────────────────────────────────────────── +final allTransactionsProvider = StreamProvider>((ref) { + final db = ref.watch(dbProvider); + return (db.select(db.transactions) + ..orderBy([(t) => OrderingTerm(expression: t.date, mode: OrderingMode.desc)])) + .watch(); +}); + +final recentTransactionsProvider = Provider>((ref) { + final all = ref.watch(allTransactionsProvider).valueOrNull ?? []; + return all.take(10).toList(); +}); + +final monthlyTransactionsProvider = Provider.family, String>((ref, month) { + final all = ref.watch(allTransactionsProvider).valueOrNull ?? []; + return all.where((t) { + final ym = '${t.date.year}-${t.date.month.toString().padLeft(2, '0')}'; + return ym == month; + }).toList(); +}); + +// ── Budget ────────────────────────────────────────────────────────────── +final budgetsProvider = StreamProvider>((ref) { + final db = ref.watch(dbProvider); + return db.select(db.budgets).watch(); +}); + +final currentMonthProvider = Provider((ref) { + final now = DateTime.now(); + return '${now.year}-${now.month.toString().padLeft(2, '0')}'; +}); + +final monthlyBudgetProvider = Provider.family((ref, categoryId) { + final month = ref.watch(currentMonthProvider); + final budgets = ref.watch(budgetsProvider).valueOrNull ?? []; + final match = budgets.where( + (b) => b.categoryId == categoryId && b.month == month, + ); + return match.isNotEmpty ? match.first.budgeted : null; +}); + +final categorySpentProvider = Provider.family((ref, categoryId) { + final month = ref.watch(currentMonthProvider); + final txs = ref.watch(monthlyTransactionsProvider(month)); + final filtered = txs.where((t) => t.categoryId == categoryId); + return filtered.fold(0.0, (sum, t) => sum + t.amount); +}); + +final categoryRemainingProvider = Provider.family((ref, categoryId) { + final budgeted = ref.watch(monthlyBudgetProvider(categoryId)) ?? 0.0; + final spent = ref.watch(categorySpentProvider(categoryId)); + return budgeted + spent; // spent is negative, so budgeted + spent = remaining +}); diff --git a/lib/screens/accounts_screen.dart b/lib/screens/accounts_screen.dart new file mode 100644 index 0000000..8093ac9 --- /dev/null +++ b/lib/screens/accounts_screen.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../providers/db_provider.dart'; +import '../theme/app_theme.dart'; + +class AccountsScreen extends ConsumerWidget { + const AccountsScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final accounts = ref.watch(openAccountsProvider); + + return ListView( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 90), + children: [ + ...accounts.map((a) => _AccountCard(account: a)), + ], + ); + } +} + +class _AccountCard extends StatelessWidget { + final Account account; + const _AccountCard({required this.account}); + + IconData _icon() { + switch (account.type) { + case 'savings': return Icons.savings_outlined; + case 'credit': return Icons.credit_card_outlined; + case 'cash': return Icons.money_outlined; + default: return Icons.account_balance_outlined; + } + } + + String _label() { + switch (account.type) { + case 'checking': return 'Compte courant'; + case 'savings': return 'Épargne'; + case 'credit': return 'Carte de crédit'; + case 'cash': return 'Espèces'; + default: return account.type; + } + } + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.only(bottom: 8), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: kSurfaceElevated, + borderRadius: BorderRadius.circular(12), + ), + child: Icon(_icon(), color: kTextSecondary, size: 22), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(account.name, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w600)), + const SizedBox(height: 2), + Text(_label(), style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + Text( + formatCurrency(account.balance), + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: account.balance >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/budget_screen.dart b/lib/screens/budget_screen.dart new file mode 100644 index 0000000..cf61d62 --- /dev/null +++ b/lib/screens/budget_screen.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../providers/db_provider.dart'; +import '../theme/app_theme.dart'; + +class BudgetScreen extends ConsumerWidget { + const BudgetScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final groups = ref.watch(categoryGroupsProvider).valueOrNull ?? []; + final catsByGroup = ref.watch(categoriesByGroupProvider); + + return ListView( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 90), + children: [ + Card( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Budget du mois', style: Theme.of(context).textTheme.titleMedium), + const SizedBox(height: 4), + Text('Juillet 2026', style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + ), + const SizedBox(height: 16), + ...groups.map((group) { + final cats = catsByGroup[group.id] ?? []; + if (cats.isEmpty) return const SizedBox.shrink(); + return _CategoryGroupTile(group: group, categoryIds: cats.map((c) => c.id).toList()); + }), + ], + ); + } +} + +class _CategoryGroupTile extends ConsumerWidget { + final CategoryGroup group; + final List categoryIds; + + const _CategoryGroupTile({required this.group, required this.categoryIds}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final expanded = ref.watch(_expandedGroupProvider(group.id)); + final cats = ref.watch(categoriesByGroupProvider)[group.id] ?? []; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + onTap: () => ref.read(_expandedGroupProvider(group.id).notifier).toggle(), + borderRadius: BorderRadius.circular(8), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 4), + child: Row( + children: [ + Icon( + expanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, + size: 18, + color: kTextSecondary, + ), + const SizedBox(width: 8), + Text(group.name, + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith(fontWeight: FontWeight.w600)), + const Spacer(), + Text( + formatCurrency( + cats.fold(0.0, (s, c) => s + ref.watch(categoryRemainingProvider(c.id))), + ), + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), + ), + ), + if (expanded) + ...cats.map((c) => _CategoryRow(categoryId: c.id)), + const Divider(height: 1), + ], + ); + } +} + +class _CategoryRow extends ConsumerWidget { + final int categoryId; + + const _CategoryRow({required this.categoryId}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final cats = ref.watch(categoriesByGroupProvider); + final category = cats.values + .expand((list) => list) + .firstWhere((c) => c.id == categoryId, orElse: () => throw StateError('missing')); + + final budgeted = ref.watch(monthlyBudgetProvider(categoryId)) ?? 0.0; + final spent = ref.watch(categorySpentProvider(categoryId)); + final remaining = ref.watch(categoryRemainingProvider(categoryId)); + final pct = budgeted > 0 ? ((budgeted + spent) / budgeted).clamp(0.0, 1.0) : 0.0; + + return Padding( + padding: const EdgeInsets.only(left: 8, bottom: 4), + child: Card( + margin: EdgeInsets.zero, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text(category.name, style: Theme.of(context).textTheme.bodyMedium), + ), + Text( + formatCurrency(remaining), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: remaining >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ], + ), + const SizedBox(height: 4), + ClipRRect( + borderRadius: BorderRadius.circular(4), + child: LinearProgressIndicator( + value: pct, + backgroundColor: kDivider, + valueColor: AlwaysStoppedAnimation( + remaining >= 0 ? kGreenAccent : kRedAccent, + ), + minHeight: 4, + ), + ), + const SizedBox(height: 2), + Row( + children: [ + Text('Budget: ${formatCurrency(budgeted)}', + style: Theme.of(context).textTheme.bodySmall), + const SizedBox(width: 12), + Text('Dépensé: ${formatCurrency(spent.abs())}', + style: Theme.of(context).textTheme.bodySmall), + ], + ), + ], + ), + ), + ), + ); + } +} + +class _ExpandedGroupNotifier extends StateNotifier { + _ExpandedGroupNotifier() : super(true); + + void toggle() => state = !state; +} + +final _expandedGroupProvider = + StateNotifierProvider.family<_ExpandedGroupNotifier, bool, int>( + (ref, id) => _ExpandedGroupNotifier()); diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart new file mode 100644 index 0000000..218ebe4 --- /dev/null +++ b/lib/screens/dashboard_screen.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import '../providers/db_provider.dart'; +import '../theme/app_theme.dart'; + +class DashboardScreen extends ConsumerWidget { + const DashboardScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final totalBalance = ref.watch(totalBalanceProvider); + final accounts = ref.watch(openAccountsProvider); + final recentTxs = ref.watch(recentTransactionsProvider); + + return ListView( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 90), + children: [ + // Total Balance + _BalanceCard(balance: totalBalance), + const SizedBox(height: 16), + + // By accounts + Text('Comptes', style: Theme.of(context).textTheme.titleMedium), + const SizedBox(height: 8), + ...accounts.map((a) => _AccountMiniCard(account: a)), + const SizedBox(height: 24), + + // Recent transactions + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Transactions récentes', style: Theme.of(context).textTheme.titleMedium), + TextButton.icon( + onPressed: () {}, + icon: const Icon(Icons.arrow_forward_ios, size: 14), + label: const Text('Voir tout'), + ), + ], + ), + const SizedBox(height: 8), + if (recentTxs.isEmpty) + Card( + child: Padding( + padding: const EdgeInsets.all(32), + child: Center(child: Text('Aucune transaction', style: Theme.of(context).textTheme.bodyMedium)), + ), + ) + else + ...recentTxs.map((t) => _TxItem(transaction: t)), + ], + ); + } +} + +class _BalanceCard extends StatelessWidget { + final double balance; + const _BalanceCard({required this.balance}); + + @override + Widget build(BuildContext context) { + return Card( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Solde total', style: Theme.of(context).textTheme.bodyMedium), + const SizedBox(height: 8), + Text( + formatCurrency(balance), + style: Theme.of(context).textTheme.headlineLarge?.copyWith( + fontSize: 36, + fontWeight: FontWeight.w700, + color: balance >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ], + ), + ), + ); + } +} + +class _AccountMiniCard extends StatelessWidget { + final Account account; + const _AccountMiniCard({required this.account}); + + IconData _icon() { + switch (account.type) { + case 'savings': return Icons.savings_outlined; + case 'credit': return Icons.credit_card_outlined; + case 'cash': return Icons.money_outlined; + default: return Icons.account_balance_outlined; + } + } + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.only(bottom: 6), + child: ListTile( + dense: true, + leading: Icon(_icon(), color: kTextSecondary), + title: Text(account.name, style: Theme.of(context).textTheme.bodyMedium), + trailing: Text( + formatCurrency(account.balance), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: account.balance >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ), + ); + } +} + +class _TxItem extends StatelessWidget { + final Transaction transaction; + const _TxItem({required this.transaction}); + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.only(bottom: 4), + child: ListTile( + dense: true, + leading: CircleAvatar( + radius: 18, + backgroundColor: kSurfaceElevated, + child: Icon( + transaction.amount >= 0 ? Icons.arrow_downward : Icons.arrow_upward, + size: 16, + color: transaction.amount >= 0 ? kGreenAccent : kRedAccent, + ), + ), + title: Text(transaction.payee, style: Theme.of(context).textTheme.bodyMedium), + subtitle: Text( + DateFormat('dd/MM/yy').format(transaction.date), + style: Theme.of(context).textTheme.bodySmall, + ), + trailing: Text( + formatCurrency(transaction.amount), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: transaction.amount >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ), + ); + } +} diff --git a/lib/screens/transactions_screen.dart b/lib/screens/transactions_screen.dart new file mode 100644 index 0000000..08eac71 --- /dev/null +++ b/lib/screens/transactions_screen.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import '../providers/db_provider.dart'; +import '../theme/app_theme.dart'; + +class TransactionsScreen extends ConsumerWidget { + const TransactionsScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final all = ref.watch(allTransactionsProvider).valueOrNull ?? []; + + return ListView.builder( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 90), + itemCount: all.length, + itemBuilder: (context, index) { + final t = all[index]; + return Card( + margin: const EdgeInsets.only(bottom: 4), + child: ListTile( + dense: true, + leading: CircleAvatar( + radius: 18, + backgroundColor: kSurfaceElevated, + child: Icon( + t.amount >= 0 ? Icons.arrow_downward : Icons.arrow_upward, + size: 16, + color: t.amount >= 0 ? kGreenAccent : kRedAccent, + ), + ), + title: Text(t.payee, style: Theme.of(context).textTheme.bodyMedium), + subtitle: Text( + DateFormat('dd/MM/yy').format(t.date), + style: Theme.of(context).textTheme.bodySmall, + ), + trailing: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + formatCurrency(t.amount), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: t.amount >= 0 ? kGreenAccent : kRedAccent, + ), + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart new file mode 100644 index 0000000..711c428 --- /dev/null +++ b/lib/theme/app_theme.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +// ── Couleurs custom ─────────────────────────────────────────────────────────── +// Fond très sombre mais pas noir, vert fluo pour accent, elevation uniquement. +const kSurfaceBg = Color(0xFF12161C); +const kSurfaceCard = Color(0xFF1A1E26); +const kSurfaceElevated = Color(0xFF232730); +const kGreenAccent = Color(0xFF00E676); +const kGreenAccentDim = Color(0xFF00B85C); +const kRedAccent = Color(0xFFFF5252); +const kTextPrimary = Color(0xFFE8EAED); +const kTextSecondary = Color(0xFF9AA0A6); +const kDivider = Color(0xFF2C3038); + +final ThemeData ynabDarkTheme = ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + colorScheme: ColorScheme.fromSeed( + seedColor: kGreenAccent, + brightness: Brightness.dark, + surface: kSurfaceBg, + primary: kGreenAccent, + secondary: kGreenAccentDim, + error: kRedAccent, + onSurface: kTextPrimary, + onSurfaceVariant: kTextSecondary, + outline: kDivider, + ), + scaffoldBackgroundColor: kSurfaceBg, + cardTheme: CardThemeData( + color: kSurfaceCard, + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + clipBehavior: Clip.antiAlias, + ), + navigationRailTheme: NavigationRailThemeData( + backgroundColor: kSurfaceCard, + indicatorColor: kGreenAccent.withAlpha(40), + unselectedIconTheme: const IconThemeData(color: kTextSecondary), + selectedIconTheme: const IconThemeData(color: kGreenAccent), + unselectedLabelTextStyle: GoogleFonts.inter( + color: kTextSecondary, + fontSize: 11, + ), + selectedLabelTextStyle: GoogleFonts.inter( + color: kGreenAccent, + fontSize: 11, + fontWeight: FontWeight.w600, + ), + labelType: NavigationRailLabelType.none, + ), + appBarTheme: AppBarTheme( + backgroundColor: kSurfaceBg, + elevation: 0, + scrolledUnderElevation: 1, + centerTitle: false, + titleTextStyle: GoogleFonts.inter( + fontSize: 20, + fontWeight: FontWeight.w600, + color: kTextPrimary, + ), + iconTheme: const IconThemeData(color: kTextSecondary), + ), + textTheme: GoogleFonts.interTextTheme( + ThemeData.dark().textTheme.copyWith( + headlineLarge: const TextStyle(color: kTextPrimary), + headlineMedium: const TextStyle(color: kTextPrimary), + headlineSmall: const TextStyle(color: kTextPrimary), + titleLarge: const TextStyle(color: kTextPrimary), + titleMedium: const TextStyle(color: kTextPrimary), + titleSmall: const TextStyle(color: kTextPrimary), + bodyLarge: const TextStyle(color: kTextPrimary), + bodyMedium: const TextStyle(color: kTextPrimary, fontSize: 14), + bodySmall: const TextStyle(color: kTextSecondary, fontSize: 12), + labelLarge: const TextStyle(color: kTextPrimary), + labelMedium: const TextStyle(color: kTextSecondary), + labelSmall: const TextStyle(color: kTextSecondary), + ), + ), + dividerTheme: const DividerThemeData(color: kDivider, thickness: 1), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: kGreenAccent, + foregroundColor: kSurfaceBg, + elevation: 4, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + ), + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: kSurfaceElevated, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: const BorderSide(color: kGreenAccent, width: 1.5), + ), + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + ), + bottomSheetTheme: const BottomSheetThemeData( + backgroundColor: kSurfaceCard, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + ), + sliderTheme: SliderThemeData( + activeTrackColor: kGreenAccent, + thumbColor: kGreenAccent, + inactiveTrackColor: kDivider, + overlayColor: kGreenAccent.withAlpha(30), + ), + dialogTheme: DialogThemeData( + backgroundColor: kSurfaceCard, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + ), +); + +// Utils +String formatCurrency(double amount) { + final sign = amount < 0 ? '-' : ''; + final abs = amount.abs(); + final parts = abs.toStringAsFixed(2).split('.'); + final intPart = parts[0]; + final decPart = parts[1]; + final buf = StringBuffer(); + int count = 0; + for (int i = intPart.length - 1; i >= 0; i--) { + if (count > 0 && count % 3 == 0) buf.write(' '); + buf.write(intPart[i]); + count++; + } + final formatted = '${buf.toString().split('').reversed.join()},$decPart'; + return '$sign$formatted €'; +} + +String formatCurrencyShort(double amount) { + final abs = amount.abs(); + if (abs >= 1000000) return '${(abs / 1000000).toStringAsFixed(1)} M'; + if (abs >= 1000) return '${(abs / 1000).toStringAsFixed(1)} k'; + return '${abs.toStringAsFixed(2)} €'; +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..a02345f --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,954 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + url: "https://pub.dev" + source: hosted + version: "85.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c + url: "https://pub.dev" + source: hosted + version: "7.6.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: a5ab7590c27b779f3d4de67f31c4109dbe13dd7339f86461a6f2a8ab2594d8ce + url: "https://pub.dev" + source: hosted + version: "0.13.4" + 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" + 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: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: fd754058c342243718d5171a95f352cfc9fcf0cba8cfa26df67cb13a5836db78 + url: "https://pub.dev" + source: hosted + version: "4.1.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + url: "https://pub.dev" + source: hosted + version: "9.1.2" + 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" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.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" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + url: "https://pub.dev" + source: hosted + version: "4.11.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" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + custom_lint: + dependency: transitive + description: + name: custom_lint + sha256: "9656925637516c5cf0f5da018b33df94025af2088fe09c8ae2ca54c53f2d9a84" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + custom_lint_builder: + dependency: transitive + description: + name: custom_lint_builder + sha256: "6cdc8e87e51baaaba9c43e283ed8d28e59a0c4732279df62f66f7b5984655414" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: "31110af3dde9d29fb10828ca33f1dce24d2798477b167675543ce3d208dee8be" + url: "https://pub.dev" + source: hosted + version: "0.7.5" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2" + url: "https://pub.dev" + source: hosted + version: "1.0.0+7.7.0" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + drift: + dependency: "direct main" + description: + name: drift + sha256: "540cf382a3bfa99b76e51514db5b0ebcd81ce3679b7c1c9cb9478ff3735e47a1" + url: "https://pub.dev" + source: hosted + version: "2.28.2" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + sha256: "68c138e884527d2bd61df2ade276c3a144df84d1adeb0ab8f3196b5afe021bd4" + url: "https://pub.dev" + source: hosted + version: "2.28.0" + drift_flutter: + dependency: "direct main" + description: + name: drift_flutter + sha256: b7534bf320aac5213259aac120670ba67b63a1fd010505babc436ff86083818f + url: "https://pub.dev" + source: hosted + version: "0.2.7" + 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" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d" + url: "https://pub.dev" + source: hosted + version: "0.66.2" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + flutter_slidable: + dependency: "direct main" + description: + name: flutter_slidable + sha256: a857de7ea701f276fd6a6c4c67ae885b60729a3449e42766bb0e655171042801 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: b465e99ce64ba75e61c8c0ce3d87b66d8ac07f0b35d0a7e0263fcfc10f99e836 + url: "https://pub.dev" + source: hosted + version: "13.2.5" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 + url: "https://pub.dev" + source: hosted + version: "6.3.3" + 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" + hotreloader: + dependency: transitive + description: + name: hotreloader + sha256: "66871df468fc24eee81f1a0a7cb98acc104716f9b7376d355437b48d633c4ebf" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + 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" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + 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: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + 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: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + 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: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + url: "https://pub.dev" + source: hosted + version: "1.18.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + 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: "direct main" + 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" + 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" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: "03a17170088c63aab6c54c44456f5ab78876a1ddb6032ffde1662ddab4959611" + url: "https://pub.dev" + source: hosted + version: "0.5.10" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: "44a0992d54473eb199ede00e2260bd3c262a86560e3c6f6374503d86d0580e36" + url: "https://pub.dev" + source: hosted + version: "2.6.5" + riverpod_lint: + dependency: "direct dev" + description: + name: riverpod_lint + sha256: "89a52b7334210dbff8605c3edf26cfe69b15062beed5cbfeff2c3812c33c9e35" + url: "https://pub.dev" + source: hosted + version: "2.6.5" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + 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" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + 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: "57090342af1ce32bb499aa641f4ecdd2d6231b9403cea537ac059e803cc20d67" + url: "https://pub.dev" + source: hosted + version: "0.41.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" + 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" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + 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" + 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.12.2 <4.0.0" + flutter: ">=3.38.4" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..c1abc17 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,34 @@ +name: ynab_lite +description: "Budget manager — YNAB-like" +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ^3.12.2 + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.8 + flutter_riverpod: ^2.5.1 + riverpod_annotation: ^2.3.0 + drift: ^2.20.0 + drift_flutter: ^0.2.0 + path_provider: ^2.1.3 + go_router: ^13.0.1 + intl: ^0.19.0 + fl_chart: ^0.66.2 + flutter_slidable: ^3.1.1 + google_fonts: ^6.1.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + build_runner: ^2.4.9 + drift_dev: ^2.20.0 + riverpod_generator: ^2.4.0 + riverpod_lint: ^2.3.0 + +flutter: + uses-material-design: true diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..515cace --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,21 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:ynab_lite/app.dart'; +import 'package:ynab_lite/theme/app_theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +void main() { + testWidgets('App renders dashboard by default', (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + theme: ynabDarkTheme, + home: YnabApp(), + ), + ), + ); + + expect(find.text('Tableau de bord'), findsOneWidget); + expect(find.text('Solde total'), findsOneWidget); + }); +}