10 Commits
17 changed files with 1399 additions and 940 deletions
+65 -97
View File
@@ -5,14 +5,14 @@
<entry key="_fe_analyzer_shared">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-82.0.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-61.0.0/lib" />
</list>
</value>
</entry>
<entry key="analyzer">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-7.4.4/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-5.13.0/lib" />
</list>
</value>
</entry>
@@ -40,7 +40,7 @@
<entry key="build">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build-2.4.2/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build-2.4.1/lib" />
</list>
</value>
</entry>
@@ -61,21 +61,21 @@
<entry key="build_resolvers">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_resolvers-2.4.4/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_resolvers-2.4.2/lib" />
</list>
</value>
</entry>
<entry key="build_runner">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner-2.4.15/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner-2.4.13/lib" />
</list>
</value>
</entry>
<entry key="build_runner_core">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner_core-8.0.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner_core-7.3.2/lib" />
</list>
</value>
</entry>
@@ -100,13 +100,6 @@
</list>
</value>
</entry>
<entry key="charcode">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/charcode-1.4.0/lib" />
</list>
</value>
</entry>
<entry key="checked_yaml">
<value>
<list>
@@ -114,13 +107,6 @@
</list>
</value>
</entry>
<entry key="cli_util">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/cli_util-0.4.2/lib" />
</list>
</value>
</entry>
<entry key="clock">
<value>
<list>
@@ -166,21 +152,14 @@
<entry key="dart_style">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_style-3.0.1/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_style-2.3.2/lib" />
</list>
</value>
</entry>
<entry key="drift">
<entry key="dartx">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/drift-2.26.0/lib" />
</list>
</value>
</entry>
<entry key="drift_dev">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/drift_dev-2.26.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dartx-1.2.0/lib" />
</list>
</value>
</entry>
@@ -268,13 +247,6 @@
</list>
</value>
</entry>
<entry key="http">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http-1.3.0/lib" />
</list>
</value>
</entry>
<entry key="http_multi_server">
<value>
<list>
@@ -292,7 +264,7 @@
<entry key="intl">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.19.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.20.2/lib" />
</list>
</value>
</entry>
@@ -303,10 +275,31 @@
</list>
</value>
</entry>
<entry key="isar">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar-3.1.0+1/lib" />
</list>
</value>
</entry>
<entry key="isar_flutter_libs">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar_flutter_libs-3.1.0+1/lib" />
</list>
</value>
</entry>
<entry key="isar_generator">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar_generator-3.1.0+1/lib" />
</list>
</value>
</entry>
<entry key="js">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.7.2/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.6.7/lib" />
</list>
</value>
</entry>
@@ -471,20 +464,6 @@
</list>
</value>
</entry>
<entry key="recase">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/recase-4.1.0/lib" />
</list>
</value>
</entry>
<entry key="rxdart">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/rxdart-0.28.0/lib" />
</list>
</value>
</entry>
<entry key="shelf">
<value>
<list>
@@ -495,7 +474,7 @@
<entry key="shelf_web_socket">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-3.0.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-2.0.1/lib" />
</list>
</value>
</entry>
@@ -509,7 +488,7 @@
<entry key="source_gen">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_gen-2.0.0/lib" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_gen-1.5.0/lib" />
</list>
</value>
</entry>
@@ -520,27 +499,6 @@
</list>
</value>
</entry>
<entry key="sqlite3">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlite3-2.7.5/lib" />
</list>
</value>
</entry>
<entry key="sqlite3_flutter_libs">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/lib" />
</list>
</value>
</entry>
<entry key="sqlparser">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlparser-0.41.0/lib" />
</list>
</value>
</entry>
<entry key="stack_trace">
<value>
<list>
@@ -583,6 +541,13 @@
</list>
</value>
</entry>
<entry key="time">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/time-2.1.5/lib" />
</list>
</value>
</entry>
<entry key="timing">
<value>
<list>
@@ -646,6 +611,13 @@
</list>
</value>
</entry>
<entry key="xxh3">
<value>
<list>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/xxh3-1.2.0/lib" />
</list>
</value>
</entry>
<entry key="yaml">
<value>
<list>
@@ -659,32 +631,29 @@
<root url="file://$PROJECT_DIR$/../../../../../Sanders/Flutter/flutter/bin/cache/pkg/sky_engine/lib" />
<root url="file://$PROJECT_DIR$/../../../../../Sanders/Flutter/flutter/packages/flutter/lib" />
<root url="file://$PROJECT_DIR$/../../../../../Sanders/Flutter/flutter/packages/flutter_test/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-82.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-7.4.4/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-61.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-5.13.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/args-2.7.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/async-2.12.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/boolean_selector-2.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build-2.4.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build-2.4.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_config-1.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_daemon-4.0.4/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_resolvers-2.4.4/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner-2.4.15/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner_core-8.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_resolvers-2.4.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner-2.4.13/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/build_runner_core-7.3.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/built_collection-5.1.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/built_value-8.9.5/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/characters-1.4.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/charcode-1.4.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/checked_yaml-2.0.3/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/cli_util-0.4.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/clock-1.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/code_builder-4.10.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/collection-1.19.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/convert-3.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/crypto-3.0.6/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_style-3.0.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/drift-2.26.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/drift_dev-2.26.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_style-2.3.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dartx-1.2.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/equatable-2.0.7/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/ffi-2.1.4/lib" />
@@ -695,12 +664,14 @@
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/frontend_server_client-4.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/glob-2.1.3/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/graphs-2.3.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http-1.3.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_multi_server-3.2.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_parser-4.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.19.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.20.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/io-1.0.5/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.7.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar-3.1.0+1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar_flutter_libs-3.1.0+1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/isar_generator-3.1.0+1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.6.7/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/json_annotation-4.9.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/leak_tracker-10.0.8/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.9/lib" />
@@ -724,21 +695,17 @@
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pool-1.5.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pub_semver-2.2.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pubspec_parse-1.5.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/recase-4.1.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/rxdart-0.28.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf-1.4.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-3.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_gen-2.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-2.0.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_gen-1.5.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_span-1.10.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlite3-2.7.5/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/sqlparser-0.41.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stack_trace-1.12.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stream_channel-2.1.4/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stream_transform-2.1.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/string_scanner-1.4.1/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/term_glyph-1.2.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test_api-0.7.4/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/time-2.1.5/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/timing-1.0.2/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/typed_data-1.4.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/vector_math-2.1.4/lib" />
@@ -748,6 +715,7 @@
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket-1.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket_channel-3.0.3/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/xdg_directories-1.1.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/xxh3-1.2.0/lib" />
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/yaml-3.1.3/lib" />
</CLASSES>
<JAVADOC />
+1 -1
View File
@@ -1,4 +1,4 @@
# This file configures the analyzer, which statically analyzes Dart code to
# 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
+5 -4
View File
@@ -1,12 +1,13 @@
import 'package:flutter/material.dart';
import 'package:isar/isar.dart'; // Импорт Isar
import 'screens/expenses_screen.dart';
import 'theme/app_theme.dart';
import 'database/database.dart'; // Import the database
// import 'database/database.dart'; // Больше не нужен прямой импорт AppDatabase или IsarService
class MyApp extends StatefulWidget {
final AppDatabase database; // Принимаем экземпляр базы данных
final Isar isar; // Принимаем экземпляр Isar
const MyApp({Key? key, required this.database}) : super(key: key);
const MyApp({Key? key, required this.isar}) : super(key: key); // Обновленный конструктор
@override
State<MyApp> createState() => _MyAppState();
@@ -32,7 +33,7 @@ class _MyAppState extends State<MyApp> {
theme: AppTheme.lightTheme, // Светлая тема
darkTheme: AppTheme.darkTheme, // Темная тема
home: ExpensesScreen(
database: widget.database, // Передаем базу данных в главный экран
isar: widget.isar, // Передаем Isar в главный экран
toggleTheme: toggleTheme, // Передаем функцию переключения темы
isDarkMode: _isDarkMode, // Передаем текущее состояние темы
),
+83 -91
View File
@@ -1,80 +1,74 @@
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
// import 'package:flutter/material.dart'; // Не требуется напрямую, т.к. Category импортируется
import 'dart:async';
import 'package:flutter/material.dart'; // Для Color/IconData в Category
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
// import 'package:rxdart/rxdart.dart'; // Не используется
// Импортируем модель категории для возвращаемого типа и утилиты
// Импортируем модели
import '../models/category.dart';
// Удален ненужный импорт: import '../models/transaction_record.dart';
import '../utils/category_utils.dart'; // Helper for category details
import '../models/isar_transaction.dart'; // Наша Isar модель
import '../utils/category_utils.dart'; // Помощник для деталей категории
// Эта строка указывает Drift сгенерировать файл database.g.dart
part 'database.g.dart';
// Этот файл больше не использует Drift, поэтому part 'database.g.dart'; удален.
// Определение таблицы Transactions
// Имя таблицы в SQL будет 'transactions' (snake_case от имени класса)
@DataClassName('Transaction') // Keep the generated class name as Transaction
class Transactions extends Table {
IntColumn get id => integer().autoIncrement()(); // Primary key
TextColumn get categoryName => text().named('category_name')(); // Имя категории
RealColumn get amount => real()(); // Сумма транзакции
DateTimeColumn get date => dateTime()(); // Дата транзакции
TextColumn get merchant => text()(); // Название продавца/магазина
}
// Класс-сервис для инкапсуляции логики работы с Isar
class IsarService {
final Isar isar;
// Класс базы данных
// Аннотация @DriftDatabase указывает Drift сгенерировать код для этой базы данных
@DriftDatabase(tables: [Transactions])
class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
// Версия схемы. Увеличивайте при изменении структуры таблиц.
@override
int get schemaVersion => 1;
IsarService(this.isar);
// --- Методы для работы с транзакциями ---
// Получить все транзакции в виде потока, упорядоченные по дате (сначала новые)
// Возвращает non-nullable Stream<List<Transaction>> (Transaction - сгенерированный Drift класс)
Stream<List<Transaction>> watchAllTransactions() {
return (select(transactions)
..orderBy([(t) => OrderingTerm(expression: t.date, mode: OrderingMode.desc)]))
.watch();
// Возвращает Stream<List<IsarTransaction>>
Stream<List<IsarTransaction>> watchAllTransactions() {
// isar.isarTransactions ссылается на коллекцию IsarTransaction
// .where() без условий выбирает все
// .sortByDateDesc() сортирует по полю date по убыванию
// .watch(fireImmediately: true) создает поток, который срабатывает сразу
return isar.isarTransactions
.where()
.sortByDateDesc()
.watch(fireImmediately: true);
}
// Получить транзакции, отфильтрованные по категории, в виде потока
// Возвращает non-nullable Stream<List<Transaction>> (Transaction - сгенерированный Drift класс)
Stream<List<Transaction>> watchFilteredTransactions(String categoryName) {
if (categoryName == 'All') {
// watchAllTransactions теперь возвращает non-nullable Stream
return watchAllTransactions(); // Return all if filter is 'All'
}
// Otherwise, filter by the provided category name
return (select(transactions)
..where((t) => t.categoryName.equals(categoryName))
..orderBy([(t) => OrderingTerm(expression: t.date, mode: OrderingMode.desc)]))
.watch();
}
// Возвращает Stream<List<IsarTransaction>>
Stream<List<IsarTransaction>> watchFilteredTransactions(String categoryName) {
if (categoryName == 'All') {
return watchAllTransactions(); // Возвращаем все, если фильтр 'All'
}
// Иначе фильтруем по categoryName
return isar.isarTransactions
.filter()
.categoryNameEqualTo(categoryName) // Используем сгенерированный Isar фильтр
.sortByDateDesc()
.watch(fireImmediately: true);
}
// Добавить новую транзакцию
// Принимает TransactionsCompanion - сгенерированный Drift класс
Future<int> addTransaction(TransactionsCompanion entry) {
return into(transactions).insert(entry);
// Принимает объект IsarTransaction
Future<void> addTransaction(IsarTransaction transaction) async {
// Используем writeTxn для выполнения операции записи
await isar.writeTxn(() async {
await isar.isarTransactions.put(transaction); // put добавляет или обновляет запись
});
}
// Добавить несколько транзакций (для начальных данных)
Future<void> addTransactions(List<IsarTransaction> transactions) async {
await isar.writeTxn(() async {
await isar.isarTransactions.putAll(transactions);
});
}
// --- Методы для работы с категориями (вычисляются из транзакций) ---
// Вычислить и наблюдать за общими суммами по категориям
Stream<List<Category>> calculateCategoryTotals() {
// 1. Получаем поток всех транзакций (теперь non-nullable Stream<List<Transaction>>)
// 1. Получаем поток всех транзакций
return watchAllTransactions().map((transactionList) {
// 2. Группируем транзакции по categoryName и суммируем amount
final categoryTotals = <String, double>{};
// transactionList теперь содержит объекты Transaction, сгенерированные Drift
for (var transaction in transactionList) {
categoryTotals.update(
transaction.categoryName,
@@ -85,9 +79,6 @@ class AppDatabase extends _$AppDatabase {
// 3. Преобразуем сгруппированные данные в список объектов Category
return categoryTotals.entries.map((entry) {
// Используем CategoryUtils для получения деталей (иконка, цвет)
// Убедитесь, что CategoryUtils корректно обрабатывает все categoryName,
// включая 'Utilities' из начальных данных, или предоставляет дефолтные значения.
final categoryDetails = CategoryUtils.getCategoryDetails(entry.key);
return Category(
entry.key, // name
@@ -96,7 +87,7 @@ class AppDatabase extends _$AppDatabase {
categoryDetails.iconCode,
);
}).toList()
// Сортируем категории по сумме (от большей к меньшей) для диаграммы/легенды
// Сортируем категории по сумме (от большей к меньшей)
..sort((a, b) => b.amount.compareTo(a.amount));
});
}
@@ -104,42 +95,43 @@ class AppDatabase extends _$AppDatabase {
// Пример добавления начальных данных (если база данных пуста)
Future<void> insertInitialDataIfNeeded() async {
// Проверяем, есть ли уже транзакции
final existingTransactions = await select(transactions).get();
if (existingTransactions.isEmpty) {
print("Database is empty. Inserting initial data...");
// Используем batch для эффективной вставки нескольких записей
await batch((batch) {
batch.insertAll(transactions, [
// Используем TransactionsCompanion для создания записей для вставки
TransactionsCompanion.insert(categoryName: 'Groceries', amount: 45.99, date: DateTime.now().subtract(const Duration(days: 1, hours: 2)), merchant: 'Whole Foods Market'),
TransactionsCompanion.insert(categoryName: 'Subscriptions', amount: 39.99, date: DateTime.now().subtract(const Duration(days: 2, hours: 5)), merchant: 'Netflix Premium'),
TransactionsCompanion.insert(categoryName: 'Restaurant', amount: 78.50, date: DateTime.now().subtract(const Duration(days: 2, hours: 19)), merchant: 'Italian Corner'),
TransactionsCompanion.insert(categoryName: 'Shopping', amount: 132.75, date: DateTime.now().subtract(const Duration(days: 3, hours: 11)), merchant: 'Apple Store'),
TransactionsCompanion.insert(categoryName: 'Groceries', amount: 23.45, date: DateTime.now().subtract(const Duration(days: 4, hours: 9)), merchant: 'Local Market'),
TransactionsCompanion.insert(categoryName: 'Transport', amount: 15.00, date: DateTime.now().subtract(const Duration(days: 5, hours: 8)), merchant: 'City Bus'),
TransactionsCompanion.insert(categoryName: 'Restaurant', amount: 56.80, date: DateTime.now().subtract(const Duration(days: 5, hours: 20)), merchant: 'Sushi Express'),
// Убедитесь, что 'Utilities' определена в CategoryUtils или обрабатывается как неизвестная категория
TransactionsCompanion.insert(categoryName: 'Utilities', amount: 85.20, date: DateTime.now().subtract(const Duration(days: 6, hours: 10)), merchant: 'Electricity Bill'),
]);
});
print("Initial data inserted successfully.");
final count = await isar.isarTransactions.count();
if (count == 0) {
print("Isar Database is empty. Inserting initial data...");
final initialTransactions = [
IsarTransaction(categoryName: 'Groceries', amount: 45.99, date: DateTime.now().subtract(const Duration(days: 1, hours: 2)), merchant: 'Whole Foods Market'),
IsarTransaction(categoryName: 'Subscriptions', amount: 39.99, date: DateTime.now().subtract(const Duration(days: 2, hours: 5)), merchant: 'Netflix Premium'),
IsarTransaction(categoryName: 'Restaurant', amount: 78.50, date: DateTime.now().subtract(const Duration(days: 2, hours: 19)), merchant: 'Italian Corner'),
IsarTransaction(categoryName: 'Shopping', amount: 132.75, date: DateTime.now().subtract(const Duration(days: 3, hours: 11)), merchant: 'Apple Store'),
IsarTransaction(categoryName: 'Groceries', amount: 23.45, date: DateTime.now().subtract(const Duration(days: 4, hours: 9)), merchant: 'Local Market'),
IsarTransaction(categoryName: 'Transport', amount: 15.00, date: DateTime.now().subtract(const Duration(days: 5, hours: 8)), merchant: 'City Bus'),
IsarTransaction(categoryName: 'Restaurant', amount: 56.80, date: DateTime.now().subtract(const Duration(days: 5, hours: 20)), merchant: 'Sushi Express'),
// Убедитесь, что 'Utilities' определена в CategoryUtils или обрабатывается как неизвестная категория
IsarTransaction(categoryName: 'Utilities', amount: 85.20, date: DateTime.now().subtract(const Duration(days: 6, hours: 10)), merchant: 'Electricity Bill'),
];
await addTransactions(initialTransactions);
print("Initial data inserted successfully into Isar.");
} else {
print("Database already contains data (${existingTransactions.length} transactions). Skipping initial data insertion.");
print("Isar Database already contains data ($count transactions). Skipping initial data insertion.");
}
}
}
// Функция для открытия соединения с базой данных
LazyDatabase _openConnection() {
// Вычисление пути к файлу базы данных в папке документов приложения
return LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
// Создаем файл 'db.sqlite' в этой папке
final file = File(p.join(dbFolder.path, 'db.sqlite'));
print("Database file path: ${file.path}"); // Логируем путь для отладки
// Используем NativeDatabase для открытия соединения
// logStatements: true полезен для отладки SQL-запросов
return NativeDatabase(file, logStatements: false);
});
// Статический метод для открытия базы данных Isar
static Future<Isar> openDB() async {
final dir = await getApplicationDocumentsDirectory();
// Проверяем, открыт ли уже экземпляр Isar с таким именем
// Это полезно для hot reload/restart
if (Isar.instanceNames.isEmpty) {
print("Opening Isar database at: ${dir.path}");
return await Isar.open(
[IsarTransactionSchema], // Передаем сгенерированную схему
directory: dir.path,
inspector: true, // Включаем инспектор для отладки (доступен в debug режиме)
);
}
// Возвращаем существующий экземпляр
print("Returning existing Isar instance.");
// ignore: RETHROW_IF_NOT_THROWING
return Future.value(Isar.getInstance()); // Возвращаем существующий экземпляр
}
}
-586
View File
@@ -1,586 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'database.dart';
// ignore_for_file: type=lint
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<int> id = GeneratedColumn<int>(
'id',
aliasedName,
false,
hasAutoIncrement: true,
type: DriftSqlType.int,
requiredDuringInsert: false,
defaultConstraints: GeneratedColumn.constraintIsAlways(
'PRIMARY KEY AUTOINCREMENT',
),
);
static const VerificationMeta _categoryNameMeta = const VerificationMeta(
'categoryName',
);
@override
late final GeneratedColumn<String> categoryName = GeneratedColumn<String>(
'category_name',
aliasedName,
false,
type: DriftSqlType.string,
requiredDuringInsert: true,
);
static const VerificationMeta _amountMeta = const VerificationMeta('amount');
@override
late final GeneratedColumn<double> amount = GeneratedColumn<double>(
'amount',
aliasedName,
false,
type: DriftSqlType.double,
requiredDuringInsert: true,
);
static const VerificationMeta _dateMeta = const VerificationMeta('date');
@override
late final GeneratedColumn<DateTime> date = GeneratedColumn<DateTime>(
'date',
aliasedName,
false,
type: DriftSqlType.dateTime,
requiredDuringInsert: true,
);
static const VerificationMeta _merchantMeta = const VerificationMeta(
'merchant',
);
@override
late final GeneratedColumn<String> merchant = GeneratedColumn<String>(
'merchant',
aliasedName,
false,
type: DriftSqlType.string,
requiredDuringInsert: true,
);
@override
List<GeneratedColumn> get $columns => [
id,
categoryName,
amount,
date,
merchant,
];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'transactions';
@override
VerificationContext validateIntegrity(
Insertable<Transaction> 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_name')) {
context.handle(
_categoryNameMeta,
categoryName.isAcceptableOrUnknown(
data['category_name']!,
_categoryNameMeta,
),
);
} else if (isInserting) {
context.missing(_categoryNameMeta);
}
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('merchant')) {
context.handle(
_merchantMeta,
merchant.isAcceptableOrUnknown(data['merchant']!, _merchantMeta),
);
} else if (isInserting) {
context.missing(_merchantMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Transaction map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return Transaction(
id:
attachedDatabase.typeMapping.read(
DriftSqlType.int,
data['${effectivePrefix}id'],
)!,
categoryName:
attachedDatabase.typeMapping.read(
DriftSqlType.string,
data['${effectivePrefix}category_name'],
)!,
amount:
attachedDatabase.typeMapping.read(
DriftSqlType.double,
data['${effectivePrefix}amount'],
)!,
date:
attachedDatabase.typeMapping.read(
DriftSqlType.dateTime,
data['${effectivePrefix}date'],
)!,
merchant:
attachedDatabase.typeMapping.read(
DriftSqlType.string,
data['${effectivePrefix}merchant'],
)!,
);
}
@override
$TransactionsTable createAlias(String alias) {
return $TransactionsTable(attachedDatabase, alias);
}
}
class Transaction extends DataClass implements Insertable<Transaction> {
final int id;
final String categoryName;
final double amount;
final DateTime date;
final String merchant;
const Transaction({
required this.id,
required this.categoryName,
required this.amount,
required this.date,
required this.merchant,
});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['id'] = Variable<int>(id);
map['category_name'] = Variable<String>(categoryName);
map['amount'] = Variable<double>(amount);
map['date'] = Variable<DateTime>(date);
map['merchant'] = Variable<String>(merchant);
return map;
}
TransactionsCompanion toCompanion(bool nullToAbsent) {
return TransactionsCompanion(
id: Value(id),
categoryName: Value(categoryName),
amount: Value(amount),
date: Value(date),
merchant: Value(merchant),
);
}
factory Transaction.fromJson(
Map<String, dynamic> json, {
ValueSerializer? serializer,
}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return Transaction(
id: serializer.fromJson<int>(json['id']),
categoryName: serializer.fromJson<String>(json['categoryName']),
amount: serializer.fromJson<double>(json['amount']),
date: serializer.fromJson<DateTime>(json['date']),
merchant: serializer.fromJson<String>(json['merchant']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
'categoryName': serializer.toJson<String>(categoryName),
'amount': serializer.toJson<double>(amount),
'date': serializer.toJson<DateTime>(date),
'merchant': serializer.toJson<String>(merchant),
};
}
Transaction copyWith({
int? id,
String? categoryName,
double? amount,
DateTime? date,
String? merchant,
}) => Transaction(
id: id ?? this.id,
categoryName: categoryName ?? this.categoryName,
amount: amount ?? this.amount,
date: date ?? this.date,
merchant: merchant ?? this.merchant,
);
Transaction copyWithCompanion(TransactionsCompanion data) {
return Transaction(
id: data.id.present ? data.id.value : this.id,
categoryName:
data.categoryName.present
? data.categoryName.value
: this.categoryName,
amount: data.amount.present ? data.amount.value : this.amount,
date: data.date.present ? data.date.value : this.date,
merchant: data.merchant.present ? data.merchant.value : this.merchant,
);
}
@override
String toString() {
return (StringBuffer('Transaction(')
..write('id: $id, ')
..write('categoryName: $categoryName, ')
..write('amount: $amount, ')
..write('date: $date, ')
..write('merchant: $merchant')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(id, categoryName, amount, date, merchant);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is Transaction &&
other.id == this.id &&
other.categoryName == this.categoryName &&
other.amount == this.amount &&
other.date == this.date &&
other.merchant == this.merchant);
}
class TransactionsCompanion extends UpdateCompanion<Transaction> {
final Value<int> id;
final Value<String> categoryName;
final Value<double> amount;
final Value<DateTime> date;
final Value<String> merchant;
const TransactionsCompanion({
this.id = const Value.absent(),
this.categoryName = const Value.absent(),
this.amount = const Value.absent(),
this.date = const Value.absent(),
this.merchant = const Value.absent(),
});
TransactionsCompanion.insert({
this.id = const Value.absent(),
required String categoryName,
required double amount,
required DateTime date,
required String merchant,
}) : categoryName = Value(categoryName),
amount = Value(amount),
date = Value(date),
merchant = Value(merchant);
static Insertable<Transaction> custom({
Expression<int>? id,
Expression<String>? categoryName,
Expression<double>? amount,
Expression<DateTime>? date,
Expression<String>? merchant,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
if (categoryName != null) 'category_name': categoryName,
if (amount != null) 'amount': amount,
if (date != null) 'date': date,
if (merchant != null) 'merchant': merchant,
});
}
TransactionsCompanion copyWith({
Value<int>? id,
Value<String>? categoryName,
Value<double>? amount,
Value<DateTime>? date,
Value<String>? merchant,
}) {
return TransactionsCompanion(
id: id ?? this.id,
categoryName: categoryName ?? this.categoryName,
amount: amount ?? this.amount,
date: date ?? this.date,
merchant: merchant ?? this.merchant,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (id.present) {
map['id'] = Variable<int>(id.value);
}
if (categoryName.present) {
map['category_name'] = Variable<String>(categoryName.value);
}
if (amount.present) {
map['amount'] = Variable<double>(amount.value);
}
if (date.present) {
map['date'] = Variable<DateTime>(date.value);
}
if (merchant.present) {
map['merchant'] = Variable<String>(merchant.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('TransactionsCompanion(')
..write('id: $id, ')
..write('categoryName: $categoryName, ')
..write('amount: $amount, ')
..write('date: $date, ')
..write('merchant: $merchant')
..write(')'))
.toString();
}
}
abstract class _$AppDatabase extends GeneratedDatabase {
_$AppDatabase(QueryExecutor e) : super(e);
$AppDatabaseManager get managers => $AppDatabaseManager(this);
late final $TransactionsTable transactions = $TransactionsTable(this);
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [transactions];
}
typedef $$TransactionsTableCreateCompanionBuilder =
TransactionsCompanion Function({
Value<int> id,
required String categoryName,
required double amount,
required DateTime date,
required String merchant,
});
typedef $$TransactionsTableUpdateCompanionBuilder =
TransactionsCompanion Function({
Value<int> id,
Value<String> categoryName,
Value<double> amount,
Value<DateTime> date,
Value<String> merchant,
});
class $$TransactionsTableFilterComposer
extends Composer<_$AppDatabase, $TransactionsTable> {
$$TransactionsTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnFilters<int> get id => $composableBuilder(
column: $table.id,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<String> get categoryName => $composableBuilder(
column: $table.categoryName,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<double> get amount => $composableBuilder(
column: $table.amount,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<DateTime> get date => $composableBuilder(
column: $table.date,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<String> get merchant => $composableBuilder(
column: $table.merchant,
builder: (column) => ColumnFilters(column),
);
}
class $$TransactionsTableOrderingComposer
extends Composer<_$AppDatabase, $TransactionsTable> {
$$TransactionsTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnOrderings<int> get id => $composableBuilder(
column: $table.id,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<String> get categoryName => $composableBuilder(
column: $table.categoryName,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<double> get amount => $composableBuilder(
column: $table.amount,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<DateTime> get date => $composableBuilder(
column: $table.date,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<String> get merchant => $composableBuilder(
column: $table.merchant,
builder: (column) => ColumnOrderings(column),
);
}
class $$TransactionsTableAnnotationComposer
extends Composer<_$AppDatabase, $TransactionsTable> {
$$TransactionsTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
GeneratedColumn<int> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
GeneratedColumn<String> get categoryName => $composableBuilder(
column: $table.categoryName,
builder: (column) => column,
);
GeneratedColumn<double> get amount =>
$composableBuilder(column: $table.amount, builder: (column) => column);
GeneratedColumn<DateTime> get date =>
$composableBuilder(column: $table.date, builder: (column) => column);
GeneratedColumn<String> get merchant =>
$composableBuilder(column: $table.merchant, builder: (column) => column);
}
class $$TransactionsTableTableManager
extends
RootTableManager<
_$AppDatabase,
$TransactionsTable,
Transaction,
$$TransactionsTableFilterComposer,
$$TransactionsTableOrderingComposer,
$$TransactionsTableAnnotationComposer,
$$TransactionsTableCreateCompanionBuilder,
$$TransactionsTableUpdateCompanionBuilder,
(
Transaction,
BaseReferences<_$AppDatabase, $TransactionsTable, Transaction>,
),
Transaction,
PrefetchHooks Function()
> {
$$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<int> id = const Value.absent(),
Value<String> categoryName = const Value.absent(),
Value<double> amount = const Value.absent(),
Value<DateTime> date = const Value.absent(),
Value<String> merchant = const Value.absent(),
}) => TransactionsCompanion(
id: id,
categoryName: categoryName,
amount: amount,
date: date,
merchant: merchant,
),
createCompanionCallback:
({
Value<int> id = const Value.absent(),
required String categoryName,
required double amount,
required DateTime date,
required String merchant,
}) => TransactionsCompanion.insert(
id: id,
categoryName: categoryName,
amount: amount,
date: date,
merchant: merchant,
),
withReferenceMapper:
(p0) =>
p0
.map(
(e) => (
e.readTable(table),
BaseReferences(db, table, e),
),
)
.toList(),
prefetchHooksCallback: null,
),
);
}
typedef $$TransactionsTableProcessedTableManager =
ProcessedTableManager<
_$AppDatabase,
$TransactionsTable,
Transaction,
$$TransactionsTableFilterComposer,
$$TransactionsTableOrderingComposer,
$$TransactionsTableAnnotationComposer,
$$TransactionsTableCreateCompanionBuilder,
$$TransactionsTableUpdateCompanionBuilder,
(
Transaction,
BaseReferences<_$AppDatabase, $TransactionsTable, Transaction>,
),
Transaction,
PrefetchHooks Function()
>;
class $AppDatabaseManager {
final _$AppDatabase _db;
$AppDatabaseManager(this._db);
$$TransactionsTableTableManager get transactions =>
$$TransactionsTableTableManager(_db, _db.transactions);
}
+25 -8
View File
@@ -1,18 +1,35 @@
import 'package:flutter/material.dart';
import 'package:isar/isar.dart'; // Импорт Isar
// import 'package:path_provider/path_provider.dart'; // Больше не нужен здесь
import 'app.dart'; // Import the new app root widget
import 'database/database.dart'; // Import the database
import 'database/database.dart'; // Импортируем наш IsarService
import 'models/isar_transaction.dart'; // Импортируем схему Isar
import 'utils/isar_web_helper.dart'; // Импортируем наш вспомогательный класс для веб
Future<void> main() async {
// Необходимо для асинхронных операций перед runApp, например, инициализации БД
// Необходимо для асинхронных операций перед runApp
WidgetsFlutterBinding.ensureInitialized();
// Создаем единственный экземпляр базы данных для всего приложения
final database = AppDatabase();
// Инициализация Isar Core (нужно для нативных библиотек)
// download: true скачает нужную библиотеку, если ее нет
// await Isar.initializeIsarCore(download: true); // Больше не требуется с isar_flutter_libs
// Проверяем, запущено ли приложение на веб-платформе
if (IsarWebHelper.isWeb) {
print('Running on web platform - using JavaScript-safe integer IDs');
}
// Открываем базу данных Isar с помощью статического метода в IsarService
final isar = await IsarService.openDB();
// Создаем экземпляр нашего сервиса (хотя он может быть не нужен здесь, если логика в IsarService)
final isarService = IsarService(isar);
// Опционально: Вставляем начальные данные, если база данных пуста
// Это полезно для первого запуска или демонстрации
await database.insertInitialDataIfNeeded();
// Используем метод из IsarService
await isarService.insertInitialDataIfNeeded();
// Запускаем приложение, передавая экземпляр базы данных
runApp(MyApp(database: database));
// Запускаем приложение, передавая экземпляр Isar
runApp(MyApp(isar: isar)); // Передаем isar вместо database
}
@@ -0,0 +1,33 @@
import 'package:isar/isar.dart';
// Эта строка указывает Isar сгенерировать файл isar_transaction.g.dart
part 'isar_transaction.g.dart';
@collection // Аннотация для Isar коллекции
@Name("Transaction") // Явно задаем имя коллекции для Isar
class IsarTransaction {
Id id = Isar.autoIncrement; // Автоинкрементный ID
@Index() // Индекс для быстрого поиска/фильтрации по имени категории
@Name("category_name") // Явно задаем имя поля для Isar
late String categoryName;
late double amount;
@Index() // Индекс для быстрой сортировки/фильтрации по дате
@Name("transaction_date") // Явно задаем имя поля для Isar (используем другое имя для надежности)
late DateTime date;
late String merchant;
// Конструктор (необязателен, но удобен)
IsarTransaction({
required this.categoryName,
required this.amount,
required this.date,
required this.merchant,
});
// Пустой конструктор для Isar (не используется напрямую)
// IsarTransaction();
}
File diff suppressed because it is too large Load Diff
+52 -37
View File
@@ -1,13 +1,16 @@
import 'package:drift/drift.dart' show Value; // Only import Value for optional fields
// import 'package:drift/drift.dart' show Value; // Больше не нужно
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart'; // Used indirectly by SpendingPieChart
import 'package:intl/intl.dart'; // For date formatting
import 'dart:async';
import 'dart:math'; // For random data generation in sample add
import 'package:isar/isar.dart'; // Импорт Isar
import '../database/database.dart' as db; // Import database with prefix 'db'
// import '../database/database.dart' as db; // Старый импорт Drift
import '../database/database.dart'; // Импортируем наш IsarService
import '../models/category.dart'; // Keep Category model for UI structure (SpendingPieChart)
// Import TransactionRecord with a different alias to avoid conflict with db.Transaction
import '../models/isar_transaction.dart'; // Импортируем Isar модель
// Import TransactionRecord with a different alias to avoid conflict
import '../models/transaction_record.dart' as model;
import '../widgets/summary_item.dart';
import '../widgets/expandable_section.dart';
@@ -20,13 +23,13 @@ import 'profile_screen.dart'; // Import profile screen
class ExpensesScreen extends StatefulWidget {
final Function toggleTheme;
final bool isDarkMode;
final db.AppDatabase database; // Accept database instance
final Isar isar; // Принимаем экземпляр Isar
const ExpensesScreen({
Key? key,
required this.toggleTheme,
required this.isDarkMode,
required this.database, // Require database instance
required this.isar, // Требуем экземпляр Isar
}) : super(key: key);
@override
@@ -44,13 +47,19 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
int _selectedPieIndex = -1; // Index of the selected pie chart slice
int _selectedNavIndex = 0; // Index for bottom navigation bar
bool _isPieChartExpanded = true; // Controls visibility of the pie chart section
bool _isFilterVisible = false; // Controls visibility of the filter chips
bool _isFilterVisible = false; // Controls visibility of the filter chip row
String _selectedFilter = 'All'; // Currently selected transaction filter
// Экземпляр нашего сервиса для удобства
late IsarService _isarService;
@override
void initState() {
super.initState();
// Создаем экземпляр сервиса, передавая Isar из виджета
_isarService = IsarService(widget.isar);
// Initialize animation controller for pie chart fade/scale effect
_pieChartAnimationController = AnimationController(
vsync: this,
@@ -84,14 +93,16 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
super.dispose();
}
// Stream that provides transactions based on the selected filter
Stream<List<db.Transaction>> _watchTransactions() {
return widget.database.watchFilteredTransactions(_selectedFilter);
// Stream that provides transactions based on the selected filter using IsarService
Stream<List<IsarTransaction>> _watchTransactions() {
// Используем метод из IsarService
return _isarService.watchFilteredTransactions(_selectedFilter);
}
// Stream that provides category totals calculated from transactions
// Stream that provides category totals calculated from transactions using IsarService
Stream<List<Category>> _watchCategoryTotals() {
return widget.database.calculateCategoryTotals();
// Используем метод из IsarService
return _isarService.calculateCategoryTotals();
}
// Toggles the visibility of the pie chart section with animation
@@ -133,7 +144,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
});
}
// --- Function to add a sample transaction (for testing/demo) ---
// --- Function to add a sample transaction (using Isar) ---
void _addSampleTransaction() async {
final random = Random();
// Get available category names from our utility class
@@ -145,8 +156,8 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
final randomHour = random.nextInt(24);
final randomMerchant = ['Amazon', 'Local Cafe', 'Gas Station', 'Online Store', 'Supermarket'][random.nextInt(5)];
// Create a companion object for inserting into the Drift table
final newTransaction = db.TransactionsCompanion.insert(
// Create an IsarTransaction object
final newTransaction = IsarTransaction(
categoryName: randomCategory,
amount: randomAmount,
date: DateTime.now().subtract(Duration(days: randomDay, hours: randomHour)),
@@ -154,9 +165,9 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
);
try {
// Insert the transaction into the database
await widget.database.addTransaction(newTransaction);
print('Sample transaction added: $randomCategory - \$${randomAmount.toStringAsFixed(2)}');
// Insert the transaction into the database using IsarService
await _isarService.addTransaction(newTransaction);
print('Sample transaction added via Isar: $randomCategory - \$${randomAmount.toStringAsFixed(2)}');
// Show a confirmation message
if (mounted) { // Check if the widget is still in the tree
ScaffoldMessenger.of(context).showSnackBar(
@@ -168,7 +179,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
);
}
} catch (e) {
print('Error adding transaction: $e');
print('Error adding Isar transaction: $e');
// Show an error message
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
@@ -249,10 +260,11 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
),
// Use StreamBuilder to get category totals for the summary and pie chart
body: StreamBuilder<List<Category>>(
stream: _watchCategoryTotals(),
stream: _watchCategoryTotals(), // Используем метод IsarService
builder: (context, categorySnapshot) {
// Handle loading state
if (categorySnapshot.connectionState == ConnectionState.waiting && !categorySnapshot.hasData) {
// Показываем индикатор загрузки, если данные еще не пришли, но соединение устанавливается
return const Center(child: CircularProgressIndicator());
}
// Handle error state
@@ -260,7 +272,8 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
return Center(child: Text('Error loading categories: ${categorySnapshot.error}'));
}
// Get categories data (or empty list if null)
// Get categories data (or empty list if null/error)
// Если есть ошибка, categories будет пустым списком, totalExpenses будет 0
final categories = categorySnapshot.data ?? [];
// Calculate total expenses from the categories stream data
final totalExpenses = categories.fold(0.0, (sum, item) => sum + item.amount);
@@ -454,7 +467,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
),
),
// --- Transactions List (using StreamBuilder) ---
// --- Transactions List (using StreamBuilder with Isar) ---
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Card( // Wrap list in a Card for background/border
@@ -465,11 +478,12 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
side: BorderSide(color: theme.dividerColor.withOpacity(0.5), width: 1) // Subtle border
),
clipBehavior: Clip.antiAlias, // Clip list items to card shape
child: StreamBuilder<List<db.Transaction>>(
stream: _watchTransactions(), // Stream based on _selectedFilter
child: StreamBuilder<List<IsarTransaction>>( // Ожидаем List<IsarTransaction>
stream: _watchTransactions(), // Stream из IsarService
builder: (context, transactionSnapshot) {
// Handle loading state for transactions
if (transactionSnapshot.connectionState == ConnectionState.waiting) {
if (transactionSnapshot.connectionState == ConnectionState.waiting && !transactionSnapshot.hasData) {
// Показываем индикатор, если данные еще не пришли
return const SizedBox(
height: 150, // Placeholder height
child: Center(child: CircularProgressIndicator(strokeWidth: 2)),
@@ -482,11 +496,11 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
child: Center(child: Text('Error: ${transactionSnapshot.error}')),
);
}
// Get transaction data (or empty list)
final transactions = transactionSnapshot.data ?? [];
// Get transaction data (or empty list if null/error)
final isarTransactions = transactionSnapshot.data ?? [];
// Display message if no transactions match the filter
if (transactions.isEmpty) {
if (isarTransactions.isEmpty) {
return SizedBox(
height: 150,
child: Center(
@@ -502,7 +516,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
// Use ListView.builder to display transactions efficiently
return ListView.separated(
itemCount: transactions.length,
itemCount: isarTransactions.length,
physics: const NeverScrollableScrollPhysics(), // Disable inner scrolling
shrinkWrap: true, // Fit content height
padding: const EdgeInsets.symmetric(vertical: 8.0), // Padding inside the card
@@ -511,24 +525,25 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
color: theme.dividerColor.withOpacity(0.3),
),
itemBuilder: (context, index) {
// Get the db.Transaction object from the stream
final dbTransaction = transactions[index];
// Get the IsarTransaction object from the stream
final isarTx = isarTransactions[index];
// Get the corresponding category details (icon, color)
final categoryDetails = CategoryUtils.getCategoryDetails(dbTransaction.categoryName);
final categoryDetails = CategoryUtils.getCategoryDetails(isarTx.categoryName);
// Create the model.TransactionRecord needed by TransactionListItem
// Преобразуем IsarTransaction -> model.TransactionRecord
final transactionRecord = model.TransactionRecord(
dbTransaction.categoryName,
dbTransaction.amount,
isarTx.categoryName,
isarTx.amount,
categoryDetails.iconCode, // Get icon from utils
categoryDetails.colorCode, // Get color from utils
dbTransaction.date,
dbTransaction.merchant,
isarTx.date,
isarTx.merchant,
);
// Use the TransactionListItem widget with the correct model type
return TransactionListItem(
transaction: transactionRecord, // Pass the model.TransactionRecord
animation: kAlwaysCompleteAnimation, // Required by FadeTransition
animation: kAlwaysCompleteAnimation, // Required by FadeTransition (or remove animation)
);
},
);
@@ -587,7 +602,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
),
// Floating Action Button to add new transaction
floatingActionButton: FloatingActionButton.extended( // Use extended FAB
onPressed: _addSampleTransaction, // Add sample data on press
onPressed: _addSampleTransaction, // Add sample data on press (uses Isar now)
tooltip: 'Add Transaction',
icon: const Icon(Icons.add),
label: const Text('Add'),
@@ -0,0 +1,21 @@
import 'package:flutter/foundation.dart';
/// Helper class for handling Isar compatibility issues with web platform
class IsarWebHelper {
/// Checks if the current platform is web
static bool get isWeb => kIsWeb;
/// Returns a JavaScript-safe integer ID
///
/// When running on web, this will return a smaller integer that's safe for JavaScript
/// When running on native platforms, it will return the original ID
static int safeId(int originalId) {
if (isWeb) {
// For web, return a smaller integer by taking modulo with a safe JavaScript integer
// Number.MAX_SAFE_INTEGER in JavaScript is 9007199254740991
return originalId % 9007199;
}
// For native platforms, return the original ID
return originalId;
}
}
@@ -6,10 +6,10 @@
#include "generated_plugin_registrant.h"
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin");
isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar);
}
@@ -3,7 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
sqlite3_flutter_libs
isar_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
@@ -5,10 +5,10 @@
import FlutterMacOS
import Foundation
import isar_flutter_libs
import path_provider_foundation
import sqlite3_flutter_libs
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
}
+67 -99
View File
@@ -5,18 +5,18 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
url: "https://pub.dev"
source: hosted
version: "82.0.0"
version: "61.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "13c1e6c6fd460522ea840abec3f677cc226f5fec7872c04ad7b425517ccf54f7"
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
url: "https://pub.dev"
source: hosted
version: "7.4.4"
version: "5.13.0"
args:
dependency: transitive
description:
@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: build
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.1"
build_config:
dependency: transitive
description:
@@ -69,26 +69,26 @@ packages:
dependency: transitive
description:
name: build_resolvers
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
url: "https://pub.dev"
source: hosted
version: "2.4.4"
version: "2.4.2"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev"
source: hosted
version: "2.4.15"
version: "2.4.13"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
url: "https://pub.dev"
source: hosted
version: "8.0.0"
version: "7.3.2"
built_collection:
dependency: transitive
description:
@@ -113,14 +113,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
charcode:
dependency: transitive
description:
name: charcode
sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
url: "https://pub.dev"
source: hosted
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@@ -129,14 +121,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
clock:
dependency: transitive
description:
@@ -189,26 +173,18 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac"
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
drift:
dependency: "direct main"
version: "2.3.2"
dartx:
dependency: transitive
description:
name: drift
sha256: "14a61af39d4584faf1d73b5b35e4b758a43008cf4c0fdb0576ec8e7032c0d9a5"
name: dartx
sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
url: "https://pub.dev"
source: hosted
version: "2.26.0"
drift_dev:
dependency: "direct dev"
description:
name: drift_dev
sha256: "0d3f8b33b76cf1c6a82ee34d9511c40957549c4674b8f1688609e6d6c7306588"
url: "https://pub.dev"
source: hosted
version: "2.26.0"
version: "1.2.0"
equatable:
dependency: transitive
description:
@@ -299,14 +275,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
http:
dependency: transitive
description:
name: http
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
@@ -327,10 +295,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.dev"
source: hosted
version: "0.19.0"
version: "0.20.2"
io:
dependency: transitive
description:
@@ -339,14 +307,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
isar:
dependency: "direct main"
description:
name: isar
sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea"
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
isar_flutter_libs:
dependency: "direct main"
description:
name: isar_flutter_libs
sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
isar_generator:
dependency: "direct dev"
description:
name: isar_generator
sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133"
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.6.7"
json_annotation:
dependency: transitive
description:
@@ -531,22 +523,6 @@ packages:
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"
rxdart:
dependency: "direct main"
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shelf:
dependency: transitive
description:
@@ -559,10 +535,10 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
@@ -572,10 +548,10 @@ packages:
dependency: transitive
description:
name: source_gen
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "1.5.0"
source_span:
dependency: transitive
description:
@@ -584,30 +560,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
sqlite3:
dependency: transitive
description:
name: sqlite3
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
url: "https://pub.dev"
source: hosted
version: "2.7.5"
sqlite3_flutter_libs:
dependency: "direct main"
description:
name: sqlite3_flutter_libs
sha256: "1a96b59227828d9eb1463191d684b37a27d66ee5ed7597fcf42eee6452c88a14"
url: "https://pub.dev"
source: hosted
version: "0.5.32"
sqlparser:
dependency: transitive
description:
name: sqlparser
sha256: "27dd0a9f0c02e22ac0eb42a23df9ea079ce69b52bb4a3b478d64e0ef34a263ee"
url: "https://pub.dev"
source: hosted
version: "0.41.0"
stack_trace:
dependency: transitive
description:
@@ -656,6 +608,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.4"
time:
dependency: transitive
description:
name: time
sha256: "370572cf5d1e58adcb3e354c47515da3f7469dac3a95b447117e728e7be6f461"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
timing:
dependency: transitive
description:
@@ -728,6 +688,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xxh3:
dependency: transitive
description:
name: xxh3
sha256: "399a0438f5d426785723c99da6b16e136f4953fb1e9db0bf270bd41dd4619916"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
yaml:
dependency: transitive
description:
+10 -6
View File
@@ -31,12 +31,14 @@ dependencies:
flutter:
sdk: flutter
fl_chart: ^0.71.0
intl: ^0.19.0 # For date formatting
drift: ^2.26.0 # Added Drift
sqlite3_flutter_libs: ^0.5.22 # Recommended for Drift on Flutter
intl: ^0.20.2 # For date formatting
# --- Isar Dependencies ---
isar: ^3.1.0+1
isar_flutter_libs: ^3.1.0+1 # Contains Isar Core for Flutter
# --- End Isar Dependencies ---
path_provider: ^2.1.3 # To find database file location
path: ^1.9.0 # To construct database file path
rxdart: ^0.28.0 # Added rxdart for combining streams in database
#rxdart: ^0.28.0 # Keep for combining streams if needed, or remove if not used elsewhere
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
@@ -44,8 +46,10 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
drift_dev: ^2.18.0 # Added Drift code generator
build_runner: ^2.4.11 # Added build_runner
# --- Isar Generator ---
isar_generator: ^3.1.0+1
# --- End Isar Generator ---
build_runner: ^2.4.13 # Added build_runner
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
@@ -6,9 +6,9 @@
#include "generated_plugin_registrant.h"
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
IsarFlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
}
@@ -3,7 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
sqlite3_flutter_libs
isar_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST