search on budget + transactions; extended FAB for add tx; M3 expressive SearchBar
This commit is contained in:
parent
993e4f62a1
commit
83523b1811
25
lib/app.dart
25
lib/app.dart
|
|
@ -93,7 +93,7 @@ class _YnabAppState extends ConsumerState<YnabApp> {
|
|||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
FilledButton.tonal(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
|
|
@ -139,14 +139,12 @@ class _YnabAppState extends ConsumerState<YnabApp> {
|
|||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: _searchActive
|
||||
? TextField(
|
||||
? SearchBar(
|
||||
controller: _searchController,
|
||||
autofocus: true,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Rechercher…',
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
),
|
||||
hintText: 'Rechercher…',
|
||||
leading: const Icon(Icons.search, size: 20),
|
||||
padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 4)),
|
||||
constraints: BoxConstraints.tightFor(height: 44),
|
||||
onChanged: (v) => ref.read(searchQueryProvider.notifier).state = v,
|
||||
)
|
||||
: Text(_navItems[selectedIndex].label),
|
||||
|
|
@ -158,13 +156,13 @@ class _YnabAppState extends ConsumerState<YnabApp> {
|
|||
tooltip: 'Fermer la recherche',
|
||||
)
|
||||
else ...[
|
||||
if (selectedIndex == 0 || selectedIndex == 3)
|
||||
if (selectedIndex == 0)
|
||||
IconButton(
|
||||
icon: Icon(Icons.add, color: colorScheme.primary),
|
||||
onPressed: _addTransaction,
|
||||
tooltip: 'Ajouter une transaction',
|
||||
),
|
||||
if (selectedIndex == 2 || selectedIndex == 3)
|
||||
if (selectedIndex >= 1)
|
||||
IconButton(
|
||||
icon: Icon(Icons.search, color: colorScheme.onSurfaceVariant),
|
||||
onPressed: _toggleSearch,
|
||||
|
|
@ -177,6 +175,13 @@ class _YnabAppState extends ConsumerState<YnabApp> {
|
|||
duration: const Duration(milliseconds: 200),
|
||||
child: _screens[selectedIndex],
|
||||
),
|
||||
floatingActionButton: selectedIndex == 3
|
||||
? FloatingActionButton.extended(
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Transaction'),
|
||||
onPressed: _addTransaction,
|
||||
)
|
||||
: null,
|
||||
bottomNavigationBar: NavigationBar(
|
||||
selectedIndex: selectedIndex,
|
||||
onDestinationSelected: (int index) {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class _AccountCard extends ConsumerWidget {
|
|||
child: const Text('Supprimer'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
TextButton(
|
||||
FilledButton.tonal(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -12,10 +12,25 @@ class BudgetScreen extends ConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final groups = ref.watch(categoryGroupsProvider).valueOrNull ?? [];
|
||||
final catsByGroup = ref.watch(categoriesByGroupProvider);
|
||||
final query = ref.watch(searchQueryProvider).toLowerCase();
|
||||
final now = DateTime.now();
|
||||
final months = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
|
||||
final monthLabel = '${months[now.month]} ${now.year}';
|
||||
|
||||
// filter categories and groups by search query
|
||||
final filteredGroups = query.isEmpty
|
||||
? groups
|
||||
: groups.where((g) {
|
||||
final cats = catsByGroup[g.id] ?? [];
|
||||
return cats.any((c) => c.name.toLowerCase().contains(query));
|
||||
}).toList();
|
||||
final filteredCatsByGroup = query.isEmpty
|
||||
? catsByGroup
|
||||
: catsByGroup.map((key, value) => MapEntry(
|
||||
key,
|
||||
value.where((c) => c.name.toLowerCase().contains(query)).toList(),
|
||||
));
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 90),
|
||||
children: [
|
||||
|
|
@ -33,8 +48,8 @@ class BudgetScreen extends ConsumerWidget {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
...groups.map((group) {
|
||||
final cats = catsByGroup[group.id] ?? [];
|
||||
...filteredGroups.map((group) {
|
||||
final cats = filteredCatsByGroup[group.id] ?? [];
|
||||
if (cats.isEmpty) return const SizedBox.shrink();
|
||||
return _CategoryGroupTile(group: group, categoryIds: cats.map((c) => c.id).toList());
|
||||
}),
|
||||
|
|
@ -119,7 +134,7 @@ class _CategoryRow extends ConsumerWidget {
|
|||
autofocus: true,
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
|
||||
FilledButton.tonal(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
final v = double.tryParse(ctrl.text.trim().replaceAll(',', '.'));
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class DashboardScreen extends ConsumerWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Transactions récentes', style: Theme.of(context).textTheme.titleMedium),
|
||||
TextButton.icon(
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.arrow_forward_ios, size: 14),
|
||||
label: const Text('Voir tout'),
|
||||
|
|
|
|||
|
|
@ -123,6 +123,17 @@ final ThemeData ynabTheme = ThemeData(
|
|||
backgroundColor: kSurfaceCard,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
searchBarTheme: SearchBarThemeData(
|
||||
elevation: WidgetStatePropertyAll(0),
|
||||
backgroundColor: WidgetStatePropertyAll(kSurfaceCard),
|
||||
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
side: BorderSide(color: kDivider),
|
||||
)),
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 8)),
|
||||
textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontSize: 14, color: kTextPrimary)),
|
||||
hintStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontSize: 14, color: kTextSecondary)),
|
||||
),
|
||||
);
|
||||
|
||||
final ThemeData ynabDarkTheme = ThemeData(
|
||||
|
|
|
|||
Loading…
Reference in a new issue