Files
.github
.vscode
android
assets
buildtools
ios
lib
database
models
pods
screens
services
widgets
account
chat
content
post
post_item.dart
post_list.dart
post_list.g.dart
post_quick_reply.dart
post_replies.dart
post_replies.g.dart
publishers_modal.dart
realms
tour
alert.dart
app_notification.dart
app_notification.freezed.dart
app_notification.g.dart
app_scaffold.dart
check_in.dart
check_in.g.dart
context_menu.dart
response.dart
firebase_options.dart
main.dart
route.dart
route.gr.dart
linux
macos
web
windows
.gitignore
.metadata
README.md
analysis_options.yaml
build.yaml
devtools_options.yaml
firebase.json
pubspec.lock
pubspec.yaml
App/lib/widgets/post/post_list.dart
2025-06-08 22:33:47 +08:00

78 lines
2.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart';
import 'package:island/pods/network.dart';
import 'package:island/widgets/content/paging_helper_ext.dart';
import 'package:island/widgets/post/post_item.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
part 'post_list.g.dart';
@riverpod
class PostListNotifier extends _$PostListNotifier
with CursorPagingNotifierMixin<SnPost> {
static const int _pageSize = 20;
@override
Future<CursorPagingData<SnPost>> build(String? pubName) {
return fetch(cursor: null);
}
@override
Future<CursorPagingData<SnPost>> fetch({required String? cursor}) async {
final client = ref.read(apiClientProvider);
final offset = cursor == null ? 0 : int.parse(cursor);
final queryParams = {
'offset': offset,
'take': _pageSize,
if (pubName != null) 'pub': pubName,
};
final response = await client.get('/posts', queryParameters: queryParams);
final total = int.parse(response.headers.value('X-Total') ?? '0');
final List<dynamic> data = response.data;
final posts = data.map((json) => SnPost.fromJson(json)).toList();
final hasMore = offset + posts.length < total;
final nextCursor = hasMore ? (offset + posts.length).toString() : null;
return CursorPagingData(
items: posts,
hasMore: hasMore,
nextCursor: nextCursor,
);
}
}
class SliverPostList extends HookConsumerWidget {
final String? pubName;
const SliverPostList({super.key, this.pubName});
@override
Widget build(BuildContext context, WidgetRef ref) {
return PagingHelperSliverView(
provider: postListNotifierProvider(pubName),
futureRefreshable: postListNotifierProvider(pubName).future,
notifierRefreshable: postListNotifierProvider(pubName).notifier,
contentBuilder:
(data, widgetCount, endItemView) => SliverList.builder(
itemCount: widgetCount,
itemBuilder: (context, index) {
if (index == widgetCount - 1) {
return endItemView;
}
return Column(
children: [
PostItem(item: data.items[index]),
const Divider(height: 1),
],
);
},
),
);
}
}