This commit is contained in:
2026-03-22 17:25:22 +03:00
parent f013753f80
commit d67d8cb89c
3 changed files with 135 additions and 34 deletions
-1
View File
@@ -5,7 +5,6 @@ import '../core/constants.dart';
TextStyle? _f(TextStyle? s) { TextStyle? _f(TextStyle? s) {
final result = s?.copyWith(fontFamilyFallback: ['NunitoCyrillic']); final result = s?.copyWith(fontFamilyFallback: ['NunitoCyrillic']);
debugPrint('fallback: ${result?.fontFamilyFallback}'); // проверь в логах
return result; return result;
} }
+5 -2
View File
@@ -16,7 +16,6 @@ class CardColorService {
static const defaultGradient = GradientType.sweep; static const defaultGradient = GradientType.sweep;
static Future<(Color, Color, GradientType)> load() async { static Future<(Color, Color, GradientType)> load() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final c1 = prefs.getInt(_key1); final c1 = prefs.getInt(_key1);
@@ -29,7 +28,11 @@ class CardColorService {
); );
} }
static Future<void> save(Color primary, Color secondary, GradientType gradient) async { static Future<void> save(
Color primary,
Color secondary,
GradientType gradient,
) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setInt(_key1, primary.value); await prefs.setInt(_key1, primary.value);
await prefs.setInt(_key2, secondary.value); await prefs.setInt(_key2, secondary.value);
+125 -26
View File
@@ -18,7 +18,7 @@ final transactionsProvider =
StateNotifierProvider<TransactionsNotifier, List<Transaction>>((ref) { StateNotifierProvider<TransactionsNotifier, List<Transaction>>((ref) {
final storage = ref.watch(storageServiceProvider); final storage = ref.watch(storageServiceProvider);
return TransactionsNotifier(storage); return TransactionsNotifier(storage);
}); });
class TransactionsNotifier extends StateNotifier<List<Transaction>> { class TransactionsNotifier extends StateNotifier<List<Transaction>> {
final StorageService _storage; final StorageService _storage;
@@ -47,7 +47,9 @@ class TransactionsNotifier extends StateNotifier<List<Transaction>> {
void clearAll() { void clearAll() {
state = []; state = [];
SharedPreferences.getInstance().then((prefs) => prefs.remove('transactions')); SharedPreferences.getInstance().then(
(prefs) => prefs.remove('transactions'),
);
} }
} }
@@ -57,10 +59,13 @@ enum TransactionFilter { all, income, expense }
enum TimeFilter { allTime, lastMonth } enum TimeFilter { allTime, lastMonth }
final transactionFilterProvider = final transactionFilterProvider = StateProvider<TransactionFilter>(
StateProvider<TransactionFilter>((ref) => TransactionFilter.all); (ref) => TransactionFilter.all,
);
final timeFilterProvider = StateProvider<TimeFilter>((ref) => TimeFilter.lastMonth); final timeFilterProvider = StateProvider<TimeFilter>(
(ref) => TimeFilter.lastMonth,
);
final totalBalanceProvider = Provider<double>((ref) { final totalBalanceProvider = Provider<double>((ref) {
final txs = ref.watch(transactionsProvider); final txs = ref.watch(transactionsProvider);
@@ -68,42 +73,57 @@ final totalBalanceProvider = Provider<double>((ref) {
final targetCurrency = ref.watch(currencyProvider).code; final targetCurrency = ref.watch(currencyProvider).code;
return txs.fold(0.0, (sum, t) { return txs.fold(0.0, (sum, t) {
final converted = exchangeService.convert(t.amount, t.currencyCode, targetCurrency); final converted = exchangeService.convert(
t.amount,
t.currencyCode,
targetCurrency,
);
return t.type == TransactionType.income ? sum + converted : sum - converted; return t.type == TransactionType.income ? sum + converted : sum - converted;
}); });
}); });
final totalIncomeProvider = Provider<double>((ref) { final totalIncomeProvider = Provider<double>((ref) {
final txs = ref.watch(transactionsProvider).where((t) => t.type == TransactionType.income); final txs = ref
.watch(transactionsProvider)
.where((t) => t.type == TransactionType.income);
final exchangeService = ref.watch(exchangeRateServiceProvider); final exchangeService = ref.watch(exchangeRateServiceProvider);
final targetCurrency = ref.watch(currencyProvider).code; final targetCurrency = ref.watch(currencyProvider).code;
return txs.fold(0.0, (sum, t) { return txs.fold(0.0, (sum, t) {
return sum + exchangeService.convert(t.amount, t.currencyCode, targetCurrency); return sum +
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
}); });
}); });
final totalExpenseProvider = Provider<double>((ref) { final totalExpenseProvider = Provider<double>((ref) {
final txs = ref.watch(transactionsProvider).where((t) => t.type == TransactionType.expense); final txs = ref
.watch(transactionsProvider)
.where((t) => t.type == TransactionType.expense);
final exchangeService = ref.watch(exchangeRateServiceProvider); final exchangeService = ref.watch(exchangeRateServiceProvider);
final targetCurrency = ref.watch(currencyProvider).code; final targetCurrency = ref.watch(currencyProvider).code;
return txs.fold(0.0, (sum, t) { return txs.fold(0.0, (sum, t) {
return sum + exchangeService.convert(t.amount, t.currencyCode, targetCurrency); return sum +
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
}); });
}); });
final currentMonthExpenseProvider = Provider<double>((ref) { final currentMonthExpenseProvider = Provider<double>((ref) {
final now = DateTime.now(); final now = DateTime.now();
final txs = ref.watch(transactionsProvider).where((t) => final txs = ref
.watch(transactionsProvider)
.where(
(t) =>
t.type == TransactionType.expense && t.type == TransactionType.expense &&
t.date.year == now.year && t.date.year == now.year &&
t.date.month == now.month); t.date.month == now.month,
);
final exchangeService = ref.watch(exchangeRateServiceProvider); final exchangeService = ref.watch(exchangeRateServiceProvider);
final targetCurrency = ref.watch(currencyProvider).code; final targetCurrency = ref.watch(currencyProvider).code;
return txs.fold(0.0, (sum, t) { return txs.fold(0.0, (sum, t) {
return sum + exchangeService.convert(t.amount, t.currencyCode, targetCurrency); return sum +
exchangeService.convert(t.amount, t.currencyCode, targetCurrency);
}); });
}); });
@@ -119,16 +139,21 @@ final filteredTransactionsProvider = Provider<List<Transaction>>((ref) {
final now = DateTime.now(); final now = DateTime.now();
final start = DateTime(now.year, now.month, 1); final start = DateTime(now.year, now.month, 1);
final end = DateTime(now.year, now.month + 1, 1); final end = DateTime(now.year, now.month + 1, 1);
filtered = filtered.where((t) => filtered = filtered
.where(
(t) =>
t.date.isAfter(start.subtract(const Duration(seconds: 1))) && t.date.isAfter(start.subtract(const Duration(seconds: 1))) &&
t.date.isBefore(end) t.date.isBefore(end),
).toList(); )
.toList();
} }
if (typeFilter == TransactionFilter.income) { if (typeFilter == TransactionFilter.income) {
filtered = filtered.where((t) => t.type == TransactionType.income).toList(); filtered = filtered.where((t) => t.type == TransactionType.income).toList();
} else if (typeFilter == TransactionFilter.expense) { } else if (typeFilter == TransactionFilter.expense) {
filtered = filtered.where((t) => t.type == TransactionType.expense).toList(); filtered = filtered
.where((t) => t.type == TransactionType.expense)
.toList();
} }
if (query.isNotEmpty) { if (query.isNotEmpty) {
@@ -155,34 +180,108 @@ class CardColors {
const CardColors(this.primary, this.secondary, this.gradientType); const CardColors(this.primary, this.secondary, this.gradientType);
} }
final cardColorsProvider = StateNotifierProvider<CardColorsNotifier, CardColors>((ref) { final cardColorsProvider =
return CardColorsNotifier(); StateNotifierProvider<CardColorsNotifier, CardColors>((ref) {
}); final notifier = CardColorsNotifier();
notifier.setupThemeListener(ref);
return notifier;
});
class CardColorsNotifier extends StateNotifier<CardColors> { class CardColorsNotifier extends StateNotifier<CardColors> {
CardColorsNotifier() CardColorsNotifier()
: super(const CardColors( : super(
const CardColors(
CardColorService.defaultPrimary, CardColorService.defaultPrimary,
CardColorService.defaultSecondary, CardColorService.defaultSecondary,
CardColorService.defaultGradient, CardColorService.defaultGradient,
)) { ),
) {
_load(); _load();
} }
void setupThemeListener(Ref ref) {
ref.listen<ThemeMode>(themeProvider, (previous, next) {
if (previous != null) {
_onThemeChanged(previous, next);
}
});
}
Future<void> _load() async { Future<void> _load() async {
final (c1, c2, g) = await CardColorService.load(); final (c1, c2, g) = await CardColorService.load();
state = CardColors(c1, c2, g); state = CardColors(c1, c2, g);
} }
Future<void> save(Color primary, Color secondary, GradientType gradient) async { Future<void> save(
Color primary,
Color secondary,
GradientType gradient,
) async {
state = CardColors(primary, secondary, gradient); state = CardColors(primary, secondary, gradient);
await CardColorService.save(primary, secondary, gradient); await CardColorService.save(primary, secondary, gradient);
} }
Future<void> reset(bool isDark) async { Future<void> reset(bool isDark) async {
final primary = isDark ? CardColorService.defaultPrimary : CardColorService.defaultPrimaryLight; final primary = isDark
final secondary = isDark ? CardColorService.defaultSecondary : CardColorService.defaultSecondaryLight; ? CardColorService.defaultPrimary
: CardColorService.defaultPrimaryLight;
final secondary = isDark
? CardColorService.defaultSecondary
: CardColorService.defaultSecondaryLight;
state = CardColors(primary, secondary, CardColorService.defaultGradient); state = CardColors(primary, secondary, CardColorService.defaultGradient);
await CardColorService.save(primary, secondary, CardColorService.defaultGradient); await CardColorService.save(
primary,
secondary,
CardColorService.defaultGradient,
);
}
void _onThemeChanged(ThemeMode previous, ThemeMode next) {
final previousBrightness = _resolve(previous);
final nextBrightness = _resolve(next);
// No change in actual brightness
if (previousBrightness == nextBrightness) return;
final oldDefaults = _defaultsFor(previousBrightness);
final newDefaults = _defaultsFor(nextBrightness);
// Check if current colors match old theme defaults
final isUsingOldDefaults =
state.primary == oldDefaults.primary &&
state.secondary == oldDefaults.secondary &&
state.gradientType == oldDefaults.gradient;
// Only auto-switch if using default colors
if (isUsingOldDefaults) {
state = CardColors(
newDefaults.primary,
newDefaults.secondary,
newDefaults.gradient,
);
}
}
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.defaultGradient,
)
: (
primary: CardColorService.defaultPrimaryLight,
secondary: CardColorService.defaultSecondaryLight,
gradient: CardColorService.defaultGradient,
);
} }
} }