// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../core/formatting/count_format.dart'; import '../../core/theme/app_colors.dart'; import '../../core/theme/app_dimens.dart'; import '../../core/widgets/drama_genre_ribbon.dart'; import '../../core/widgets/remote_image.dart'; class FollowingGridCard extends StatelessWidget { const FollowingGridCard({ super.key, required this.dramaId, required this.title, required this.posterUrl, required this.viewCount, required this.tags, required this.subtitle, required this.onTap, this.progress, this.editing = false, this.onRemove, }); final String dramaId; final String title; final String posterUrl; final int viewCount; final List tags; final String subtitle; final VoidCallback onTap; final double? progress; final bool editing; final VoidCallback? onRemove; @override Widget build(BuildContext context) { return InkWell( key: Key('following-card-$dramaId'), borderRadius: BorderRadius.circular(AppDimens.cardCoverRadius), onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ AspectRatio( key: Key('following-cover-$dramaId'), aspectRatio: AppDimens.cardCoverAspectRatio, child: Stack( clipBehavior: Clip.none, children: [ Positioned.fill( child: ClipRRect( borderRadius: BorderRadius.circular( AppDimens.cardCoverRadius, ), child: RemoteImage( posterUrl, fit: BoxFit.cover, showFallbackIcon: true, fallbackColor: AppColors.contentSurface, ), ), ), Positioned( left: AppDimens.spaceXs, bottom: AppDimens.spaceXs, child: Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: AppColors.playerOverlayPill, borderRadius: BorderRadius.circular(AppDimens.pillRadius), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.auto_awesome_rounded, color: AppColors.textPrimary, size: AppDimens.cardViewsIcon, ), Text( formatPlayCount(viewCount), key: Key('following-views-$dramaId'), style: const TextStyle( color: AppColors.textPrimary, fontSize: AppDimens.cardViewsFont, ), ), ], ), ), ), if (!editing) Positioned( top: 0, right: 0, child: DramaGenreRibbon(tags: tags, keyPrefix: dramaId), ), if (editing) Positioned( top: -6, right: -6, child: GestureDetector( key: Key('following-remove-$dramaId'), onTap: onRemove, child: const CircleAvatar( radius: 13, backgroundColor: AppColors.contentChip, child: Icon( Icons.remove_rounded, color: AppColors.textPrimary, size: 18, ), ), ), ), ], ), ), const SizedBox(height: AppDimens.cardCoverTitleGap), Text( title, maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.left, style: const TextStyle( color: AppColors.textPrimary, fontSize: AppDimens.cardTitleFont, fontWeight: FontWeight.w500, height: AppDimens.cardTitleLineHeight, ), ), const SizedBox(height: AppDimens.spaceXs), Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.textTertiary, fontSize: AppDimens.cardViewsFont, ), ), if (progress != null) ...[ const SizedBox(height: AppDimens.spaceXs), ClipRRect( borderRadius: BorderRadius.circular(AppDimens.progressRadius), child: LinearProgressIndicator( key: Key('following-progress-$dramaId'), value: progress!.clamp(0.0, 1.0).toDouble(), minHeight: 2, backgroundColor: AppColors.inactiveTrack, valueColor: const AlwaysStoppedAnimation( AppColors.primary, ), ), ), ], ], ), ); } }