170 lines
5.6 KiB
Dart
170 lines
5.6 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../core/data/models/watch_progress.dart';
|
|
import '../../../core/theme/app_colors.dart';
|
|
import '../../../core/theme/app_dimens.dart';
|
|
import '../../../core/widgets/remote_image.dart';
|
|
import '../../../l10n/app_localizations.dart';
|
|
|
|
class MineContinueWatching extends StatelessWidget {
|
|
const MineContinueWatching({
|
|
super.key,
|
|
required this.records,
|
|
required this.onOpenAll,
|
|
});
|
|
|
|
final List<WatchProgress> records;
|
|
final VoidCallback onOpenAll;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final visible = records.take(10).toList(growable: false);
|
|
if (visible.isEmpty) return const SizedBox.shrink();
|
|
return Column(
|
|
key: const Key('mine-continue-watching'),
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: AppDimens.mineGridHorizontal,
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
l10n.continueWatching,
|
|
style: const TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: AppDimens.mineSectionTitleFont,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
InkWell(
|
|
key: const Key('mine-continue-all'),
|
|
onTap: onOpenAll,
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
l10n.all,
|
|
style: const TextStyle(
|
|
color: AppColors.textTertiary,
|
|
fontSize: AppDimens.mineSectionLinkFont,
|
|
),
|
|
),
|
|
const Icon(
|
|
Icons.chevron_right_rounded,
|
|
color: AppColors.textTertiary,
|
|
size: 16,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: AppDimens.spaceSm),
|
|
SizedBox(
|
|
height: AppDimens.mineContinueRowHeight,
|
|
child: ListView.separated(
|
|
key: const Key('mine-continue-list'),
|
|
scrollDirection: Axis.horizontal,
|
|
physics: const BouncingScrollPhysics(),
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: AppDimens.mineGridHorizontal,
|
|
),
|
|
itemCount: visible.length,
|
|
separatorBuilder: (_, _) =>
|
|
const SizedBox(width: AppDimens.spaceMd),
|
|
itemBuilder: (_, index) {
|
|
final record = visible[index];
|
|
return _card(l10n, record);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _card(AppLocalizations l10n, WatchProgress record) {
|
|
final title = record.dramaTitle?.trim() ?? '';
|
|
final episode = record.episodeNumber;
|
|
final hasProgress = record.duration > Duration.zero;
|
|
return SizedBox(
|
|
width: AppDimens.mineContinueCardWidth,
|
|
child: InkWell(
|
|
key: Key('mine-continue-${record.dramaId}'),
|
|
borderRadius: BorderRadius.circular(AppDimens.homeCardRadius),
|
|
onTap: onOpenAll,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
AspectRatio(
|
|
aspectRatio: AppDimens.cardCoverAspectRatio,
|
|
child: Stack(
|
|
clipBehavior: Clip.hardEdge,
|
|
children: [
|
|
Positioned.fill(
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(
|
|
AppDimens.homeCardRadius,
|
|
),
|
|
child: RemoteImage(
|
|
record.dramaCover ?? '',
|
|
fit: BoxFit.cover,
|
|
showFallbackIcon: true,
|
|
fallbackColor: AppColors.contentSurface,
|
|
),
|
|
),
|
|
),
|
|
if (hasProgress)
|
|
Positioned(
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
child: LinearProgressIndicator(
|
|
value: record.fraction,
|
|
minHeight: AppDimens.followingProgressHeight,
|
|
backgroundColor: AppColors.inactiveTrack,
|
|
valueColor: const AlwaysStoppedAnimation<Color>(
|
|
AppColors.primary,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: AppDimens.cardCoverTitleGap),
|
|
Text(
|
|
title.isEmpty ? l10n.dataUnavailable : title,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: AppDimens.mineContinueTitleFont,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
episode == null || episode <= 0
|
|
? l10n.dataUnavailable
|
|
: l10n.episodeLabel(episode),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
color: AppColors.textTertiary,
|
|
fontSize: AppDimens.mineContinueMetaFont,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|