- 引导页协议多语言支持(languageId传递) - 登录页双书名号修复 + 注册页协议勾选 - 个人中心页面多语言(18个翻译键) - 网络断开提示增加关闭/刷新按钮 - 了解我们:新增秋叶qy开发者 + ayk签名修改 + 贡献者精简 + 微风暴微信搜索 - iOS快捷按钮重复修复(删除Info.plist静态定义) - 测试账号123456警告提示 - 扫码登录自动跳转(HTTP轮询+WebSocket双通道) - 登录页老用户按钮改次要色 - Syncfusion图表崩溃修复(DeferredBuilder+animationDuration:0) - macOS标题栏跟随软件夜间模式 - 平台兼容分发渠道弹窗 - 软件著作权图片+交叉水印 - 桌面小部件平台兼容说明默认收起 - iOS/macOS图标更新+名称确认为闲言 - 12个语言文件补全roleNative+7个分发渠道翻译字段
123 lines
3.6 KiB
Dart
123 lines
3.6 KiB
Dart
// ============================================================
|
|
// 闲言APP — 传输速度实时折线图
|
|
// 创建时间: 2026-05-19
|
|
// 更新时间: 2026-05-19
|
|
// 作用: 紧凑型实时速度图表 — 嵌入聊天页输入栏上方
|
|
// 上次更新: 初始创建
|
|
// ============================================================
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'package:xianyan/core/theme/app_theme.dart';
|
|
import 'package:xianyan/core/theme/app_spacing.dart';
|
|
import 'package:xianyan/core/theme/app_typography.dart';
|
|
import 'package:xianyan/shared/widgets/containers/deferred_builder.dart';
|
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
|
|
|
class TransferSpeedChart extends StatelessWidget {
|
|
const TransferSpeedChart({
|
|
super.key,
|
|
required this.speedHistory,
|
|
this.currentSpeed,
|
|
});
|
|
|
|
final List<double> speedHistory;
|
|
final double? currentSpeed;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final ext = AppTheme.ext(context);
|
|
|
|
return Container(
|
|
height: 60,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: AppSpacing.md,
|
|
vertical: AppSpacing.xs,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: ext.bgCard,
|
|
border: Border(
|
|
top: BorderSide(color: ext.bgElevated, width: 0.5),
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
if (currentSpeed != null && currentSpeed! > 0)
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: AppSpacing.sm),
|
|
child: Text(
|
|
_formatSpeed(currentSpeed!),
|
|
style: AppTypography.caption2.copyWith(
|
|
color: ext.accent,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
Expanded(child: _buildChart(ext)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildChart(AppThemeExtension ext) {
|
|
final data = speedHistory.isEmpty ? [0.0] : speedHistory;
|
|
final chartData = data.asMap().entries.map((e) => _SpeedPt(e.key, e.value)).toList();
|
|
|
|
return DeferredBuilder(
|
|
builder: (context) => SfCartesianChart(
|
|
plotAreaBorderWidth: 0,
|
|
margin: EdgeInsets.zero,
|
|
primaryXAxis: const NumericAxis(
|
|
majorGridLines: MajorGridLines(width: 0),
|
|
majorTickLines: MajorTickLines(size: 0),
|
|
axisLine: AxisLine(width: 0),
|
|
labelStyle: TextStyle(fontSize: 0),
|
|
isVisible: false,
|
|
),
|
|
primaryYAxis: const NumericAxis(
|
|
majorGridLines: MajorGridLines(width: 0),
|
|
majorTickLines: MajorTickLines(size: 0),
|
|
axisLine: AxisLine(width: 0),
|
|
labelStyle: TextStyle(fontSize: 0),
|
|
isVisible: false,
|
|
minimum: 0,
|
|
),
|
|
series: [
|
|
AreaSeries<_SpeedPt, int>(
|
|
dataSource: chartData,
|
|
xValueMapper: (d, _) => d.index,
|
|
yValueMapper: (d, _) => d.speed,
|
|
color: ext.accent,
|
|
borderColor: ext.accent,
|
|
borderWidth: 1.5,
|
|
animationDuration: 0,
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [
|
|
ext.accent.withValues(alpha: 0.25),
|
|
ext.accent.withValues(alpha: 0.02),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
String _formatSpeed(double speed) {
|
|
if (speed <= 0) return '0 KB/s';
|
|
if (speed < 1024) return '${speed.toStringAsFixed(0)} B/s';
|
|
if (speed < 1024 * 1024) {
|
|
return '${(speed / 1024).toStringAsFixed(1)} KB/s';
|
|
}
|
|
return '${(speed / (1024 * 1024)).toStringAsFixed(1)} MB/s';
|
|
}
|
|
}
|
|
|
|
class _SpeedPt {
|
|
const _SpeedPt(this.index, this.speed);
|
|
final int index;
|
|
final double speed;
|
|
}
|