Add all/sub/block etc. filters to mags/users/domains list

This commit is contained in:
John Wesley 2024-01-11 12:14:50 -05:00
parent 89b35d7852
commit df850e65e0
6 changed files with 216 additions and 70 deletions

View File

@ -4,14 +4,20 @@ import 'package:http/http.dart' as http;
import 'package:interstellar/src/models/domain.dart'; import 'package:interstellar/src/models/domain.dart';
import 'package:interstellar/src/utils/utils.dart'; import 'package:interstellar/src/utils/utils.dart';
enum DomainsFilter { all, subscribed, blocked }
Future<DomainListModel> fetchDomains( Future<DomainListModel> fetchDomains(
http.Client client, http.Client client,
String instanceHost, { String instanceHost, {
int? page, int? page,
DomainsFilter? filter,
String? search, String? search,
}) async { }) async {
final response = await client.get(Uri.https( final response = (filter == null || filter == DomainsFilter.all)
instanceHost, '/api/domains', {'p': page?.toString(), 'q': search})); ? await client.get(Uri.https(
instanceHost, '/api/domains', {'p': page?.toString(), 'q': search}))
: await client.get(Uri.https(instanceHost, '/api/domains/${filter.name}',
{'p': page?.toString()}));
httpErrorHandler(response, message: 'Failed to load domains'); httpErrorHandler(response, message: 'Failed to load domains');

View File

@ -4,17 +4,23 @@ import 'package:http/http.dart' as http;
import 'package:interstellar/src/models/magazine.dart'; import 'package:interstellar/src/models/magazine.dart';
import 'package:interstellar/src/utils/utils.dart'; import 'package:interstellar/src/utils/utils.dart';
enum MagazinesFilter { all, subscribed, moderated, blocked }
enum MagazinesSort { active, hot, newest } enum MagazinesSort { active, hot, newest }
Future<MagazineListModel> fetchMagazines( Future<MagazineListModel> fetchMagazines(
http.Client client, http.Client client,
String instanceHost, { String instanceHost, {
int? page, int? page,
MagazinesFilter? filter,
MagazinesSort? sort, MagazinesSort? sort,
String? search, String? search,
}) async { }) async {
final response = await client.get(Uri.https(instanceHost, '/api/magazines', final response = (filter == null || filter == MagazinesFilter.all)
{'p': page?.toString(), 'sort': sort?.name, 'q': search})); ? await client.get(Uri.https(instanceHost, '/api/magazines',
{'p': page?.toString(), 'sort': sort?.name, 'q': search}))
: await client.get(Uri.https(instanceHost,
'/api/magazines/${filter.name}', {'p': page?.toString()}));
httpErrorHandler(response, message: 'Failed to load magazines'); httpErrorHandler(response, message: 'Failed to load magazines');

View File

@ -4,14 +4,20 @@ import 'package:http/http.dart' as http;
import 'package:interstellar/src/models/user.dart'; import 'package:interstellar/src/models/user.dart';
import 'package:interstellar/src/utils/utils.dart'; import 'package:interstellar/src/utils/utils.dart';
enum UsersFilter { all, followed, followers, blocked }
Future<UserListModel> fetchUsers( Future<UserListModel> fetchUsers(
http.Client client, http.Client client,
String instanceHost, { String instanceHost, {
int? page, int? page,
UsersFilter? filter,
}) async { }) async {
final response = await client.get(Uri.https(instanceHost, '/api/users', { final response = (filter == null || filter == UsersFilter.all)
'p': page?.toString(), ? await client.get(Uri.https(instanceHost, '/api/users', {
})); 'p': page?.toString(),
}))
: await client.get(Uri.https(
instanceHost, '/api/users/${filter.name}', {'p': page?.toString()}));
httpErrorHandler(response, message: 'Failed to load users'); httpErrorHandler(response, message: 'Failed to load users');

View File

@ -17,6 +17,7 @@ class DomainsScreen extends StatefulWidget {
} }
class _DomainsScreenState extends State<DomainsScreen> { class _DomainsScreenState extends State<DomainsScreen> {
api_domains.DomainsFilter filter = api_domains.DomainsFilter.all;
String search = ""; String search = "";
final PagingController<int, DomainModel> _pagingController = final PagingController<int, DomainModel> _pagingController =
@ -34,10 +35,12 @@ class _DomainsScreenState extends State<DomainsScreen> {
Future<void> _fetchPage(int pageKey) async { Future<void> _fetchPage(int pageKey) async {
try { try {
final newPage = await api_domains.fetchDomains( final newPage = await api_domains.fetchDomains(
context.read<SettingsController>().httpClient, context.read<SettingsController>().httpClient,
context.read<SettingsController>().instanceHost, context.read<SettingsController>().instanceHost,
page: pageKey, page: pageKey,
search: search.isEmpty ? null : search); filter: filter,
search: search.isEmpty ? null : search,
);
final isLastPage = final isLastPage =
newPage.pagination.currentPage == newPage.pagination.maxPage; newPage.pagination.currentPage == newPage.pagination.maxPage;
@ -66,20 +69,53 @@ class _DomainsScreenState extends State<DomainsScreen> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
SizedBox( ...whenLoggedIn(context, [
width: 128, Padding(
child: TextFormField( padding: const EdgeInsets.only(right: 12),
initialValue: search, child: DropdownButton<api_domains.DomainsFilter>(
onChanged: (newSearch) { value: filter,
setState(() { onChanged: (newFilter) {
search = newSearch; if (newFilter != null) {
_pagingController.refresh(); setState(() {
}); filter = newFilter;
}, _pagingController.refresh();
decoration: const InputDecoration( });
border: OutlineInputBorder(), label: Text('Search')), }
), },
) items: const [
DropdownMenuItem(
value: api_domains.DomainsFilter.all,
child: Text('All'),
),
DropdownMenuItem(
value: api_domains.DomainsFilter.subscribed,
child: Text('Subscribed'),
),
DropdownMenuItem(
value: api_domains.DomainsFilter.blocked,
child: Text('Blocked'),
),
],
),
)
]) ??
[],
if (filter != api_domains.DomainsFilter.all)
SizedBox(
width: 128,
child: TextFormField(
initialValue: search,
onChanged: (newSearch) {
setState(() {
search = newSearch;
_pagingController.refresh();
});
},
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text('Search')),
),
)
], ],
), ),
), ),

View File

@ -18,6 +18,7 @@ class MagazinesScreen extends StatefulWidget {
} }
class _MagazinesScreenState extends State<MagazinesScreen> { class _MagazinesScreenState extends State<MagazinesScreen> {
api_magazines.MagazinesFilter filter = api_magazines.MagazinesFilter.all;
api_magazines.MagazinesSort sort = api_magazines.MagazinesSort.hot; api_magazines.MagazinesSort sort = api_magazines.MagazinesSort.hot;
String search = ""; String search = "";
@ -36,11 +37,13 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
Future<void> _fetchPage(int pageKey) async { Future<void> _fetchPage(int pageKey) async {
try { try {
final newPage = await api_magazines.fetchMagazines( final newPage = await api_magazines.fetchMagazines(
context.read<SettingsController>().httpClient, context.read<SettingsController>().httpClient,
context.read<SettingsController>().instanceHost, context.read<SettingsController>().instanceHost,
page: pageKey, page: pageKey,
sort: sort, filter: filter,
search: search.isEmpty ? null : search); sort: sort,
search: search.isEmpty ? null : search,
);
final isLastPage = final isLastPage =
newPage.pagination.currentPage == newPage.pagination.maxPage; newPage.pagination.currentPage == newPage.pagination.maxPage;
@ -69,46 +72,88 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
DropdownButton<api_magazines.MagazinesSort>( ...whenLoggedIn(context, [
value: sort, Padding(
onChanged: (newSort) { padding: const EdgeInsets.only(right: 12),
if (newSort != null) { child: DropdownButton<api_magazines.MagazinesFilter>(
setState(() { value: filter,
sort = newSort; onChanged: (newFilter) {
_pagingController.refresh(); if (newFilter != null) {
}); setState(() {
} filter = newFilter;
}, _pagingController.refresh();
items: const [ });
DropdownMenuItem( }
value: api_magazines.MagazinesSort.hot, },
child: Text('Hot'), items: const [
), DropdownMenuItem(
DropdownMenuItem( value: api_magazines.MagazinesFilter.all,
value: api_magazines.MagazinesSort.active, child: Text('All'),
child: Text('Active'), ),
), DropdownMenuItem(
DropdownMenuItem( value: api_magazines.MagazinesFilter.subscribed,
value: api_magazines.MagazinesSort.newest, child: Text('Subscribed'),
child: Text('Newest'), ),
), DropdownMenuItem(
], value: api_magazines.MagazinesFilter.moderated,
), child: Text('Moderated'),
const SizedBox(width: 12), ),
SizedBox( DropdownMenuItem(
width: 128, value: api_magazines.MagazinesFilter.blocked,
child: TextFormField( child: Text('Blocked'),
initialValue: search, ),
onChanged: (newSearch) { ],
setState(() { ),
search = newSearch; )
_pagingController.refresh(); ]) ??
}); [],
}, ...(filter == api_magazines.MagazinesFilter.all
decoration: const InputDecoration( ? [
border: OutlineInputBorder(), label: Text('Search')), Padding(
), padding: const EdgeInsets.only(right: 12),
) child: DropdownButton<api_magazines.MagazinesSort>(
value: sort,
onChanged: (newSort) {
if (newSort != null) {
setState(() {
sort = newSort;
_pagingController.refresh();
});
}
},
items: const [
DropdownMenuItem(
value: api_magazines.MagazinesSort.hot,
child: Text('Hot'),
),
DropdownMenuItem(
value: api_magazines.MagazinesSort.active,
child: Text('Active'),
),
DropdownMenuItem(
value: api_magazines.MagazinesSort.newest,
child: Text('Newest'),
),
],
),
),
SizedBox(
width: 128,
child: TextFormField(
initialValue: search,
onChanged: (newSearch) {
setState(() {
search = newSearch;
_pagingController.refresh();
});
},
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text('Search')),
),
),
]
: []),
], ],
), ),
), ),

View File

@ -18,6 +18,8 @@ class UsersScreen extends StatefulWidget {
} }
class _UsersScreenState extends State<UsersScreen> { class _UsersScreenState extends State<UsersScreen> {
api_users.UsersFilter filter = api_users.UsersFilter.all;
final PagingController<int, DetailedUserModel> _pagingController = final PagingController<int, DetailedUserModel> _pagingController =
PagingController(firstPageKey: 1); PagingController(firstPageKey: 1);
@ -36,6 +38,7 @@ class _UsersScreenState extends State<UsersScreen> {
context.read<SettingsController>().httpClient, context.read<SettingsController>().httpClient,
context.read<SettingsController>().instanceHost, context.read<SettingsController>().instanceHost,
page: pageKey, page: pageKey,
filter: filter,
); );
final isLastPage = final isLastPage =
@ -60,6 +63,50 @@ class _UsersScreenState extends State<UsersScreen> {
), ),
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
...whenLoggedIn(context, [
Padding(
padding: const EdgeInsets.only(right: 12),
child: DropdownButton<api_users.UsersFilter>(
value: filter,
onChanged: (newFilter) {
if (newFilter != null) {
setState(() {
filter = newFilter;
_pagingController.refresh();
});
}
},
items: const [
DropdownMenuItem(
value: api_users.UsersFilter.all,
child: Text('All'),
),
DropdownMenuItem(
value: api_users.UsersFilter.followed,
child: Text('Followed'),
),
DropdownMenuItem(
value: api_users.UsersFilter.followers,
child: Text('Followers'),
),
DropdownMenuItem(
value: api_users.UsersFilter.blocked,
child: Text('Blocked'),
),
],
),
)
]) ??
[],
],
),
),
),
PagedSliverList<int, DetailedUserModel>( PagedSliverList<int, DetailedUserModel>(
pagingController: _pagingController, pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<DetailedUserModel>( builderDelegate: PagedChildBuilderDelegate<DetailedUserModel>(