This commit is contained in:
sjk
2025-11-17 14:09:17 +08:00
commit 31e46c5bf6
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
import 'package:flutter/material.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimensions.dart';
import '../../../core/theme/app_text_styles.dart';
/// 阅读进度条组件
class ReadingProgressBar extends StatelessWidget {
final int current;
final int total;
final double? progress;
final String? label;
final bool showPercentage;
final Color? progressColor;
final Color? backgroundColor;
const ReadingProgressBar({
super.key,
required this.current,
required this.total,
this.progress,
this.label,
this.showPercentage = true,
this.progressColor,
this.backgroundColor,
});
@override
Widget build(BuildContext context) {
final progressValue = progress ?? (total > 0 ? current / total : 0.0);
final percentage = (progressValue * 100).toInt();
return Container(
padding: const EdgeInsets.all(AppDimensions.spacingMd),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题和进度信息
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label ?? '进度',
style: AppTextStyles.titleMedium,
),
Row(
children: [
Text(
'$current / $total',
style: AppTextStyles.bodyMedium.copyWith(
fontWeight: FontWeight.w500,
),
),
if (showPercentage) ...[
const SizedBox(width: AppDimensions.spacingSm),
Text(
'$percentage%',
style: AppTextStyles.bodyMedium.copyWith(
color: progressColor ?? AppColors.primary,
fontWeight: FontWeight.bold,
),
),
],
],
),
],
),
const SizedBox(height: AppDimensions.spacingSm),
// 进度条
LinearProgressIndicator(
value: progressValue,
backgroundColor: backgroundColor ?? AppColors.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
progressColor ?? AppColors.primary,
),
minHeight: 6,
),
],
),
);
}
}
/// 圆形进度条组件
class ReadingCircularProgressBar extends StatelessWidget {
final int current;
final int total;
final double? progress;
final double size;
final double strokeWidth;
final Color? progressColor;
final Color? backgroundColor;
final Widget? child;
const ReadingCircularProgressBar({
super.key,
required this.current,
required this.total,
this.progress,
this.size = 80,
this.strokeWidth = 6,
this.progressColor,
this.backgroundColor,
this.child,
});
@override
Widget build(BuildContext context) {
final progressValue = progress ?? (total > 0 ? current / total : 0.0);
final percentage = (progressValue * 100).toInt();
return SizedBox(
width: size,
height: size,
child: Stack(
alignment: Alignment.center,
children: [
// 圆形进度条
CircularProgressIndicator(
value: progressValue,
strokeWidth: strokeWidth,
backgroundColor: backgroundColor ?? AppColors.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
progressColor ?? AppColors.primary,
),
),
// 中心内容
child ??
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$percentage%',
style: AppTextStyles.titleMedium.copyWith(
fontWeight: FontWeight.bold,
color: progressColor ?? AppColors.primary,
),
),
Text(
'$current/$total',
style: AppTextStyles.bodySmall.copyWith(
color: AppColors.onSurfaceVariant,
),
),
],
),
],
),
);
}
}
/// 步骤进度条组件
class ReadingStepProgressBar extends StatelessWidget {
final int currentStep;
final int totalSteps;
final List<String>? stepLabels;
final Color? activeColor;
final Color? inactiveColor;
final Color? completedColor;
const ReadingStepProgressBar({
super.key,
required this.currentStep,
required this.totalSteps,
this.stepLabels,
this.activeColor,
this.inactiveColor,
this.completedColor,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(AppDimensions.spacingMd),
child: Row(
children: List.generate(totalSteps, (index) {
final stepNumber = index + 1;
final isCompleted = stepNumber < currentStep;
final isActive = stepNumber == currentStep;
final isInactive = stepNumber > currentStep;
Color stepColor;
if (isCompleted) {
stepColor = completedColor ?? AppColors.success;
} else if (isActive) {
stepColor = activeColor ?? AppColors.primary;
} else {
stepColor = inactiveColor ?? AppColors.surfaceVariant;
}
return Expanded(
child: Row(
children: [
// 步骤圆圈
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: stepColor,
),
child: Center(
child: isCompleted
? Icon(
Icons.check,
color: AppColors.onPrimary,
size: 16,
)
: Text(
stepNumber.toString(),
style: AppTextStyles.bodySmall.copyWith(
color: isInactive
? AppColors.onSurfaceVariant
: AppColors.onPrimary,
fontWeight: FontWeight.bold,
),
),
),
),
// 连接线(除了最后一个步骤)
if (index < totalSteps - 1)
Expanded(
child: Container(
height: 2,
color: isCompleted
? (completedColor ?? AppColors.success)
: (inactiveColor ?? AppColors.surfaceVariant),
),
),
],
),
);
}),
),
);
}
}