|
|
@ -1,12 +1,10 @@ |
|
|
import 'dart:ui'; |
|
|
|
|
|
|
|
|
|
|
|
import '../../../routes/app_routes.dart'; |
|
|
import '../../../routes/app_routes.dart'; |
|
|
import '/modules/devices/controllers/devices_controller.dart'; |
|
|
|
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import '/core/theme/app_colors.dart'; |
|
|
import '/core/theme/app_colors.dart'; |
|
|
import '/data/models/user_Info.dart'; |
|
|
import '/data/models/user_Info.dart'; |
|
|
|
|
|
import '/data/services/ble_manager.dart'; |
|
|
import '../controllers/devices_controller.dart'; |
|
|
import '../controllers/devices_controller.dart'; |
|
|
|
|
|
|
|
|
// 设备类型枚举 |
|
|
// 设备类型枚举 |
|
|
@ -20,7 +18,6 @@ enum DeviceType { |
|
|
const DeviceType(this.value); |
|
|
const DeviceType(this.value); |
|
|
final int value; |
|
|
final int value; |
|
|
|
|
|
|
|
|
// 使用getter获取多语言显示名称 |
|
|
|
|
|
String get displayName { |
|
|
String get displayName { |
|
|
switch (this) { |
|
|
switch (this) { |
|
|
case DeviceType.Unknown: |
|
|
case DeviceType.Unknown: |
|
|
@ -61,112 +58,240 @@ enum DeviceType { |
|
|
class DevicesView extends GetView<DevicesController> { |
|
|
class DevicesView extends GetView<DevicesController> { |
|
|
const DevicesView({super.key}); |
|
|
const DevicesView({super.key}); |
|
|
|
|
|
|
|
|
|
|
|
bool _isConnected(UserDevice device) { |
|
|
|
|
|
try { |
|
|
|
|
|
final bleManager = Get.find<BleManager>(); |
|
|
|
|
|
return bleManager.currentDeviceAddress != null && |
|
|
|
|
|
bleManager.currentDeviceAddress == device.devicemac; |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
|
final isDark = Theme.of(context).brightness == Brightness.dark; |
|
|
|
|
|
final bg = isDark ? const Color(0xFF0A0A0F) : const Color(0xFFF5F6FA); |
|
|
|
|
|
final topBg = isDark ? const Color(0xFF0F1018) : const Color(0xFFF0F1F6); |
|
|
|
|
|
|
|
|
return Scaffold( |
|
|
return Scaffold( |
|
|
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.white, |
|
|
backgroundColor: bg, |
|
|
body: Column( |
|
|
body: Column( |
|
|
children: [ |
|
|
children: [ |
|
|
// 顶部标题栏 |
|
|
// 顶部区域 |
|
|
Container( |
|
|
_buildTopArea(context, isDark, bg, topBg), |
|
|
padding: EdgeInsets.only( |
|
|
// 设备列表 |
|
|
top: MediaQuery.of(context).padding.top + 10.h, |
|
|
Expanded(child: _buildDevicesList(isDark, topBg)), |
|
|
left: 20.w, |
|
|
], |
|
|
right: 20.w, |
|
|
), |
|
|
bottom: 20.h, |
|
|
); |
|
|
), |
|
|
} |
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: isDarkMode ? Colors.black : Colors.white, |
|
|
Widget _buildTopArea( |
|
|
boxShadow: [ |
|
|
BuildContext context, bool isDark, Color bg, Color topBg) { |
|
|
BoxShadow( |
|
|
return Container( |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
padding: EdgeInsets.only( |
|
|
blurRadius: 10, |
|
|
top: MediaQuery.of(context).padding.top + 8.h, |
|
|
offset: const Offset(0, 2), |
|
|
left: 20.w, |
|
|
), |
|
|
right: 20.w, |
|
|
], |
|
|
bottom: 24.h, |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
decoration: BoxDecoration(color: bg), |
|
|
children: [ |
|
|
child: Column( |
|
|
GestureDetector( |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
onTap: () => Get.back(), |
|
|
children: [ |
|
|
|
|
|
// 导航栏 |
|
|
|
|
|
Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
GestureDetector( |
|
|
|
|
|
onTap: () => Get.back(), |
|
|
|
|
|
child: Container( |
|
|
|
|
|
width: 40.w, |
|
|
|
|
|
height: 40.w, |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
shape: BoxShape.circle, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.06) |
|
|
|
|
|
: Colors.black.withOpacity(0.04), |
|
|
|
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
Icons.arrow_back_ios, |
|
|
Icons.arrow_back_ios_new, |
|
|
color: isDarkMode ? Colors.white : Colors.black, |
|
|
size: 18.sp, |
|
|
size: 24.sp, |
|
|
color: isDark ? Colors.white : const Color(0xFF222222), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
SizedBox(width: 16.w), |
|
|
), |
|
|
Text( |
|
|
SizedBox(width: 16.w), |
|
|
"deviceManagement".tr, |
|
|
Text( |
|
|
style: TextStyle( |
|
|
"deviceManagement".tr, |
|
|
fontSize: 20.sp, |
|
|
style: TextStyle( |
|
|
fontWeight: FontWeight.w600, |
|
|
fontSize: 26.sp, |
|
|
color: isDarkMode ? Colors.white : Colors.black, |
|
|
fontWeight: FontWeight.w800, |
|
|
), |
|
|
color: isDark ? Colors.white : const Color(0xFF111111), |
|
|
|
|
|
letterSpacing: -0.5, |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
|
|
|
// 设备列表内容 |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: _buildDevicesList(isDarkMode), |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
SizedBox(height: 20.h), |
|
|
|
|
|
// 摘要卡片 |
|
|
|
|
|
Obx(() { |
|
|
|
|
|
final totalDevices = controller.devices.values |
|
|
|
|
|
.fold<int>(0, (sum, list) => sum + list.length); |
|
|
|
|
|
final connectedCount = controller.devices.values |
|
|
|
|
|
.expand((list) => list) |
|
|
|
|
|
.where((d) => _isConnected(d)) |
|
|
|
|
|
.length; |
|
|
|
|
|
return Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
_buildSummaryCard( |
|
|
|
|
|
number: totalDevices.toString(), |
|
|
|
|
|
label: "boundDevices".tr, |
|
|
|
|
|
isActive: true, |
|
|
|
|
|
isDark: isDark, |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(width: 12.w), |
|
|
|
|
|
_buildSummaryCard( |
|
|
|
|
|
number: connectedCount.toString(), |
|
|
|
|
|
label: "currentConnection".tr, |
|
|
|
|
|
isActive: false, |
|
|
|
|
|
isDark: isDark, |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _buildDevicesList(bool isDarkMode) { |
|
|
Widget _buildSummaryCard({ |
|
|
|
|
|
required String number, |
|
|
|
|
|
required String label, |
|
|
|
|
|
required bool isActive, |
|
|
|
|
|
required bool isDark, |
|
|
|
|
|
}) { |
|
|
|
|
|
final activeGradient = isDark |
|
|
|
|
|
? [ |
|
|
|
|
|
const Color(0xFF6366F1).withOpacity(0.15), |
|
|
|
|
|
const Color(0xFF8B5CF6).withOpacity(0.1), |
|
|
|
|
|
] |
|
|
|
|
|
: [const Color(0xFFEEF2FF), const Color(0xFFF5F3FF)]; |
|
|
|
|
|
|
|
|
|
|
|
return Expanded( |
|
|
|
|
|
child: Container( |
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 14.h), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
borderRadius: BorderRadius.circular(16.r), |
|
|
|
|
|
gradient: isActive ? LinearGradient(colors: activeGradient) : null, |
|
|
|
|
|
color: isActive |
|
|
|
|
|
? null |
|
|
|
|
|
: (isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.04) |
|
|
|
|
|
: Colors.white), |
|
|
|
|
|
border: Border.all( |
|
|
|
|
|
color: isActive |
|
|
|
|
|
? (isDark |
|
|
|
|
|
? const Color(0xFF6366F1).withOpacity(0.2) |
|
|
|
|
|
: const Color(0xFF6366F1).withOpacity(0.15)) |
|
|
|
|
|
: (isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.06) |
|
|
|
|
|
: Colors.black.withOpacity(0.04)), |
|
|
|
|
|
), |
|
|
|
|
|
boxShadow: isDark |
|
|
|
|
|
? null |
|
|
|
|
|
: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: Colors.black.withOpacity(0.04), |
|
|
|
|
|
blurRadius: 4, |
|
|
|
|
|
offset: const Offset(0, 1), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
child: Column( |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Text( |
|
|
|
|
|
number, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 24.sp, |
|
|
|
|
|
fontWeight: FontWeight.w700, |
|
|
|
|
|
color: isActive |
|
|
|
|
|
? (isDark |
|
|
|
|
|
? const Color(0xFFA5B4FC) |
|
|
|
|
|
: const Color(0xFF6366F1)) |
|
|
|
|
|
: (isDark ? Colors.white : const Color(0xFF222222)), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(height: 2.h), |
|
|
|
|
|
Text( |
|
|
|
|
|
label, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 11.sp, |
|
|
|
|
|
fontWeight: FontWeight.w500, |
|
|
|
|
|
color: isActive |
|
|
|
|
|
? (isDark |
|
|
|
|
|
? const Color(0xFFA5B4FC).withOpacity(0.6) |
|
|
|
|
|
: const Color(0xFF818CF8)) |
|
|
|
|
|
: (isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.35) |
|
|
|
|
|
: const Color(0xFF999999)), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Widget _buildDevicesList(bool isDark, Color topBg) { |
|
|
return Obx(() { |
|
|
return Obx(() { |
|
|
// 使用控制器的响应式数据,这会触发控制器的实例化 |
|
|
|
|
|
final groupedDevices = controller.devices; |
|
|
final groupedDevices = controller.devices; |
|
|
|
|
|
|
|
|
if (groupedDevices.isEmpty) { |
|
|
if (groupedDevices.isEmpty) { |
|
|
return _buildEmptyState(isDarkMode); |
|
|
return _buildEmptyState(isDark); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return ListView( |
|
|
return ListView( |
|
|
padding: EdgeInsets.all(20.w), |
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h), |
|
|
children: [ |
|
|
children: [ |
|
|
// 遍历每个设备类型 |
|
|
|
|
|
...groupedDevices.entries.map((entry) { |
|
|
...groupedDevices.entries.map((entry) { |
|
|
final deviceTypeValue = entry.key; |
|
|
final deviceType = DeviceType.fromValue(entry.key); |
|
|
final deviceList = entry.value; |
|
|
final deviceList = entry.value; |
|
|
final deviceType = DeviceType.fromValue(deviceTypeValue); |
|
|
|
|
|
|
|
|
|
|
|
return Column( |
|
|
return Column( |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
// 设备类型标题 |
|
|
// 分类标题 |
|
|
Padding( |
|
|
Padding( |
|
|
padding: EdgeInsets.only(bottom: 12.h), |
|
|
padding: EdgeInsets.only(left: 8.w, bottom: 12.h), |
|
|
child: Text( |
|
|
child: Text( |
|
|
deviceType.displayName, |
|
|
deviceType.displayName.toUpperCase(), |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 16.sp, |
|
|
fontSize: 12.sp, |
|
|
fontWeight: FontWeight.w600, |
|
|
fontWeight: FontWeight.w600, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.25) |
|
|
|
|
|
: const Color(0xFFAAAAAA), |
|
|
|
|
|
letterSpacing: 1.5, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
// 该类型下的设备列表 |
|
|
|
|
|
...deviceList.map((device) => _buildDeviceCard( |
|
|
...deviceList.map((device) => _buildDeviceCard( |
|
|
device: device, |
|
|
device: device, |
|
|
deviceType: deviceType, |
|
|
deviceType: deviceType, |
|
|
isDarkMode: isDarkMode, |
|
|
isDark: isDark, |
|
|
)), |
|
|
)), |
|
|
SizedBox(height: 20.h), |
|
|
SizedBox(height: 16.h), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
}).toList(), |
|
|
}), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _buildEmptyState(bool isDarkMode) { |
|
|
Widget _buildEmptyState(bool isDark) { |
|
|
return Center( |
|
|
return Center( |
|
|
child: Column( |
|
|
child: Column( |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
@ -174,14 +299,14 @@ class DevicesView extends GetView<DevicesController> { |
|
|
Icon( |
|
|
Icon( |
|
|
Icons.devices_other, |
|
|
Icons.devices_other, |
|
|
size: 80.sp, |
|
|
size: 80.sp, |
|
|
color: isDarkMode ? Colors.white54 : Colors.grey[400], |
|
|
color: isDark ? Colors.white54 : Colors.grey[400], |
|
|
), |
|
|
), |
|
|
SizedBox(height: 20.h), |
|
|
SizedBox(height: 20.h), |
|
|
Text( |
|
|
Text( |
|
|
"noDevicesBound".tr, |
|
|
"noDevicesBound".tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 16.sp, |
|
|
fontSize: 16.sp, |
|
|
color: isDarkMode ? Colors.white70 : Colors.grey[600], |
|
|
color: isDark ? Colors.white70 : Colors.grey[600], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
SizedBox(height: 12.h), |
|
|
SizedBox(height: 12.h), |
|
|
@ -189,7 +314,7 @@ class DevicesView extends GetView<DevicesController> { |
|
|
"pleaseBindDeviceFirst".tr, |
|
|
"pleaseBindDeviceFirst".tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 14.sp, |
|
|
fontSize: 14.sp, |
|
|
color: isDarkMode ? Colors.white54 : Colors.grey[500], |
|
|
color: isDark ? Colors.white54 : Colors.grey[500], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
@ -200,121 +325,263 @@ class DevicesView extends GetView<DevicesController> { |
|
|
Widget _buildDeviceCard({ |
|
|
Widget _buildDeviceCard({ |
|
|
required UserDevice device, |
|
|
required UserDevice device, |
|
|
required DeviceType deviceType, |
|
|
required DeviceType deviceType, |
|
|
required bool isDarkMode, |
|
|
required bool isDark, |
|
|
}) { |
|
|
}) { |
|
|
|
|
|
final connected = _isConnected(device); |
|
|
|
|
|
final connectedColor = const Color(0xFF22C55E); |
|
|
|
|
|
|
|
|
return GestureDetector( |
|
|
return GestureDetector( |
|
|
onTap: () => Get.toNamed(Routes.eqSettings), |
|
|
onTap: () => Get.toNamed(Routes.eqSettings), |
|
|
child: Container( |
|
|
child: Container( |
|
|
margin: EdgeInsets.only(bottom: 12.h), |
|
|
margin: EdgeInsets.only(bottom: 10.h), |
|
|
padding: EdgeInsets.all(16.w), |
|
|
padding: EdgeInsets.all(20.w), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
borderRadius: BorderRadius.circular(20.r), |
|
|
borderRadius: BorderRadius.circular(12.r), |
|
|
color: isDark |
|
|
boxShadow: [ |
|
|
? (connected |
|
|
BoxShadow( |
|
|
? connectedColor.withOpacity(0.04) |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
: Colors.white.withOpacity(0.03)) |
|
|
blurRadius: 8, |
|
|
: (connected |
|
|
offset: const Offset(0, 2), |
|
|
? connectedColor.withOpacity(0.03) |
|
|
), |
|
|
: Colors.white), |
|
|
], |
|
|
border: Border.all( |
|
|
|
|
|
color: connected |
|
|
|
|
|
? connectedColor.withOpacity(0.2) |
|
|
|
|
|
: (isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.05) |
|
|
|
|
|
: Colors.black.withOpacity(0.04)), |
|
|
|
|
|
), |
|
|
|
|
|
boxShadow: isDark |
|
|
|
|
|
? null |
|
|
|
|
|
: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: Colors.black.withOpacity(0.03), |
|
|
|
|
|
blurRadius: 12, |
|
|
|
|
|
offset: const Offset(0, 2), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
child: Column( |
|
|
children: [ |
|
|
children: [ |
|
|
// 设备图标 |
|
|
// 上部:图标 + 名称/MAC + 解绑 |
|
|
Container( |
|
|
Row( |
|
|
width: 48.w, |
|
|
children: [ |
|
|
height: 48.w, |
|
|
// 设备图标 |
|
|
decoration: BoxDecoration( |
|
|
Container( |
|
|
color: isDarkMode |
|
|
width: 46.w, |
|
|
? Colors.white.withOpacity(0.1) |
|
|
height: 46.w, |
|
|
: Colors.grey[100], |
|
|
decoration: BoxDecoration( |
|
|
borderRadius: BorderRadius.circular(12.r), |
|
|
borderRadius: BorderRadius.circular(14.r), |
|
|
), |
|
|
gradient: LinearGradient( |
|
|
child: Icon( |
|
|
begin: Alignment.topLeft, |
|
|
deviceType.icon, |
|
|
end: Alignment.bottomRight, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
colors: connected |
|
|
size: 24.sp, |
|
|
? [connectedColor, const Color(0xFF16A34A)] |
|
|
), |
|
|
: [const Color(0xFF6366F1), const Color(0xFF8B5CF6)], |
|
|
), |
|
|
|
|
|
SizedBox(width: 16.w), |
|
|
|
|
|
// 设备信息 |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: Column( |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Text( |
|
|
|
|
|
device.devicename.isNotEmpty |
|
|
|
|
|
? device.devicename |
|
|
|
|
|
: "deviceTypeUnknown".tr, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 16.sp, |
|
|
|
|
|
fontWeight: FontWeight.w500, |
|
|
|
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
boxShadow: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: (connected ? connectedColor : const Color(0xFF6366F1)) |
|
|
|
|
|
.withOpacity(0.3), |
|
|
|
|
|
blurRadius: 16, |
|
|
|
|
|
offset: const Offset(0, 4), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
SizedBox(height: 4.h), |
|
|
child: Icon( |
|
|
Text( |
|
|
deviceType.icon, |
|
|
device.devicemac.isNotEmpty |
|
|
color: Colors.white, |
|
|
? device.devicemac |
|
|
size: 22.sp, |
|
|
: "noMacAddress".tr, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 14.sp, |
|
|
|
|
|
color: isDarkMode ? Colors.white70 : Colors.grey[600], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
if (device.license.isNotEmpty) ...[ |
|
|
), |
|
|
SizedBox(height: 4.h), |
|
|
SizedBox(width: 14.w), |
|
|
Text( |
|
|
// 设备名 + MAC |
|
|
"${"licenseCode".tr}: ${device.license}", |
|
|
Expanded( |
|
|
|
|
|
child: Column( |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Text( |
|
|
|
|
|
device.devicename.isNotEmpty |
|
|
|
|
|
? device.devicename |
|
|
|
|
|
: "deviceTypeUnknown".tr, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 16.sp, |
|
|
|
|
|
fontWeight: FontWeight.w700, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: const Color(0xFF1A1A2E), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
if (connected) ...[ |
|
|
|
|
|
SizedBox(width: 8.w), |
|
|
|
|
|
Container( |
|
|
|
|
|
width: 6.w, |
|
|
|
|
|
height: 6.w, |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
shape: BoxShape.circle, |
|
|
|
|
|
color: connectedColor, |
|
|
|
|
|
boxShadow: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: connectedColor.withOpacity(0.6), |
|
|
|
|
|
blurRadius: 8, |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(width: 6.w), |
|
|
|
|
|
Container( |
|
|
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 8.w, vertical: 3.h), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
borderRadius: BorderRadius.circular(6.r), |
|
|
|
|
|
color: connectedColor.withOpacity(0.1), |
|
|
|
|
|
), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
"connected".tr, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
|
fontWeight: FontWeight.w600, |
|
|
|
|
|
color: connectedColor, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(height: 3.h), |
|
|
|
|
|
Text( |
|
|
|
|
|
device.devicemac.isNotEmpty |
|
|
|
|
|
? device.devicemac |
|
|
|
|
|
: "noMacAddress".tr, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
fontWeight: FontWeight.w500, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.3) |
|
|
|
|
|
: const Color(0xFF999999), |
|
|
|
|
|
fontFamily: 'Menlo', |
|
|
|
|
|
letterSpacing: 0.5, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
// 解绑按钮 |
|
|
|
|
|
GestureDetector( |
|
|
|
|
|
onTap: () => _showUnbindDialog(device, isDark), |
|
|
|
|
|
child: Container( |
|
|
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 14.w, vertical: 8.h), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
borderRadius: BorderRadius.circular(10.r), |
|
|
|
|
|
border: Border.all( |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.08) |
|
|
|
|
|
: Colors.black.withOpacity(0.08), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
"unbind".tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 12.sp, |
|
|
fontSize: 12.sp, |
|
|
color: isDarkMode ? Colors.white54 : Colors.grey[500], |
|
|
fontWeight: FontWeight.w600, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.4) |
|
|
|
|
|
: const Color(0xFF999999), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
// 解绑按钮 |
|
|
|
|
|
GestureDetector( |
|
|
|
|
|
onTap: () => _showUnbindDialog(device, isDarkMode), |
|
|
|
|
|
child: Container( |
|
|
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 12.w, |
|
|
|
|
|
vertical: 6.h, |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
// 下部:授权码 / CMEI |
|
|
|
|
|
if (device.license.isNotEmpty || device.cmei.isNotEmpty) ...[ |
|
|
|
|
|
SizedBox(height: 16.h), |
|
|
|
|
|
Container( |
|
|
|
|
|
padding: EdgeInsets.all(12.w), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: Colors.red.withOpacity(0.1), |
|
|
borderRadius: BorderRadius.circular(12.r), |
|
|
borderRadius: BorderRadius.circular(6.r), |
|
|
color: isDark |
|
|
border: Border.all( |
|
|
? Colors.white.withOpacity(0.03) |
|
|
color: Colors.red.withOpacity(0.3), |
|
|
: const Color(0xFFF7F7FA), |
|
|
width: 1, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
child: Text( |
|
|
child: Column( |
|
|
"unbind".tr, |
|
|
children: [ |
|
|
style: TextStyle( |
|
|
if (device.license.isNotEmpty) |
|
|
fontSize: 12.sp, |
|
|
_buildFieldRow( |
|
|
color: Colors.red, |
|
|
label: "licenseCode".tr, |
|
|
fontWeight: FontWeight.w500, |
|
|
value: device.license, |
|
|
), |
|
|
isDark: isDark, |
|
|
|
|
|
), |
|
|
|
|
|
if (device.license.isNotEmpty && device.cmei.isNotEmpty) |
|
|
|
|
|
SizedBox(height: 8.h), |
|
|
|
|
|
if (device.cmei.isNotEmpty) |
|
|
|
|
|
_buildFieldRow( |
|
|
|
|
|
label: "CMEI", |
|
|
|
|
|
value: device.cmei, |
|
|
|
|
|
isDark: isDark, |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _showUnbindDialog(UserDevice device, bool isDarkMode) { |
|
|
Widget _buildFieldRow({ |
|
|
|
|
|
required String label, |
|
|
|
|
|
required String value, |
|
|
|
|
|
required bool isDark, |
|
|
|
|
|
}) { |
|
|
|
|
|
return Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
SizedBox( |
|
|
|
|
|
width: 44.w, |
|
|
|
|
|
child: Text( |
|
|
|
|
|
label, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
|
fontWeight: FontWeight.w600, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.2) |
|
|
|
|
|
: const Color(0xFFBBBBBB), |
|
|
|
|
|
letterSpacing: 0.5, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(width: 8.w), |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: Text( |
|
|
|
|
|
value, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 11.sp, |
|
|
|
|
|
fontWeight: FontWeight.w500, |
|
|
|
|
|
color: isDark |
|
|
|
|
|
? Colors.white.withOpacity(0.5) |
|
|
|
|
|
: const Color(0xFF666666), |
|
|
|
|
|
fontFamily: 'Menlo', |
|
|
|
|
|
letterSpacing: 0.3, |
|
|
|
|
|
), |
|
|
|
|
|
overflow: TextOverflow.ellipsis, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _showUnbindDialog(UserDevice device, bool isDark) { |
|
|
Get.dialog( |
|
|
Get.dialog( |
|
|
AlertDialog( |
|
|
AlertDialog( |
|
|
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
backgroundColor: isDark ? AppColors.cardBackground : Colors.white, |
|
|
title: Text( |
|
|
title: Text( |
|
|
"confirmUnbind".tr, |
|
|
"confirmUnbind".tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDark ? Colors.white : Colors.black87, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
content: Text( |
|
|
content: Text( |
|
|
@ -322,7 +589,7 @@ class DevicesView extends GetView<DevicesController> { |
|
|
.tr |
|
|
.tr |
|
|
.replaceAll('{deviceName}', device.devicename), |
|
|
.replaceAll('{deviceName}', device.devicename), |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
color: isDarkMode ? Colors.white70 : Colors.black54, |
|
|
color: isDark ? Colors.white70 : Colors.black54, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
actions: [ |
|
|
actions: [ |
|
|
@ -331,7 +598,7 @@ class DevicesView extends GetView<DevicesController> { |
|
|
child: Text( |
|
|
child: Text( |
|
|
"cancel".tr, |
|
|
"cancel".tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
color: isDarkMode ? Colors.white70 : Colors.grey[600], |
|
|
color: isDark ? Colors.white70 : Colors.grey[600], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|