1036 lines
33 KiB
Dart
1036 lines
33 KiB
Dart
import 'dart:ui';
|
|
import 'dart:io' as io show Platform;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:platform_info/platform_info.dart';
|
|
import 'package:flutter_udid/flutter_udid.dart';
|
|
import '../../../constants/app_constants.dart';
|
|
|
|
/// 时间: 2026-03-26
|
|
/// 功能: 应用信息页面
|
|
/// 介绍: 展示应用版本、技术栈、构建信息、设备信息等
|
|
/// 最新变化: 添加 UDID 显示
|
|
|
|
class AppInfoPage extends StatefulWidget {
|
|
const AppInfoPage({super.key});
|
|
|
|
@override
|
|
State<AppInfoPage> createState() => _AppInfoPageState();
|
|
}
|
|
|
|
class _AppInfoPageState extends State<AppInfoPage> {
|
|
String _udid = '获取中...';
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadUdid();
|
|
}
|
|
|
|
Future<void> _loadUdid() async {
|
|
try {
|
|
final String udid = await FlutterUdid.udid;
|
|
if (mounted) {
|
|
setState(() {
|
|
_udid = udid;
|
|
});
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
setState(() {
|
|
_udid = '获取失败';
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: const Color(0xFFF5F5F5),
|
|
appBar: AppBar(
|
|
title: Text(
|
|
'应用信息',
|
|
style: TextStyle(
|
|
color: AppConstants.primaryColor,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
backgroundColor: Colors.white,
|
|
elevation: 0,
|
|
centerTitle: true,
|
|
leading: IconButton(
|
|
icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
_buildHeaderCard(),
|
|
const SizedBox(height: 16),
|
|
_buildTechStackCard(),
|
|
const SizedBox(height: 16),
|
|
_buildBuildInfoCard(context),
|
|
const SizedBox(height: 16),
|
|
_buildServerInfoCard(),
|
|
const SizedBox(height: 16),
|
|
_buildDeviceInfoCard(context),
|
|
const SizedBox(height: 16),
|
|
_buildUpdateLogCard(),
|
|
const SizedBox(height: 16),
|
|
_buildDesignStyleCard(),
|
|
const SizedBox(height: 24),
|
|
_buildBottomIndicator(),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildHeaderCard() {
|
|
return ClipRRect(
|
|
borderRadius: BorderRadius.circular(16),
|
|
child: BackdropFilter(
|
|
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(24),
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
AppConstants.primaryColor.withValues(alpha: 0.66),
|
|
AppConstants.primaryColor.withValues(alpha: 0.7),
|
|
AppConstants.primaryColor.withValues(alpha: 0.99),
|
|
],
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
),
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Colors.white.withValues(alpha: 0.3),
|
|
width: 1,
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppConstants.primaryColor.withValues(alpha: 0.35),
|
|
blurRadius: 20,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 70,
|
|
height: 70,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.25),
|
|
borderRadius: BorderRadius.circular(18),
|
|
border: Border.all(
|
|
color: Colors.white.withValues(alpha: 0.3),
|
|
),
|
|
),
|
|
child: const Center(
|
|
child: Text('📱', style: TextStyle(fontSize: 36)),
|
|
),
|
|
),
|
|
const SizedBox(width: 20),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'情景诗词',
|
|
style: TextStyle(
|
|
fontSize: 26,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
const SizedBox(height: 6),
|
|
Text(
|
|
'Poes · 应用信息',
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.white.withValues(alpha: 0.85),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 12,
|
|
vertical: 6,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.2),
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Colors.white.withValues(alpha: 0.25),
|
|
),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(
|
|
Icons.info_outline,
|
|
size: 14,
|
|
color: Colors.white.withValues(alpha: 0.9),
|
|
),
|
|
const SizedBox(width: 6),
|
|
const Text(
|
|
'框架 1.3',
|
|
style: TextStyle(fontSize: 12, color: Colors.white),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 8,
|
|
vertical: 2,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.2),
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: const Text(
|
|
'软件版本 1.5',
|
|
style: TextStyle(
|
|
fontSize: 10,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildTechStackCard() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(Icons.code, color: Colors.blue[700], size: 20),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Text(
|
|
'技术栈',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
// 2x2 网格布局展示技术栈
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: GridView.count(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
crossAxisCount: 2,
|
|
mainAxisSpacing: 12,
|
|
crossAxisSpacing: 12,
|
|
childAspectRatio: 2.2,
|
|
children: [
|
|
_buildTechStackItem(
|
|
'Flutter',
|
|
'跨平台UI框架',
|
|
Icons.flutter_dash,
|
|
Colors.blue,
|
|
),
|
|
_buildTechStackItem('Dart', '编程语言', Icons.code, Colors.teal),
|
|
_buildTechStackItem('SP', '本地存储', Icons.storage, Colors.orange),
|
|
_buildTechStackItem(
|
|
'dio',
|
|
'网络处理',
|
|
Icons.network_check,
|
|
Colors.purple,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildBuildInfoCard(BuildContext context) {
|
|
String buildSdk = 'Unknown';
|
|
try {
|
|
final String osName = io.Platform.operatingSystem;
|
|
if (osName == 'ohos' ||
|
|
osName == 'harmonyos' ||
|
|
osName == 'openharmony') {
|
|
buildSdk = 'Deveco API 23';
|
|
} else if (io.Platform.isAndroid) {
|
|
buildSdk = 'Android Target 36';
|
|
} else if (io.Platform.isWindows) {
|
|
buildSdk = 'Win10 SDK';
|
|
} else if (io.Platform.isIOS) {
|
|
buildSdk = 'iOS 26';
|
|
} else if (io.Platform.isMacOS) {
|
|
buildSdk = 'macOS 18';
|
|
} else if (io.Platform.isLinux) {
|
|
buildSdk = 'Linux 20';
|
|
} else {
|
|
buildSdk = 'PHP 7.4';
|
|
}
|
|
} catch (e) {
|
|
buildSdk = 'PHP 7.4';
|
|
}
|
|
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.green.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(Icons.build, color: Colors.green[700], size: 20),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Text(
|
|
'构建信息',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
_buildCopyableItem(context, '版本号', '1.2', Icons.verified),
|
|
_buildCopyableItem(
|
|
context,
|
|
'Builder version',
|
|
'26d03a26',
|
|
Icons.developer_mode,
|
|
),
|
|
_buildInfoItem(
|
|
'打包时间',
|
|
DateTime.now().toString().split(' ').first,
|
|
Icons.schedule,
|
|
),
|
|
_buildInfoItem('Build SDK', buildSdk, Icons.new_releases),
|
|
_buildLicenseItem(context),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildLicenseItem(BuildContext context) {
|
|
return InkWell(
|
|
onTap: () => _showFlutterLicense(context),
|
|
borderRadius: BorderRadius.circular(8),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
child: Row(
|
|
children: [
|
|
Icon(Icons.gavel, size: 20, color: Colors.grey[600]),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'开源框架',
|
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
'Flutter SDK',
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Icon(Icons.chevron_right, size: 20, color: Colors.grey[400]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showFlutterLicense(BuildContext context) {
|
|
final licenses = [
|
|
{'name': 'Flutter SDK', 'license': 'BSD 3-Clause'},
|
|
{'name': 'OpenHarmony SDK', 'license': 'Apache 2.0'},
|
|
{'name': 'Cupertino Icons', 'license': 'MIT'},
|
|
{'name': 'Shared Preferences', 'license': 'BSD 3-Clause'},
|
|
{'name': 'Dio', 'license': 'MIT'},
|
|
{'name': 'Platform Info', 'license': 'MIT'},
|
|
{'name': 'flutter_udid', 'license': 'MIT'},
|
|
];
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: Row(
|
|
children: [
|
|
Icon(Icons.description, color: AppConstants.primaryColor),
|
|
const SizedBox(width: 8),
|
|
const Text('开源框架'),
|
|
],
|
|
),
|
|
content: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: licenses.map((item) {
|
|
return Container(
|
|
margin: const EdgeInsets.only(bottom: 8),
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[50],
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: Colors.grey.withValues(alpha: 0.2)),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(6),
|
|
decoration: BoxDecoration(
|
|
color: AppConstants.primaryColor.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(6),
|
|
),
|
|
child: Icon(
|
|
Icons.widgets,
|
|
size: 16,
|
|
color: AppConstants.primaryColor,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
item['name']!,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
item['license']!,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey[500],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: Text(
|
|
'关闭',
|
|
style: TextStyle(color: AppConstants.primaryColor),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildServerInfoCard() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.orange.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(Icons.dns, color: Colors.orange[700], size: 20),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Text(
|
|
'后端服务',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
_buildInfoItem('后端语言', 'PHP', Icons.php),
|
|
_buildInfoItem('Web服务器', 'Nginx', Icons.web),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDeviceInfoCard(BuildContext context) {
|
|
final platform = Platform.instance;
|
|
|
|
bool isHarmonyOS = false;
|
|
String platformName = 'Unknown';
|
|
|
|
try {
|
|
final String osName = io.Platform.operatingSystem;
|
|
final String osVersion = io.Platform.operatingSystemVersion.toLowerCase();
|
|
|
|
if (osName == 'ohos' || osName == 'harmonyos' || osName == 'harmonyos') {
|
|
platformName = 'HarmonyOS';
|
|
isHarmonyOS = true;
|
|
} else if (io.Platform.isAndroid) {
|
|
platformName = 'Android';
|
|
if (osVersion.contains('harmony') ||
|
|
osVersion.contains('ohos') ||
|
|
osVersion.contains('openharmony')) {
|
|
platformName = 'HarmonyOS';
|
|
isHarmonyOS = true;
|
|
}
|
|
} else if (io.Platform.isIOS) {
|
|
platformName = 'iOS';
|
|
} else if (io.Platform.isMacOS) {
|
|
platformName = 'macOS';
|
|
} else if (io.Platform.isWindows) {
|
|
platformName = 'Windows';
|
|
} else if (io.Platform.isLinux) {
|
|
platformName = 'Linux';
|
|
} else if (io.Platform.isFuchsia) {
|
|
platformName = 'Fuchsia';
|
|
} else {
|
|
platformName = osName[0].toUpperCase() + osName.substring(1);
|
|
}
|
|
} catch (e) {
|
|
platformName = switch (platform.operatingSystem) {
|
|
const OperatingSystem.android() => 'Android',
|
|
const OperatingSystem.fuchsia() => 'Fuchsia',
|
|
const OperatingSystem.iOS() => 'iOS',
|
|
const OperatingSystem.linux() => 'Linux',
|
|
const OperatingSystem.macOS() => 'macOS',
|
|
const OperatingSystem.windows() => 'Windows',
|
|
const OperatingSystem.unknown() || _ => 'Unknown',
|
|
};
|
|
}
|
|
|
|
final String designStyle =
|
|
platform.when<String?>(
|
|
material: () => isHarmonyOS ? 'HarmonyOS Design' : 'Material Design',
|
|
cupertino: () => 'Cupertino Design',
|
|
orElse: () => null,
|
|
) ??
|
|
'Unknown';
|
|
|
|
String deviceType = '未知设备';
|
|
if (isHarmonyOS) {
|
|
final String osName = io.Platform.operatingSystem;
|
|
if (osName == 'ohos') {
|
|
deviceType = 'OHOS';
|
|
} else if (osName == 'harmonyos') {
|
|
deviceType = 'HarmonyOS';
|
|
} else if (osName == 'openharmony') {
|
|
deviceType = 'OpenHarmony';
|
|
} else {
|
|
deviceType = 'HarmonyOS';
|
|
}
|
|
} else {
|
|
deviceType =
|
|
platform.when<String?>(
|
|
mobile: () => '移动设备',
|
|
desktop: () => '桌面设备',
|
|
js: () => 'Web浏览器',
|
|
orElse: () => null,
|
|
) ??
|
|
'未知设备';
|
|
}
|
|
|
|
final String buildMode = switch (platform.buildMode) {
|
|
BuildMode$Debug _ => 'Debug',
|
|
BuildMode$Profile _ => 'Profile',
|
|
BuildMode$Release _ => 'Release',
|
|
};
|
|
|
|
final String runtimeEnv =
|
|
platform.when<String?>(
|
|
vm: () => 'VM (Dart)',
|
|
js: () => 'JS (Web)',
|
|
orElse: () => null,
|
|
) ??
|
|
'Unknown';
|
|
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.purple.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(
|
|
Icons.devices,
|
|
color: Colors.purple[700],
|
|
size: 20,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Text(
|
|
'设备信息',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
_buildInfoItem('操作系统', platformName, Icons.phone_iphone),
|
|
if (!isHarmonyOS) ...[
|
|
_buildInfoItem('设计风格', designStyle, Icons.palette),
|
|
],
|
|
_buildInfoItem('设备类型', deviceType, Icons.devices),
|
|
_buildInfoItem('构建模式', buildMode, Icons.build),
|
|
_buildInfoItem('运行环境', runtimeEnv, Icons.code),
|
|
_buildCopyableItem(
|
|
context,
|
|
'Flutter UDID',
|
|
_udid,
|
|
Icons.perm_identity,
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[50],
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: Colors.grey.withValues(alpha: 0.2)),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
Icons.info_outline,
|
|
size: 16,
|
|
color: Colors.grey[600],
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'设备详细信息',
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey[700],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'窗口尺寸: ${MediaQuery.of(context).size.width.toStringAsFixed(0)} x ${MediaQuery.of(context).size.height.toStringAsFixed(0)}',
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'像素密度: ${MediaQuery.of(context).devicePixelRatio.toStringAsFixed(2)} (越大越好)',
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildUpdateLogCard() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(
|
|
Icons.new_releases,
|
|
color: Colors.blue[700],
|
|
size: 20,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Text(
|
|
'软件更新日志',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildUpdateItem('版本 1.2.40', '2026-03-27', [
|
|
'新增:主题个性化页面',
|
|
'新增:设计风格卡片',
|
|
'优化:界面布局和响应式设计',
|
|
]),
|
|
const SizedBox(height: 16),
|
|
_buildUpdateItem('版本 1.2.39', '2026-03-27', [
|
|
'修复:引导页滑动问题',
|
|
'优化:左侧进度条位置',
|
|
'新增:协议内容焦点功能',
|
|
]),
|
|
const SizedBox(height: 16),
|
|
_buildUpdateItem('版本 1.2.38', '2026-03-27', [
|
|
'优化:引导页滑动逻辑',
|
|
'新增:页面进度指示器',
|
|
'更新:滑动提示文本',
|
|
]),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildUpdateItem(String version, String date, List<String> changes) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[50],
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: Colors.grey.withValues(alpha: 0.2)),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
version,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
Text(
|
|
date,
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: changes.map((change) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const SizedBox(width: 8),
|
|
const Text('• ', style: TextStyle(color: Colors.blue)),
|
|
Expanded(
|
|
child: Text(
|
|
change,
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[700]),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDesignStyleCard() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: []),
|
|
);
|
|
}
|
|
|
|
// 2x2 网格技术栈项
|
|
Widget _buildTechStackItem(
|
|
String title,
|
|
String value,
|
|
IconData icon,
|
|
Color color,
|
|
) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: color.withAlpha(20),
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: color.withAlpha(50), width: 1),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: color.withAlpha(30),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(icon, size: 20, color: color),
|
|
),
|
|
const SizedBox(width: 10),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w600,
|
|
color: color,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: TextStyle(fontSize: 11, color: Colors.grey[600]),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildInfoItem(String title, String value, IconData icon) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
child: Row(
|
|
children: [
|
|
Icon(icon, size: 20, color: Colors.grey[600]),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildCopyableItem(
|
|
BuildContext context,
|
|
String title,
|
|
String value,
|
|
IconData icon,
|
|
) {
|
|
return InkWell(
|
|
onTap: () => _copyToClipboard(context, value),
|
|
borderRadius: BorderRadius.circular(8),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
child: Row(
|
|
children: [
|
|
Icon(icon, size: 20, color: Colors.grey[600]),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Icon(
|
|
Icons.content_copy,
|
|
size: 16,
|
|
color: AppConstants.primaryColor.withValues(alpha: 0.6),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _copyToClipboard(BuildContext context, String text) {
|
|
Clipboard.setData(ClipboardData(text: text));
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.check_circle, color: Colors.white, size: 20),
|
|
const SizedBox(width: 8),
|
|
Text('$text 已复制到剪贴板'),
|
|
],
|
|
),
|
|
backgroundColor: AppConstants.primaryColor,
|
|
behavior: SnackBarBehavior.floating,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
duration: const Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildBottomIndicator() {
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 24),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Container(width: 10, height: 1, color: Colors.grey[300]),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: Text(
|
|
'若有卡顿闪退信息,请将此页面长截图发给开发者',
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[400]),
|
|
),
|
|
),
|
|
Container(width: 10, height: 1, color: Colors.grey[300]),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|