mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 02:15:29 +03:00
stableee
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
targets:
|
||||
$default:
|
||||
builders:
|
||||
drift_dev:
|
||||
options:
|
||||
store_date_time_values_as_text: true
|
||||
@@ -0,0 +1,256 @@
|
||||
import 'dart:io';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import '../../core/utils/result.dart';
|
||||
import 'tables.dart';
|
||||
|
||||
part 'app_database.g.dart';
|
||||
|
||||
@DriftDatabase(tables: [Transactions, Categories, Budgets, ExchangeRates])
|
||||
class AppDatabase extends _$AppDatabase {
|
||||
AppDatabase() : super(_openConnection());
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
|
||||
// ============================================================================
|
||||
// TRANSACTIONS
|
||||
// ============================================================================
|
||||
|
||||
/// Get all transactions ordered by date descending
|
||||
Future<List<dynamic>> getAllTransactions() {
|
||||
return (select(
|
||||
transactions,
|
||||
)..orderBy([(t) => OrderingTerm.desc(t.date)])).get();
|
||||
}
|
||||
|
||||
/// Get transactions by date range
|
||||
Future<List<dynamic>> getTransactionsByDateRange(
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
) {
|
||||
return (select(transactions)
|
||||
..where((t) => t.date.isBiggerOrEqualValue(start))
|
||||
..where((t) => t.date.isSmallerOrEqualValue(end))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.date)]))
|
||||
.get();
|
||||
}
|
||||
|
||||
/// Get transactions by type
|
||||
Future<List<dynamic>> getTransactionsByType(String type) {
|
||||
return (select(transactions)
|
||||
..where((t) => t.type.equals(type))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.date)]))
|
||||
.get();
|
||||
}
|
||||
|
||||
/// Get transactions by category
|
||||
Future<List<dynamic>> getTransactionsByCategory(String category) {
|
||||
return (select(transactions)
|
||||
..where((t) => t.category.equals(category))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.date)]))
|
||||
.get();
|
||||
}
|
||||
|
||||
/// Search transactions by note or category
|
||||
Future<List<dynamic>> searchTransactions(String query) {
|
||||
final lowerQuery = query.toLowerCase();
|
||||
return (select(transactions)
|
||||
..where(
|
||||
(t) =>
|
||||
t.category.lower().like('%$lowerQuery%') |
|
||||
t.note.lower().like('%$lowerQuery%'),
|
||||
)
|
||||
..orderBy([(t) => OrderingTerm.desc(t.date)]))
|
||||
.get();
|
||||
}
|
||||
|
||||
/// Get transaction by ID
|
||||
Future<dynamic> getTransactionById(String id) {
|
||||
return (select(
|
||||
transactions,
|
||||
)..where((t) => t.id.equals(id))).getSingleOrNull();
|
||||
}
|
||||
|
||||
/// Insert transaction
|
||||
Future<Result<void>> insertTransaction(
|
||||
TransactionsCompanion transaction,
|
||||
) async {
|
||||
return asyncResultOf(() async {
|
||||
await into(transactions).insert(transaction);
|
||||
});
|
||||
}
|
||||
|
||||
/// Update transaction
|
||||
Future<Result<void>> updateTransaction(dynamic transaction) async {
|
||||
return asyncResultOf(() async {
|
||||
final companion = transaction as TransactionsCompanion;
|
||||
final updated = await (update(
|
||||
transactions,
|
||||
)..where((t) => t.id.equals(companion.id.value))).write(companion);
|
||||
|
||||
if (updated == 0) {
|
||||
throw Exception('Transaction not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Delete transaction
|
||||
Future<Result<void>> deleteTransaction(String id) async {
|
||||
return asyncResultOf(() async {
|
||||
final deleted = await (delete(
|
||||
transactions,
|
||||
)..where((t) => t.id.equals(id))).go();
|
||||
|
||||
if (deleted == 0) {
|
||||
throw Exception('Transaction not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Delete all transactions
|
||||
Future<void> deleteAllTransactions() {
|
||||
return delete(transactions).go();
|
||||
}
|
||||
|
||||
/// Get recurring transactions that need processing
|
||||
Future<List<dynamic>> getRecurringTransactions() {
|
||||
return (select(
|
||||
transactions,
|
||||
)..where((t) => t.recurrence.equals('none').not())).get();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CATEGORIES
|
||||
// ============================================================================
|
||||
|
||||
/// Get all categories
|
||||
Future<List<Category>> getAllCategories() {
|
||||
return select(categories).get();
|
||||
}
|
||||
|
||||
/// Get categories by type
|
||||
Future<List<Category>> getCategoriesByType(String type) {
|
||||
return (select(categories)..where((c) => c.type.equals(type))).get();
|
||||
}
|
||||
|
||||
/// Insert category
|
||||
Future<int> insertCategory(CategoriesCompanion category) {
|
||||
return into(categories).insert(category);
|
||||
}
|
||||
|
||||
/// Update category
|
||||
Future<bool> updateCategory(Category category) {
|
||||
return update(categories).replace(category);
|
||||
}
|
||||
|
||||
/// Delete category
|
||||
Future<int> deleteCategory(int id) {
|
||||
return (delete(categories)..where((c) => c.id.equals(id))).go();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// BUDGETS
|
||||
// ============================================================================
|
||||
|
||||
/// Get budget for month/year
|
||||
Future<Budget?> getBudget(int month, int year) {
|
||||
return (select(budgets)
|
||||
..where((b) => b.month.equals(month) & b.year.equals(year)))
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
/// Insert or update budget
|
||||
Future<void> upsertBudget(BudgetsCompanion budget) {
|
||||
return into(budgets).insertOnConflictUpdate(budget);
|
||||
}
|
||||
|
||||
/// Delete budget
|
||||
Future<int> deleteBudget(int id) {
|
||||
return (delete(budgets)..where((b) => b.id.equals(id))).go();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EXCHANGE RATES
|
||||
// ============================================================================
|
||||
|
||||
/// Get exchange rate
|
||||
Future<ExchangeRate?> getExchangeRate(String from, String to) {
|
||||
return (select(exchangeRates)
|
||||
..where((r) => r.fromCurrency.equals(from) & r.toCurrency.equals(to)))
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
/// Insert or update exchange rate
|
||||
Future<void> upsertExchangeRate(ExchangeRatesCompanion rate) {
|
||||
return into(exchangeRates).insertOnConflictUpdate(rate);
|
||||
}
|
||||
|
||||
/// Get all exchange rates
|
||||
Future<List<ExchangeRate>> getAllExchangeRates() {
|
||||
return select(exchangeRates).get();
|
||||
}
|
||||
|
||||
/// Delete old exchange rates (older than 24 hours)
|
||||
Future<int> deleteOldExchangeRates() {
|
||||
final yesterday = DateTime.now().subtract(const Duration(hours: 24));
|
||||
return (delete(
|
||||
exchangeRates,
|
||||
)..where((r) => r.updatedAt.isSmallerThanValue(yesterday))).go();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STATISTICS & AGGREGATIONS
|
||||
// ============================================================================
|
||||
|
||||
/// Get total balance
|
||||
Future<double> getTotalBalance() async {
|
||||
final txs = await getAllTransactions();
|
||||
return txs.fold<double>(0.0, (sum, tx) {
|
||||
return tx.type == 'income' ? sum + tx.amount : sum - tx.amount;
|
||||
});
|
||||
}
|
||||
|
||||
/// Get total income for date range
|
||||
Future<double> getTotalIncome(DateTime start, DateTime end) async {
|
||||
final txs = await getTransactionsByDateRange(start, end);
|
||||
return txs
|
||||
.where((tx) => tx.type == 'income')
|
||||
.fold<double>(0.0, (sum, tx) => sum + tx.amount);
|
||||
}
|
||||
|
||||
/// Get total expense for date range
|
||||
Future<double> getTotalExpense(DateTime start, DateTime end) async {
|
||||
final txs = await getTransactionsByDateRange(start, end);
|
||||
return txs
|
||||
.where((tx) => tx.type == 'expense')
|
||||
.fold<double>(0.0, (sum, tx) => sum + tx.amount);
|
||||
}
|
||||
|
||||
/// Get category totals for date range
|
||||
Future<Map<String, double>> getCategoryTotals(
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
String type,
|
||||
) async {
|
||||
final txs = await getTransactionsByDateRange(start, end);
|
||||
final filtered = txs.where((tx) => tx.type == type);
|
||||
|
||||
final Map<String, double> totals = {};
|
||||
for (final tx in filtered) {
|
||||
totals[tx.category] = (totals[tx.category] ?? 0) + tx.amount;
|
||||
}
|
||||
|
||||
return totals;
|
||||
}
|
||||
}
|
||||
|
||||
LazyDatabase _openConnection() {
|
||||
return LazyDatabase(() async {
|
||||
final dbFolder = await getApplicationDocumentsDirectory();
|
||||
final file = File(p.join(dbFolder.path, 'casha.db'));
|
||||
return NativeDatabase(file);
|
||||
});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
/// Transactions table
|
||||
class Transactions extends Table {
|
||||
TextColumn get id => text()();
|
||||
RealColumn get amount => real()();
|
||||
TextColumn get category => text()();
|
||||
TextColumn get type => text()(); // 'income' or 'expense'
|
||||
DateTimeColumn get date => dateTime()();
|
||||
TextColumn get note => text().nullable()();
|
||||
TextColumn get recurrence => text().withDefault(const Constant('none'))();
|
||||
DateTimeColumn get lastOccurrence => dateTime().nullable()();
|
||||
TextColumn get currency => text().withDefault(const Constant('\$'))();
|
||||
TextColumn get currencyCode => text().withDefault(const Constant('USD'))();
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
}
|
||||
|
||||
/// Categories table for custom categories
|
||||
class Categories extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text().withLength(min: 1, max: 50)();
|
||||
TextColumn get type => text()(); // 'income' or 'expense'
|
||||
TextColumn get icon => text().nullable()();
|
||||
TextColumn get color => text().nullable()();
|
||||
BoolColumn get isDefault => boolean().withDefault(const Constant(false))();
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
}
|
||||
|
||||
/// Budgets table for monthly budgets
|
||||
class Budgets extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
RealColumn get amount => real()();
|
||||
TextColumn get categoryId => text().nullable()();
|
||||
IntColumn get month => integer()();
|
||||
IntColumn get year => integer()();
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
}
|
||||
|
||||
/// Exchange rates cache
|
||||
class ExchangeRates extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get fromCurrency => text()();
|
||||
TextColumn get toCurrency => text()();
|
||||
RealColumn get rate => real()();
|
||||
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import '../../core/utils/result.dart';
|
||||
import '../../shared/models/transaction.dart' as model;
|
||||
import '../database/app_database.dart';
|
||||
|
||||
class TransactionRepository {
|
||||
final AppDatabase _db;
|
||||
|
||||
TransactionRepository(this._db);
|
||||
|
||||
/// Get all transactions
|
||||
Future<Result<List<model.Transaction>>> getAll() async {
|
||||
return asyncResultOf(() async {
|
||||
final transactions = await _db.getAllTransactions();
|
||||
return transactions.map<model.Transaction>(_toModel).toList();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get transactions by date range
|
||||
Future<Result<List<model.Transaction>>> getByDateRange(
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
) async {
|
||||
return asyncResultOf(() async {
|
||||
final transactions = await _db.getTransactionsByDateRange(start, end);
|
||||
return transactions.map<model.Transaction>(_toModel).toList();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get transactions by type
|
||||
Future<Result<List<model.Transaction>>> getByType(
|
||||
model.TransactionType type,
|
||||
) async {
|
||||
return asyncResultOf(() async {
|
||||
final transactions = await _db.getTransactionsByType(type.name);
|
||||
return transactions.map<model.Transaction>(_toModel).toList();
|
||||
});
|
||||
}
|
||||
|
||||
/// Search transactions
|
||||
Future<Result<List<model.Transaction>>> search(String query) async {
|
||||
return asyncResultOf(() async {
|
||||
final transactions = await _db.searchTransactions(query);
|
||||
return transactions.map<model.Transaction>(_toModel).toList();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get transaction by ID
|
||||
Future<Result<model.Transaction?>> getById(String id) async {
|
||||
return asyncResultOf(() async {
|
||||
final transaction = await _db.getTransactionById(id);
|
||||
return transaction != null ? _toModel(transaction) : null;
|
||||
});
|
||||
}
|
||||
|
||||
/// Add transaction
|
||||
Future<Result<void>> add(model.Transaction transaction) async {
|
||||
return asyncResultOf(() async {
|
||||
final companion = _toCompanion(transaction);
|
||||
final result = await _db.insertTransaction(companion);
|
||||
|
||||
if (result.isFailure) {
|
||||
throw Exception(result.errorOrNull);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Update transaction
|
||||
Future<Result<void>> update(model.Transaction transaction) async {
|
||||
return asyncResultOf(() async {
|
||||
final dbTransaction = _toDbModel(transaction);
|
||||
final result = await _db.updateTransaction(dbTransaction);
|
||||
|
||||
if (result.isFailure) {
|
||||
throw Exception(result.errorOrNull);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Delete transaction
|
||||
Future<Result<void>> delete(String id) async {
|
||||
return _db.deleteTransaction(id);
|
||||
}
|
||||
|
||||
/// Delete all transactions
|
||||
Future<Result<void>> deleteAll() async {
|
||||
return asyncResultOf(() async {
|
||||
await _db.deleteAllTransactions();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get recurring transactions
|
||||
Future<Result<List<model.Transaction>>> getRecurring() async {
|
||||
return asyncResultOf(() async {
|
||||
final transactions = await _db.getRecurringTransactions();
|
||||
return transactions.map<model.Transaction>(_toModel).toList();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get total balance
|
||||
Future<Result<double>> getTotalBalance() async {
|
||||
return asyncResultOf(() async {
|
||||
return await _db.getTotalBalance();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get total income for date range
|
||||
Future<Result<double>> getTotalIncome(DateTime start, DateTime end) async {
|
||||
return asyncResultOf(() async {
|
||||
return await _db.getTotalIncome(start, end);
|
||||
});
|
||||
}
|
||||
|
||||
/// Get total expense for date range
|
||||
Future<Result<double>> getTotalExpense(DateTime start, DateTime end) async {
|
||||
return asyncResultOf(() async {
|
||||
return await _db.getTotalExpense(start, end);
|
||||
});
|
||||
}
|
||||
|
||||
/// Get category totals
|
||||
Future<Result<Map<String, double>>> getCategoryTotals(
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
model.TransactionType type,
|
||||
) async {
|
||||
return asyncResultOf(() async {
|
||||
return await _db.getCategoryTotals(start, end, type.name);
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CONVERTERS
|
||||
// ============================================================================
|
||||
|
||||
/// Convert database model to app model
|
||||
model.Transaction _toModel(dynamic dbTransaction) {
|
||||
return model.Transaction(
|
||||
id: dbTransaction.id as String,
|
||||
amount: dbTransaction.amount as double,
|
||||
category: dbTransaction.category as String,
|
||||
type: (dbTransaction.type as String) == 'income'
|
||||
? model.TransactionType.income
|
||||
: model.TransactionType.expense,
|
||||
date: dbTransaction.date as DateTime,
|
||||
note: dbTransaction.note as String?,
|
||||
recurrence: _parseRecurrence(dbTransaction.recurrence as String),
|
||||
lastOccurrence: dbTransaction.lastOccurrence as DateTime?,
|
||||
currency: dbTransaction.currency as String,
|
||||
currencyCode: dbTransaction.currencyCode as String,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert app model to database model
|
||||
dynamic _toDbModel(model.Transaction transaction) {
|
||||
// This will be replaced with proper TransactionData after code generation
|
||||
return TransactionsCompanion(
|
||||
id: Value(transaction.id),
|
||||
amount: Value(transaction.amount),
|
||||
category: Value(transaction.category),
|
||||
type: Value(transaction.type.name),
|
||||
date: Value(transaction.date),
|
||||
note: Value(transaction.note),
|
||||
recurrence: Value(transaction.recurrence.name),
|
||||
lastOccurrence: Value(transaction.lastOccurrence),
|
||||
currency: Value(transaction.currency),
|
||||
currencyCode: Value(transaction.currencyCode),
|
||||
createdAt: Value(DateTime.now()),
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert app model to companion for insert
|
||||
TransactionsCompanion _toCompanion(model.Transaction transaction) {
|
||||
return TransactionsCompanion(
|
||||
id: Value(transaction.id),
|
||||
amount: Value(transaction.amount),
|
||||
category: Value(transaction.category),
|
||||
type: Value(transaction.type.name),
|
||||
date: Value(transaction.date),
|
||||
note: Value(transaction.note),
|
||||
recurrence: Value(transaction.recurrence.name),
|
||||
lastOccurrence: Value(transaction.lastOccurrence),
|
||||
currency: Value(transaction.currency),
|
||||
currencyCode: Value(transaction.currencyCode),
|
||||
);
|
||||
}
|
||||
|
||||
/// Parse recurrence type
|
||||
model.RecurrenceType _parseRecurrence(String recurrence) {
|
||||
return model.RecurrenceType.values.firstWhere(
|
||||
(e) => e.name == recurrence,
|
||||
orElse: () => model.RecurrenceType.none,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,37 +3,40 @@ import '../../shared/models/transaction.dart';
|
||||
import '../dashboard/provider.dart';
|
||||
|
||||
final categoryExpenseProvider = Provider<Map<String, double>>((ref) {
|
||||
final txs = ref.watch(transactionsProvider)
|
||||
.where((t) => t.type == TransactionType.expense);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
||||
|
||||
final map = <String, double>{};
|
||||
for (final t in txs) {
|
||||
for (final t in filtered) {
|
||||
map[t.category] = (map[t.category] ?? 0) + t.amount;
|
||||
}
|
||||
return map;
|
||||
});
|
||||
|
||||
final categoryIncomeProvider = Provider<Map<String, double>>((ref) {
|
||||
final txs = ref.watch(transactionsProvider)
|
||||
.where((t) => t.type == TransactionType.income);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where((t) => t.type == TransactionType.income);
|
||||
|
||||
final map = <String, double>{};
|
||||
for (final t in txs) {
|
||||
for (final t in filtered) {
|
||||
map[t.category] = (map[t.category] ?? 0) + t.amount;
|
||||
}
|
||||
return map;
|
||||
});
|
||||
|
||||
final monthlyBreakdownProvider = Provider<List<MonthlyData>>((ref) {
|
||||
final txs = ref.watch(transactionsProvider)
|
||||
.where((t) => t.type == TransactionType.expense);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
||||
|
||||
final now = DateTime.now();
|
||||
final months = <MonthlyData>[];
|
||||
|
||||
for (var i = 5; i >= 0; i--) {
|
||||
final month = DateTime(now.year, now.month - i, 1);
|
||||
final total = txs
|
||||
final total = filtered
|
||||
.where((t) => t.date.year == month.year && t.date.month == month.month)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
months.add(MonthlyData(month: month, amount: total));
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../core/services/card_color_service.dart';
|
||||
import '../../core/utils/result.dart';
|
||||
import '../../data/database/app_database.dart' as db;
|
||||
import '../../data/repositories/transaction_repository.dart';
|
||||
import '../../shared/models/transaction.dart';
|
||||
import '../../shared/services/storage_service.dart';
|
||||
import '../settings/provider.dart';
|
||||
@@ -11,53 +13,86 @@ final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
||||
throw UnimplementedError('Override in main');
|
||||
});
|
||||
|
||||
final appDatabaseProvider = Provider<db.AppDatabase>((ref) {
|
||||
return db.AppDatabase();
|
||||
});
|
||||
|
||||
final transactionRepositoryProvider = Provider<TransactionRepository>((ref) {
|
||||
final db = ref.watch(appDatabaseProvider);
|
||||
return TransactionRepository(db);
|
||||
});
|
||||
|
||||
final storageServiceProvider = Provider<StorageService>((ref) {
|
||||
return StorageService(ref.watch(sharedPreferencesProvider));
|
||||
});
|
||||
|
||||
final transactionsProvider =
|
||||
StateNotifierProvider<TransactionsNotifier, List<Transaction>>((ref) {
|
||||
final storage = ref.watch(storageServiceProvider);
|
||||
return TransactionsNotifier(storage);
|
||||
StateNotifierProvider<TransactionsNotifier, AsyncValue<List<Transaction>>>((
|
||||
ref,
|
||||
) {
|
||||
final repository = ref.watch(transactionRepositoryProvider);
|
||||
return TransactionsNotifier(repository);
|
||||
});
|
||||
|
||||
class TransactionsNotifier extends StateNotifier<List<Transaction>> {
|
||||
final StorageService _storage;
|
||||
class TransactionsNotifier
|
||||
extends StateNotifier<AsyncValue<List<Transaction>>> {
|
||||
final TransactionRepository _repository;
|
||||
|
||||
TransactionsNotifier(this._storage)
|
||||
: super(_storage.loadTransactionsUnsafe());
|
||||
TransactionsNotifier(this._repository) : super(const AsyncValue.loading()) {
|
||||
_load();
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
state = const AsyncValue.loading();
|
||||
final result = await _repository.getAll();
|
||||
|
||||
state = result.isSuccess
|
||||
? AsyncValue.data(result.dataOrNull!)
|
||||
: AsyncValue.error(result.errorOrNull!, StackTrace.current);
|
||||
}
|
||||
|
||||
Future<Result<void>> add(Transaction transaction) async {
|
||||
final result = await _storage.addTransaction(transaction);
|
||||
return result.onSuccess((_) {
|
||||
state = _storage.loadTransactionsUnsafe();
|
||||
});
|
||||
final result = await _repository.add(transaction);
|
||||
|
||||
if (result.isSuccess) {
|
||||
await _load();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Result<void>> update(Transaction transaction) async {
|
||||
final result = await _storage.updateTransaction(transaction);
|
||||
return result.onSuccess((_) {
|
||||
state = _storage.loadTransactionsUnsafe();
|
||||
});
|
||||
final result = await _repository.update(transaction);
|
||||
|
||||
if (result.isSuccess) {
|
||||
await _load();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Result<void>> delete(String id) async {
|
||||
final result = await _storage.deleteTransaction(id);
|
||||
return result.onSuccess((_) {
|
||||
state = _storage.loadTransactionsUnsafe();
|
||||
});
|
||||
final result = await _repository.delete(id);
|
||||
|
||||
if (result.isSuccess) {
|
||||
await _load();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void restore(Transaction transaction) {
|
||||
state = [...state, transaction];
|
||||
_storage.addTransaction(transaction);
|
||||
Future<void> restore(Transaction transaction) async {
|
||||
await _repository.add(transaction);
|
||||
await _load();
|
||||
}
|
||||
|
||||
void clearAll() {
|
||||
state = [];
|
||||
SharedPreferences.getInstance().then(
|
||||
(prefs) => prefs.remove('transactions'),
|
||||
);
|
||||
Future<void> clearAll() async {
|
||||
await _repository.deleteAll();
|
||||
state = const AsyncValue.data([]);
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
await _load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +111,8 @@ final timeFilterProvider = StateProvider<TimeFilter>(
|
||||
);
|
||||
|
||||
final totalBalanceProvider = Provider<double>((ref) {
|
||||
final txs = ref.watch(transactionsProvider);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||
final targetCurrency = ref.watch(currencyProvider).code;
|
||||
|
||||
@@ -91,26 +127,26 @@ final totalBalanceProvider = Provider<double>((ref) {
|
||||
});
|
||||
|
||||
final totalIncomeProvider = Provider<double>((ref) {
|
||||
final txs = ref
|
||||
.watch(transactionsProvider)
|
||||
.where((t) => t.type == TransactionType.income);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where((t) => t.type == TransactionType.income);
|
||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||
final targetCurrency = ref.watch(currencyProvider).code;
|
||||
|
||||
return txs.fold(0.0, (sum, t) {
|
||||
return filtered.fold(0.0, (sum, t) {
|
||||
return sum +
|
||||
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
|
||||
});
|
||||
});
|
||||
|
||||
final totalExpenseProvider = Provider<double>((ref) {
|
||||
final txs = ref
|
||||
.watch(transactionsProvider)
|
||||
.where((t) => t.type == TransactionType.expense);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||
final targetCurrency = ref.watch(currencyProvider).code;
|
||||
|
||||
return txs.fold(0.0, (sum, t) {
|
||||
return filtered.fold(0.0, (sum, t) {
|
||||
return sum +
|
||||
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
|
||||
});
|
||||
@@ -118,25 +154,26 @@ final totalExpenseProvider = Provider<double>((ref) {
|
||||
|
||||
final currentMonthExpenseProvider = Provider<double>((ref) {
|
||||
final now = DateTime.now();
|
||||
final txs = ref
|
||||
.watch(transactionsProvider)
|
||||
.where(
|
||||
(t) =>
|
||||
t.type == TransactionType.expense &&
|
||||
t.date.year == now.year &&
|
||||
t.date.month == now.month,
|
||||
);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final filtered = txs.where(
|
||||
(t) =>
|
||||
t.type == TransactionType.expense &&
|
||||
t.date.year == now.year &&
|
||||
t.date.month == now.month,
|
||||
);
|
||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||
final targetCurrency = ref.watch(currencyProvider).code;
|
||||
|
||||
return txs.fold(0.0, (sum, t) {
|
||||
return filtered.fold(0.0, (sum, t) {
|
||||
return sum +
|
||||
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
|
||||
});
|
||||
});
|
||||
|
||||
final filteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
||||
final txs = ref.watch(transactionsProvider);
|
||||
final txsAsync = ref.watch(transactionsProvider);
|
||||
final txs = txsAsync.valueOrNull ?? [];
|
||||
final query = ref.watch(searchQueryProvider).toLowerCase();
|
||||
final typeFilter = ref.watch(transactionFilterProvider);
|
||||
final timeFilter = ref.watch(timeFilterProvider);
|
||||
|
||||
@@ -26,7 +26,11 @@ class BudgetNotifier extends StateNotifier<double?> {
|
||||
state = budget;
|
||||
}
|
||||
|
||||
void onCurrencyChanged(String oldCode, String newCode, ExchangeRateService rates) {
|
||||
void onCurrencyChanged(
|
||||
String oldCode,
|
||||
String newCode,
|
||||
ExchangeRateService rates,
|
||||
) {
|
||||
if (state == null) return;
|
||||
final converted = rates.convert(state!, oldCode, newCode);
|
||||
setBudget(converted);
|
||||
@@ -64,12 +68,12 @@ class CurrencyNotifier extends StateNotifier<CurrencyInfo> {
|
||||
}
|
||||
}
|
||||
|
||||
final currencyProvider = StateNotifierProvider<CurrencyNotifier, CurrencyInfo>(
|
||||
(ref) {
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
return CurrencyNotifier(prefs);
|
||||
},
|
||||
);
|
||||
final currencyProvider = StateNotifierProvider<CurrencyNotifier, CurrencyInfo>((
|
||||
ref,
|
||||
) {
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
return CurrencyNotifier(prefs);
|
||||
});
|
||||
|
||||
class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
||||
final SharedPreferences _prefs;
|
||||
@@ -95,12 +99,12 @@ class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
||||
}
|
||||
}
|
||||
|
||||
final themeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>(
|
||||
(ref) {
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
return ThemeModeNotifier(prefs);
|
||||
},
|
||||
);
|
||||
final themeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>((
|
||||
ref,
|
||||
) {
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
return ThemeModeNotifier(prefs);
|
||||
});
|
||||
|
||||
final exchangeRateServiceProvider = Provider<ExchangeRateService>((ref) {
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
@@ -111,7 +115,9 @@ final ratesInitProvider = FutureProvider<void>((ref) async {
|
||||
await ref.read(exchangeRateServiceProvider).fetchRates();
|
||||
});
|
||||
|
||||
final hapticEnabledProvider = StateNotifierProvider<HapticNotifier, bool>((ref) {
|
||||
final hapticEnabledProvider = StateNotifierProvider<HapticNotifier, bool>((
|
||||
ref,
|
||||
) {
|
||||
return HapticNotifier();
|
||||
});
|
||||
|
||||
@@ -141,7 +147,8 @@ class ExportService {
|
||||
ExportService(this._ref);
|
||||
|
||||
Future<String> exportToCSV() async {
|
||||
final transactions = _ref.read(transactionsProvider);
|
||||
final transactionsAsync = _ref.read(transactionsProvider);
|
||||
final transactions = transactionsAsync.valueOrNull ?? [];
|
||||
final currency = _ref.read(currencyProvider);
|
||||
final fmt = _ref.read(amountFormatProvider);
|
||||
|
||||
|
||||
+8
-3
@@ -1,15 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'app/app.dart';
|
||||
import 'core/services/haptic_service.dart';
|
||||
import 'data/database/app_database.dart';
|
||||
import 'features/dashboard/provider.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
|
||||
await initializeDateFormatting('en_US', null);
|
||||
await initializeDateFormatting('ru_RU', null);
|
||||
await initializeDateFormatting('en', null);
|
||||
@@ -18,9 +18,14 @@ void main() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await HapticService.init();
|
||||
|
||||
final database = AppDatabase();
|
||||
|
||||
runApp(
|
||||
ProviderScope(
|
||||
overrides: [sharedPreferencesProvider.overrideWithValue(prefs)],
|
||||
overrides: [
|
||||
sharedPreferencesProvider.overrideWithValue(prefs),
|
||||
appDatabaseProvider.overrideWithValue(database),
|
||||
],
|
||||
child: const App(),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <sqlite3_flutter_libs/sqlite3_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);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
sqlite3_flutter_libs
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@@ -7,8 +7,10 @@ import Foundation
|
||||
|
||||
import local_auth_darwin
|
||||
import shared_preferences_foundation
|
||||
import sqlite3_flutter_libs
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||
}
|
||||
|
||||
+257
-1
@@ -1,6 +1,22 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "93.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.1"
|
||||
ansicolor:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -41,6 +57,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.5"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "521daf8d189deb79ba474e43a696b41c49fb3987818dbacf3308f1e03673a75e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.1"
|
||||
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: "6ae8a6435a8c6520c7077b107e77f1fb4ba7009633259a4d49a8afd8e7efc5e9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.12.4"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -49,6 +113,14 @@ packages:
|
||||
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:
|
||||
@@ -81,6 +153,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.11.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -89,6 +169,14 @@ packages:
|
||||
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:
|
||||
@@ -113,6 +201,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.7"
|
||||
drift:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: drift
|
||||
sha256: "61f876c0291b194980bafd203f48e85d5fb04e4a7334367d1a89f44004dbcb83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.32.0"
|
||||
drift_dev:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: drift_dev
|
||||
sha256: d687e955cc4b1706ad49b3860fcc1045c09bbf1d84c3c7383615f7f9c3320aa2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.32.0"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -248,6 +360,14 @@ packages:
|
||||
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:
|
||||
@@ -272,6 +392,14 @@ packages:
|
||||
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:
|
||||
@@ -296,6 +424,14 @@ packages:
|
||||
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"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -408,6 +544,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
native_toolchain_c:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -424,8 +568,16 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.3.0"
|
||||
path:
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
@@ -504,6 +656,14 @@ packages:
|
||||
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"
|
||||
posix:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -520,6 +680,22 @@ packages:
|
||||
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"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -600,11 +776,35 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
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: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.2"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -613,6 +813,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.2"
|
||||
sqlite3:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: caa693ad15a587a2b4fde093b728131a1827903872171089dedb16f7665d3a91
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: eeb9e3a45207649076b808f8a5a74d68770d0b7f26ccef6d5f43106eee5375ad
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.42"
|
||||
sqlparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlparser
|
||||
sha256: ab2b467425f1d4f3acfa5fd11a08226f7d6c26ff102c06be1807e1dff34e050b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.44.3"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -637,6 +861,14 @@ packages:
|
||||
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:
|
||||
@@ -701,6 +933,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.2"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -709,6 +949,22 @@ packages:
|
||||
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:
|
||||
|
||||
@@ -22,6 +22,9 @@ dependencies:
|
||||
sensors_plus: ^6.1.0
|
||||
local_auth: ^2.3.0
|
||||
flutter_colorpicker: ^1.1.0
|
||||
drift: ^2.14.1
|
||||
sqlite3_flutter_libs: ^0.5.20
|
||||
path: ^1.8.3
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: true
|
||||
@@ -50,6 +53,8 @@ dev_dependencies:
|
||||
flutter_lints: ^6.0.0
|
||||
flutter_launcher_icons: ^0.14.1
|
||||
flutter_native_splash: ^2.4.3
|
||||
drift_dev: ^2.14.1
|
||||
build_runner: ^2.4.7
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <local_auth_windows/local_auth_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
LocalAuthPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
local_auth_windows
|
||||
sqlite3_flutter_libs
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
Reference in New Issue
Block a user