diff --git a/lib/data/transactions_filter.dart b/lib/data/transactions_filter.dart index 4867cdd..43eb70b 100644 --- a/lib/data/transactions_filter.dart +++ b/lib/data/transactions_filter.dart @@ -36,11 +36,22 @@ class TransactionFilter { final bool sortDescending; final TransactionSortField sortBy; + final bool? isPending; + + final double? minAmount; + final double? maxAmount; + + final List? currencies; + const TransactionFilter({ this.categories, this.accounts, this.range, this.types, + this.isPending = false, + this.minAmount, + this.maxAmount, + this.currencies, this.sortDescending = true, this.searchData = const TransactionSearchData(), this.sortBy = TransactionSortField.transactionDate, @@ -125,6 +136,28 @@ class TransactionFilter { .oneOf(accounts!.map((account) => account.uuid).toList())); } + if (minAmount != null) { + conditions.add(Transaction_.amount.greaterOrEqual(minAmount!)); + } + + if (maxAmount != null) { + conditions.add(Transaction_.amount.lessOrEqual(maxAmount!)); + } + + if (currencies?.isNotEmpty == true) { + conditions.add(Transaction_.currency.oneOf(currencies!)); + } + + if (isPending != null) { + if (isPending!) { + conditions.add(Transaction_.isPending.equals(true)); + } else { + conditions.add(Transaction_.isPending + .notEquals(true) + .or(Transaction_.isPending.isNull())); + } + } + final filtered = ObjectBox() .box() .query(conditions.reduce((a, b) => a & b)); diff --git a/lib/main.dart b/lib/main.dart index 82f9e45..af196f8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -155,38 +155,15 @@ class FlowState extends State { } void _reloadTheme() { - final ThemeMode legacyThemeMode = - LocalPreferences().themeMode.value ?? ThemeMode.system; final String? themeName = LocalPreferences().themeName.value; log("[Theme] Reloading theme $themeName"); - ({FlowColorScheme scheme, ThemeMode mode})? experimentalTheme = - getTheme(themeName); - - if (experimentalTheme == null) { - final bool fallbackToDarkTheme = - switch ((legacyThemeMode, useDarkTheme)) { - (ThemeMode.system, true) => true, - (ThemeMode.system, false) => true, - (ThemeMode.dark, _) => true, - (ThemeMode.light, _) => false - }; - - log("[Theme] Didn't find theme for $themeName"); - unawaited( - LocalPreferences() - .themeName - .set((fallbackToDarkTheme ? darkThemes : lightThemes).keys.first), - ); - } + FlowColorScheme theme = getTheme(themeName, useDarkTheme); setState(() { - _themeMode = experimentalTheme?.mode ?? legacyThemeMode; - _themeFactory = ThemeFactory( - experimentalTheme?.scheme ?? - (useDarkTheme ? electricLavender : shadeOfViolet), - ); + _themeMode = theme.mode; + _themeFactory = ThemeFactory(theme); }); } @@ -213,6 +190,7 @@ class FlowState extends State { MomentLocalizations.byLocale(overriddenLocale.code) ?? MomentLocalizations.enUS(), ); + Intl.defaultLocale = overriddenLocale.code; setState(() {}); } diff --git a/lib/prefs.dart b/lib/prefs.dart index 5098a3c..19b81b2 100644 --- a/lib/prefs.dart +++ b/lib/prefs.dart @@ -11,7 +11,6 @@ import "package:flow/entity/transaction.dart"; import "package:flow/objectbox.dart"; import "package:flow/objectbox/objectbox.g.dart"; import "package:flow/theme/color_themes/registry.dart"; -import "package:flutter/material.dart"; import "package:intl/intl.dart"; import "package:local_settings/local_settings.dart"; import "package:moment_dart/moment_dart.dart"; @@ -73,7 +72,6 @@ class LocalPreferences { late final BoolSettingsEntry autoAttachTransactionGeo; - late final ThemeModeSettingsEntry themeMode; late final PrimitiveSettingsEntry themeName; late final BoolSettingsEntry themeChangesAppIcon; late final BoolSettingsEntry enableDynamicTheme; @@ -175,11 +173,6 @@ class LocalPreferences { initialValue: false, ); - themeMode = ThemeModeSettingsEntry( - key: "themeMode", - preferences: _prefs, - initialValue: ThemeMode.system, - ); themeName = PrimitiveSettingsEntry( key: "themeName", preferences: _prefs, diff --git a/lib/routes/preferences_page.dart b/lib/routes/preferences_page.dart index e8a1663..a8f87cd 100644 --- a/lib/routes/preferences_page.dart +++ b/lib/routes/preferences_page.dart @@ -28,7 +28,7 @@ class _PreferencesPageState extends State { @override Widget build(BuildContext context) { final FlowColorScheme currentTheme = - getTheme(LocalPreferences().themeName.get())?.scheme ?? shadeOfViolet; + getTheme(LocalPreferences().themeName.get()); final UpcomingTransactionsDuration homeTabPlannedTransactionsDuration = LocalPreferences().homeTabPlannedTransactionsDuration.get() ?? diff --git a/lib/theme/color_themes/registry.dart b/lib/theme/color_themes/registry.dart index 6bf098a..2d45c47 100644 --- a/lib/theme/color_themes/registry.dart +++ b/lib/theme/color_themes/registry.dart @@ -5,7 +5,6 @@ import "package:flow/theme/color_themes/default_darks.dart"; import "package:flow/theme/color_themes/default_lights.dart"; import "package:flow/theme/color_themes/palenight.dart"; import "package:flow/theme/flow_color_scheme.dart"; -import "package:flutter/material.dart"; import "package:flutter_dynamic_icon_plus/flutter_dynamic_icon_plus.dart"; export "default_darks.dart"; @@ -98,25 +97,17 @@ bool validateThemeName(String? themeName) { return allThemes.containsKey(themeName); } -bool isThemeDark(String? themeName) { - final themeData = getTheme(themeName); - - return themeData?.mode == ThemeMode.dark; -} - -({FlowColorScheme scheme, ThemeMode mode})? getTheme(String? themeName) { - if (themeName == null) return null; +FlowColorScheme getTheme(String? themeName, [bool preferDark = false]) { + if (themeName == null) return preferDark ? electricLavender : shadeOfViolet; final FlowColorScheme? scheme = allThemes[themeName]; if (scheme == null) { log("Unknown theme: $themeName"); - return null; + return preferDark ? electricLavender : shadeOfViolet; } - final mode = scheme.isDark ? ThemeMode.dark : ThemeMode.light; - - return (scheme: scheme, mode: mode); + return scheme; } void trySetThemeIcon(String? name) async { diff --git a/lib/theme/flow_color_scheme.dart b/lib/theme/flow_color_scheme.dart index a4d766b..8a22a31 100644 --- a/lib/theme/flow_color_scheme.dart +++ b/lib/theme/flow_color_scheme.dart @@ -48,6 +48,8 @@ class FlowColorScheme { late final ColorScheme colorScheme; + ThemeMode get mode => isDark ? ThemeMode.dark : ThemeMode.light; + FlowColorScheme({ required this.isDark, required this.surface, diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index 6221a87..54eccc7 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -153,11 +153,18 @@ class ThemeFactory { ); } - factory ThemeFactory.fromThemeName(String? themeName) { - final resolved = getTheme(themeName); - - if (resolved == null) return ThemeFactory(shadeOfViolet); + /// Returns a [ThemeFactory] instance based on the provided [themeName]. + /// + /// If [themeName] is `null`, the default theme is returned. + /// + /// Pass [preferDark] to influence the choice of default theme. + factory ThemeFactory.fromThemeName(String? themeName, + [bool preferDark = false]) { + final resolved = getTheme( + themeName, + preferDark, + ); - return ThemeFactory(resolved.scheme); + return ThemeFactory(resolved); } } diff --git a/lib/utils/extensions/transaction_context_actions.dart b/lib/utils/extensions/transaction_context_actions.dart new file mode 100644 index 0000000..8c0261c --- /dev/null +++ b/lib/utils/extensions/transaction_context_actions.dart @@ -0,0 +1,28 @@ +import "package:flow/entity/transaction.dart"; +import "package:flow/l10n/extensions.dart"; +import "package:flow/objectbox/actions.dart"; +import "package:flow/utils/utils.dart"; +import "package:flutter/widgets.dart"; + +extension TransactionContextActions on BuildContext { + Future deleteTransaction(Transaction transaction) async { + final String txnTitle = + transaction.title ?? "transaction.fallbackTitle".t(this); + + final confirmation = await showConfirmDialog( + isDeletionConfirmation: true, + title: "general.delete.confirmName".t(this, txnTitle), + ); + + if (confirmation == true) { + transaction.delete(); + } + } + + Future confirmTransaction( + Transaction transaction, [ + bool confirm = true, + ]) async { + transaction.confirm(confirm); + } +} diff --git a/lib/widgets/grouped_transaction_list.dart b/lib/widgets/grouped_transaction_list.dart index 8ebd120..4450967 100644 --- a/lib/widgets/grouped_transaction_list.dart +++ b/lib/widgets/grouped_transaction_list.dart @@ -1,10 +1,8 @@ import "package:flow/data/transactions_filter.dart"; import "package:flow/entity/transaction.dart"; -import "package:flow/l10n/extensions.dart"; -import "package:flow/objectbox/actions.dart"; import "package:flow/prefs.dart"; -import "package:flow/utils/utils.dart"; -import "package:flow/widgets/grouped_transaction_list/pending_group_header.dart"; +import "package:flow/utils/extensions/transaction_context_actions.dart"; +import "package:flow/widgets/grouped_transaction_list/default_pending_group_header.dart"; import "package:flow/widgets/transaction_list_tile.dart"; import "package:flutter/material.dart"; import "package:moment_dart/moment_dart.dart"; @@ -109,7 +107,9 @@ class _GroupedTransactionListState extends State { final Widget? header = widget.header ?? (widget.implyHeader - ? PendingGroupHeader(futureTransactions: widget.pendingTransactions) + ? DefaultPendingGroupHeader( + futureTransactions: widget.pendingTransactions, + ) : null); final List flattened = [ @@ -147,9 +147,9 @@ class _GroupedTransactionListState extends State { transaction: transaction, padding: widget.itemPadding, dismissibleKey: ValueKey(transaction.id), - deleteFn: () => deleteTransaction(context, transaction), + deleteFn: () => context.deleteTransaction(transaction), confirmFn: ([bool confirm = true]) => - confirmTransaction(context, transaction, confirm), + context.confirmTransaction(transaction, confirm), overrideObscure: widget.overrideObscure, ), (_) => Container(), @@ -158,31 +158,6 @@ class _GroupedTransactionListState extends State { ); } - Future deleteTransaction( - BuildContext context, - Transaction transaction, - ) async { - final String txnTitle = - transaction.title ?? "transaction.fallbackTitle".t(context); - - final confirmation = await context.showConfirmDialog( - isDeletionConfirmation: true, - title: "general.delete.confirmName".t(context, txnTitle), - ); - - if (confirmation == true) { - transaction.delete(); - } - } - - Future confirmTransaction( - BuildContext context, - Transaction transaction, [ - bool confirm = true, - ]) async { - transaction.confirm(confirm); - } - _privacyModeUpdate() { globalPrivacyMode = LocalPreferences().sessionPrivacyMode.get(); if (!mounted) return; diff --git a/lib/widgets/grouped_transaction_list/pending_group_header.dart b/lib/widgets/grouped_transaction_list/default_pending_group_header.dart similarity index 93% rename from lib/widgets/grouped_transaction_list/pending_group_header.dart rename to lib/widgets/grouped_transaction_list/default_pending_group_header.dart index 4e45abd..c7b98bb 100644 --- a/lib/widgets/grouped_transaction_list/pending_group_header.dart +++ b/lib/widgets/grouped_transaction_list/default_pending_group_header.dart @@ -6,10 +6,10 @@ import "package:flutter/material.dart"; import "package:go_router/go_router.dart"; import "package:moment_dart/moment_dart.dart"; -class PendingGroupHeader extends StatelessWidget { +class DefaultPendingGroupHeader extends StatelessWidget { final Map>? futureTransactions; - const PendingGroupHeader({ + const DefaultPendingGroupHeader({ super.key, required this.futureTransactions, }); diff --git a/lib/widgets/theme_petal_selector.dart b/lib/widgets/theme_petal_selector.dart index 6c988a9..273aace 100644 --- a/lib/widgets/theme_petal_selector.dart +++ b/lib/widgets/theme_petal_selector.dart @@ -93,7 +93,7 @@ class _ThemePetalSelectorState extends State @override Widget build(BuildContext context) { final String currentTheme = LocalPreferences().getCurrentTheme(); - final bool isDark = isThemeDark(currentTheme); + final bool isDark = getTheme(currentTheme).isDark; final int selectedIndex = isDark ? lightDarkThemeMapping.values.toList().indexOf(currentTheme) : lightDarkThemeMapping.keys.toList().indexOf(currentTheme);