🐛 Fixes in new pagination list
This commit is contained in:
@@ -45,11 +45,12 @@ mixin AsyncPaginationController<T> on AsyncNotifier<List<T>>
|
||||
return await fetch();
|
||||
});
|
||||
state = newState;
|
||||
fetchedCount = newState.value?.length ?? 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fetchFurther() async {
|
||||
if (!fetchedAll) return;
|
||||
if (fetchedAll) return;
|
||||
|
||||
state = AsyncLoading<List<T>>();
|
||||
|
||||
@@ -67,6 +68,7 @@ mixin AsyncPaginationFilter<F, T> on AsyncPaginationController<T>
|
||||
implements PaginationFiltered<F> {
|
||||
@override
|
||||
Future<void> applyFilter(F filter) async {
|
||||
if (currentFilter == filter) return;
|
||||
// Reset the data
|
||||
totalCount = null;
|
||||
fetchedCount = 0;
|
||||
|
||||
@@ -23,7 +23,11 @@ class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
final cursor =
|
||||
state.valueOrNull?.lastOrNull?.createdAt.toUtc().toIso8601String();
|
||||
state.isLoading
|
||||
? null
|
||||
: state.valueOrNull?.lastOrNull?.createdAt
|
||||
.toUtc()
|
||||
.toIso8601String();
|
||||
|
||||
final queryParameters = {
|
||||
if (cursor != null) 'cursor': cursor,
|
||||
|
||||
@@ -72,8 +72,8 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final tabController = useTabController(initialLength: 3);
|
||||
final currentFilter = useState<String?>(null);
|
||||
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||
|
||||
useEffect(() {
|
||||
// Set FAB type to chat
|
||||
@@ -91,33 +91,10 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() {
|
||||
void listener() {
|
||||
switch (tabController.index) {
|
||||
case 0:
|
||||
currentFilter.value = null;
|
||||
break;
|
||||
case 1:
|
||||
currentFilter.value = 'subscriptions';
|
||||
break;
|
||||
case 2:
|
||||
currentFilter.value = 'friends';
|
||||
break;
|
||||
void handleFilterChange(String? filter) {
|
||||
currentFilter.value = filter;
|
||||
notifier.applyFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
tabController.addListener(listener);
|
||||
return () => tabController.removeListener(listener);
|
||||
}, [tabController]);
|
||||
|
||||
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||
|
||||
useEffect(() {
|
||||
Future(() {
|
||||
notifier.applyFilter(currentFilter.value);
|
||||
});
|
||||
return null;
|
||||
}, [currentFilter.value]);
|
||||
|
||||
// Listen for post creation events to refresh activities
|
||||
useEffect(() {
|
||||
@@ -149,35 +126,42 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TabBar(
|
||||
controller: tabController,
|
||||
tabAlignment: TabAlignment.start,
|
||||
isScrollable: true,
|
||||
dividerColor: Colors.transparent,
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'explore'.tr(),
|
||||
child: Icon(Symbols.explore),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange(null),
|
||||
icon: Icon(Symbols.explore),
|
||||
tooltip: 'explore'.tr(),
|
||||
isSelected: currentFilter.value == null,
|
||||
color:
|
||||
currentFilter.value == null
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange('subscriptions'),
|
||||
icon: Icon(Symbols.subscriptions),
|
||||
tooltip: 'exploreFilterSubscriptions'.tr(),
|
||||
isSelected: currentFilter.value == 'subscriptions',
|
||||
color:
|
||||
currentFilter.value == 'subscriptions'
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'exploreFilterSubscriptions'.tr(),
|
||||
child: Icon(Symbols.subscriptions),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'exploreFilterFriends'.tr(),
|
||||
child: Icon(Symbols.people),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange('friends'),
|
||||
icon: Icon(Symbols.people),
|
||||
tooltip: 'exploreFilterFriends'.tr(),
|
||||
isSelected: currentFilter.value == 'friends',
|
||||
color:
|
||||
currentFilter.value == 'friends'
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.pushNamed('articles');
|
||||
@@ -241,10 +225,13 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
tooltip: 'search'.tr(),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 8),
|
||||
).padding(horizontal: 8, vertical: 4),
|
||||
);
|
||||
|
||||
final appBar = isWide ? null : _buildAppBar(tabController, context);
|
||||
final appBar =
|
||||
isWide
|
||||
? null
|
||||
: _buildAppBar(currentFilter.value, handleFilterChange, context);
|
||||
|
||||
final dragging = useState(false);
|
||||
|
||||
@@ -324,6 +311,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
notifier: activityListNotifierProvider.notifier,
|
||||
// Sliver list cannot provide refresh handled by the pagination list
|
||||
isRefreshable: false,
|
||||
isSliver: true,
|
||||
contentBuilder: (data) => _ActivityListView(data: data, isWide: isWide),
|
||||
);
|
||||
}
|
||||
@@ -433,7 +421,8 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar(
|
||||
TabController tabController,
|
||||
String? currentFilter,
|
||||
void Function(String?) handleFilterChange,
|
||||
BuildContext context,
|
||||
) {
|
||||
final foregroundColor = Theme.of(context).appBarTheme.foregroundColor;
|
||||
@@ -449,38 +438,25 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TabBar(
|
||||
controller: tabController,
|
||||
tabAlignment: TabAlignment.start,
|
||||
isScrollable: true,
|
||||
dividerColor: Colors.transparent,
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'explore'.tr(),
|
||||
child: Icon(Symbols.explore, color: foregroundColor),
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange(null),
|
||||
icon: Icon(Symbols.explore, color: foregroundColor),
|
||||
tooltip: 'explore'.tr(),
|
||||
isSelected: currentFilter == null,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange('subscriptions'),
|
||||
icon: Icon(Symbols.subscriptions, color: foregroundColor),
|
||||
tooltip: 'exploreFilterSubscriptions'.tr(),
|
||||
isSelected: currentFilter == 'subscriptions',
|
||||
),
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'exploreFilterSubscriptions'.tr(),
|
||||
child: Icon(
|
||||
Symbols.subscriptions,
|
||||
color: foregroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
icon: Tooltip(
|
||||
message: 'exploreFilterFriends'.tr(),
|
||||
child: Icon(Symbols.people, color: foregroundColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => handleFilterChange('friends'),
|
||||
icon: Icon(Symbols.people, color: foregroundColor),
|
||||
tooltip: 'exploreFilterFriends'.tr(),
|
||||
isSelected: currentFilter == 'friends',
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.pushNamed('articles');
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||
|
||||
class PaginationList<T> extends HookConsumerWidget {
|
||||
@@ -34,7 +35,7 @@ class PaginationList<T> extends HookConsumerWidget {
|
||||
if (scrollInfo is ScrollEndNotification &&
|
||||
scrollInfo.metrics.axisDirection == AxisDirection.down &&
|
||||
scrollInfo.metrics.pixels >= scrollInfo.metrics.maxScrollExtent) {
|
||||
if (!noti.fetchedAll) {
|
||||
if (!noti.fetchedAll && !data.isLoading && !data.hasError) {
|
||||
noti.fetchFurther();
|
||||
}
|
||||
}
|
||||
@@ -54,24 +55,42 @@ class PaginationWidget<T> extends HookConsumerWidget {
|
||||
final Refreshable<PaginationController<T>> notifier;
|
||||
final Widget Function(List<T>) contentBuilder;
|
||||
final bool isRefreshable;
|
||||
final bool isSliver;
|
||||
final bool showDefaultWidgets;
|
||||
const PaginationWidget({
|
||||
super.key,
|
||||
required this.provider,
|
||||
required this.notifier,
|
||||
required this.contentBuilder,
|
||||
this.isRefreshable = true,
|
||||
this.isSliver = false,
|
||||
this.showDefaultWidgets = true,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final data = ref.watch(provider);
|
||||
final noti = ref.watch(notifier);
|
||||
|
||||
if (data.isLoading) {
|
||||
final content = ResponseLoadingWidget();
|
||||
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||
}
|
||||
|
||||
if (data.hasError) {
|
||||
final content = ResponseErrorWidget(
|
||||
error: data.error,
|
||||
onRetry: noti.refresh,
|
||||
);
|
||||
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||
}
|
||||
|
||||
final content = NotificationListener(
|
||||
onNotification: (ScrollNotification scrollInfo) {
|
||||
if (scrollInfo is ScrollEndNotification &&
|
||||
scrollInfo.metrics.axisDirection == AxisDirection.down &&
|
||||
scrollInfo.metrics.pixels >= scrollInfo.metrics.maxScrollExtent) {
|
||||
if (!noti.fetchedAll) {
|
||||
if (!noti.fetchedAll && !data.isLoading && !data.hasError) {
|
||||
noti.fetchFurther();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user