feat(app): 客户端展示多语言并支持筛选分页
This commit is contained in:
1 parent
8481611372
commit
8b50b5bd06
68 files changed
+2742
-1120
No files matched your search
@@ -0,0 +1,119 @@
|
||||
// Author: fruit.com.cn
|
||||
// 评论楼中楼:展开回复、继续加载,没有下一页时给出结束提示。
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/data/models/comment.dart';
|
||||
import '../../../core/data/services/comment_controller.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import 'comment_tile.dart';
|
||||
|
||||
const double _replyIndent = 52;
|
||||
|
||||
/// 一条评论及其回复。
|
||||
class CommentThread extends StatelessWidget {
|
||||
const CommentThread({
|
||||
super.key,
|
||||
required this.comment,
|
||||
required this.controller,
|
||||
required this.handlers,
|
||||
});
|
||||
|
||||
final DramaComment comment;
|
||||
final CommentController controller;
|
||||
final CommentInteractionHandlers handlers;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final replies = controller.repliesFor(comment.id);
|
||||
final expanded = controller.repliesExpanded(comment.id);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CommentTile(comment: comment, handlers: handlers),
|
||||
if (comment.replyCount > 0 || replies.isNotEmpty) _toggle(context, expanded),
|
||||
if (expanded) _replies(context, replies),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _toggle(BuildContext context, bool expanded) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: _replyIndent, bottom: 4),
|
||||
child: TextButton(
|
||||
key: Key('comment-replies-${comment.id}'),
|
||||
onPressed: () => _toggleReplies(context),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColors.muted,
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: const Size(0, 24),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(width: 16, height: 1, color: AppColors.border),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
expanded ? l10n.hideReplies : l10n.viewReplies(comment.replyCount),
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
expanded
|
||||
? Icons.keyboard_arrow_up_rounded
|
||||
: Icons.keyboard_arrow_down_rounded,
|
||||
size: 14,
|
||||
color: AppColors.muted,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _replies(BuildContext context, List<DramaComment> replies) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: _replyIndent),
|
||||
child: Column(
|
||||
children: [
|
||||
if (controller.repliesLoading(comment.id))
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
for (final reply in replies)
|
||||
CommentTile(comment: reply, handlers: handlers, isReply: true),
|
||||
if (controller.repliesHasMore(comment.id))
|
||||
TextButton(
|
||||
onPressed: () => controller.loadMoreReplies(comment.id),
|
||||
child: Text(l10n.loadMore),
|
||||
)
|
||||
else if (replies.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Text(
|
||||
l10n.noMoreItems,
|
||||
style: const TextStyle(color: AppColors.textHint, fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleReplies(BuildContext context) async {
|
||||
if (controller.repliesExpanded(comment.id)) {
|
||||
controller.hideReplies(comment.id);
|
||||
return;
|
||||
}
|
||||
await controller.loadReplies(comment.id);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user