Files
hlaskovnik-reimagined/frontend/lib/pages/list.dart
T
2026-03-23 11:36:02 +01:00

270 lines
8.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<QuoteProvider>();
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.quotes.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<String>(
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),
),
],
)
);
},
);
}
}