import 'package:flutter/material.dart'; import 'package:frontend/provider/quote_provider.dart'; import 'package:frontend/model/quote.dart'; import 'package:frontend/values/strings.dart'; import 'package:provider/provider.dart'; import 'package:frontend/values/constants.dart'; class ListPage extends StatelessWidget { const ListPage({super.key}); @override Widget build(BuildContext context) { final provider = context.watch(); return RefreshIndicator( onRefresh: () async { await provider.readQuotes(); }, child: _bodyBuilder(context, provider), ); } Widget _bodyBuilder(BuildContext context, QuoteProvider provider) { if (provider.loading) { return Center(child: CircularProgressIndicator()); } if (provider.error != null) { return Center(child: Text(provider.error!)); } final quoteCount = provider.filteredQuotes.length; return Column( children: [ Center( child: Padding( padding: const EdgeInsets.all(Constants.edgeInset), child: Text( '${Strings.allQuotesCount} – $quoteCount', style: TextStyle(fontSize: 18), ), ), ), filterBar(context, provider), Expanded( child: ListView.builder( padding: EdgeInsets.all(Constants.edgeInset), itemCount: provider.filteredQuotes.length, itemBuilder: (context, index) { final quote = provider.filteredQuotes[index]; return ListTile( contentPadding: EdgeInsets.only( bottom: Constants.edgeInset, left: Constants.edgeInset, right: Constants.edgeInset, ), title: Text(quote.body), subtitle: Text("– ${quote.author}"), trailing: PopupMenuButton( icon: const Icon(Icons.more_vert), onSelected: (value) { if (value == 'update') { // open a dialog window that allows for mods _showUpdateDialog(context, provider, quote); } else if (value == 'delete') { // open a confirmation dialog window for deletion _showDeleteDialog(context, provider, quote); } }, itemBuilder: (context) => [ const PopupMenuItem( value: 'update', child: Row( children: [ Icon(Icons.edit), SizedBox(width: 10), Text(Strings.updateQuote), ], ), ), const PopupMenuItem( value: 'delete', child: Row( children: [ Icon(Icons.delete), SizedBox(width: 10), Text(Strings.deleteQuote), ], ), ), ], ) ); }, ), ), ], ); } void _showUpdateDialog(BuildContext context, QuoteProvider provider, Quote quote) { final bodyController = TextEditingController(text: quote.body); final authorController = TextEditingController(text: quote.author); showDialog( context: context, builder: (context) { return AlertDialog( title: Text(Strings.updateQuote), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( autofocus: true, controller: bodyController, ), TextField( controller: authorController, decoration: InputDecoration( label: Text(Strings.author), suffixIcon: IconButton( icon: Icon(Icons.arrow_drop_down), onPressed: () { showModalBottomSheet( context: context, builder: (context) { var authors = provider.authors.toList()..sort(); return SizedBox( height: 300, child: ListView.builder( padding: const EdgeInsets.all(Constants.edgeInset), itemCount: authors.length, itemBuilder: (context, index) { final author = authors[index]; return ListTile( title: Text(author), onTap: () { authorController.text = author; Navigator.pop(context); }, ); }, ), ); }, ); }, ), ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text(Strings.cancel), ), ElevatedButton( onPressed: () { final updatedQuote = Quote( id: quote.id, body: bodyController.text, author: authorController.text, ); Navigator.pop(context); provider.updateQuote(updatedQuote); }, child: const Text(Strings.save), ), ], ); }, ); } void _showDeleteDialog(BuildContext context, QuoteProvider provider, Quote quote) { showDialog( context: context, builder: (context) { return AlertDialog( title: const Text('${Strings.deleteQuote}?'), content: const Text(Strings.noUndo), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text(Strings.cancel), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), onPressed: () { Navigator.pop(context); provider.deleteQuote(quote); }, child: const Text(Strings.delete), ), ], ); }, ); } Widget filterBar(BuildContext context, QuoteProvider provider) { return Padding( padding: const EdgeInsets.all(Constants.edgeInset), child: Row( children: [ Expanded( child: TextField( controller: provider.filterController, decoration: InputDecoration( label: Text(Strings.filterQuery), suffixIcon: IconButton( icon: Icon(Icons.cancel), onPressed: provider.clearFilterController ) ), ), ), IconButton( icon: Icon(Icons.search), onPressed: provider.filterQuotes, ), IconButton( icon: Icon(Icons.more_horiz), onPressed: () { _showOptionsBottomSheet(context, provider); }, ), ], ), ); } void _showOptionsBottomSheet(BuildContext context, QuoteProvider provider) { showModalBottomSheet( context: context, builder: (context) { return SizedBox( height: 300, child: ListView( padding: const EdgeInsets.all(Constants.edgeInset), children: [ ListTile( title: Text(Strings.filterBy), trailing: Icon(Icons.filter_alt), ), ListTile( title: Text(Strings.exportSelectedQuotes), trailing: Icon(Icons.import_export), ), ], ) ); }, ); } }