added prototype of the filter bar + all quotes count

This commit is contained in:
Odweta
2026-03-23 11:06:39 +01:00
parent 67008188b9
commit 2085f010f1
4 changed files with 141 additions and 70 deletions
+129 -52
View File
@@ -17,11 +17,11 @@ class ListPage extends StatelessWidget {
onRefresh: () async { onRefresh: () async {
await provider.readQuotes(); await provider.readQuotes();
}, },
child: _bodyBuilder(provider), child: _bodyBuilder(context, provider),
); );
} }
Widget _bodyBuilder(QuoteProvider provider) { Widget _bodyBuilder(BuildContext context, QuoteProvider provider) {
if (provider.loading) { if (provider.loading) {
return Center(child: CircularProgressIndicator()); return Center(child: CircularProgressIndicator());
} }
@@ -30,61 +30,79 @@ class ListPage extends StatelessWidget {
return Center(child: Text(provider.error!)); return Center(child: Text(provider.error!));
} }
final quoteCount = provider.quotes.length;
return return
ListView.builder( Column(
padding: EdgeInsets.all(Constants.edgeInset), children: [
itemCount: provider.quotes.length, Center(
itemBuilder: (context, index) { child: Padding(
final quote = provider.quotes[index]; 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.quotes.length,
itemBuilder: (context, index) {
final quote = provider.quotes[index];
return return
ListTile( ListTile(
contentPadding: EdgeInsets.only( contentPadding: EdgeInsets.only(
bottom: Constants.edgeInset, bottom: Constants.edgeInset,
left: Constants.edgeInset, left: Constants.edgeInset,
right: 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),
],
), ),
), title: Text(quote.body),
subtitle: Text(" ${quote.author}"),
trailing: PopupMenuButton<String>(
icon: const Icon(Icons.more_vert),
const PopupMenuItem( onSelected: (value) {
value: 'delete', if (value == 'update') {
child: Row( // open a dialog window that allows for mods
children: [ _showUpdateDialog(context, provider, quote);
Icon(Icons.delete), } else if (value == 'delete') {
SizedBox(width: 10), // open a confirmation dialog window for deletion
Text(Strings.deleteQuote), _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),
],
),
),
], ],
), )
), );
], },
) ),
); ),
}, ],
); );
} }
@@ -191,4 +209,63 @@ class ListPage extends StatelessWidget {
}, },
); );
} }
Widget filterBar(BuildContext context, QuoteProvider provider) {
int filterBy = 0; // 0 = by author, 1 = by quote
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: () {
// TODO: filtering
},
),
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),
),
],
)
);
},
);
}
} }
@@ -18,6 +18,12 @@ class QuoteProvider extends ChangeNotifier {
final QuoteRepository repo = QuoteRepository(); final QuoteRepository repo = QuoteRepository();
var filterController = TextEditingController(text: '');
void clearFilterController() {
filterController.text = '';
}
QuoteProvider() { QuoteProvider() {
readQuotes(); // auto-load on creation readQuotes(); // auto-load on creation
} }
@@ -1,16 +0,0 @@
// talks to the DB itself
// TODO: mock for now!
import 'package:frontend/model/quote.dart';
class QuoteRepository {
//final String _dbBaseUrl = 'https://hlaskovnik-reimagined-latest.onrender.com';
Future<List<Quote>> getQuotes() async {
return [
Quote(id: 1, author: 'Adam', body: 'kratom je vule bozi'),
Quote(id: 2, author: 'Vojta', body: 'kalach s kecupem'),
Quote(id: 3, author: 'Anton', body: 'have you ever noticed how long cows are'),
];
}
}
+4
View File
@@ -20,4 +20,8 @@ class Strings {
static const String author = "Autor"; static const String author = "Autor";
static const String noUndo = "Tuto akci nelze odčinit."; static const String noUndo = "Tuto akci nelze odčinit.";
static const String filterQuery = "Filtrovací požadavek";
static const String allQuotesCount = "Celkový počet hlášek";
static const String filterBy = "Filtrovat podle";
static const String exportSelectedQuotes = "Exportovat vybrané hlášky";
} }