You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
727 lines
23 KiB
727 lines
23 KiB
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import '../controllers/home_controller.dart';
|
|
import '../../../core/routes/app_pages.dart';
|
|
import '../../../core/routes/app_routes.dart';
|
|
import '../../../core/widgets/common_bottom_nav.dart';
|
|
|
|
// 导入枚举
|
|
import '../controllers/home_controller.dart' show ConnectionStatus;
|
|
|
|
// 呼吸光动画组件
|
|
class AnimatedPulsing extends StatefulWidget {
|
|
@override
|
|
_AnimatedPulsingState createState() => _AnimatedPulsingState();
|
|
}
|
|
|
|
class _AnimatedPulsingState extends State<AnimatedPulsing> with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
late Animation<double> _animation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
duration: Duration(seconds: 2),
|
|
vsync: this,
|
|
)..repeat(reverse: true);
|
|
_animation = Tween<double>(begin: 0.5, end: 0.8).animate(
|
|
CurvedAnimation(
|
|
parent: _controller,
|
|
curve: Curves.easeInOut,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _animation,
|
|
builder: (context, child) {
|
|
return Opacity(
|
|
opacity: _animation.value,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
Colors.white.withOpacity(0.3),
|
|
Colors.transparent,
|
|
],
|
|
center: Alignment.topRight,
|
|
radius: 0.8,
|
|
stops: [0.0, 1.0],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class HomeView extends GetView<HomeController> {
|
|
const HomeView({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: Color(0xFFF9FAFC),
|
|
appBar: AppBar(
|
|
elevation: 0,
|
|
backgroundColor: Color(0xFFF9FAFC),
|
|
title: Text(
|
|
'智能耳机',
|
|
style: TextStyle(
|
|
color: Colors.black87,
|
|
fontSize: 18.sp,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
actions: [
|
|
IconButton(
|
|
icon: Icon(Icons.settings_outlined, color: Colors.black54),
|
|
onPressed: () {
|
|
Get.toNamed(Routes.settings);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
body: SafeArea(
|
|
child: SingleChildScrollView(
|
|
padding: EdgeInsets.all(16.w),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 顶部图片
|
|
Center(
|
|
child: _buildEarbudsImage(),
|
|
),
|
|
SizedBox(height: 20.h),
|
|
|
|
// 设备状态卡片
|
|
_buildDeviceStatusCard(),
|
|
SizedBox(height: 20.h),
|
|
|
|
// 热门AI体验
|
|
Row(
|
|
children: [
|
|
Text(
|
|
'热门AI体验',
|
|
style: TextStyle(
|
|
fontSize: 18.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
SizedBox(width: 8.w),
|
|
Icon(
|
|
Icons.star,
|
|
color: Colors.amber,
|
|
size: 20.w,
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 16.h),
|
|
_buildPremiumAILayout(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
bottomNavigationBar: const CommonBottomNav(currentIndex: 0),
|
|
);
|
|
}
|
|
|
|
// 页面顶部:状态栏和标题
|
|
Widget _buildHeader() {
|
|
return Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
|
|
child: Column(
|
|
children: [
|
|
// 删除状态栏
|
|
|
|
// 标题区域
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
'DeepVoice Pro',
|
|
style: TextStyle(
|
|
fontSize: 20.sp,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey[800],
|
|
),
|
|
),
|
|
Container(
|
|
width: 32.w,
|
|
height: 32.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[200],
|
|
shape: BoxShape.circle,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.grey.withOpacity(0.2),
|
|
blurRadius: 4,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: IconButton(
|
|
icon: Icon(Icons.more_horiz, size: 16.sp, color: Colors.grey[600]),
|
|
padding: EdgeInsets.zero,
|
|
onPressed: () {
|
|
// 打开更多选项菜单
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 耳机图片
|
|
Widget _buildEarbudsImage() {
|
|
return Container(
|
|
height: 180.h,
|
|
alignment: Alignment.center,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(20.r),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.grey.withOpacity(0.15),
|
|
blurRadius: 15,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
BoxShadow(
|
|
color: Colors.blue.withOpacity(0.05),
|
|
blurRadius: 20,
|
|
offset: const Offset(0, -2),
|
|
),
|
|
],
|
|
),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(20.r),
|
|
child: Container(
|
|
color: Colors.white,
|
|
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h),
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
// 背景光效
|
|
Positioned.fill(
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
Colors.blue.withOpacity(0.05),
|
|
Colors.white,
|
|
],
|
|
center: Alignment.topRight,
|
|
radius: 0.8,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
// 耳机图片
|
|
Image.asset(
|
|
'assets/images/headphone_light.png',
|
|
height: 150.h,
|
|
fit: BoxFit.contain,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// 设备状态卡片
|
|
Widget _buildDeviceStatusCard() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.grey.withOpacity(0.1),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
padding: EdgeInsets.all(16.w),
|
|
child: Column(
|
|
children: [
|
|
// 状态标题行
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
'设备状态',
|
|
style: TextStyle(
|
|
fontSize: 14.sp,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey[700],
|
|
),
|
|
),
|
|
Obx(() => Row(
|
|
children: [
|
|
Container(
|
|
width: 8.w,
|
|
height: 8.w,
|
|
decoration: BoxDecoration(
|
|
color: controller.getConnectionStatusColor(),
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
SizedBox(width: 4.w),
|
|
Text(
|
|
controller.getConnectionStatusText(),
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: controller.getConnectionStatusColor(),
|
|
),
|
|
),
|
|
// 添加刷新按钮
|
|
SizedBox(width: 8.w),
|
|
InkWell(
|
|
onTap: controller.refreshDeviceInfo,
|
|
child: Icon(
|
|
Icons.refresh,
|
|
size: 16.sp,
|
|
color: Colors.grey[600],
|
|
),
|
|
),
|
|
],
|
|
)),
|
|
],
|
|
),
|
|
|
|
// 设备信息
|
|
SizedBox(height: 12.h),
|
|
Obx(() {
|
|
// 如果连接失败且有错误信息,显示错误提示
|
|
if (controller.connectionStatus == ConnectionStatus.failed &&
|
|
controller.connectionErrorMsg.isNotEmpty) {
|
|
return Column(
|
|
children: [
|
|
Container(
|
|
padding: EdgeInsets.all(8.w),
|
|
decoration: BoxDecoration(
|
|
color: Colors.red[50],
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
border: Border.all(color: Colors.red[200]!),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.error_outline,
|
|
color: Colors.red,
|
|
size: 16.sp,
|
|
),
|
|
SizedBox(width: 8.w),
|
|
Expanded(
|
|
child: Text(
|
|
controller.connectionErrorMsg,
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: Colors.red[800],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
SizedBox(height: 12.h),
|
|
// 连接按钮
|
|
ElevatedButton(
|
|
onPressed: controller.rescanDevices,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blue,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: Size(double.infinity, 36.h),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
),
|
|
child: Text('重新连接'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// 如果正在连接中,显示连接中提示
|
|
if (controller.connectionStatus == ConnectionStatus.connecting) {
|
|
return Container(
|
|
padding: EdgeInsets.symmetric(vertical: 16.h),
|
|
child: Center(
|
|
child: Column(
|
|
children: [
|
|
SizedBox(
|
|
width: 24.w,
|
|
height: 24.w,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2.w,
|
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
|
|
),
|
|
),
|
|
SizedBox(height: 8.h),
|
|
Text(
|
|
'正在连接设备...',
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: Colors.blue,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return controller.isConnected
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
'已连接到:${controller.getDeviceName()}',
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey[700],
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(4.r),
|
|
),
|
|
child: Text(
|
|
'信号: ${controller.getSignalStrength()}',
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.blue[700],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 8.h),
|
|
Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[50],
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'设备ID:${controller.getDeviceId()}',
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.grey[500],
|
|
),
|
|
),
|
|
SizedBox(height: 4.h),
|
|
Text(
|
|
'固件版本:${controller.firmwareVersion}',
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.grey[500],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
)
|
|
: Container(
|
|
padding: EdgeInsets.symmetric(vertical: 8.h),
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[100],
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.bluetooth_disabled,
|
|
size: 14.sp,
|
|
color: Colors.grey[700],
|
|
),
|
|
SizedBox(width: 4.w),
|
|
Text(
|
|
'未连接设备,点击下方按钮连接',
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: Colors.grey[700],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}),
|
|
|
|
// 连接按钮(仅在未连接时显示)
|
|
SizedBox(height: 12.h),
|
|
Obx(() {
|
|
if (controller.connectionStatus == ConnectionStatus.disconnected) {
|
|
return ElevatedButton(
|
|
onPressed: controller.rescanDevices,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blue,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: Size(double.infinity, 36.h),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
),
|
|
child: Text('连接设备'),
|
|
);
|
|
} else {
|
|
return SizedBox();
|
|
}
|
|
}),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 优质AI体验布局(左1右2)
|
|
Widget _buildPremiumAILayout() {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 左侧大卡片 - AI助理
|
|
Expanded(
|
|
flex: 1,
|
|
child: Stack(
|
|
children: [
|
|
// 呼吸光效果
|
|
Positioned.fill(
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
Color(0xFF4ECDC4).withOpacity(0.6),
|
|
Colors.transparent,
|
|
],
|
|
center: Alignment.topRight,
|
|
radius: 1.0,
|
|
),
|
|
),
|
|
child: AnimatedPulsing(),
|
|
),
|
|
),
|
|
// 卡片内容
|
|
_buildFeatureCard(
|
|
title: 'AI全能助手',
|
|
description: '24小时专属顾问,解答问题、提供建议',
|
|
icon: Icons.smart_toy,
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [
|
|
Color(0xFF4ECDC4),
|
|
Color(0xFF556270),
|
|
],
|
|
),
|
|
onTap: controller.exploreAIFeatures,
|
|
iconOnTop: true,
|
|
height: 175.h, // 增加高度
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
SizedBox(width: 16.w),
|
|
|
|
// 右侧两个卡片
|
|
Expanded(
|
|
flex: 1,
|
|
child: Column(
|
|
children: [
|
|
// 右上卡片 - 同声翻译
|
|
_buildFeatureCard(
|
|
title: '同声传译',
|
|
description: '80+语言实时翻译,出国无忧',
|
|
icon: Icons.translate,
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [
|
|
Color(0xFF5E72EB),
|
|
Color(0xFF4776E6),
|
|
],
|
|
),
|
|
onTap: controller.openTranslation,
|
|
height: 83.h, // 增加高度
|
|
),
|
|
|
|
SizedBox(height: 5.h), // 减少间距
|
|
|
|
// 右下卡片 - AI女友
|
|
_buildFeatureCard(
|
|
title: 'AI伴侣',
|
|
description: '懂你心意,温暖陪伴',
|
|
icon: Icons.favorite,
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [
|
|
Color(0xFFFF758C),
|
|
Color(0xFFFF7EB3),
|
|
],
|
|
),
|
|
onTap: controller.openAIGirlfriend,
|
|
height: 85.h, // 增加高度
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// 特性卡片构建方法
|
|
Widget _buildFeatureCard({
|
|
required String title,
|
|
required String description,
|
|
required IconData icon,
|
|
required LinearGradient gradient,
|
|
required VoidCallback onTap,
|
|
double? height,
|
|
bool iconOnTop = false,
|
|
}) {
|
|
return InkWell(
|
|
onTap: onTap,
|
|
child: Container(
|
|
height: height ?? 175.h,
|
|
padding: EdgeInsets.all(14.w),
|
|
decoration: BoxDecoration(
|
|
gradient: gradient,
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.1),
|
|
blurRadius: 5,
|
|
offset: Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: iconOnTop
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 图标靠左而不是居中
|
|
Container(
|
|
width: 45.w,
|
|
height: 45.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(12.r),
|
|
),
|
|
child: Icon(
|
|
icon,
|
|
color: Colors.white,
|
|
size: 24.w,
|
|
),
|
|
),
|
|
SizedBox(height: 8.h),
|
|
// 标题
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
SizedBox(height: 4.h),
|
|
// 描述
|
|
Expanded(
|
|
child: Text(
|
|
description,
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.9),
|
|
fontSize: 12.sp,
|
|
),
|
|
maxLines: 3,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 图标
|
|
Container(
|
|
width: 34.w,
|
|
height: 34.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
child: Icon(
|
|
icon,
|
|
color: Colors.white,
|
|
size: 18.w,
|
|
),
|
|
),
|
|
SizedBox(width: 10.w),
|
|
// 文本内容
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// 标题
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 14.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
SizedBox(height: 2.h),
|
|
// 描述
|
|
Text(
|
|
description,
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.9),
|
|
fontSize: 10.sp,
|
|
),
|
|
maxLines: 2,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|