add author selection menu
This commit is contained in:
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'strings.dart';
|
import 'values/strings.dart';
|
||||||
import 'main_scaffold.dart';
|
import 'main_scaffold.dart';
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'strings.dart';
|
import 'values/strings.dart';
|
||||||
|
|
||||||
class MainScaffold extends StatelessWidget {
|
class MainScaffold extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:frontend/provider/quote_provider.dart';
|
import 'package:frontend/provider/quote_provider.dart';
|
||||||
import 'package:frontend/model/quote.dart';
|
import 'package:frontend/model/quote.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:frontend/values/strings.dart';
|
import 'package:frontend/values/strings.dart';
|
||||||
import 'package:frontend/values/constants.dart';
|
import 'package:frontend/values/constants.dart';
|
||||||
|
|
||||||
@@ -12,7 +14,7 @@ class AddPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bodyController = TextEditingController(text: '');
|
final bodyController = TextEditingController(text: '');
|
||||||
final authorController = TextEditingController(text: '');
|
final authorController = TextEditingController(text: '');
|
||||||
final provider = QuoteProvider();
|
final provider = Provider.of<QuoteProvider>(context);
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(Constants.edgeInset),
|
margin: const EdgeInsets.all(Constants.edgeInset),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -40,11 +42,40 @@ class AddPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
controller: authorController,
|
controller: authorController,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: Strings.author,
|
labelText: 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);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'package:frontend/provider/quote_provider.dart';
|
import 'package:frontend/provider/quote_provider.dart';
|
||||||
import 'package:frontend/model/quote.dart';
|
import 'package:frontend/model/quote.dart';
|
||||||
import 'package:frontend/strings.dart';
|
import 'package:frontend/values/strings.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:frontend/values/constants.dart';
|
||||||
|
|
||||||
class ListPage extends StatelessWidget {
|
class ListPage extends StatelessWidget {
|
||||||
const ListPage({super.key});
|
const ListPage({super.key});
|
||||||
|
|
||||||
@@ -30,12 +32,18 @@ class ListPage extends StatelessWidget {
|
|||||||
|
|
||||||
return
|
return
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
|
padding: EdgeInsets.all(Constants.edgeInset),
|
||||||
itemCount: provider.quotes.length,
|
itemCount: provider.quotes.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final quote = provider.quotes[index];
|
final quote = provider.quotes[index];
|
||||||
|
|
||||||
return
|
return
|
||||||
ListTile(
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.only(
|
||||||
|
bottom: Constants.edgeInset,
|
||||||
|
left: Constants.edgeInset,
|
||||||
|
right: Constants.edgeInset,
|
||||||
|
),
|
||||||
title: Text(quote.body),
|
title: Text(quote.body),
|
||||||
subtitle: Text("– ${quote.author}"),
|
subtitle: Text("– ${quote.author}"),
|
||||||
trailing: PopupMenuButton<String>(
|
trailing: PopupMenuButton<String>(
|
||||||
@@ -97,6 +105,39 @@ class ListPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextField(
|
TextField(
|
||||||
controller: authorController,
|
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);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import 'package:frontend/repository/quote_repository.dart';
|
|||||||
|
|
||||||
class QuoteProvider extends ChangeNotifier {
|
class QuoteProvider extends ChangeNotifier {
|
||||||
List<Quote> _quotes = [];
|
List<Quote> _quotes = [];
|
||||||
|
Set<String> _authors = {};
|
||||||
bool _loading = false;
|
bool _loading = false;
|
||||||
String? _error;
|
String? _error;
|
||||||
|
|
||||||
List<Quote> get quotes => _quotes;
|
List<Quote> get quotes => _quotes;
|
||||||
|
Set<String> get authors => _authors;
|
||||||
bool get loading => _loading;
|
bool get loading => _loading;
|
||||||
String? get error => _error;
|
String? get error => _error;
|
||||||
|
|
||||||
@@ -20,6 +22,13 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
readQuotes(); // auto-load on creation
|
readQuotes(); // auto-load on creation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void populateAuthors() {
|
||||||
|
_authors = {};
|
||||||
|
for (var i = 0; i < quotes.length; i++) {
|
||||||
|
_authors.add(quotes[i].author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> readQuotes() async {
|
Future<void> readQuotes() async {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_error = null;
|
_error = null;
|
||||||
@@ -31,6 +40,8 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
_error = e.toString();
|
_error = e.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
populateAuthors();
|
||||||
|
|
||||||
_loading = false;
|
_loading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -38,6 +49,7 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
Future<void> createQuote(Quote quote) async {
|
Future<void> createQuote(Quote quote) async {
|
||||||
final newQuote = await repo.createQuote(quote);
|
final newQuote = await repo.createQuote(quote);
|
||||||
_quotes.add(newQuote);
|
_quotes.add(newQuote);
|
||||||
|
populateAuthors();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,9 +62,18 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
final index = _quotes.indexWhere((q) => q.id == quote.id);
|
final index = _quotes.indexWhere((q) => q.id == quote.id);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
|
final oldAuthor = _quotes[index].author;
|
||||||
final newList = List<Quote>.from(_quotes);
|
final newList = List<Quote>.from(_quotes);
|
||||||
newList[index] = updated;
|
newList[index] = updated;
|
||||||
_quotes = newList;
|
_quotes = newList;
|
||||||
|
Map<String, int> authorMap = {};
|
||||||
|
for (final q in quotes) {
|
||||||
|
authorMap[q.author] = (authorMap[q.author] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
if (authorMap[oldAuthor] == 1) {
|
||||||
|
_authors.remove(oldAuthor);
|
||||||
|
}
|
||||||
|
_authors.add(updated.author);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
_loading = false;
|
_loading = false;
|
||||||
@@ -64,6 +85,7 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
await repo.deleteQuote(quote);
|
await repo.deleteQuote(quote);
|
||||||
|
|
||||||
_quotes.removeWhere((q) => q.id == quote.id);
|
_quotes.removeWhere((q) => q.id == quote.id);
|
||||||
|
populateAuthors();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user