mirror of
https://github.com/koloideal/Casha.git
synced 2026-08-08 17:51:14 +03:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 127a917eac | |||
| 8fb785944c |
@@ -0,0 +1,128 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Personal finance Flutter app for Android. Tracks accounts, transactions, categories, budgets with multi-currency support, biometric auth, and haptic feedback.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **Flutter** — UI framework
|
||||||
|
- **Riverpod** — state management (per-feature `provider.dart` files)
|
||||||
|
- **Drift** — local database (code generation via `.g.dart`)
|
||||||
|
- **Feature-first architecture**
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
├── app/ # App root, router, theme
|
||||||
|
├── core/ # Constants, l10n, core services, utils
|
||||||
|
├── data/ # Database schema, repositories
|
||||||
|
├── features/ # Feature modules (provider + screen + widgets)
|
||||||
|
├── shared/ # Cross-feature models, providers, services, widgets
|
||||||
|
└── main.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Layer Responsibilities
|
||||||
|
|
||||||
|
**`core/`** — app-wide infrastructure. No business logic.
|
||||||
|
- `constants.dart` — global constants
|
||||||
|
- `l10n/` — localization strings and locale provider
|
||||||
|
- `services/` — biometric, haptic, card color services
|
||||||
|
- `utils/result.dart` — `Result<T>` type for error handling
|
||||||
|
|
||||||
|
**`data/`** — persistence only. No UI, no Riverpod providers.
|
||||||
|
- `database/` — Drift tables and generated code. Do not edit `.g.dart` files manually.
|
||||||
|
- `repositories/` — `AccountRepository`, `TransactionRepository`. All DB access goes through repositories.
|
||||||
|
|
||||||
|
**`features/<name>/`** — self-contained feature modules.
|
||||||
|
- `provider.dart` — Riverpod providers scoped to this feature
|
||||||
|
- `screen.dart` — top-level screen widget, minimal logic
|
||||||
|
- `widgets/` — feature-specific widgets
|
||||||
|
|
||||||
|
**`shared/`** — reusable across features.
|
||||||
|
- `models/` — `Account`, `Transaction` data classes
|
||||||
|
- `providers/` — providers used by multiple features
|
||||||
|
- `services/` — `ExchangeRateService`, `StorageService`
|
||||||
|
- `utils/` — `CurrencyUtils`
|
||||||
|
- `widgets/` — `BynSign`, `ErrorSnackbar`
|
||||||
|
|
||||||
|
## Architecture Rules
|
||||||
|
|
||||||
|
- Widgets never access repositories directly — always through providers
|
||||||
|
- Providers in `features/<name>/provider.dart` are local to that feature
|
||||||
|
- Providers in `shared/providers/` are app-wide
|
||||||
|
- Business logic lives in providers or repositories, not in widgets or screens
|
||||||
|
- `Result<T>` from `core/utils/result.dart` is used for fallible operations in repositories
|
||||||
|
- Database queries are in repositories only — no raw Drift queries in providers or widgets
|
||||||
|
- After any changes to Drift tables or DAOs, run `dart run build_runner build --delete-conflicting-outputs`
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
**No comments anywhere in the codebase.** No `//`, no `/* */`, no `///` doc comments. Code must be self-explanatory through naming.
|
||||||
|
|
||||||
|
- Use descriptive names — no abbreviations unless universally known (`id`, `url`, `db`)
|
||||||
|
- Prefer named constructors and named parameters
|
||||||
|
- Extract widgets aggressively — if a build method exceeds ~40 lines, split it
|
||||||
|
- Widget files: one primary widget per file, name matches filename
|
||||||
|
- Use `final` everywhere possible
|
||||||
|
- No `dynamic` types
|
||||||
|
- Avoid `late` unless genuinely necessary
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
|
||||||
|
| Element | Convention | Example |
|
||||||
|
|---|---|---|
|
||||||
|
| Files | `snake_case.dart` | `balance_card.dart` |
|
||||||
|
| Classes | `PascalCase` | `BalanceCard` |
|
||||||
|
| Providers | `camelCase` + `Provider` suffix | `transactionListProvider` |
|
||||||
|
| Riverpod notifiers | `PascalCase` + `Notifier` suffix | `AddTransactionNotifier` |
|
||||||
|
| Private members | `_camelCase` | `_handleSubmit` |
|
||||||
|
|
||||||
|
## Feature Structure Template
|
||||||
|
|
||||||
|
When adding a new feature, follow this pattern:
|
||||||
|
|
||||||
|
```
|
||||||
|
features/
|
||||||
|
└── <feature_name>/
|
||||||
|
├── provider.dart # Riverpod providers for this feature
|
||||||
|
├── screen.dart # Top-level screen widget
|
||||||
|
└── widgets/ # Sub-widgets (create only if needed)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Patterns
|
||||||
|
|
||||||
|
**Error handling** — use `Result<T>`:
|
||||||
|
```dart
|
||||||
|
final result = await repository.getAccounts();
|
||||||
|
result.when(
|
||||||
|
success: (accounts) => ...,
|
||||||
|
failure: (error) => ...,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Localization** — use `AppStrings` from `core/l10n/app_strings.dart`, never hardcode strings visible to the user.
|
||||||
|
|
||||||
|
**Currency formatting** — use `CurrencyUtils` and `amountFormatProvider`, never format amounts manually.
|
||||||
|
|
||||||
|
**Haptics** — route all haptic feedback through `HapticService`, never call `HapticFeedback` directly.
|
||||||
|
|
||||||
|
**Colors for accounts** — use `CardColorService`, not hardcoded colors.
|
||||||
|
|
||||||
|
## Existing Features
|
||||||
|
|
||||||
|
- **dashboard** — main screen with account carousel (`BalanceCard`), transaction list, search, filter chips, budget progress, account editor overlay
|
||||||
|
- **add_transaction** — form screen: amount input, type toggle (income/expense), category picker, currency picker, account selector, date/time pickers, note field
|
||||||
|
- **categories** — category list management
|
||||||
|
- **settings** — theme, language, currency, budget, amount format, card text color, haptics, currency conversions
|
||||||
|
|
||||||
|
## What NOT to Do
|
||||||
|
|
||||||
|
- Do not add comments
|
||||||
|
- Do not put business logic in screen or widget files
|
||||||
|
- Do not access `AppDatabase` directly from features — use repositories
|
||||||
|
- Do not create new providers in `shared/providers/` unless the provider is needed by 2+ features
|
||||||
|
- Do not use `BuildContext` across async gaps without checking `mounted`
|
||||||
|
- Do not hardcode user-facing strings — use `AppStrings`
|
||||||
|
- Do not format currency amounts manually — use `CurrencyUtils`
|
||||||
@@ -3,7 +3,6 @@ import java.io.FileInputStream
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("kotlin-android")
|
|
||||||
id("dev.flutter.flutter-gradle-plugin")
|
id("dev.flutter.flutter-gradle-plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,10 +22,6 @@ android {
|
|||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.kolo.casha"
|
applicationId = "com.kolo.casha"
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||||
|
android.builtInKotlin=false
|
||||||
|
# This newDsl flag was added automatically by Flutter migrator
|
||||||
|
android.newDsl=false
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ pluginManagement {
|
|||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.11.1" apply false
|
id("com.android.application") version "8.11.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ class AppStrings {
|
|||||||
|
|
||||||
String get colorPrimary => _ru ? 'Основной' : 'Primary';
|
String get colorPrimary => _ru ? 'Основной' : 'Primary';
|
||||||
String get colorSecondary => _ru ? 'Второй' : 'Secondary';
|
String get colorSecondary => _ru ? 'Второй' : 'Secondary';
|
||||||
|
String get colorSecond => _ru ? 'Второй' : 'Second';
|
||||||
String get colorSolid => _ru ? 'Однотон' : 'Solid';
|
String get colorSolid => _ru ? 'Однотон' : 'Solid';
|
||||||
String get gradientLinear => _ru ? 'Линейный' : 'Linear';
|
String get gradientLinear => _ru ? 'Линейный' : 'Linear';
|
||||||
String get gradientReverse => _ru ? 'Обратный' : 'Reverse';
|
String get gradientReverse => _ru ? 'Обратный' : 'Reverse';
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ class BiometricService {
|
|||||||
try {
|
try {
|
||||||
return await _auth.authenticate(
|
return await _auth.authenticate(
|
||||||
localizedReason: 'Confirm your identity to open Casha',
|
localizedReason: 'Confirm your identity to open Casha',
|
||||||
options: const AuthenticationOptions(
|
|
||||||
biometricOnly: false,
|
|
||||||
stickyAuth: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -80,13 +80,22 @@ class AddTransactionState {
|
|||||||
bool get isEditing => editingId != null;
|
bool get isEditing => editingId != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddTransactionNotifier extends StateNotifier<AddTransactionState> {
|
final addTransactionProvider = NotifierProvider.autoDispose
|
||||||
AddTransactionNotifier(Transaction? initial)
|
.family<AddTransactionNotifier, AddTransactionState, Transaction?>(
|
||||||
: super(
|
(initial) => AddTransactionNotifier(initial),
|
||||||
initial != null
|
);
|
||||||
? AddTransactionState.fromTransaction(initial)
|
|
||||||
: AddTransactionState.empty(),
|
class AddTransactionNotifier extends Notifier<AddTransactionState> {
|
||||||
);
|
AddTransactionNotifier(this._initial);
|
||||||
|
|
||||||
|
final Transaction? _initial;
|
||||||
|
|
||||||
|
@override
|
||||||
|
AddTransactionState build() {
|
||||||
|
return _initial != null
|
||||||
|
? AddTransactionState.fromTransaction(_initial!)
|
||||||
|
: AddTransactionState.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void setAmount(double? v) => state = state.copyWith(amount: v);
|
void setAmount(double? v) => state = state.copyWith(amount: v);
|
||||||
|
|
||||||
@@ -123,11 +132,6 @@ class AddTransactionNotifier extends StateNotifier<AddTransactionState> {
|
|||||||
void reset() => state = AddTransactionState.empty();
|
void reset() => state = AddTransactionState.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
final addTransactionProvider = StateNotifierProvider.autoDispose
|
|
||||||
.family<AddTransactionNotifier, AddTransactionState, Transaction?>(
|
|
||||||
(ref, initial) => AddTransactionNotifier(initial),
|
|
||||||
);
|
|
||||||
|
|
||||||
final availableCategoriesProvider = Provider.autoDispose
|
final availableCategoriesProvider = Provider.autoDispose
|
||||||
.family<List<String>, Transaction?>((ref, initial) {
|
.family<List<String>, Transaction?>((ref, initial) {
|
||||||
final type = ref.watch(
|
final type = ref.watch(
|
||||||
@@ -135,3 +139,4 @@ final availableCategoriesProvider = Provider.autoDispose
|
|||||||
);
|
);
|
||||||
return AppCategories.forType(type);
|
return AppCategories.forType(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
|
|
||||||
if (widget.initial!.category == 'Transfer') {
|
if (widget.initial!.category == 'Transfer') {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
final allTxs = ref.read(transactionsProvider).valueOrNull ?? [];
|
final allTxs = ref.read(transactionsProvider).value ?? [];
|
||||||
|
|
||||||
if (widget.initial!.type == TransactionType.expense) {
|
if (widget.initial!.type == TransactionType.expense) {
|
||||||
final counterpart = allTxs.firstWhereOrNull(
|
final counterpart = allTxs.firstWhereOrNull(
|
||||||
@@ -271,7 +271,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
currencyCode: currencyCode,
|
currencyCode: currencyCode,
|
||||||
accountId: state.selectedAccountId!,
|
accountId: state.selectedAccountId!,
|
||||||
);
|
);
|
||||||
await ref.read(transactionsProvider.notifier).update(updatedExpense);
|
await ref.read(transactionsProvider.notifier).updateTransaction(updatedExpense);
|
||||||
|
|
||||||
if (_transferIncomeRecordId != null) {
|
if (_transferIncomeRecordId != null) {
|
||||||
final updatedIncome = Transaction(
|
final updatedIncome = Transaction(
|
||||||
@@ -285,7 +285,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
currencyCode: currencyCode,
|
currencyCode: currencyCode,
|
||||||
accountId: state.toAccountId!,
|
accountId: state.toAccountId!,
|
||||||
);
|
);
|
||||||
await ref.read(transactionsProvider.notifier).update(updatedIncome);
|
await ref.read(transactionsProvider.notifier).updateTransaction(updatedIncome);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mounted) context.pop();
|
if (mounted) context.pop();
|
||||||
@@ -349,7 +349,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (state.isEditing) {
|
if (state.isEditing) {
|
||||||
await ref.read(transactionsProvider.notifier).update(tx);
|
await ref.read(transactionsProvider.notifier).updateTransaction(tx);
|
||||||
} else {
|
} else {
|
||||||
final res = await ref.read(transactionsProvider.notifier).add(tx);
|
final res = await ref.read(transactionsProvider.notifier).add(tx);
|
||||||
|
|
||||||
@@ -486,7 +486,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
.delete(counterpartId);
|
.delete(counterpartId);
|
||||||
} else {
|
} else {
|
||||||
final allTxs =
|
final allTxs =
|
||||||
ref.read(transactionsProvider).valueOrNull ??
|
ref.read(transactionsProvider).value ??
|
||||||
[];
|
[];
|
||||||
final oppositeType =
|
final oppositeType =
|
||||||
widget.initial!.type ==
|
widget.initial!.type ==
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class AccountRow extends ConsumerWidget {
|
|||||||
final s = ref.watch(stringsProvider);
|
final s = ref.watch(stringsProvider);
|
||||||
final state = ref.watch(addTransactionProvider(initial));
|
final state = ref.watch(addTransactionProvider(initial));
|
||||||
final accountsAsync = ref.watch(accountsProvider);
|
final accountsAsync = ref.watch(accountsProvider);
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
final isTransfer = state.type == TransactionType.transfer;
|
final isTransfer = state.type == TransactionType.transfer;
|
||||||
|
|
||||||
if (isTransfer && accounts.length == 2 && state.selectedAccountId != null) {
|
if (isTransfer && accounts.length == 2 && state.selectedAccountId != null) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class TypeToggle extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final accountsAsync = ref.watch(accountsProvider);
|
final accountsAsync = ref.watch(accountsProvider);
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
final transferDisabled = accounts.length <= 1;
|
final transferDisabled = accounts.length <= 1;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import '../dashboard/provider.dart';
|
|||||||
|
|
||||||
final categoryExpenseProvider = Provider<Map<String, double>>((ref) {
|
final categoryExpenseProvider = Provider<Map<String, double>>((ref) {
|
||||||
final txsAsync = ref.watch(transactionsProvider);
|
final txsAsync = ref.watch(transactionsProvider);
|
||||||
final txs = txsAsync.valueOrNull ?? [];
|
final txs = txsAsync.value ?? [];
|
||||||
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
||||||
|
|
||||||
final map = <String, double>{};
|
final map = <String, double>{};
|
||||||
@@ -16,7 +16,7 @@ final categoryExpenseProvider = Provider<Map<String, double>>((ref) {
|
|||||||
|
|
||||||
final categoryIncomeProvider = Provider<Map<String, double>>((ref) {
|
final categoryIncomeProvider = Provider<Map<String, double>>((ref) {
|
||||||
final txsAsync = ref.watch(transactionsProvider);
|
final txsAsync = ref.watch(transactionsProvider);
|
||||||
final txs = txsAsync.valueOrNull ?? [];
|
final txs = txsAsync.value ?? [];
|
||||||
final filtered = txs.where((t) => t.type == TransactionType.income);
|
final filtered = txs.where((t) => t.type == TransactionType.income);
|
||||||
|
|
||||||
final map = <String, double>{};
|
final map = <String, double>{};
|
||||||
@@ -28,7 +28,7 @@ final categoryIncomeProvider = Provider<Map<String, double>>((ref) {
|
|||||||
|
|
||||||
final monthlyBreakdownProvider = Provider<List<MonthlyData>>((ref) {
|
final monthlyBreakdownProvider = Provider<List<MonthlyData>>((ref) {
|
||||||
final txsAsync = ref.watch(transactionsProvider);
|
final txsAsync = ref.watch(transactionsProvider);
|
||||||
final txs = txsAsync.valueOrNull ?? [];
|
final txs = txsAsync.value ?? [];
|
||||||
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
final filtered = txs.where((t) => t.type == TransactionType.expense);
|
||||||
|
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
|
|||||||
@@ -35,77 +35,75 @@ final storageServiceProvider = Provider<StorageService>((ref) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final transactionsProvider =
|
final transactionsProvider =
|
||||||
StateNotifierProvider<TransactionsNotifier, AsyncValue<List<Transaction>>>((
|
AsyncNotifierProvider<TransactionsNotifier, List<Transaction>>(
|
||||||
ref,
|
TransactionsNotifier.new,
|
||||||
) {
|
);
|
||||||
final repository = ref.watch(transactionRepositoryProvider);
|
|
||||||
return TransactionsNotifier(repository);
|
|
||||||
});
|
|
||||||
|
|
||||||
class TransactionsNotifier
|
class TransactionsNotifier extends AsyncNotifier<List<Transaction>> {
|
||||||
extends StateNotifier<AsyncValue<List<Transaction>>> {
|
@override
|
||||||
final TransactionRepository _repository;
|
Future<List<Transaction>> build() async {
|
||||||
|
final repository = ref.watch(transactionRepositoryProvider);
|
||||||
|
final result = await repository.getAll();
|
||||||
|
|
||||||
TransactionsNotifier(this._repository) : super(const AsyncValue.loading()) {
|
if (result.isSuccess) {
|
||||||
_load();
|
return result.dataOrNull!;
|
||||||
}
|
} else {
|
||||||
|
throw result.errorOrNull!;
|
||||||
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 {
|
Future<Result<void>> add(Transaction transaction) async {
|
||||||
final result = await _repository.add(transaction);
|
final repository = ref.read(transactionRepositoryProvider);
|
||||||
|
final result = await repository.add(transaction);
|
||||||
|
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
await _load();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<void>> update(Transaction transaction) async {
|
Future<Result<void>> updateTransaction(Transaction transaction) async {
|
||||||
final result = await _repository.update(transaction);
|
final repository = ref.read(transactionRepositoryProvider);
|
||||||
|
final result = await repository.update(transaction);
|
||||||
|
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
await _load();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<void>> delete(String id) async {
|
Future<Result<void>> delete(String id) async {
|
||||||
final result = await _repository.delete(id);
|
final repository = ref.read(transactionRepositoryProvider);
|
||||||
|
final result = await repository.delete(id);
|
||||||
|
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
await _load();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> restore(Transaction transaction) async {
|
Future<void> restore(Transaction transaction) async {
|
||||||
await _repository.add(transaction);
|
final repository = ref.read(transactionRepositoryProvider);
|
||||||
await _load();
|
await repository.add(transaction);
|
||||||
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearAll() async {
|
Future<void> clearAll() async {
|
||||||
await _repository.deleteAll();
|
final repository = ref.read(transactionRepositoryProvider);
|
||||||
|
await repository.deleteAll();
|
||||||
state = const AsyncValue.data([]);
|
state = const AsyncValue.data([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
await _load();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final transferPairsProvider = Provider<Map<String, Transaction>>((ref) {
|
final transferPairsProvider = Provider<Map<String, Transaction>>((ref) {
|
||||||
final txs = ref.watch(transactionsProvider).valueOrNull ?? [];
|
final txs = ref.watch(transactionsProvider).value ?? [];
|
||||||
final transfers = txs.where((t) => t.category == 'Transfer').toList();
|
final transfers = txs.where((t) => t.category == 'Transfer').toList();
|
||||||
final Map<String, Transaction> pairs = {};
|
final Map<String, Transaction> pairs = {};
|
||||||
|
|
||||||
@@ -131,23 +129,46 @@ final transferPairsProvider = Provider<Map<String, Transaction>>((ref) {
|
|||||||
return pairs;
|
return pairs;
|
||||||
});
|
});
|
||||||
|
|
||||||
final searchQueryProvider = StateProvider<String>((ref) => '');
|
final searchQueryProvider = NotifierProvider<_SearchQueryNotifier, String>(
|
||||||
|
_SearchQueryNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
|
class _SearchQueryNotifier extends Notifier<String> {
|
||||||
|
@override
|
||||||
|
String build() => '';
|
||||||
|
|
||||||
|
void set(String v) => state = v;
|
||||||
|
}
|
||||||
|
|
||||||
enum TransactionFilter { all, income, expense, transfer }
|
enum TransactionFilter { all, income, expense, transfer }
|
||||||
|
|
||||||
enum TimeFilter { allTime, lastMonth }
|
enum TimeFilter { allTime, lastMonth }
|
||||||
|
|
||||||
final transactionFilterProvider = StateProvider<TransactionFilter>(
|
final transactionFilterProvider = NotifierProvider<_TransactionFilterNotifier, TransactionFilter>(
|
||||||
(ref) => TransactionFilter.all,
|
_TransactionFilterNotifier.new,
|
||||||
);
|
);
|
||||||
|
|
||||||
final timeFilterProvider = StateProvider<TimeFilter>(
|
class _TransactionFilterNotifier extends Notifier<TransactionFilter> {
|
||||||
(ref) => TimeFilter.lastMonth,
|
@override
|
||||||
|
TransactionFilter build() => TransactionFilter.all;
|
||||||
|
|
||||||
|
void set(TransactionFilter v) => state = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
final timeFilterProvider = NotifierProvider<_TimeFilterNotifier, TimeFilter>(
|
||||||
|
_TimeFilterNotifier.new,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
class _TimeFilterNotifier extends Notifier<TimeFilter> {
|
||||||
|
@override
|
||||||
|
TimeFilter build() => TimeFilter.lastMonth;
|
||||||
|
|
||||||
|
void set(TimeFilter v) => state = v;
|
||||||
|
}
|
||||||
|
|
||||||
final accountFilteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
final accountFilteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
||||||
final txsAsync = ref.watch(transactionsProvider);
|
final txsAsync = ref.watch(transactionsProvider);
|
||||||
final txs = txsAsync.valueOrNull ?? [];
|
final txs = txsAsync.value ?? [];
|
||||||
final activeAccount = ref.watch(activeAccountProvider);
|
final activeAccount = ref.watch(activeAccountProvider);
|
||||||
|
|
||||||
if (activeAccount == null) {
|
if (activeAccount == null) {
|
||||||
@@ -158,7 +179,7 @@ final accountFilteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final globalTotalBalanceProvider = Provider<double>((ref) {
|
final globalTotalBalanceProvider = Provider<double>((ref) {
|
||||||
final txs = ref.watch(transactionsProvider).valueOrNull ?? [];
|
final txs = ref.watch(transactionsProvider).value ?? [];
|
||||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||||
final targetCurrency = ref.watch(currencyProvider).code;
|
final targetCurrency = ref.watch(currencyProvider).code;
|
||||||
|
|
||||||
@@ -181,7 +202,7 @@ final totalBalanceProvider = Provider<double>((ref) {
|
|||||||
|
|
||||||
String targetCurrency = globalCurrency;
|
String targetCurrency = globalCurrency;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
if (index <= accounts.length) {
|
if (index <= accounts.length) {
|
||||||
targetCurrency = accounts[index - 1].currency;
|
targetCurrency = accounts[index - 1].currency;
|
||||||
}
|
}
|
||||||
@@ -211,7 +232,7 @@ final totalIncomeProvider = Provider<double>((ref) {
|
|||||||
|
|
||||||
String targetCurrency = globalCurrency;
|
String targetCurrency = globalCurrency;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
if (index <= accounts.length) {
|
if (index <= accounts.length) {
|
||||||
targetCurrency = accounts[index - 1].currency;
|
targetCurrency = accounts[index - 1].currency;
|
||||||
}
|
}
|
||||||
@@ -237,7 +258,7 @@ final totalExpenseProvider = Provider<double>((ref) {
|
|||||||
|
|
||||||
String targetCurrency = globalCurrency;
|
String targetCurrency = globalCurrency;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
if (index <= accounts.length) {
|
if (index <= accounts.length) {
|
||||||
targetCurrency = accounts[index - 1].currency;
|
targetCurrency = accounts[index - 1].currency;
|
||||||
}
|
}
|
||||||
@@ -267,7 +288,7 @@ final currentMonthExpenseProvider = Provider<double>((ref) {
|
|||||||
|
|
||||||
String targetCurrency = globalCurrency;
|
String targetCurrency = globalCurrency;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final accounts = accountsAsync.valueOrNull ?? [];
|
final accounts = accountsAsync.value ?? [];
|
||||||
if (index <= accounts.length) {
|
if (index <= accounts.length) {
|
||||||
targetCurrency = accounts[index - 1].currency;
|
targetCurrency = accounts[index - 1].currency;
|
||||||
}
|
}
|
||||||
@@ -349,7 +370,16 @@ final accountsProvider = StreamProvider<List<Account>>((ref) async* {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final activeAccountIndexProvider = StateProvider<int>((ref) => 0);
|
final activeAccountIndexProvider = NotifierProvider<_ActiveAccountIndexNotifier, int>(
|
||||||
|
_ActiveAccountIndexNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
|
class _ActiveAccountIndexNotifier extends Notifier<int> {
|
||||||
|
@override
|
||||||
|
int build() => 0;
|
||||||
|
|
||||||
|
void set(int v) => state = v;
|
||||||
|
}
|
||||||
|
|
||||||
final activeAccountProvider = Provider<Account?>((ref) {
|
final activeAccountProvider = Provider<Account?>((ref) {
|
||||||
final index = ref.watch(activeAccountIndexProvider);
|
final index = ref.watch(activeAccountIndexProvider);
|
||||||
@@ -387,52 +417,37 @@ class CardColors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final cardColorsProvider =
|
final cardColorsProvider =
|
||||||
StateNotifierProvider<CardColorsNotifier, CardColors>((ref) {
|
NotifierProvider<CardColorsNotifier, CardColors>(
|
||||||
final notifier = CardColorsNotifier();
|
CardColorsNotifier.new,
|
||||||
notifier.setupThemeListener(ref);
|
);
|
||||||
return notifier;
|
|
||||||
});
|
|
||||||
|
|
||||||
final accountCardColorsProvider =
|
final accountCardColorsProvider =
|
||||||
StateNotifierProvider.family<CardColorsNotifier, CardColors, int>((
|
NotifierProvider.family<AccountCardColorsNotifier, CardColors, int>(
|
||||||
ref,
|
(accountId) => AccountCardColorsNotifier(accountId),
|
||||||
accountId,
|
);
|
||||||
) {
|
|
||||||
final notifier = CardColorsNotifier(accountId: accountId);
|
|
||||||
notifier.setupThemeListener(ref);
|
|
||||||
return notifier;
|
|
||||||
});
|
|
||||||
|
|
||||||
class CardColorsNotifier extends StateNotifier<CardColors> {
|
|
||||||
final int? accountId;
|
|
||||||
|
|
||||||
CardColorsNotifier({this.accountId})
|
|
||||||
: super(
|
|
||||||
const CardColors(
|
|
||||||
CardColorService.defaultPrimary,
|
|
||||||
CardColorService.defaultSecondary,
|
|
||||||
CardColorService.defaultGradientLight,
|
|
||||||
CardColorService.defaultGradientDark,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
_load();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class CardColorsNotifier extends Notifier<CardColors> {
|
||||||
int _loadGeneration = 0;
|
int _loadGeneration = 0;
|
||||||
|
|
||||||
void setupThemeListener(Ref ref) {
|
@override
|
||||||
|
CardColors build() {
|
||||||
ref.listen<ThemeMode>(themeProvider, (previous, next) {
|
ref.listen<ThemeMode>(themeProvider, (previous, next) {
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
_onThemeChanged(previous, next);
|
_onThemeChanged(previous, next);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
_load();
|
||||||
|
return const CardColors(
|
||||||
|
CardColorService.defaultPrimary,
|
||||||
|
CardColorService.defaultSecondary,
|
||||||
|
CardColorService.defaultGradientLight,
|
||||||
|
CardColorService.defaultGradientDark,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
final currentGeneration = ++_loadGeneration;
|
final currentGeneration = ++_loadGeneration;
|
||||||
final (c1, c2, lightG, darkG) = await CardColorService.load(
|
final (c1, c2, lightG, darkG) = await CardColorService.load();
|
||||||
accountId: accountId,
|
|
||||||
);
|
|
||||||
if (currentGeneration != _loadGeneration) return;
|
if (currentGeneration != _loadGeneration) return;
|
||||||
state = CardColors(c1, c2, lightG, darkG);
|
state = CardColors(c1, c2, lightG, darkG);
|
||||||
}
|
}
|
||||||
@@ -450,7 +465,6 @@ class CardColorsNotifier extends StateNotifier<CardColors> {
|
|||||||
secondary,
|
secondary,
|
||||||
lightGradient,
|
lightGradient,
|
||||||
darkGradient,
|
darkGradient,
|
||||||
accountId: accountId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +487,127 @@ class CardColorsNotifier extends StateNotifier<CardColors> {
|
|||||||
secondary,
|
secondary,
|
||||||
CardColorService.defaultGradientLight,
|
CardColorService.defaultGradientLight,
|
||||||
CardColorService.defaultGradientDark,
|
CardColorService.defaultGradientDark,
|
||||||
accountId: accountId,
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onThemeChanged(ThemeMode previous, ThemeMode next) {
|
||||||
|
final previousBrightness = _resolve(previous);
|
||||||
|
final nextBrightness = _resolve(next);
|
||||||
|
|
||||||
|
if (previousBrightness == nextBrightness) return;
|
||||||
|
|
||||||
|
final oldDefaults = _defaultsFor(previousBrightness);
|
||||||
|
final newDefaults = _defaultsFor(nextBrightness);
|
||||||
|
|
||||||
|
final isUsingOldDefaults =
|
||||||
|
state.primary == oldDefaults.primary &&
|
||||||
|
state.secondary == oldDefaults.secondary &&
|
||||||
|
state.gradientTypeForBrightness(previousBrightness) ==
|
||||||
|
oldDefaults.gradient;
|
||||||
|
|
||||||
|
if (isUsingOldDefaults) {
|
||||||
|
_loadGeneration++;
|
||||||
|
state = CardColors(
|
||||||
|
newDefaults.primary,
|
||||||
|
newDefaults.secondary,
|
||||||
|
state.lightGradientType,
|
||||||
|
state.darkGradientType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Brightness _resolve(ThemeMode mode) {
|
||||||
|
if (mode == ThemeMode.system) {
|
||||||
|
return WidgetsBinding.instance.platformDispatcher.platformBrightness;
|
||||||
|
}
|
||||||
|
return mode == ThemeMode.dark ? Brightness.dark : Brightness.light;
|
||||||
|
}
|
||||||
|
|
||||||
|
({Color primary, Color secondary, GradientType gradient}) _defaultsFor(
|
||||||
|
Brightness brightness,
|
||||||
|
) {
|
||||||
|
return brightness == Brightness.dark
|
||||||
|
? (
|
||||||
|
primary: CardColorService.defaultPrimary,
|
||||||
|
secondary: CardColorService.defaultSecondary,
|
||||||
|
gradient: CardColorService.defaultGradientDark,
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
primary: CardColorService.defaultPrimaryLight,
|
||||||
|
secondary: CardColorService.defaultSecondaryLight,
|
||||||
|
gradient: CardColorService.defaultGradientLight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountCardColorsNotifier extends Notifier<CardColors> {
|
||||||
|
AccountCardColorsNotifier(this._accountId);
|
||||||
|
|
||||||
|
final int _accountId;
|
||||||
|
int _loadGeneration = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
CardColors build() {
|
||||||
|
ref.listen<ThemeMode>(themeProvider, (previous, next) {
|
||||||
|
if (previous != null) {
|
||||||
|
_onThemeChanged(previous, next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_load(_accountId);
|
||||||
|
return const CardColors(
|
||||||
|
CardColorService.defaultPrimary,
|
||||||
|
CardColorService.defaultSecondary,
|
||||||
|
CardColorService.defaultGradientLight,
|
||||||
|
CardColorService.defaultGradientDark,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _load(int accountId) async {
|
||||||
|
final currentGeneration = ++_loadGeneration;
|
||||||
|
final (c1, c2, lightG, darkG) = await CardColorService.load(
|
||||||
|
accountId: accountId,
|
||||||
|
);
|
||||||
|
if (currentGeneration != _loadGeneration) return;
|
||||||
|
state = CardColors(c1, c2, lightG, darkG);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> save(
|
||||||
|
Color primary,
|
||||||
|
Color secondary,
|
||||||
|
GradientType lightGradient,
|
||||||
|
GradientType darkGradient,
|
||||||
|
) async {
|
||||||
|
_loadGeneration++;
|
||||||
|
state = CardColors(primary, secondary, lightGradient, darkGradient);
|
||||||
|
await CardColorService.save(
|
||||||
|
primary,
|
||||||
|
secondary,
|
||||||
|
lightGradient,
|
||||||
|
darkGradient,
|
||||||
|
accountId: _accountId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> reset(bool isDark) async {
|
||||||
|
final primary = isDark
|
||||||
|
? CardColorService.defaultPrimary
|
||||||
|
: CardColorService.defaultPrimaryLight;
|
||||||
|
final secondary = isDark
|
||||||
|
? CardColorService.defaultSecondary
|
||||||
|
: CardColorService.defaultSecondaryLight;
|
||||||
|
_loadGeneration++;
|
||||||
|
state = CardColors(
|
||||||
|
primary,
|
||||||
|
secondary,
|
||||||
|
CardColorService.defaultGradientLight,
|
||||||
|
CardColorService.defaultGradientDark,
|
||||||
|
);
|
||||||
|
await CardColorService.save(
|
||||||
|
primary,
|
||||||
|
secondary,
|
||||||
|
CardColorService.defaultGradientLight,
|
||||||
|
CardColorService.defaultGradientDark,
|
||||||
|
accountId: _accountId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
|||||||
|
|
||||||
final activeIndex = ref.watch(activeAccountIndexProvider);
|
final activeIndex = ref.watch(activeAccountIndexProvider);
|
||||||
final accountsAsync = ref.watch(accountsProvider);
|
final accountsAsync = ref.watch(accountsProvider);
|
||||||
final accountCount = accountsAsync.valueOrNull?.length ?? 0;
|
final accountCount = accountsAsync.value?.length ?? 0;
|
||||||
final isOnAddAccountPage =
|
final isOnAddAccountPage =
|
||||||
accountCount < 5 && activeIndex == accountCount + 1;
|
accountCount < 5 && activeIndex == accountCount + 1;
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class _AccountEditorOverlayState extends State<AccountEditorOverlay> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final mq = MediaQuery.of(widget.context);
|
final mq = MediaQuery.of(widget.context);
|
||||||
final cardTop = mq.padding.top + kToolbarHeight + 16;
|
final cardTop = mq.padding.top + kToolbarHeight + 16;
|
||||||
const cardHeight = 230.0;
|
const cardHeight = 190.0;
|
||||||
const editorPanelHeight = 102.0;
|
const editorPanelHeight = 102.0;
|
||||||
final editorPanelTop = cardTop + cardHeight + 20;
|
final editorPanelTop = cardTop + cardHeight + 20;
|
||||||
final colorPanelTop = editorPanelTop + editorPanelHeight + 12;
|
final colorPanelTop = editorPanelTop + editorPanelHeight + 12;
|
||||||
@@ -377,7 +377,7 @@ class _AccountEditorOverlayState extends State<AccountEditorOverlay> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (!dash.isAddingAccount &&
|
if (!dash.isAddingAccount &&
|
||||||
(ref.watch(accountsProvider).valueOrNull?.length ?? 0) >
|
(ref.watch(accountsProvider).value?.length ?? 0) >
|
||||||
1) ...[
|
1) ...[
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => setState(() => _showDeleteDialog = true),
|
onTap: () => setState(() => _showDeleteDialog = true),
|
||||||
|
|||||||
@@ -588,7 +588,7 @@ class AccountColorPanel extends StatelessWidget {
|
|||||||
final accounts =
|
final accounts =
|
||||||
ProviderScope.containerOf(
|
ProviderScope.containerOf(
|
||||||
dashboardContext,
|
dashboardContext,
|
||||||
).read(accountsProvider).valueOrNull ??
|
).read(accountsProvider).value ??
|
||||||
[];
|
[];
|
||||||
|
|
||||||
if (isDuplicateName(
|
if (isDuplicateName(
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class AccountDeleteDialog extends ConsumerWidget {
|
|||||||
|
|
||||||
onConfirm();
|
onConfirm();
|
||||||
|
|
||||||
final txs = ref.read(transactionsProvider).valueOrNull ?? [];
|
final txs = ref.read(transactionsProvider).value ?? [];
|
||||||
final accountTxs = txs
|
final accountTxs = txs
|
||||||
.where((t) => t.accountId == accountId)
|
.where((t) => t.accountId == accountId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import '../../../../core/constants.dart';
|
import '../../../../core/constants.dart';
|
||||||
import '../../../../shared/widgets/byn_sign.dart';
|
import '../../../../shared/widgets/byn_sign.dart';
|
||||||
|
|
||||||
class AccountEditorPanel extends ConsumerWidget {
|
class AccountEditorPanel extends ConsumerStatefulWidget {
|
||||||
final TextEditingController nameController;
|
final TextEditingController nameController;
|
||||||
final String selectedCurrency;
|
final String selectedCurrency;
|
||||||
final bool showCurrencyDropdown;
|
final bool showCurrencyDropdown;
|
||||||
@@ -26,15 +26,29 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
ConsumerState<AccountEditorPanel> createState() => _AccountEditorPanelState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountEditorPanelState extends ConsumerState<AccountEditorPanel> {
|
||||||
|
bool _showNameError = false;
|
||||||
|
|
||||||
|
void _triggerNameError() {
|
||||||
|
setState(() => _showNameError = true);
|
||||||
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
|
if (mounted) setState(() => _showNameError = false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: panelHeight,
|
height: widget.panelHeight,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(dashboardContext).colorScheme.surface,
|
color: Theme.of(widget.dashboardContext).colorScheme.surface,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.1),
|
).colorScheme.onSurface.withOpacity(0.1),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
@@ -58,7 +72,7 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.6),
|
).colorScheme.onSurface.withOpacity(0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -70,7 +84,7 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: nameController,
|
controller: widget.nameController,
|
||||||
buildCounter:
|
buildCounter:
|
||||||
(
|
(
|
||||||
context, {
|
context, {
|
||||||
@@ -84,23 +98,23 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.4),
|
).colorScheme.onSurface.withOpacity(0.4),
|
||||||
),
|
),
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Theme.of(
|
fillColor: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.05),
|
).colorScheme.onSurface.withOpacity(0.05),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color:
|
color:
|
||||||
(showLimitError ||
|
(widget.showLimitError ||
|
||||||
showDuplicateError ||
|
widget.showDuplicateError ||
|
||||||
nameController.text.trim().isEmpty)
|
_showNameError)
|
||||||
? Colors.red
|
? Colors.red
|
||||||
: Theme.of(
|
: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.15),
|
).colorScheme.onSurface.withOpacity(0.15),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
@@ -109,12 +123,12 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color:
|
color:
|
||||||
(showLimitError ||
|
(widget.showLimitError ||
|
||||||
showDuplicateError ||
|
widget.showDuplicateError ||
|
||||||
nameController.text.trim().isEmpty)
|
_showNameError)
|
||||||
? Colors.red
|
? Colors.red
|
||||||
: Theme.of(
|
: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.15),
|
).colorScheme.onSurface.withOpacity(0.15),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
@@ -123,9 +137,9 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color:
|
color:
|
||||||
(showLimitError ||
|
(widget.showLimitError ||
|
||||||
showDuplicateError ||
|
widget.showDuplicateError ||
|
||||||
nameController.text.trim().isEmpty)
|
_showNameError)
|
||||||
? Colors.red
|
? Colors.red
|
||||||
: const Color(0xFF7C6DED),
|
: const Color(0xFF7C6DED),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
@@ -141,19 +155,19 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: onCurrencyDropdownToggle,
|
onTap: widget.onCurrencyDropdownToggle,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.05),
|
).colorScheme.onSurface.withOpacity(0.05),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: showCurrencyDropdown
|
color: widget.showCurrencyDropdown
|
||||||
? const Color(0xFF7C6DED)
|
? const Color(0xFF7C6DED)
|
||||||
: Theme.of(
|
: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.15),
|
).colorScheme.onSurface.withOpacity(0.15),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
@@ -162,17 +176,17 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
selectedCurrency == 'BYN'
|
widget.selectedCurrency == 'BYN'
|
||||||
? BynSign(
|
? BynSign(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface,
|
).colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
: Text(
|
: Text(
|
||||||
kDisplayCurrencies
|
kDisplayCurrencies
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(c) => c.$1 == selectedCurrency,
|
(c) => c.$1 == widget.selectedCurrency,
|
||||||
)
|
)
|
||||||
.$2,
|
.$2,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -182,12 +196,12 @@ class AccountEditorPanel extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Icon(
|
Icon(
|
||||||
showCurrencyDropdown
|
widget.showCurrencyDropdown
|
||||||
? Icons.arrow_drop_up
|
? Icons.arrow_drop_up
|
||||||
: Icons.arrow_drop_down,
|
: Icons.arrow_drop_down,
|
||||||
size: 20,
|
size: 20,
|
||||||
color: Theme.of(
|
color: Theme.of(
|
||||||
dashboardContext,
|
widget.dashboardContext,
|
||||||
).colorScheme.onSurface.withOpacity(0.6),
|
).colorScheme.onSurface.withOpacity(0.6),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -145,15 +145,12 @@ class BalanceCardState extends ConsumerState<BalanceCard>
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final textColorMode = ref.watch(cardTextColorProvider);
|
final textColorMode = ref.watch(cardTextColorProvider);
|
||||||
final Color onCard;
|
final Color onCard = switch (textColorMode) {
|
||||||
switch (textColorMode) {
|
CardTextColorMode.white => Colors.white,
|
||||||
case CardTextColorMode.white:
|
CardTextColorMode.black => Colors.black,
|
||||||
onCard = Colors.white;
|
CardTextColorMode.adaptive => primary.computeLuminance() > 0.3 ? Colors.black : Colors.white,
|
||||||
case CardTextColorMode.black:
|
_ => Colors.white,
|
||||||
onCard = Colors.black;
|
};
|
||||||
case CardTextColorMode.adaptive:
|
|
||||||
onCard = primary.computeLuminance() > 0.3 ? Colors.black : Colors.white;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
@@ -174,7 +171,7 @@ class BalanceCardState extends ConsumerState<BalanceCard>
|
|||||||
..rotateY(_tiltY * 0.42),
|
..rotateY(_tiltY * 0.42),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 220,
|
height: 180,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
gradient: _buildGradient(primary, secondary, gradientType),
|
gradient: _buildGradient(primary, secondary, gradientType),
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class _BalanceCardCarouselState extends ConsumerState<BalanceCardCarousel> {
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 230,
|
height: 190,
|
||||||
child: OverflowBox(
|
child: OverflowBox(
|
||||||
maxWidth: MediaQuery.of(context).size.width,
|
maxWidth: MediaQuery.of(context).size.width,
|
||||||
child: PageView.builder(
|
child: PageView.builder(
|
||||||
@@ -75,7 +75,7 @@ class _BalanceCardCarouselState extends ConsumerState<BalanceCardCarousel> {
|
|||||||
Clip.none,
|
Clip.none,
|
||||||
itemCount: totalPages,
|
itemCount: totalPages,
|
||||||
onPageChanged: (index) {
|
onPageChanged: (index) {
|
||||||
ref.read(activeAccountIndexProvider.notifier).state = index;
|
ref.read(activeAccountIndexProvider.notifier).set(index);
|
||||||
if (ref.read(hapticEnabledProvider)) {
|
if (ref.read(hapticEnabledProvider)) {
|
||||||
HapticService.light();
|
HapticService.light();
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ class _BalanceCardCarouselState extends ConsumerState<BalanceCardCarousel> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final txs =
|
final txs =
|
||||||
ref.watch(transactionsProvider).valueOrNull ?? [];
|
ref.watch(transactionsProvider).value ?? [];
|
||||||
final accountTxs = txs
|
final accountTxs = txs
|
||||||
.where((t) => t.accountId == account.id)
|
.where((t) => t.accountId == account.id)
|
||||||
.toList();
|
.toList();
|
||||||
@@ -154,14 +154,14 @@ class _BalanceCardCarouselState extends ConsumerState<BalanceCardCarousel> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
loading: () => const SizedBox(
|
loading: () => const SizedBox(
|
||||||
height: 220,
|
height: 180,
|
||||||
child: Center(child: CircularProgressIndicator()),
|
child: Center(child: CircularProgressIndicator()),
|
||||||
),
|
),
|
||||||
error: (error, stack) {
|
error: (error, stack) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 220,
|
height: 180,
|
||||||
child: BalanceCard(
|
child: BalanceCard(
|
||||||
balance: widget.balance,
|
balance: widget.balance,
|
||||||
currencyInfo: widget.currencyInfo,
|
currencyInfo: widget.currencyInfo,
|
||||||
@@ -198,7 +198,7 @@ class AddAccountCard extends StatelessWidget {
|
|||||||
painter: _DashedBorderPainter(),
|
painter: _DashedBorderPainter(),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 205,
|
height: 165,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surface.withOpacity(0.4),
|
color: Theme.of(context).colorScheme.surface.withOpacity(0.4),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ class FilterChips extends ConsumerWidget {
|
|||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterAllTime,
|
label: strings.filterAllTime,
|
||||||
isSelected: timeFilter == TimeFilter.allTime,
|
isSelected: timeFilter == TimeFilter.allTime,
|
||||||
onTap: () => ref.read(timeFilterProvider.notifier).state =
|
onTap: () => ref.read(timeFilterProvider.notifier).set(
|
||||||
TimeFilter.allTime,
|
TimeFilter.allTime),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterMonth,
|
label: strings.filterMonth,
|
||||||
isSelected: timeFilter == TimeFilter.lastMonth,
|
isSelected: timeFilter == TimeFilter.lastMonth,
|
||||||
onTap: () => ref.read(timeFilterProvider.notifier).state =
|
onTap: () => ref.read(timeFilterProvider.notifier).set(
|
||||||
TimeFilter.lastMonth,
|
TimeFilter.lastMonth),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
@@ -46,32 +46,32 @@ class FilterChips extends ConsumerWidget {
|
|||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterAll,
|
label: strings.filterAll,
|
||||||
isSelected: typeFilter == TransactionFilter.all,
|
isSelected: typeFilter == TransactionFilter.all,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).set(
|
||||||
TransactionFilter.all,
|
TransactionFilter.all),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterIncome,
|
label: strings.filterIncome,
|
||||||
isSelected: typeFilter == TransactionFilter.income,
|
isSelected: typeFilter == TransactionFilter.income,
|
||||||
color: AppColors.income,
|
color: AppColors.income,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).set(
|
||||||
TransactionFilter.income,
|
TransactionFilter.income),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterExpense,
|
label: strings.filterExpense,
|
||||||
isSelected: typeFilter == TransactionFilter.expense,
|
isSelected: typeFilter == TransactionFilter.expense,
|
||||||
color: AppColors.expense,
|
color: AppColors.expense,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).set(
|
||||||
TransactionFilter.expense,
|
TransactionFilter.expense),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: strings.filterTransfer,
|
label: strings.filterTransfer,
|
||||||
isSelected: typeFilter == TransactionFilter.transfer,
|
isSelected: typeFilter == TransactionFilter.transfer,
|
||||||
color: Colors.blueAccent,
|
color: Colors.blueAccent,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).set(
|
||||||
TransactionFilter.transfer,
|
TransactionFilter.transfer),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class SearchBar extends StatelessWidget {
|
|||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.clear();
|
controller.clear();
|
||||||
ref.read(searchQueryProvider.notifier).state = '';
|
ref.read(searchQueryProvider.notifier).set('');
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
@@ -63,7 +63,7 @@ class SearchBar extends StatelessWidget {
|
|||||||
vertical: 12,
|
vertical: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onChanged: (v) => ref.read(searchQueryProvider.notifier).state = v,
|
onChanged: (v) => ref.read(searchQueryProvider.notifier).set(v),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class TransactionTile extends ConsumerWidget {
|
|||||||
: 0.0;
|
: 0.0;
|
||||||
final displaySymbol = currencyMap[displayCurrency]?.symbol ?? '';
|
final displaySymbol = currencyMap[displayCurrency]?.symbol ?? '';
|
||||||
|
|
||||||
final accounts = ref.watch(accountsProvider).valueOrNull ?? [];
|
final accounts = ref.watch(accountsProvider).value ?? [];
|
||||||
final txAccount = accounts.firstWhereOrNull(
|
final txAccount = accounts.firstWhereOrNull(
|
||||||
(a) => a.id == transaction.accountId,
|
(a) => a.id == transaction.accountId,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,18 +11,20 @@ import '../../shared/utils/currency_utils.dart';
|
|||||||
import '../../shared/providers/amount_format_provider.dart';
|
import '../../shared/providers/amount_format_provider.dart';
|
||||||
import '../dashboard/provider.dart';
|
import '../dashboard/provider.dart';
|
||||||
|
|
||||||
final budgetProvider = StateNotifierProvider<BudgetNotifier, double?>((ref) {
|
final budgetProvider = NotifierProvider<BudgetNotifier, double?>(
|
||||||
final storage = ref.watch(storageServiceProvider);
|
BudgetNotifier.new,
|
||||||
return BudgetNotifier(storage.loadBudget(), storage);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
class BudgetNotifier extends StateNotifier<double?> {
|
class BudgetNotifier extends Notifier<double?> {
|
||||||
final dynamic _storage;
|
@override
|
||||||
|
double? build() {
|
||||||
BudgetNotifier(super.initialBudget, this._storage);
|
final storage = ref.watch(storageServiceProvider);
|
||||||
|
return storage.loadBudget();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> setBudget(double? budget) async {
|
Future<void> setBudget(double? budget) async {
|
||||||
await _storage.saveBudget(budget);
|
final storage = ref.read(storageServiceProvider);
|
||||||
|
await storage.saveBudget(budget);
|
||||||
state = budget;
|
state = budget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,70 +52,60 @@ const Map<String, CurrencyInfo> currencyMap = {
|
|||||||
'RUB': CurrencyInfo('₽', 'RUB'),
|
'RUB': CurrencyInfo('₽', 'RUB'),
|
||||||
};
|
};
|
||||||
|
|
||||||
class CurrencyNotifier extends StateNotifier<CurrencyInfo> {
|
class CurrencyNotifier extends Notifier<CurrencyInfo> {
|
||||||
final SharedPreferences _prefs;
|
@override
|
||||||
|
CurrencyInfo build() {
|
||||||
CurrencyNotifier(this._prefs) : super(currencyMap['USD']!) {
|
final prefs = ref.watch(sharedPreferencesProvider);
|
||||||
_load();
|
final code = prefs.getString('currency_code') ?? 'USD';
|
||||||
}
|
return currencyMap[code] ?? currencyMap['USD']!;
|
||||||
|
|
||||||
void _load() {
|
|
||||||
final code = _prefs.getString('currency_code') ?? 'USD';
|
|
||||||
state = currencyMap[code] ?? currencyMap['USD']!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setCurrency(String code) async {
|
Future<void> setCurrency(String code) async {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
state = currencyMap[code] ?? currencyMap['USD']!;
|
state = currencyMap[code] ?? currencyMap['USD']!;
|
||||||
await _prefs.setString('currency_code', code);
|
await prefs.setString('currency_code', code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final currencyProvider = StateNotifierProvider<CurrencyNotifier, CurrencyInfo>((
|
final currencyProvider = NotifierProvider<CurrencyNotifier, CurrencyInfo>(
|
||||||
ref,
|
CurrencyNotifier.new,
|
||||||
) {
|
);
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
|
||||||
return CurrencyNotifier(prefs);
|
|
||||||
});
|
|
||||||
|
|
||||||
class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
class ThemeModeNotifier extends Notifier<ThemeMode> {
|
||||||
final SharedPreferences _prefs;
|
@override
|
||||||
|
ThemeMode build() {
|
||||||
ThemeModeNotifier(this._prefs) : super(ThemeMode.system) {
|
final prefs = ref.watch(sharedPreferencesProvider);
|
||||||
_load();
|
final saved = prefs.getString('theme_mode');
|
||||||
}
|
|
||||||
|
|
||||||
void _load() {
|
|
||||||
final saved = _prefs.getString('theme_mode');
|
|
||||||
if (saved == 'dark') {
|
if (saved == 'dark') {
|
||||||
state = ThemeMode.dark;
|
return ThemeMode.dark;
|
||||||
} else if (saved == 'light') {
|
} else if (saved == 'light') {
|
||||||
state = ThemeMode.light;
|
return ThemeMode.light;
|
||||||
} else {
|
} else {
|
||||||
state = ThemeMode.system;
|
return ThemeMode.system;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setThemeMode(ThemeMode mode) async {
|
Future<void> setThemeMode(ThemeMode mode) async {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
state = mode;
|
state = mode;
|
||||||
await _prefs.setString('theme_mode', mode.name);
|
await prefs.setString('theme_mode', mode.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final themeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>((
|
final themeProvider = NotifierProvider<ThemeModeNotifier, ThemeMode>(
|
||||||
ref,
|
ThemeModeNotifier.new,
|
||||||
) {
|
);
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
|
||||||
return ThemeModeNotifier(prefs);
|
|
||||||
});
|
|
||||||
|
|
||||||
enum CardTextColorMode { white, adaptive, black }
|
enum CardTextColorMode { white, adaptive, black }
|
||||||
|
|
||||||
class CardTextColorNotifier extends StateNotifier<CardTextColorMode> {
|
class CardTextColorNotifier extends Notifier<CardTextColorMode> {
|
||||||
static const _key = 'card_text_color';
|
static const _key = 'card_text_color';
|
||||||
final SharedPreferences _prefs;
|
|
||||||
|
|
||||||
CardTextColorNotifier(this._prefs)
|
@override
|
||||||
: super(_fromString(_prefs.getString(_key)));
|
CardTextColorMode build() {
|
||||||
|
final prefs = ref.watch(sharedPreferencesProvider);
|
||||||
|
return _fromString(prefs.getString(_key));
|
||||||
|
}
|
||||||
|
|
||||||
static CardTextColorMode _fromString(String? value) {
|
static CardTextColorMode _fromString(String? value) {
|
||||||
return CardTextColorMode.values.firstWhere(
|
return CardTextColorMode.values.firstWhere(
|
||||||
@@ -123,16 +115,16 @@ class CardTextColorNotifier extends StateNotifier<CardTextColorMode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set(CardTextColorMode mode) {
|
void set(CardTextColorMode mode) {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
state = mode;
|
state = mode;
|
||||||
_prefs.setString(_key, mode.name);
|
prefs.setString(_key, mode.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final cardTextColorProvider =
|
final cardTextColorProvider =
|
||||||
StateNotifierProvider<CardTextColorNotifier, CardTextColorMode>((ref) {
|
NotifierProvider<CardTextColorNotifier, CardTextColorMode>(
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
CardTextColorNotifier.new,
|
||||||
return CardTextColorNotifier(prefs);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
final exchangeRateServiceProvider = Provider<ExchangeRateService>((ref) {
|
final exchangeRateServiceProvider = Provider<ExchangeRateService>((ref) {
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
final prefs = ref.watch(sharedPreferencesProvider);
|
||||||
@@ -143,15 +135,15 @@ final ratesInitProvider = FutureProvider<void>((ref) async {
|
|||||||
await ref.read(exchangeRateServiceProvider).fetchRates();
|
await ref.read(exchangeRateServiceProvider).fetchRates();
|
||||||
});
|
});
|
||||||
|
|
||||||
final hapticEnabledProvider = StateNotifierProvider<HapticNotifier, bool>((
|
final hapticEnabledProvider = NotifierProvider<HapticNotifier, bool>(
|
||||||
ref,
|
HapticNotifier.new,
|
||||||
) {
|
);
|
||||||
return HapticNotifier();
|
|
||||||
});
|
|
||||||
|
|
||||||
class HapticNotifier extends StateNotifier<bool> {
|
class HapticNotifier extends Notifier<bool> {
|
||||||
HapticNotifier() : super(true) {
|
@override
|
||||||
|
bool build() {
|
||||||
_load();
|
_load();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
@@ -166,13 +158,15 @@ class HapticNotifier extends StateNotifier<bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final showCurrencyConversionsProvider =
|
final showCurrencyConversionsProvider =
|
||||||
StateNotifierProvider<ShowCurrencyConversionsNotifier, bool>((ref) {
|
NotifierProvider<ShowCurrencyConversionsNotifier, bool>(
|
||||||
return ShowCurrencyConversionsNotifier();
|
ShowCurrencyConversionsNotifier.new,
|
||||||
});
|
);
|
||||||
|
|
||||||
class ShowCurrencyConversionsNotifier extends StateNotifier<bool> {
|
class ShowCurrencyConversionsNotifier extends Notifier<bool> {
|
||||||
ShowCurrencyConversionsNotifier() : super(true) {
|
@override
|
||||||
|
bool build() {
|
||||||
_load();
|
_load();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
@@ -198,7 +192,7 @@ class ExportService {
|
|||||||
|
|
||||||
Future<String> exportToCSV() async {
|
Future<String> exportToCSV() async {
|
||||||
final transactionsAsync = _ref.read(transactionsProvider);
|
final transactionsAsync = _ref.read(transactionsProvider);
|
||||||
final transactions = transactionsAsync.valueOrNull ?? [];
|
final transactions = transactionsAsync.value ?? [];
|
||||||
final fmt = _ref.read(amountFormatProvider);
|
final fmt = _ref.read(amountFormatProvider);
|
||||||
|
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
|
|||||||
+181
-1
@@ -2,10 +2,188 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
import 'app/app.dart';
|
import 'app/app.dart';
|
||||||
import 'core/services/haptic_service.dart';
|
import 'core/services/haptic_service.dart';
|
||||||
import 'data/database/app_database.dart';
|
import 'data/database/app_database.dart' hide Account, Transaction;
|
||||||
|
import 'data/repositories/account_repository.dart';
|
||||||
|
import 'data/repositories/transaction_repository.dart';
|
||||||
import 'features/dashboard/provider.dart';
|
import 'features/dashboard/provider.dart';
|
||||||
|
import 'shared/models/account.dart';
|
||||||
|
import 'shared/models/transaction.dart';
|
||||||
|
|
||||||
|
Future<void> seedTestData(AppDatabase database) async {
|
||||||
|
final accountRepo = AccountRepository(database);
|
||||||
|
final transactionRepo = TransactionRepository(database);
|
||||||
|
|
||||||
|
final existingAccounts = await accountRepo.getAll();
|
||||||
|
if (existingAccounts.length > 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final uuid = const Uuid();
|
||||||
|
|
||||||
|
final cashId = await accountRepo.add(
|
||||||
|
Account(
|
||||||
|
id: 0,
|
||||||
|
name: 'Cash',
|
||||||
|
isMain: false,
|
||||||
|
sortOrder: 1,
|
||||||
|
currency: 'USD',
|
||||||
|
createdAt: now,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final cardId = await accountRepo.add(
|
||||||
|
Account(
|
||||||
|
id: 0,
|
||||||
|
name: 'Card',
|
||||||
|
isMain: false,
|
||||||
|
sortOrder: 2,
|
||||||
|
currency: 'USD',
|
||||||
|
createdAt: now,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final savingsId = await accountRepo.add(
|
||||||
|
Account(
|
||||||
|
id: 0,
|
||||||
|
name: 'Savings',
|
||||||
|
isMain: false,
|
||||||
|
sortOrder: 3,
|
||||||
|
currency: 'USD',
|
||||||
|
createdAt: now,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final transactions = [
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 3500.0,
|
||||||
|
category: 'Salary',
|
||||||
|
type: TransactionType.income,
|
||||||
|
date: now.subtract(const Duration(days: 28)),
|
||||||
|
note: 'Monthly salary',
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 85.50,
|
||||||
|
category: 'Groceries',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 27)),
|
||||||
|
note: 'Weekly shopping',
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 45.00,
|
||||||
|
category: 'Transportation',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 25)),
|
||||||
|
accountId: cashId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 120.00,
|
||||||
|
category: 'Utilities',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 22)),
|
||||||
|
note: 'Electricity bill',
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 200.0,
|
||||||
|
category: 'Freelance',
|
||||||
|
type: TransactionType.income,
|
||||||
|
date: now.subtract(const Duration(days: 20)),
|
||||||
|
note: 'Side project',
|
||||||
|
accountId: cashId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 500.0,
|
||||||
|
category: 'Savings',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 18)),
|
||||||
|
note: 'Monthly savings',
|
||||||
|
accountId: savingsId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 65.25,
|
||||||
|
category: 'Dining',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 15)),
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 30.00,
|
||||||
|
category: 'Entertainment',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 12)),
|
||||||
|
note: 'Movie tickets',
|
||||||
|
accountId: cashId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 95.00,
|
||||||
|
category: 'Groceries',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 10)),
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 150.0,
|
||||||
|
category: 'Bonus',
|
||||||
|
type: TransactionType.income,
|
||||||
|
date: now.subtract(const Duration(days: 8)),
|
||||||
|
note: 'Performance bonus',
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 75.00,
|
||||||
|
category: 'Shopping',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 6)),
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 40.00,
|
||||||
|
category: 'Transportation',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 4)),
|
||||||
|
accountId: cashId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 55.80,
|
||||||
|
category: 'Dining',
|
||||||
|
type: TransactionType.expense,
|
||||||
|
date: now.subtract(const Duration(days: 2)),
|
||||||
|
note: 'Dinner with friends',
|
||||||
|
accountId: cardId,
|
||||||
|
),
|
||||||
|
Transaction(
|
||||||
|
id: uuid.v4(),
|
||||||
|
amount: 100.0,
|
||||||
|
category: 'Gift',
|
||||||
|
type: TransactionType.income,
|
||||||
|
date: now.subtract(const Duration(days: 1)),
|
||||||
|
accountId: cashId,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final transaction in transactions) {
|
||||||
|
await transactionRepo.add(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@@ -19,6 +197,8 @@ void main() async {
|
|||||||
await HapticService.init();
|
await HapticService.init();
|
||||||
|
|
||||||
final database = AppDatabase();
|
final database = AppDatabase();
|
||||||
|
|
||||||
|
await seedTestData(database);
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../../core/constants.dart';
|
import '../../core/constants.dart';
|
||||||
|
|
||||||
class AmountFormatNotifier extends StateNotifier<AmountFormat> {
|
class AmountFormatNotifier extends Notifier<AmountFormat> {
|
||||||
AmountFormatNotifier() : super(AmountFormat.commasDot) {
|
@override
|
||||||
|
AmountFormat build() {
|
||||||
_load();
|
_load();
|
||||||
|
return AmountFormat.commasDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _load() async {
|
void _load() async {
|
||||||
@@ -20,6 +22,6 @@ class AmountFormatNotifier extends StateNotifier<AmountFormat> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final amountFormatProvider = StateNotifierProvider<AmountFormatNotifier, AmountFormat>(
|
final amountFormatProvider = NotifierProvider<AmountFormatNotifier, AmountFormat>(
|
||||||
(ref) => AmountFormatNotifier(),
|
AmountFormatNotifier.new,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,10 +6,6 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
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,10 +3,10 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
sqlite3_flutter_libs
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
jni
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import Foundation
|
|||||||
|
|
||||||
import local_auth_darwin
|
import local_auth_darwin
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqlite3_flutter_libs
|
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
|
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
|
||||||
}
|
}
|
||||||
|
|||||||
+196
-92
@@ -5,18 +5,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
|
sha256: a49d6cf99e8d8e7a8e93668d09ced0bbdb954d0b4fccc2f5f9241c6b87fad95c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "93.0.0"
|
version: "99.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
|
sha256: "663efa951fb8a45e06f491223a604c93820598f20e6a99c25617a1576065e8b7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.1"
|
version: "12.1.0"
|
||||||
ansicolor:
|
ansicolor:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -45,10 +45,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -61,10 +61,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c
|
sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.5"
|
version: "4.0.6"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -85,10 +85,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "521daf8d189deb79ba474e43a696b41c49fb3987818dbacf3308f1e03673a75e"
|
sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.1"
|
version: "2.15.0"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -101,10 +101,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "6ae8a6435a8c6520c7077b107e77f1fb4ba7009633259a4d49a8afd8e7efc5e9"
|
sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.12.4"
|
version: "8.12.6"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -129,6 +129,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.4"
|
||||||
|
cli_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_config
|
||||||
|
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
cli_util:
|
cli_util:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -149,18 +157,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_assets
|
name: code_assets
|
||||||
sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687"
|
sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.2.1"
|
||||||
code_builder:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: code_builder
|
|
||||||
sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.11.1"
|
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -177,6 +177,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
|
coverage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: coverage
|
||||||
|
sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.15.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -197,34 +205,34 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.9"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
|
sha256: a4c1ccfee44c7e75ed80484071a5c142a385345e658fd8bd7c4b5c97e7198f98
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.7"
|
version: "3.1.8"
|
||||||
drift:
|
drift:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: drift
|
name: drift
|
||||||
sha256: "055c249d1f91be5a47fe447f88afc24c4ca6f4cd6c5ed66767b4797d48acc2e5"
|
sha256: "6cc0b623c0e83f7080524d8396e9301b1d78b9c66a4fdceeb0f798211303254c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.32.1"
|
version: "2.34.0"
|
||||||
drift_dev:
|
drift_dev:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
sha256: "88a9de3af8571518148a6d8a513b57779fd1e60a026d3ab8a481a878fba01d91"
|
sha256: "9cfff1576b49725da0d32c040651a41ae195e8c4af8d8da301593e41d7abc2f7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.32.1"
|
version: "2.34.0"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -269,10 +277,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: fl_chart
|
name: fl_chart
|
||||||
sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08"
|
sha256: b938f77d042cbcd822936a7a359a7235bad8bd72070de1f827efc2cc297ac888
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.69.2"
|
version: "1.2.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -306,26 +314,26 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_native_splash
|
name: flutter_native_splash
|
||||||
sha256: "4fb9f4113350d3a80841ce05ebf1976a36de622af7d19aca0ca9a9911c7ff002"
|
sha256: "9db4b80b044e9af17cc4b1272137fc7ace0054d879ef8210a76adc34aaf4cdff"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.7"
|
version: "2.4.8"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1
|
sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.33"
|
version: "2.0.35"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_riverpod
|
name: flutter_riverpod
|
||||||
sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1"
|
sha256: "9255e1e3ad6e38906a1b4f8287678f95f378744c5b46b1985588543f3f19046e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "3.3.2"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -336,6 +344,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -348,18 +364,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3
|
sha256: "5922b2861e2235a3504896f0d6fa07d84141b480cf52eecd2f42cd25585a9e8a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.8.1"
|
version: "17.3.0"
|
||||||
google_fonts:
|
google_fonts:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_fonts
|
name: google_fonts
|
||||||
sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055
|
sha256: "4e9391085e524954a51e3625b7c9c7e9851dc3f376603208bb45c24b9a66255d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.3"
|
version: "8.1.0"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -372,10 +388,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hooks
|
name: hooks
|
||||||
sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388
|
sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "2.0.2"
|
||||||
html:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -412,18 +428,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
|
sha256: "6300175e00616bbc832e2fc91bfa4d776af5402c81c7151bee6905bb08473c52"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.0"
|
version: "4.9.1"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: intl
|
name: intl
|
||||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.19.0"
|
version: "0.20.2"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -432,14 +448,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
jni:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: jni
|
||||||
|
sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
jni_flutter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: jni_flutter
|
||||||
|
sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8
|
sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.11.0"
|
version: "4.12.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -476,26 +508,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: local_auth
|
name: local_auth
|
||||||
sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b"
|
sha256: ae6f382f638108c6becd134318d7c3f0a93875383a54010f61d7c97ac05d5137
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "3.0.1"
|
||||||
local_auth_android:
|
local_auth_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_android
|
name: local_auth_android
|
||||||
sha256: a0bdfcc0607050a26ef5b31d6b4b254581c3d3ce3c1816ab4d4f4a9173e84467
|
sha256: fdb936d59ab945c7af297defd67bd1ed87b11b6db1bc16d01e94677a8f1c38ec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.56"
|
version: "2.0.9"
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_darwin
|
name: local_auth_darwin
|
||||||
sha256: "699873970067a40ef2f2c09b4c72eb1cfef64224ef041b3df9fdc5c4c1f91f49"
|
sha256: a8c3d4e17454111f7fd31ff72a31222359f6059f7fe956c2dcfe0f88f49826d4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.1"
|
version: "2.0.3"
|
||||||
local_auth_platform_interface:
|
local_auth_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -508,10 +540,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_windows
|
name: local_auth_windows
|
||||||
sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
|
sha256: be12c5b8ba5e64896983123655c5f67d2484ecfcc95e367952ad6e3bff94cb16
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.11"
|
version: "2.0.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -540,10 +572,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -556,18 +588,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: native_toolchain_c
|
name: native_toolchain_c
|
||||||
sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572"
|
sha256: f59351d28f49520cd3a74eb1f41c5f19ae15e53c65a3231d14af672e46510a96
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.17.6"
|
version: "0.19.1"
|
||||||
|
node_preamble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_preamble
|
||||||
|
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
objective_c:
|
objective_c:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: objective_c
|
name: objective_c
|
||||||
sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52"
|
sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.3.0"
|
version: "9.4.1"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -596,10 +636,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e
|
sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.22"
|
version: "2.3.1"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -696,22 +736,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.0"
|
||||||
|
record_use:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: record_use
|
||||||
|
sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.0"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: riverpod
|
name: riverpod
|
||||||
sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959"
|
sha256: "17100416c51db7810c71a7bb2c34d1f881faa0074fd452afb0c4db6f8f126c76"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "3.3.2"
|
||||||
sensors_plus:
|
sensors_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sensors_plus
|
name: sensors_plus
|
||||||
sha256: "89e2bfc3d883743539ce5774a2b93df61effde40ff958ecad78cd66b1a8b8d52"
|
sha256: "56e8cd4260d9ed8e00ecd8da5d9fdc8a1b2ec12345a750dfa51ff83fcf12e3fa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.2"
|
version: "7.0.0"
|
||||||
sensors_plus_platform_interface:
|
sensors_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -724,18 +772,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64"
|
sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.4"
|
version: "2.5.5"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41"
|
sha256: "93ae5884a9df5d3bb696825bceb3a17590754548b5d740eba51500afc8d088f5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.21"
|
version: "2.4.26"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -756,10 +804,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -784,6 +832,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.2"
|
version: "1.4.2"
|
||||||
|
shelf_packages_handler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_packages_handler
|
||||||
|
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -801,10 +865,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd"
|
sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "4.2.3"
|
||||||
|
source_map_stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_map_stack_trace
|
||||||
|
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
source_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_maps
|
||||||
|
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.13"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -817,26 +897,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: caa693ad15a587a2b4fde093b728131a1827903872171089dedb16f7665d3a91
|
sha256: "37356bcb56ce0d9404d602c41e4bdb7765e7e9732a3e47adb3d98c556a6abdad"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "3.3.3"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3_flutter_libs
|
name: sqlite3_flutter_libs
|
||||||
sha256: eeb9e3a45207649076b808f8a5a74d68770d0b7f26ccef6d5f43106eee5375ad
|
sha256: "3ed7553eee7bb368f8950f58ba29f634e06e813c029aff6a0d60862b96de8454"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.42"
|
version: "0.6.0+eol"
|
||||||
sqlparser:
|
sqlparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlparser
|
name: sqlparser
|
||||||
sha256: ab2b467425f1d4f3acfa5fd11a08226f7d6c26ff102c06be1807e1dff34e050b
|
sha256: "40bdddb306a727be9ce510bd2d2b9a6c9db6c586d846ef7b22e3990a2b24f02d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.44.3"
|
version: "0.44.5"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -885,14 +965,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.2"
|
||||||
|
test:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test
|
||||||
|
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.31.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
|
test_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_core
|
||||||
|
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.17"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -929,10 +1025,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.2.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -965,6 +1061,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -977,10 +1081,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xml
|
name: xml
|
||||||
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.6.1"
|
version: "7.0.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -990,5 +1094,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.11.1 <4.0.0"
|
dart: ">=3.12.0 <4.0.0"
|
||||||
flutter: ">=3.38.4"
|
flutter: ">=3.44.0"
|
||||||
|
|||||||
+8
-8
@@ -10,20 +10,20 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
flutter_riverpod: ^2.6.1
|
flutter_riverpod: ^3.3.2
|
||||||
go_router: ^14.6.2
|
go_router: ^17.3.0
|
||||||
shared_preferences: ^2.3.3
|
shared_preferences: ^2.3.3
|
||||||
fl_chart: ^0.69.0
|
fl_chart: ^1.2.0
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^8.1.0
|
||||||
intl: ^0.19.0
|
intl: ^0.20.2
|
||||||
uuid: ^4.5.1
|
uuid: ^4.5.1
|
||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
http: ^1.2.0
|
http: ^1.2.0
|
||||||
sensors_plus: ^6.1.0
|
sensors_plus: ^7.0.0
|
||||||
local_auth: ^2.3.0
|
local_auth: ^3.0.1
|
||||||
flutter_colorpicker: ^1.1.0
|
flutter_colorpicker: ^1.1.0
|
||||||
drift: ^2.14.1
|
drift: ^2.14.1
|
||||||
sqlite3_flutter_libs: ^0.5.20
|
sqlite3_flutter_libs: ^0.6.0+eol
|
||||||
path: ^1.8.3
|
path: ^1.8.3
|
||||||
|
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
|
|||||||
@@ -7,11 +7,8 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <local_auth_windows/local_auth_plugin.h>
|
#include <local_auth_windows/local_auth_plugin.h>
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
LocalAuthPluginRegisterWithRegistrar(
|
LocalAuthPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
local_auth_windows
|
local_auth_windows
|
||||||
sqlite3_flutter_libs
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
jni
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|||||||
Reference in New Issue
Block a user