mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 00:25:43 +00:00
temp
This commit is contained in:
1 parent
2ab5a4bb53
commit
8835c2855a
11 files changed
+851
-47
No files matched your search
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"dart.mcpServer": true
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 148 B |
+2
-2
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GradientButton extends StatelessWidget {
|
||||
class GpGradientButton extends StatelessWidget {
|
||||
final String text;
|
||||
final VoidCallback onPressed;
|
||||
final IconData? icon; // 添加可选图标参数
|
||||
|
||||
const GradientButton({
|
||||
const GpGradientButton({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.onPressed,
|
||||
@@ -0,0 +1,65 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// GpIconButton - 简单的图标按钮组件
|
||||
///
|
||||
/// 用于TaskItem的操作按钮,支持鼠标悬浮效果
|
||||
class GpIconButton extends StatefulWidget {
|
||||
/// 图标
|
||||
final IconData icon;
|
||||
|
||||
/// 点击回调
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// 图标颜色
|
||||
final Color? color;
|
||||
|
||||
/// 图标大小
|
||||
final double? size;
|
||||
|
||||
const GpIconButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
this.onTap,
|
||||
this.color,
|
||||
this.size,
|
||||
});
|
||||
|
||||
@override
|
||||
State<GpIconButton> createState() => _GpIconButtonState();
|
||||
}
|
||||
|
||||
class _GpIconButtonState extends State<GpIconButton> {
|
||||
bool _isHovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor:
|
||||
widget.onTap != null
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
onEnter: (_) => setState(() => _isHovered = true),
|
||||
onExit: (_) => setState(() => _isHovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: widget.size ?? 20.0,
|
||||
height: widget.size ?? 20.0,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4.0), // 8px圆角
|
||||
color:
|
||||
_isHovered
|
||||
? const Color(0xFF4883A2)
|
||||
: Colors.transparent, // 悬浮背景色
|
||||
),
|
||||
child: Icon(
|
||||
widget.icon,
|
||||
color: widget.color ?? Colors.white,
|
||||
size: widget.size ?? 20.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// GpOutlineButton - 线框按钮组件
|
||||
///
|
||||
/// 一个带有线框边框的小型按钮组件,支持自定义图标
|
||||
class GpOutlineButton extends StatelessWidget {
|
||||
/// 按钮内的图标路径或图标数据
|
||||
final dynamic icon;
|
||||
|
||||
/// 点击回调
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// 按钮宽度,默认42px
|
||||
final double width;
|
||||
|
||||
/// 按钮高度,默认22px
|
||||
final double height;
|
||||
|
||||
/// 边框颜色,默认#39CDB9
|
||||
final Color borderColor;
|
||||
|
||||
/// 边框圆角,默认4px
|
||||
final double borderRadius;
|
||||
|
||||
/// 边框宽度,默认1px
|
||||
final double borderWidth;
|
||||
|
||||
/// 图标颜色
|
||||
final Color? iconColor;
|
||||
|
||||
/// 图标大小
|
||||
final double? iconSize;
|
||||
|
||||
/// 背景颜色
|
||||
final Color? backgroundColor;
|
||||
|
||||
const GpOutlineButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
this.onTap,
|
||||
this.width = 42.0,
|
||||
this.height = 22.0,
|
||||
this.borderColor = const Color(0xFF39CDB9),
|
||||
this.borderRadius = 4.0,
|
||||
this.borderWidth = 1.0,
|
||||
this.iconColor,
|
||||
this.iconSize,
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor:
|
||||
onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
border: Border.all(color: borderColor, width: borderWidth),
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
),
|
||||
child: _buildIcon(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildIcon() {
|
||||
if (icon == null) return const SizedBox.shrink();
|
||||
|
||||
// 如果是字符串,认为是资源路径
|
||||
if (icon is String) {
|
||||
return Center(
|
||||
child: Image.asset(
|
||||
icon as String,
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
color: iconColor,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 如果是IconData,使用Icon组件
|
||||
if (icon is IconData) {
|
||||
return Center(
|
||||
child: Icon(icon as IconData, color: iconColor, size: iconSize ?? 16.0),
|
||||
);
|
||||
}
|
||||
|
||||
// 如果是Widget,直接使用
|
||||
if (icon is Widget) {
|
||||
return Center(child: icon as Widget);
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'gradient_button.dart';
|
||||
import '../../../components/gp_gradient_button.dart';
|
||||
import '../../../components/gp_outline_button.dart';
|
||||
import '../../../components/gp_icon_button.dart';
|
||||
import '../widgets/task_item.dart';
|
||||
import 'task_tabs.dart';
|
||||
|
||||
class TaskScreen extends StatefulWidget {
|
||||
@@ -32,7 +35,7 @@ class _TaskScreenState extends State<TaskScreen> {
|
||||
padding: const EdgeInsets.only(left: 16.0, top: 16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
GradientButton(
|
||||
GpGradientButton(
|
||||
text: '创建任务',
|
||||
icon: Icons.add, // 添加加号图标
|
||||
onPressed: () {
|
||||
@@ -49,7 +52,37 @@ class _TaskScreenState extends State<TaskScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: 16),
|
||||
// 操作按钮列表
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 24.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GpOutlineButton(
|
||||
icon: 'assets/icons/pause.png',
|
||||
onTap: () {
|
||||
// 处理开始按钮点击事件
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
GpOutlineButton(
|
||||
icon: 'assets/icons/pause.png',
|
||||
onTap: () {
|
||||
// 处理暂停按钮点击事件
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
GpOutlineButton(
|
||||
icon: 'assets/icons/pause.png',
|
||||
onTap: () {
|
||||
// 处理删除按钮点击事件
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(child: _buildTaskList(_selectedTabIndex)),
|
||||
],
|
||||
),
|
||||
@@ -60,16 +93,126 @@ class _TaskScreenState extends State<TaskScreen> {
|
||||
// 根据选中的标签页显示不同的任务列表
|
||||
switch (tabIndex) {
|
||||
case 0:
|
||||
return const Center(
|
||||
child: Text('下载中的任务列表', style: TextStyle(color: Colors.white)),
|
||||
return ListView.separated(
|
||||
itemCount: 3, // 示例显示3个任务项
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemBuilder:
|
||||
(context, index) => TaskItem(
|
||||
icon: Icons.download, // 添加下载图标
|
||||
taskName: '下载任务 ${index + 1}', // 添加任务名称
|
||||
progress: (index + 1) * 0.25, // 添加进度值 (0.25, 0.5, 0.75)
|
||||
fileSizeText:
|
||||
'${(2.1 + index * 0.1).toStringAsFixed(1)}MB/2.4MB', // 示例文件大小
|
||||
bottomRightIcon: Icons.speed, // 添加速度图标
|
||||
bottomRightGradientText:
|
||||
'${(1.5 + index * 0.3).toStringAsFixed(1)}MB/s', // 下载速度
|
||||
bottomRightStatusText: '下载中', // 状态文本
|
||||
actionButtons: [
|
||||
GpIconButton(
|
||||
icon: Icons.pause,
|
||||
onTap: () => print('暂停任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.delete,
|
||||
onTap: () => print('删除任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.folder_open,
|
||||
onTap: () => print('打开所在位置 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.info,
|
||||
onTap: () => print('查看信息 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.more_vert,
|
||||
onTap: () => print('更多操作 $index'),
|
||||
),
|
||||
],
|
||||
onTap: () {
|
||||
print('任务项 $index 被点击');
|
||||
},
|
||||
),
|
||||
);
|
||||
case 1:
|
||||
return const Center(
|
||||
child: Text('已完成的任务列表', style: TextStyle(color: Colors.white)),
|
||||
return ListView.separated(
|
||||
itemCount: 2, // 示例显示2个任务项
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemBuilder:
|
||||
(context, index) => TaskItem(
|
||||
icon: Icons.check_circle, // 添加完成图标
|
||||
taskName: '已完成任务 ${index + 1}', // 添加任务名称
|
||||
progress: 1.0, // 已完成任务进度为100%
|
||||
fileSizeText: '2.4MB/2.4MB - 已完成', // 添加完成信息
|
||||
bottomRightIcon: Icons.check, // 添加完成图标
|
||||
bottomRightGradientText: '完成时间', // 完成时间文本
|
||||
bottomRightStatusText: '已完成', // 状态文本
|
||||
actionButtons: [
|
||||
GpIconButton(
|
||||
icon: Icons.pause,
|
||||
onTap: () => print('暂停任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.delete,
|
||||
onTap: () => print('删除任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.folder_open,
|
||||
onTap: () => print('打开所在位置 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.info,
|
||||
onTap: () => print('查看信息 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.more_vert,
|
||||
onTap: () => print('更多操作 $index'),
|
||||
),
|
||||
],
|
||||
onTap: () {
|
||||
print('已完成任务项 $index 被点击');
|
||||
},
|
||||
),
|
||||
);
|
||||
case 2:
|
||||
return const Center(
|
||||
child: Text('失败的任务列表', style: TextStyle(color: Colors.white)),
|
||||
return ListView.separated(
|
||||
itemCount: 1, // 示例显示1个任务项
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemBuilder:
|
||||
(context, index) => TaskItem(
|
||||
icon: Icons.error, // 添加错误图标
|
||||
taskName: '失败任务 ${index + 1}', // 添加任务名称
|
||||
progress: 0.3, // 失败任务的部分进度
|
||||
fileSizeText: '1.2MB/4.0MB - 任务失败', // 添加失败信息
|
||||
bottomRightIcon: Icons.error_outline, // 添加错误图标
|
||||
bottomRightGradientText: '重试', // 重试文本
|
||||
bottomRightStatusText: '失败', // 状态文本
|
||||
actionButtons: [
|
||||
GpIconButton(
|
||||
icon: Icons.pause,
|
||||
onTap: () => print('暂停任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.delete,
|
||||
onTap: () => print('删除任务 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.folder_open,
|
||||
onTap: () => print('打开所在位置 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.info,
|
||||
onTap: () => print('查看信息 $index'),
|
||||
),
|
||||
GpIconButton(
|
||||
icon: Icons.more_vert,
|
||||
onTap: () => print('更多操作 $index'),
|
||||
),
|
||||
],
|
||||
onTap: () {
|
||||
print('失败任务项 $index 被点击');
|
||||
},
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Container();
|
||||
|
||||
@@ -0,0 +1,491 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// TaskItem - 任务项组件
|
||||
///
|
||||
/// 一个带有毛玻璃效果和渐变边框的任务项容器,宽度自适应父组件
|
||||
class TaskItem extends StatelessWidget {
|
||||
/// 左侧图标
|
||||
final dynamic icon;
|
||||
|
||||
/// 任务名称
|
||||
final String? taskName;
|
||||
|
||||
/// 进度值 (0.0 - 1.0)
|
||||
final double? progress;
|
||||
|
||||
/// 右上角操作按钮列表
|
||||
final List<Widget>? actionButtons;
|
||||
|
||||
/// 容器高度,默认106px
|
||||
final double height;
|
||||
|
||||
/// 圆角大小,默认8px
|
||||
final double borderRadius;
|
||||
|
||||
/// 点击回调
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// 文件大小文本(如2.1MB/2.4MB)
|
||||
final String? fileSizeText;
|
||||
|
||||
/// 右下角图标
|
||||
final IconData? bottomRightIcon;
|
||||
|
||||
/// 右下角渐变文本
|
||||
final String? bottomRightGradientText;
|
||||
|
||||
/// 右下角状态文本
|
||||
final String? bottomRightStatusText;
|
||||
|
||||
const TaskItem({
|
||||
super.key,
|
||||
this.icon,
|
||||
this.taskName,
|
||||
this.progress,
|
||||
this.actionButtons,
|
||||
this.height = 106.0,
|
||||
this.borderRadius = 8.0,
|
||||
this.onTap,
|
||||
this.fileSizeText,
|
||||
this.bottomRightIcon,
|
||||
this.bottomRightGradientText,
|
||||
this.bottomRightStatusText,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor:
|
||||
onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: height,
|
||||
child: Stack(
|
||||
children: [
|
||||
// Rectangle 82: 主容器 (最底层)
|
||||
Positioned.fill(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 24.0, sigmaY: 24.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
// 背景色:rgba(178, 231, 254, 0.08)
|
||||
color: const Color(0xFFB2E7FE).withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
border: Border.all(
|
||||
width: 0.5,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
// 渐变边框效果
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
stops: [0.17, 0.92],
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Color(0x29FFFFFF), // rgba(255, 255, 255, 0.16)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 蒙版组 (中间层) - 简化测试
|
||||
Positioned.fill(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Rectangle 80: 渐变模糊背景 - 只保留这个
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 7.23,
|
||||
child: ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(
|
||||
sigmaX: 40.0,
|
||||
sigmaY: 40.0,
|
||||
),
|
||||
child: Container(
|
||||
height: 90.34,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.centerLeft, // 90deg = 从左到右
|
||||
end: Alignment.centerRight,
|
||||
stops: [0.0, 1.0],
|
||||
colors: [
|
||||
Color(0xFF2D3975), // #2D3975 at 0%
|
||||
Color(0xFF266682), // #266682 at 100%
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Rectangle 81: 纯色背景蒙版 - 图层样式穿透,所以注释掉
|
||||
// 设计稿中标明"图层样式穿透",意味着这层不影响最终视觉效果
|
||||
// Positioned(
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// top: 0,
|
||||
// child: Container(
|
||||
// height: height,
|
||||
// decoration: BoxDecoration(
|
||||
// color: const Color(0xFFB2E7FE),
|
||||
// borderRadius: BorderRadius.circular(borderRadius),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 内容层 (最上层)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16.0), // 统一的16px内边距
|
||||
child: Row(
|
||||
children: [
|
||||
// 左侧图标区域
|
||||
if (icon != null)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
), // 图标右边间隔2px
|
||||
child: _buildIcon(),
|
||||
),
|
||||
|
||||
// 右侧内容容器
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 任务名称区域 (与操作按钮在同一行)
|
||||
Row(
|
||||
children: [
|
||||
// 任务名称
|
||||
if (taskName != null)
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 22.0, // 设计稿高度22px
|
||||
child: Align(
|
||||
alignment:
|
||||
Alignment
|
||||
.bottomLeft, // align-items: flex-end
|
||||
child: Text(
|
||||
taskName!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16.0, // 16px
|
||||
fontWeight:
|
||||
FontWeight.bold, // bold
|
||||
height:
|
||||
22.0 /
|
||||
16.0, // line-height: 22px
|
||||
color: Color(
|
||||
0xFFFFFFFE,
|
||||
), // #FFFFFE
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 右侧操作按钮列表
|
||||
if (actionButtons != null &&
|
||||
actionButtons!.isNotEmpty)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _buildActionButtons(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// 进度条
|
||||
if (progress != null)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(
|
||||
top: 20.0,
|
||||
), // 距离名称下面20px
|
||||
child: _buildProgressBar(),
|
||||
),
|
||||
|
||||
// 文件大小文本和右下角元素行
|
||||
Container(
|
||||
margin: const EdgeInsets.only(
|
||||
top: 8.0,
|
||||
), // 距离进度条下面8px
|
||||
height: 16.0, // 直接指定高度为16px
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center, // 垂直居中对齐
|
||||
children: [
|
||||
// 左侧文件大小文本
|
||||
if (fileSizeText != null &&
|
||||
fileSizeText!.isNotEmpty)
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
fileSizeText!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(
|
||||
0xFFCCCCCC,
|
||||
), // #CCCCCC
|
||||
letterSpacing: 0.0,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 右下角元素组
|
||||
_buildBottomRightElements(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建图标组件
|
||||
Widget _buildIcon() {
|
||||
if (icon == null) return const SizedBox.shrink();
|
||||
|
||||
// 如果是字符串,认为是资源路径
|
||||
if (icon is String) {
|
||||
return Image.asset(
|
||||
icon as String,
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
}
|
||||
|
||||
// 如果是IconData,使用Icon组件
|
||||
if (icon is IconData) {
|
||||
return Icon(icon as IconData, size: 32.0, color: Colors.white);
|
||||
}
|
||||
|
||||
// 如果是Widget,直接使用
|
||||
if (icon is Widget) {
|
||||
return SizedBox(width: 32.0, height: 32.0, child: icon as Widget);
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
/// 构建操作按钮列表
|
||||
List<Widget> _buildActionButtons() {
|
||||
if (actionButtons == null || actionButtons!.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
List<Widget> buttons = [];
|
||||
for (int i = 0; i < actionButtons!.length; i++) {
|
||||
// 添加按钮
|
||||
buttons.add(
|
||||
SizedBox(width: 20.0, height: 20.0, child: actionButtons![i]),
|
||||
);
|
||||
|
||||
// 添加间隔 (除了最后一个按钮)
|
||||
if (i < actionButtons!.length - 1) {
|
||||
buttons.add(const SizedBox(width: 16.0));
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/// 构建进度条
|
||||
Widget _buildProgressBar() {
|
||||
if (progress == null) return const SizedBox.shrink();
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// 使用所有可用宽度,因为已经有统一的16px内边距
|
||||
final availableWidth = constraints.maxWidth;
|
||||
final progressWidth = availableWidth * progress!;
|
||||
|
||||
return SizedBox(
|
||||
height: 8.0,
|
||||
child: Stack(
|
||||
children: [
|
||||
// 底部背景条
|
||||
Container(
|
||||
width: availableWidth,
|
||||
height: 8.0,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFEBEDF3), // #EBEDF3
|
||||
borderRadius: BorderRadius.circular(548.0), // 548px圆角
|
||||
),
|
||||
),
|
||||
|
||||
// 进度条
|
||||
Container(
|
||||
width: progressWidth,
|
||||
height: 8.0,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(143.0), // 143px圆角
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.centerLeft, // 90deg
|
||||
end: Alignment.centerRight,
|
||||
stops: [0.0, 0.44, 0.99],
|
||||
colors: [
|
||||
Color(0xC93ACBBE), // rgba(58, 203, 190, 0.79)
|
||||
Color(0xFF3ACBBE), // #3ACBBE at 44%
|
||||
Color(0xFF2CDB90), // #2CDB90 at 99%
|
||||
],
|
||||
),
|
||||
border: Border.all(width: 1.0, color: Colors.transparent),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(143.0),
|
||||
// 渐变边框效果
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topCenter, // 180deg
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0xFF39CBBC), // #39CBBC at 0%
|
||||
Color(0xFF2CDA92), // #2CDA92 at 100%
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(1.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(142.0),
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
stops: [0.0, 0.44, 0.99],
|
||||
colors: [
|
||||
Color(0xC93ACBBE), // rgba(58, 203, 190, 0.79)
|
||||
Color(0xFF3ACBBE), // #3ACBBE at 44%
|
||||
Color(0xFF2CDB90), // #2CDB90 at 99%
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建右下角元素组
|
||||
Widget _buildBottomRightElements() {
|
||||
// 如果没有任何右下角元素,返回空
|
||||
if (bottomRightIcon == null &&
|
||||
bottomRightGradientText == null &&
|
||||
bottomRightStatusText == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
List<Widget> children = [];
|
||||
|
||||
// 添加图标
|
||||
if (bottomRightIcon != null) {
|
||||
children.add(Icon(bottomRightIcon!, size: 16.0, color: Colors.white));
|
||||
}
|
||||
|
||||
// 添加渐变文本
|
||||
if (bottomRightGradientText != null &&
|
||||
bottomRightGradientText!.isNotEmpty) {
|
||||
if (children.isNotEmpty) {
|
||||
children.add(const SizedBox(width: 4.0)); // 间隔4px
|
||||
}
|
||||
|
||||
children.add(
|
||||
ShaderMask(
|
||||
shaderCallback:
|
||||
(bounds) => const LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
transform: GradientRotation(272 * 3.14159 / 180), // 272度转弧度
|
||||
stops: [0.73, 1.22],
|
||||
colors: [
|
||||
Color(0xFF39CDB9), // #39CDB9 at 73%
|
||||
Color(0xFF2EDA94), // #2EDA94 at 122%
|
||||
],
|
||||
).createShader(bounds),
|
||||
child: Text(
|
||||
bottomRightGradientText!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white, // 这个颜色会被shader覆盖
|
||||
letterSpacing: 0.0,
|
||||
height: 1.0, // 设置行高为1,减少额外空间
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 添加状态文本
|
||||
if (bottomRightStatusText != null && bottomRightStatusText!.isNotEmpty) {
|
||||
if (children.isNotEmpty) {
|
||||
children.add(const SizedBox(width: 12.0)); // 间隔12px
|
||||
}
|
||||
|
||||
children.add(
|
||||
Text(
|
||||
bottomRightStatusText!,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Source Han Sans',
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFFCCCCCC), // #CCCCCC
|
||||
letterSpacing: 0.0,
|
||||
height: 1.0, // 设置行高为1,减少额外空间
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center, // 垂直居中对齐
|
||||
textBaseline: TextBaseline.alphabetic, // 统一文本基线
|
||||
children: children,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
platform :osx, '10.14'
|
||||
platform :osx, '10.15'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
@@ -19,10 +19,10 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
|
||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||
|
||||
PODFILE CHECKSUM: 7eb978b976557c8c1cd717d8185ec483fd090a82
|
||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
@@ -557,7 +557,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
@@ -639,7 +639,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -689,7 +689,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
||||
+30
-30
@@ -13,10 +13,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -61,10 +61,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -82,10 +82,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b
|
||||
sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.17"
|
||||
version: "2.2.1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -108,10 +108,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.5.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -132,26 +132,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "11.0.2"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.9"
|
||||
version: "3.0.10"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -212,10 +212,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
|
||||
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "7.0.1"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -313,10 +313,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
version: "0.7.6"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -329,10 +329,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
|
||||
sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.18"
|
||||
version: "1.1.19"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -345,26 +345,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
|
||||
sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.16"
|
||||
version: "1.1.19"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.2.0"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.2"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -385,10 +385,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
version: "6.6.1"
|
||||
sdks:
|
||||
dart: ">=3.7.2 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
dart: ">=3.8.0 <4.0.0"
|
||||
flutter: ">=3.29.0"
|
||||
Reference in new issue
Block a user