// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../core/theme/app_colors.dart'; import '../../core/theme/app_dimens.dart'; import '../../core/widgets/cover_play_count.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, ), ), ), 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 Positioned( left: 0, right: 0, bottom: 0, child: CoverBottomScrim(), ), Positioned( right: AppDimens.cardPlayCountRight, bottom: AppDimens.cardPlayCountBottom, child: CoverPlayCount( key: Key('following-views-$dramaId'), count: viewCount, ), ), ], ), ), 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, ), ), if (tags.isNotEmpty) ...[ const SizedBox(height: AppDimens.cardTitleTagGap), _tags(), ], 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, ), ), ), ], ], ), ); } Widget _tags() { final visible = tags.take(3).toList(growable: false); return Text( visible.join(' | '), key: Key('following-tags-$dramaId'), maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.left, style: const TextStyle( color: AppColors.textTertiary, fontSize: AppDimens.cardTagFont, ), ); } }