// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/data/models/drama.dart'; import '../../../core/formatting/localized_content.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../core/widgets/subpage_header.dart'; import '../../../l10n/app_localizations.dart'; const double _horizontal = 14; const double _topGap = 8; const double _posterWidth = 96; const double _posterHeight = 128; const double _posterRadius = 12; const double _infoGap = 14; const double _favoriteHeight = 34; const double _favoriteRadius = 17; const double _favoriteHorizontal = 12; /// 详情页顶部操作与短剧主信息所需的交互回调。 class DramaDetailHeaderActions { const DramaDetailHeaderActions({ required this.onBack, required this.onShare, required this.onFavorite, required this.moreMenu, }); final VoidCallback onBack; final VoidCallback onShare; final VoidCallback onFavorite; final Widget moreMenu; } /// 详情页暖色渐变头部:操作行、封面、标题、集数与收藏按钮。 class DramaDetailHeader extends StatelessWidget { const DramaDetailHeader({ super.key, required this.l10n, required this.drama, required this.saved, required this.actions, }); final AppLocalizations l10n; final Drama drama; final bool saved; final DramaDetailHeaderActions actions; @override Widget build(BuildContext context) { return Container( key: const Key('detail-hero'), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [AppColors.surfaceTop, AppColors.ink], ), ), child: SafeArea( bottom: false, child: Padding( padding: const EdgeInsets.fromLTRB(_horizontal, 8, _horizontal, 10), child: Column( children: [ _actions(context), const SizedBox(height: _topGap), _identity(context), ], ), ), ), ); } Widget _actions(BuildContext context) { return Row( children: [ AppSubpageBackButton( backKey: const Key('detail-back'), dark: true, onBack: actions.onBack, ), const Spacer(), AppSubpageCircleButton( buttonKey: const Key('detail-share'), tooltip: l10n.share, icon: Icons.share_outlined, dark: true, onPressed: actions.onShare, ), const SizedBox(width: 8), actions.moreMenu, ], ); } Widget _identity(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( key: const Key('detail-poster'), width: _posterWidth, height: _posterHeight, decoration: BoxDecoration( borderRadius: BorderRadius.circular(_posterRadius), boxShadow: const [ BoxShadow( color: AppColors.cardShadow, blurRadius: 16, offset: Offset(0, 5), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(_posterRadius), child: RemoteImage( drama.posterUrl, fit: BoxFit.cover, showFallbackIcon: true, fallbackAspectRatio: 3 / 4, ), ), ), const SizedBox(width: _infoGap), Expanded( child: SizedBox( height: _posterHeight, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( localizedDramaTitle(l10n, drama), key: const Key('detail-title'), maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.onSurface, fontSize: 20, fontWeight: FontWeight.w800, height: 1.2, ), ), const SizedBox(height: 6), Text( l10n.episodeCountLabel(drama.episodeCount), key: const Key('detail-episode-count'), style: const TextStyle( color: AppColors.muted, fontSize: 12, fontWeight: FontWeight.w500, ), ), const Spacer(), _favoriteButton(), ], ), ), ), ], ); } Widget _favoriteButton() { return GestureDetector( onTap: actions.onFavorite, child: Container( key: const Key('detail-favorite'), height: _favoriteHeight, padding: const EdgeInsets.symmetric(horizontal: _favoriteHorizontal), decoration: BoxDecoration( color: saved ? AppColors.blue : AppColors.card, borderRadius: BorderRadius.circular(_favoriteRadius), border: Border.all(color: saved ? AppColors.blue : AppColors.blue), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( saved ? Icons.star_rounded : Icons.star_border_rounded, size: 16, color: saved ? AppColors.onPrimary : AppColors.blue, ), const SizedBox(width: 4), Text( l10n.favorite, style: TextStyle( color: saved ? AppColors.onPrimary : AppColors.blue, fontSize: 12, fontWeight: FontWeight.w700, ), ), ], ), ), ); } }