mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 18:35:28 +03:00
stableee
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user