// Author: fruit.com.cn import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/data/models/drama.dart'; import '../../core/data/services/auth_controller.dart'; import '../../core/data/services/favorite_controller.dart'; import '../../core/formatting/error_text.dart'; import '../../core/platform/haptics.dart'; import '../../core/theme/app_colors.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/auth_gate.dart'; import '../../core/widgets/empty_state.dart'; import '../../core/widgets/library_drama_tile.dart'; import '../../l10n/app_localizations.dart'; import '../drama_detail/drama_detail_view.dart'; import 'favorites_binding.dart'; /// 独立我的收藏页。 class FavoritesPage extends StatefulWidget { const FavoritesPage({super.key}); @override State createState() => _FavoritesPageState(); } class _FavoritesPageState extends State { bool _requested = false; @override void didChangeDependencies() { super.didChangeDependencies(); final signedIn = context.watch().isSignedIn; if (!signedIn) { _requested = false; return; } if (_requested) return; _requested = true; final favorites = context.read(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) unawaited(FavoritesBinding().load(favorites)); }); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final signedIn = context.watch().isSignedIn; return Theme( data: AppTheme.light(), child: Scaffold( backgroundColor: AppColors.ink, appBar: AppBar( backgroundColor: AppColors.ink, foregroundColor: Colors.white, title: Text(l10n.myFavorites), ), body: SafeArea( top: false, child: signedIn ? _FavoritesBody(favorites: context.watch()) : const AuthGatePanel(), ), ), ); } } class _FavoritesBody extends StatelessWidget { const _FavoritesBody({required this.favorites}); final FavoriteController favorites; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; if (favorites.loading && favorites.cards.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (favorites.error != null && favorites.cards.isEmpty) { return EmptyState( key: const Key('favorites-error'), icon: Icons.cloud_off_rounded, title: errorText(l10n, favorites.error, l10n.favoritesError), actionLabel: l10n.retry, actionKey: const Key('favorites-retry'), onAction: () => unawaited(favorites.load()), ); } if (favorites.cards.isEmpty) { return EmptyState( key: const Key('favorites-empty'), icon: Icons.favorite_border_rounded, title: l10n.noFavorites, subtitle: l10n.emptyHint, ); } return RefreshIndicator( onRefresh: favorites.load, child: ListView.separated( padding: const EdgeInsets.fromLTRB(16, 12, 16, 28), itemCount: favorites.cards.length, separatorBuilder: (_, _) => const SizedBox(height: 10), itemBuilder: (context, index) { final drama = favorites.cards[index]; return LibraryDramaTile( key: ValueKey('favorite-card-${drama.id}'), drama: drama, onTap: () => _open(context, drama), trailing: IconButton( key: ValueKey('favorite-remove-${drama.id}'), tooltip: l10n.remove, onPressed: () => _remove(context, drama.id), icon: const Icon( Icons.favorite_rounded, color: AppColors.favorite, ), ), ); }, ), ); } Future _open(BuildContext context, Drama drama) async { await Navigator.of(context).push( MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)), ); } Future _remove(BuildContext context, String dramaId) async { unawaited(context.read().lightImpact()); final ok = await favorites.remove(dramaId); if (ok || !context.mounted) return; final l10n = AppLocalizations.of(context)!; ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(l10n.favoriteToggleFailed))); } }