fix(player): 收藏与评论数实时刷新
This commit is contained in:
1 parent
97bbced02c
commit
5e2b8d9e4d
11 files changed
+275
-29
No files matched your search
@@ -35,6 +35,7 @@ class DramaDetailLogic extends ChangeNotifier {
|
||||
int? continueIndex;
|
||||
WatchProgress? progress;
|
||||
String? progressError;
|
||||
int _favoriteCountDelta = 0;
|
||||
bool _disposed = false;
|
||||
|
||||
void notify() {
|
||||
@@ -118,8 +119,26 @@ class DramaDetailLogic extends ChangeNotifier {
|
||||
await loadContinue();
|
||||
}
|
||||
|
||||
/// 收藏切换:乐观更新失败时会回滚,由调用方给出提示。
|
||||
Future<bool> toggleFavorite() => favorites.toggle(drama.id, card: drama);
|
||||
/// 详情页展示用的收藏数;没有服务端计数时继续保持缺省展示。
|
||||
int? get adjustedFavoriteCount {
|
||||
final base = drama.favoriteCount;
|
||||
if (base == null) return null;
|
||||
final adjusted = base + _favoriteCountDelta;
|
||||
return adjusted < 0 ? 0 : adjusted;
|
||||
}
|
||||
|
||||
/// 收藏切换:乐观状态由控制器负责回滚,这里只在成功后同步计数。
|
||||
Future<bool> toggleFavorite() async {
|
||||
final wasSaved = favorites.isSaved(drama.id);
|
||||
final ok = await favorites.toggle(drama.id, card: drama);
|
||||
if (!ok) return false;
|
||||
final nowSaved = favorites.isSaved(drama.id);
|
||||
if (nowSaved != wasSaved) {
|
||||
_favoriteCountDelta += nowSaved ? 1 : -1;
|
||||
notify();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
||||
@@ -142,7 +142,11 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: DramaStatsCard(l10n: l10n, drama: drama),
|
||||
child: DramaStatsCard(
|
||||
l10n: l10n,
|
||||
drama: drama,
|
||||
favoriteCount: logic.adjustedFavoriteCount,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: DramaSynopsisSection(
|
||||
|
||||
@@ -29,16 +29,23 @@ const TextStyle _synopsisStyle = TextStyle(
|
||||
|
||||
/// 详情页三项数据卡:热度、收藏与点赞,缺失值不做伪造。
|
||||
class DramaStatsCard extends StatelessWidget {
|
||||
const DramaStatsCard({super.key, required this.l10n, required this.drama});
|
||||
const DramaStatsCard({
|
||||
super.key,
|
||||
required this.l10n,
|
||||
required this.drama,
|
||||
this.favoriteCount,
|
||||
});
|
||||
|
||||
final AppLocalizations l10n;
|
||||
final Drama drama;
|
||||
final int? favoriteCount;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final favorite = drama.favoriteCount == null
|
||||
final currentFavoriteCount = favoriteCount ?? drama.favoriteCount;
|
||||
final favorite = currentFavoriteCount == null
|
||||
? l10n.episodeCountLabel(drama.episodeCount)
|
||||
: '${formatInteractionCount(drama.favoriteCount!)} ${l10n.favorite}';
|
||||
: '${formatInteractionCount(currentFavoriteCount)} ${l10n.favorite}';
|
||||
final like = drama.likeCount == null
|
||||
? '—'
|
||||
: '${formatInteractionCount(drama.likeCount!)} ${l10n.like}';
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/repositories/comment_repository.dart';
|
||||
import '../../core/data/services/favorite_controller.dart';
|
||||
import '../../core/data/services/download_controller.dart';
|
||||
import '../../core/data/services/interaction_controller.dart';
|
||||
@@ -99,6 +100,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
|
||||
/// 收藏切换后的本地增量:基准是详情快照,切换成功按服务端状态 ±1。
|
||||
final Map<String, int> _favoriteDelta = {};
|
||||
final Map<String, int> _commentCounts = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -203,6 +205,18 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _openComments(BuildContext context, Drama drama) async {
|
||||
final comments = context.read<CommentRepository>();
|
||||
await openCommentsWithAuth(context, drama, show: logic.showComments);
|
||||
try {
|
||||
final count = await comments.count(drama.id);
|
||||
if (!mounted) return;
|
||||
setState(() => _commentCounts[drama.id] = count);
|
||||
} catch (_) {
|
||||
// 评论面板已经关闭,计数刷新失败时保留旧值即可。
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
@@ -446,7 +460,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
favoriteCount: drama.favoriteCount == null
|
||||
? null
|
||||
: drama.favoriteCount! + (_favoriteDelta[drama.id] ?? 0),
|
||||
commentCount: drama.commentCount,
|
||||
commentCount: _commentCounts[drama.id] ?? drama.commentCount,
|
||||
saved: context.watch<FavoriteController>().isSaved(drama.id),
|
||||
onLike: () async {
|
||||
if (await ensureSignedIn(context)) {
|
||||
@@ -465,21 +479,8 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
}
|
||||
}
|
||||
},
|
||||
onSave: () async {
|
||||
final favorites = context.read<FavoriteController>();
|
||||
if (await ensureSignedIn(context)) {
|
||||
if (!context.mounted) return;
|
||||
unawaited(context.read<Haptics>().lightImpact());
|
||||
final ok = await favorites.toggle(drama.id, card: drama);
|
||||
if (ok || !context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.favoriteToggleFailed)),
|
||||
);
|
||||
}
|
||||
},
|
||||
onComments: () => unawaited(
|
||||
openCommentsWithAuth(context, drama, show: logic.showComments),
|
||||
),
|
||||
onSave: () => unawaited(_toggleSave(context, drama)),
|
||||
onComments: () => unawaited(_openComments(context, drama)),
|
||||
onShare: () => logic.shareDrama(context, drama),
|
||||
onDetail: () => unawaited(logic.openDetail(context)),
|
||||
onOpenFullPlayer: () async {
|
||||
@@ -502,7 +503,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
controller: ready ? videoPort!.controller : null,
|
||||
liked: interactions.isLiked(drama.id),
|
||||
likeCount: interactions.likeCount(drama.id) ?? drama.likeCount,
|
||||
commentCount: drama.commentCount,
|
||||
commentCount: _commentCounts[drama.id] ?? drama.commentCount,
|
||||
favoriteCount: drama.favoriteCount == null
|
||||
? null
|
||||
: drama.favoriteCount! + (_favoriteDelta[drama.id] ?? 0),
|
||||
@@ -523,9 +524,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
onDetail: () => unawaited(logic.openDetail(context)),
|
||||
onSpeed: () => unawaited(_openSpeedSheet(context)),
|
||||
onEpisodes: () => logic.showEpisodes(context),
|
||||
onComments: () => unawaited(
|
||||
openCommentsWithAuth(context, drama, show: logic.showComments),
|
||||
),
|
||||
onComments: () => unawaited(_openComments(context, drama)),
|
||||
onLike: () =>
|
||||
unawaited(_toggleLike(context, interactions, drama)),
|
||||
onSave: () => unawaited(_toggleSave(context, drama)),
|
||||
|
||||
Reference in new issue
Block a user