本次提交实现了背诵模块的完整基础链路: 1. 新增词书、背单词接口层与对应数据模型 2. 完成背诵首页、章节列表页等核心页面开发 3. 实现音频播放、加载弹窗等通用组件 4. 配置路由跳转链路,替换旧版缓存传参方案 5. 对齐Vue端业务逻辑与UI样式
124 lines
3.4 KiB
Dart
124 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
|
||
/// ============================================================
|
||
/// 背诵模块进度条组件
|
||
///
|
||
/// 1. GradientProgressBar —— 对标 Vue r-progress(linear-gradient 填充)
|
||
/// 词书卡蓝色渐变 / 关卡绿色渐变 / 未解锁灰色,全靠 colors 切换。
|
||
///
|
||
/// 2. SegmentedProgressBar —— 对标 Vue SegmentedProgressBar.vue
|
||
/// 三段独立进度,每段各自按 33/33/34 比例填充,绿色渐变。
|
||
/// ============================================================
|
||
|
||
/// 渐变线性进度条(percent:0~100)
|
||
class GradientProgressBar extends StatelessWidget {
|
||
const GradientProgressBar({
|
||
super.key,
|
||
required this.percent,
|
||
this.height = 6,
|
||
this.colors = const [Color(0xFF84AFFF), Color(0xFF3C7CF6)],
|
||
this.trackColor = const Color(0xFFF5F5F5),
|
||
this.radius,
|
||
});
|
||
|
||
/// 0~100(自动 clamp)
|
||
final double percent;
|
||
final double height;
|
||
|
||
/// 填充渐变(单色时传同色两个即可)
|
||
final List<Color> colors;
|
||
final Color trackColor;
|
||
final double? radius;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final safe = percent.clamp(0, 100).toDouble();
|
||
return ClipRRect(
|
||
borderRadius: BorderRadius.circular(radius ?? (height / 2).r),
|
||
child: LayoutBuilder(
|
||
builder: (context, constraints) {
|
||
final width = constraints.maxWidth;
|
||
return Container(
|
||
height: height.w,
|
||
color: trackColor,
|
||
child: Align(
|
||
alignment: Alignment.centerLeft,
|
||
child: SizedBox(
|
||
width: width * safe / 100,
|
||
child: DecoratedBox(
|
||
decoration: BoxDecoration(
|
||
gradient: LinearGradient(
|
||
colors: colors,
|
||
begin: Alignment.centerLeft,
|
||
end: Alignment.centerRight,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 三段式分段进度条(对标 SegmentedProgressBar.vue;progress:0~100)
|
||
class SegmentedProgressBar extends StatelessWidget {
|
||
const SegmentedProgressBar({super.key, required this.progress});
|
||
|
||
final double progress;
|
||
|
||
static const Color _green1 = Color(0xFF1BC26E);
|
||
static const Color _green2 = Color(0xFF7ED8AA);
|
||
|
||
/// 与 Vue updateBarProgress 完全一致的分段算法
|
||
List<double> _segmentPercents(double p) {
|
||
double bar1;
|
||
if (p >= 33) {
|
||
bar1 = 100;
|
||
} else {
|
||
bar1 = (p / 33 * 100).clamp(0, 100).toDouble();
|
||
}
|
||
|
||
double bar2;
|
||
if (p >= 66) {
|
||
bar2 = 100;
|
||
} else if (p > 33) {
|
||
bar2 = ((p - 33) / 33 * 100).clamp(0, 100).toDouble();
|
||
} else {
|
||
bar2 = 0;
|
||
}
|
||
|
||
double bar3;
|
||
if (p >= 100) {
|
||
bar3 = 100;
|
||
} else if (p > 66) {
|
||
bar3 = ((p - 66) / 34 * 100).clamp(0, 100).toDouble();
|
||
} else {
|
||
bar3 = 0;
|
||
}
|
||
return [bar1, bar2, bar3];
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final segs = _segmentPercents(progress);
|
||
return Row(
|
||
children: [
|
||
for (var i = 0; i < 3; i++) ...[
|
||
if (i > 0) SizedBox(width: 5.w),
|
||
Expanded(
|
||
child: GradientProgressBar(
|
||
percent: segs[i],
|
||
height: 6,
|
||
colors: const [_green1, _green2],
|
||
),
|
||
),
|
||
],
|
||
],
|
||
);
|
||
}
|
||
}
|