generated from dellevin/template
v0.2.7
This commit is contained in:
@@ -24,13 +24,15 @@ class BookGridItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
return RepaintBoundary(
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
child: switch (viewMode) {
|
||||
ViewMode.relaxed => _buildRelaxed(context),
|
||||
ViewMode.compact => _buildCompact(context),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,6 +43,7 @@ class BookGridItem extends StatelessWidget {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final title = book['title'] as String? ?? '';
|
||||
final author = book['author'] as String? ?? '';
|
||||
final progress = _readingProgress;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -59,8 +62,16 @@ class BookGridItem extends StatelessWidget {
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: _buildCoverStack(context, fit: StackFit.expand, extras: [
|
||||
// 阅读状态角标
|
||||
_buildStatusBadge(context),
|
||||
// 阅读状态圆点
|
||||
_buildStatusDot(context),
|
||||
// 底部进度条
|
||||
if (progress > 0 && progress < 1.0)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: _buildProgressBar(context, progress, height: 3),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
@@ -95,13 +106,22 @@ class BookGridItem extends StatelessWidget {
|
||||
Widget _buildCompact(BuildContext context) {
|
||||
final title = book['title'] as String? ?? '';
|
||||
final author = book['author'] as String? ?? '';
|
||||
final progress = _readingProgress;
|
||||
|
||||
return _buildCoverStack(
|
||||
context,
|
||||
fit: StackFit.expand,
|
||||
extras: [
|
||||
// 阅读状态角标
|
||||
_buildStatusBadge(context),
|
||||
// 阅读状态圆点
|
||||
_buildStatusDot(context),
|
||||
// 底部进度条
|
||||
if (progress > 0 && progress < 1.0)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: _buildProgressBar(context, progress, height: 3),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
@@ -193,23 +213,30 @@ class BookGridItem extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildPlaceholder(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final title = book['title'] as String? ?? '';
|
||||
final initial = title.isNotEmpty ? title.substring(0, 1) : '';
|
||||
// 根据书名首字生成渐变色
|
||||
final gradientColors = _generateGradientColors(initial);
|
||||
return Container(
|
||||
color: colors.surfaceContainerHighest,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: gradientColors,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: initial.isNotEmpty
|
||||
? Text(initial,
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colors.onSurface.withValues(alpha: 0.2),
|
||||
color: Colors.white.withValues(alpha: 0.85),
|
||||
))
|
||||
: Icon(
|
||||
Icons.auto_stories_outlined,
|
||||
size: 36,
|
||||
color: colors.onSurface.withValues(alpha: 0.2),
|
||||
color: Colors.white.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -217,44 +244,76 @@ class BookGridItem extends StatelessWidget {
|
||||
|
||||
// ─── badge helpers ────────────────────────────────────────────────────────
|
||||
|
||||
/// 阅读状态角标(左上角,含百分比)
|
||||
Widget _buildStatusBadge(BuildContext context) {
|
||||
/// 阅读状态圆点(左上角,三色)
|
||||
Widget _buildStatusDot(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final progress = _readingProgress;
|
||||
final String label;
|
||||
final Color color;
|
||||
final Color dotColor;
|
||||
if (progress >= 1.0) {
|
||||
label = '已读';
|
||||
color = const Color(0xFF16A34A);
|
||||
dotColor = const Color(0xFF16A34A);
|
||||
} else if (progress > 0.0) {
|
||||
label = '在读 ${(progress * 100).toInt()}%';
|
||||
color = colors.primary;
|
||||
dotColor = colors.primary;
|
||||
} else {
|
||||
label = '未读';
|
||||
color = const Color(0xFFDC2626);
|
||||
dotColor = const Color(0xFFDC2626);
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
top: 6,
|
||||
left: 6,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.85),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: dotColor,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: dotColor.withValues(alpha: 0.4),
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(label,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w600,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 底部进度条
|
||||
Widget _buildProgressBar(BuildContext context, double progress, {double height = 3}) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
value: progress,
|
||||
minHeight: height,
|
||||
backgroundColor: Colors.black26,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(colors.primary),
|
||||
borderRadius: BorderRadius.zero,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// ─── helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
double get _readingProgress =>
|
||||
(book['reading_percentage'] as num?)?.toDouble() ?? 0.0;
|
||||
|
||||
/// 根据首字符生成渐变色
|
||||
List<Color> _generateGradientColors(String initial) {
|
||||
if (initial.isEmpty) return [const Color(0xFF6B7280), const Color(0xFF9CA3AF)];
|
||||
final code = initial.codeUnitAt(0);
|
||||
final palettes = [
|
||||
[const Color(0xFF6366F1), const Color(0xFF8B5CF6)], // 靛蓝-紫
|
||||
[const Color(0xFF3B82F6), const Color(0xFF06B6D4)], // 蓝-青
|
||||
[const Color(0xFF10B981), const Color(0xFF34D399)], // 绿
|
||||
[const Color(0xFFF59E0B), const Color(0xFFF97316)], // 琥珀-橙
|
||||
[const Color(0xFFEF4444), const Color(0xFFF472B6)], // 红-粉
|
||||
[const Color(0xFF8B5CF6), const Color(0xFFEC4899)], // 紫-粉
|
||||
[const Color(0xFF14B8A6), const Color(0xFF3B82F6)], // 青-蓝
|
||||
[const Color(0xFFF97316), const Color(0xFFEF4444)], // 橙-红
|
||||
];
|
||||
return palettes[code % palettes.length];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user