Testfilter, Listenbreite

This commit is contained in:
2026-06-26 20:53:21 +02:00
parent a6bd718157
commit a66ed3e6cf
3 changed files with 199 additions and 40 deletions
@@ -11,11 +11,45 @@ import 'movie_add_screen.dart';
enum _ExportFormat { csv, xlsx }
class MovieListScreen extends ConsumerWidget {
class MovieListScreen extends ConsumerStatefulWidget {
const MovieListScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ConsumerState<MovieListScreen> createState() => _MovieListScreenState();
}
class _MovieListScreenState extends ConsumerState<MovieListScreen> {
final TextEditingController _moviePrefixController = TextEditingController();
String _moviePrefix = '';
@override
void initState() {
super.initState();
_moviePrefixController.addListener(() {
final next = _moviePrefixController.text;
if (next == _moviePrefix) return;
setState(() {
_moviePrefix = next;
});
});
}
@override
void dispose() {
_moviePrefixController.dispose();
super.dispose();
}
String get _normalizedMoviePrefix => _moviePrefix.trim().toLowerCase();
bool _matchesMoviePrefix(String title) {
final prefix = _normalizedMoviePrefix;
if (prefix.isEmpty) return true;
return title.trim().toLowerCase().startsWith(prefix);
}
@override
Widget build(BuildContext context) {
final filter = ref.watch(movieFilterProvider);
final moviesAsync = ref.watch(moviesStreamProvider);
@@ -24,9 +58,43 @@ class MovieListScreen extends ConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusChip(
selected: filter,
onChanged: (f) => ref.read(movieFilterProvider.notifier).state = f,
LayoutBuilder(
builder: (context, constraints) {
final searchWidth = constraints.maxWidth >= 360
? 280.0
: constraints.maxWidth;
return Wrap(
spacing: 12,
runSpacing: 8,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
StatusChip(
selected: filter,
onChanged: (f) => ref.read(movieFilterProvider.notifier).state = f,
),
SizedBox(
width: searchWidth,
child: TextField(
controller: _moviePrefixController,
decoration: InputDecoration(
hintText: 'Filme filtern...',
prefixIcon: const Icon(Icons.search),
isDense: true,
border: const OutlineInputBorder(),
suffixIcon: _moviePrefix.isEmpty
? null
: IconButton(
onPressed: _moviePrefixController.clear,
icon: const Icon(Icons.clear),
tooltip: 'Filter loeschen',
),
),
),
),
],
);
},
),
const SizedBox(height: 8),
Align(
@@ -137,8 +205,15 @@ class MovieListScreen extends ConsumerWidget {
Expanded(
child: moviesAsync.when(
data: (items) {
final itemsSorted = [...items]
final itemsSorted = items
.where((m) => _matchesMoviePrefix(m.title))
.toList()
..sort((a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase()));
if (itemsSorted.isEmpty) {
return const Center(
child: Text('Keine Filme fuer den aktuellen Filter.'),
);
}
return RefreshIndicator(
onRefresh: () async {
// ignore: unused_result
@@ -398,3 +473,4 @@ class MovieListScreen extends ConsumerWidget {
);
}
}