117 lines
2.8 KiB
Dart
117 lines
2.8 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../core/data/models/drama.dart';
|
|
import '../../../core/theme/app_colors.dart';
|
|
|
|
const double _cellRadius = 8;
|
|
const double _numberSize = 15;
|
|
const double _lockSize = 16;
|
|
const double _lockGap = 4;
|
|
const double _lockWeight = 300;
|
|
const double _coverAlpha = 0.45;
|
|
|
|
/// 选集格子。需要解锁时铺一层透明底,锁在上,集数在锁下面。
|
|
class EpisodePickerCell extends StatelessWidget {
|
|
const EpisodePickerCell({
|
|
required this.episode,
|
|
required this.selected,
|
|
required this.lockLabel,
|
|
required this.onTap,
|
|
super.key,
|
|
});
|
|
|
|
final Episode episode;
|
|
final bool selected;
|
|
final String lockLabel;
|
|
final VoidCallback onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Material(
|
|
clipBehavior: Clip.antiAlias,
|
|
color: selected ? AppColors.bluePressed : AppColors.raised,
|
|
borderRadius: BorderRadius.circular(_cellRadius),
|
|
child: InkWell(
|
|
onTap: onTap,
|
|
child: Stack(
|
|
fit: StackFit.expand,
|
|
children: [
|
|
if (!episode.locked) Center(child: _EpisodeNumber(episode.number)),
|
|
if (episode.locked)
|
|
_LockCover(
|
|
episodeId: episode.id,
|
|
number: episode.number,
|
|
label: lockLabel,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _EpisodeNumber extends StatelessWidget {
|
|
const _EpisodeNumber(this.number);
|
|
|
|
final int number;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Text(
|
|
'$number',
|
|
style: const TextStyle(
|
|
color: AppColors.cream,
|
|
fontSize: _numberSize,
|
|
fontWeight: FontWeight.w600,
|
|
height: 1,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 透明底铺满格子,锁在上,集数在锁下面。
|
|
class _LockCover extends StatelessWidget {
|
|
const _LockCover({
|
|
required this.episodeId,
|
|
required this.number,
|
|
required this.label,
|
|
});
|
|
|
|
final String episodeId;
|
|
final int number;
|
|
final String label;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Stack(
|
|
fit: StackFit.expand,
|
|
children: [
|
|
ColoredBox(
|
|
key: ValueKey('episode-lock-cover-$episodeId'),
|
|
color: AppColors.ink.withValues(alpha: _coverAlpha),
|
|
),
|
|
Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(
|
|
Icons.lock_outline,
|
|
key: ValueKey('episode-lock-$episodeId'),
|
|
size: _lockSize,
|
|
weight: _lockWeight,
|
|
fill: 0,
|
|
color: AppColors.gold,
|
|
semanticLabel: label,
|
|
),
|
|
const SizedBox(height: _lockGap),
|
|
_EpisodeNumber(number),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|