mirror of
https://github.com/EasyTier/astral.git
synced 2025-05-19 10:30:24 +00:00
修复内存泄漏
This commit is contained in:
@@ -15,9 +15,6 @@ migration:
|
||||
- platform: root
|
||||
create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
- platform: web
|
||||
create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
|
||||
# User provided section
|
||||
|
||||
|
||||
Vendored
+6
@@ -4,6 +4,12 @@
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Flutter",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "profile"
|
||||
},
|
||||
{
|
||||
"name": "Flutter Run",
|
||||
"request": "launch",
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'dart:io';
|
||||
import 'screens/Home.dart';
|
||||
import 'config/themeconfiguration.dart';
|
||||
import 'config/app_config.dart';
|
||||
import 'package:astral/utils/up.dart'; // 添加这行导入
|
||||
|
||||
// 定义应用程序的主要StatefulWidget
|
||||
class MyApp extends StatefulWidget {
|
||||
|
||||
@@ -40,12 +40,12 @@ class NavigationConfig {
|
||||
currentThemeMode: currentThemeMode,
|
||||
)),
|
||||
),
|
||||
NavItem(
|
||||
label: '房间',
|
||||
icon: Icons.room_outlined,
|
||||
selectedIcon: Icons.room,
|
||||
pageBuilder: () => _getOrCreatePage(1, () => const RoomPage()),
|
||||
),
|
||||
// NavItem(
|
||||
// label: '房间',
|
||||
// icon: Icons.room_outlined,
|
||||
// selectedIcon: Icons.room,
|
||||
// pageBuilder: () => _getOrCreatePage(1, () => const RoomPage()),
|
||||
// ),
|
||||
NavItem(
|
||||
label: '设置',
|
||||
icon: Icons.settings_outlined,
|
||||
|
||||
+118
-277
@@ -2,35 +2,11 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'package:astral/utils/app_info.dart';
|
||||
|
||||
class InfoPage extends StatefulWidget {
|
||||
class InfoPage extends StatelessWidget {
|
||||
const InfoPage({super.key});
|
||||
|
||||
@override
|
||||
State<InfoPage> createState() => _InfoPageState();
|
||||
}
|
||||
|
||||
class _InfoPageState extends State<InfoPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 10),
|
||||
vsync: this,
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
@@ -40,156 +16,95 @@ class _InfoPageState extends State<InfoPage>
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// 旋转的图标效果
|
||||
AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (_, child) {
|
||||
return Transform.rotate(
|
||||
angle: _controller.value * 2 * math.pi,
|
||||
child: Container(
|
||||
height: 110,
|
||||
width: 110,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: SweepGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.primary,
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
Theme.of(context).colorScheme.tertiary,
|
||||
Theme.of(context).colorScheme.primary,
|
||||
],
|
||||
stops: const [0.0, 0.3, 0.6, 1.0],
|
||||
transform:
|
||||
GradientRotation(_controller.value * 2 * math.pi),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withOpacity(0.5),
|
||||
blurRadius: 15,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.games,
|
||||
size: 50,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
// 静态图标
|
||||
Container(
|
||||
height: 110,
|
||||
width: 110,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withOpacity(0.5),
|
||||
blurRadius: 15,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
);
|
||||
},
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.games,
|
||||
size: 50,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// 应用名称添加渐变效果
|
||||
ShaderMask(
|
||||
shaderCallback: (bounds) => LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.primary,
|
||||
Theme.of(context).colorScheme.tertiary,
|
||||
],
|
||||
).createShader(bounds),
|
||||
child: Text(
|
||||
'ASTRAL',
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 2.0,
|
||||
),
|
||||
),
|
||||
// 应用名称
|
||||
Text(
|
||||
'ASTRAL',
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 2.0,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 版本号添加动画效果
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0, end: 1),
|
||||
duration: const Duration(milliseconds: 800),
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - value)),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
AppInfoUtil.getVersion(),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
// 版本号
|
||||
Text(
|
||||
AppInfoUtil.getVersion(),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// 卡片添加动画和阴影效果
|
||||
_buildAnimatedCard(
|
||||
// 静态卡片
|
||||
_buildCard(
|
||||
context,
|
||||
'特别鸣谢',
|
||||
'特别感谢EasyTier作者所做的工作和帮助,为本项目提供了重要的技术支持。如果您有功能需求或遇到bug,欢迎加入我们的QQ群获取帮助和了解最新动态。',
|
||||
Icons.favorite,
|
||||
Colors.red,
|
||||
delay: 200,
|
||||
),
|
||||
// 合并后的卡片
|
||||
|
||||
const SizedBox(height: 30),
|
||||
// 按钮添加动画效果
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0, end: 1),
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
curve: Curves.elasticOut,
|
||||
builder: (context, value, child) {
|
||||
return Transform.scale(
|
||||
scale: value,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.group_add),
|
||||
label: const Text('加入QQ群'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
elevation: 5,
|
||||
// 静态按钮
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.group_add),
|
||||
label: const Text('加入QQ群'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
onPressed: () async {
|
||||
final url = 'https://qm.qq.com/q/ErscyNPTzO';
|
||||
if (await canLaunchUrl(Uri.parse(url))) {
|
||||
await launchUrl(Uri.parse(url));
|
||||
} else {
|
||||
// 无法打开链接时显示提示
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('无法打开QQ群链接')),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
elevation: 5,
|
||||
),
|
||||
onPressed: () async {
|
||||
final url = 'https://qm.qq.com/q/ErscyNPTzO';
|
||||
if (await canLaunchUrl(Uri.parse(url))) {
|
||||
await launchUrl(Uri.parse(url));
|
||||
} else {
|
||||
// 无法打开链接时显示提示
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('无法打开QQ群链接')),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// 添加版权信息
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0, end: 1),
|
||||
duration: const Duration(milliseconds: 1200),
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'© ${DateTime.now().year} ASTRAL Team',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
// 版权信息
|
||||
Text(
|
||||
'© ${DateTime.now().year} ASTRAL Team',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -198,129 +113,55 @@ class _InfoPageState extends State<InfoPage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAnimatedCard(BuildContext context, String title, String content,
|
||||
IconData icon, Color iconColor,
|
||||
{int delay = 0}) {
|
||||
// 根据当前主题调整颜色
|
||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||
final cardColor = Theme.of(context).cardColor;
|
||||
final textColor = Theme.of(context).textTheme.bodyMedium?.color;
|
||||
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0, end: 1),
|
||||
duration: Duration(milliseconds: 800 + delay),
|
||||
curve: Curves.easeOutBack,
|
||||
builder: (context, value, child) {
|
||||
// 确保 opacity 值在有效范围内 (0.0 到 1.0)
|
||||
final safeOpacity = value.clamp(0.0, 1.0);
|
||||
return Opacity(
|
||||
opacity: safeOpacity,
|
||||
child: Transform.translate(
|
||||
offset: Offset(100 * (1 - value), 0),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Card(
|
||||
elevation: 8,
|
||||
shadowColor: iconColor.withOpacity(isDarkMode ? 0.3 : 0.4),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
cardColor,
|
||||
isDarkMode
|
||||
? cardColor.withOpacity(0.9).withBlue(cardColor.blue + 5)
|
||||
: iconColor.withOpacity(0.05),
|
||||
cardColor,
|
||||
],
|
||||
stops: const [0.0, 0.5, 1.0],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: iconColor.withOpacity(isDarkMode ? 0.05 : 0.1),
|
||||
blurRadius: 10,
|
||||
spreadRadius: -5,
|
||||
offset: const Offset(0, 5),
|
||||
Widget _buildCard(
|
||||
BuildContext context,
|
||||
String title,
|
||||
String content,
|
||||
IconData icon,
|
||||
) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
size: 30,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 左侧图标 - 适配深色模式
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: iconColor.withOpacity(isDarkMode ? 0.2 : 0.15),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: iconColor.withOpacity(isDarkMode ? 0.15 : 0.2),
|
||||
blurRadius: isDarkMode ? 6 : 8,
|
||||
spreadRadius: isDarkMode ? 0 : 1,
|
||||
),
|
||||
],
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
iconColor.withOpacity(isDarkMode ? 0.8 : 0.7),
|
||||
iconColor.withOpacity(isDarkMode ? 0.2 : 0.1),
|
||||
],
|
||||
stops: const [0.0, 1.0],
|
||||
radius: 0.8,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: Colors.white,
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// 右侧内容 - 适配深色模式
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.2,
|
||||
color:
|
||||
iconColor.withOpacity(isDarkMode ? 0.9 : 0.8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Divider(
|
||||
color: iconColor.withOpacity(isDarkMode ? 0.4 : 0.3),
|
||||
thickness: 1.5,
|
||||
endIndent: 60,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
content,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
height: 1.5,
|
||||
letterSpacing: 0.5,
|
||||
color: textColor
|
||||
?.withOpacity(isDarkMode ? 0.9 : 1.0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
content,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
+44
-127
@@ -52,8 +52,7 @@ class HomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
// 定义状态枚举
|
||||
|
||||
int connectionTimeoutCounter = 0;
|
||||
// 当前连接状态
|
||||
ConnectionState _connectionState = ConnectionState.notStarted;
|
||||
|
||||
@@ -160,11 +159,19 @@ class _HomePageState extends State<HomePage> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// 释放资源
|
||||
// 取消所有计时器
|
||||
timer?.cancel();
|
||||
timer = null;
|
||||
|
||||
// 释放所有控制器和焦点节点
|
||||
_roomNameController.dispose();
|
||||
_roomPasswordController.dispose();
|
||||
_usernameController.dispose();
|
||||
_virtualIPController.dispose();
|
||||
|
||||
_virtualIPFocusNode.removeListener(_onVirtualIPFocusChange);
|
||||
_virtualIPFocusNode.dispose();
|
||||
|
||||
// 释放新增的FocusNode资源
|
||||
_usernameControllerFocusNode.removeListener(_onUsernameFocusChange);
|
||||
_usernameControllerFocusNode.dispose();
|
||||
|
||||
@@ -191,8 +198,6 @@ class _HomePageState extends State<HomePage> {
|
||||
roomName: roomName,
|
||||
roomPassword: roomPassword,
|
||||
severurl: Serverip);
|
||||
// 添加连接超时计数器
|
||||
int connectionTimeoutCounter = 0;
|
||||
|
||||
// 不再使用固定延迟模拟连接成功,而是通过定时检查IP来确定连接状态
|
||||
timer = Timer.periodic(const Duration(seconds: 1), (timer) async {
|
||||
@@ -216,49 +221,40 @@ class _HomePageState extends State<HomePage> {
|
||||
final int? version = runin.myNodeInfo?.virtualIpv4?.address?.addr;
|
||||
if (version != null) {
|
||||
String ipStr = _intToIpv4String(version);
|
||||
// 检查IP不为0.0.0.0时认为连接成功
|
||||
if (ipStr != "0.0.0.0") {
|
||||
if (publicIP != ipStr) {
|
||||
km.virtualIP = ipStr;
|
||||
}
|
||||
if (publicIP != ipStr) {
|
||||
km.virtualIP = ipStr;
|
||||
}
|
||||
|
||||
// 如果当前状态还是连接中,则更新为已连接
|
||||
if (_connectionState == ConnectionState.connecting) {
|
||||
setState(() {
|
||||
_connectionState = ConnectionState.connected;
|
||||
});
|
||||
}
|
||||
|
||||
// 重置超时计数器
|
||||
// 如果当前状态还是连接中,则更新为已连接
|
||||
if (_connectionState == ConnectionState.connecting) {
|
||||
setState(() {
|
||||
_connectionState = ConnectionState.connected;
|
||||
});
|
||||
}
|
||||
connectionTimeoutCounter = 0;
|
||||
} else if (_connectionState == ConnectionState.connecting) {
|
||||
connectionTimeoutCounter++;
|
||||
if (connectionTimeoutCounter >= 10) {
|
||||
connectionTimeoutCounter = 0;
|
||||
} else if (_connectionState == ConnectionState.connecting) {
|
||||
// 只在连接状态下增加超时计数
|
||||
connectionTimeoutCounter++;
|
||||
timer.cancel();
|
||||
setState(() {
|
||||
isRunning = false;
|
||||
_connectionState = ConnectionState.notStarted;
|
||||
runningTime = Duration.zero;
|
||||
});
|
||||
|
||||
// 如果连续10秒都是0.0.0.0,判断为连接失败
|
||||
if (connectionTimeoutCounter >= 10) {
|
||||
// 停止连接并显示失败消息
|
||||
timer.cancel();
|
||||
setState(() {
|
||||
isRunning = false;
|
||||
_connectionState = ConnectionState.notStarted;
|
||||
runningTime = Duration.zero;
|
||||
});
|
||||
|
||||
// 关闭服务器连接
|
||||
closeAllServer();
|
||||
|
||||
// 显示连接失败提示
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('连接失败,请检查网络或房间信息后重试'),
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
closeAllServer();
|
||||
// 清空玩家列表数据
|
||||
Provider.of<KM>(context, listen: false).nodes = [];
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('连接失败,未能获取节点信息'),
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +273,8 @@ class _HomePageState extends State<HomePage> {
|
||||
// 停止时重置状态
|
||||
_connectionState = ConnectionState.notStarted;
|
||||
closeAllServer();
|
||||
// 清空玩家列表数据
|
||||
Provider.of<KM>(context, listen: false).nodes = [];
|
||||
timer?.cancel();
|
||||
runningTime = Duration.zero;
|
||||
// 重置网络统计数据
|
||||
@@ -286,6 +284,7 @@ class _HomePageState extends State<HomePage> {
|
||||
_lastDownloadBytes = 0;
|
||||
uploadSpeed = 0;
|
||||
downloadSpeed = 0;
|
||||
//connectionTimeoutCounter
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -549,88 +548,6 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
}
|
||||
|
||||
// 修改卡片构建方法,移除多余的内边距
|
||||
Widget _buildDashboardCard(ColorScheme colorScheme) {
|
||||
return FloatingCard(
|
||||
colorScheme: colorScheme,
|
||||
maxWidth: 600, // 设置最大宽度
|
||||
height: 200,
|
||||
child: SizedBox(
|
||||
child: PieChart(
|
||||
PieChartData(
|
||||
sections: [
|
||||
PieChartSectionData(
|
||||
value: uploadSpeed,
|
||||
title: '上传',
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
PieChartSectionData(
|
||||
value: downloadSpeed,
|
||||
title: '下载',
|
||||
color: colorScheme.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// 修改流量统计卡片,移除多余的内边距
|
||||
Widget _buildTrafficCard(ColorScheme colorScheme) {
|
||||
return FloatingCard(
|
||||
colorScheme: colorScheme,
|
||||
maxWidth: 600,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 修改标题为图标+文字组合
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.data_usage, color: colorScheme.primary, size: 22),
|
||||
const SizedBox(width: 8),
|
||||
const Text('流量统计',
|
||||
style:
|
||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildTrafficInfo('上传速度', '$uploadSpeed MB/s', Icons.upload,
|
||||
colorScheme.primary),
|
||||
_buildTrafficInfo('下载速度', '$downloadSpeed MB/s', Icons.download,
|
||||
colorScheme.secondary),
|
||||
],
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
// 修改IP地址卡片,移除多余的内边距
|
||||
Widget _buildIPCard(ColorScheme colorScheme) {
|
||||
return FloatingCard(
|
||||
colorScheme: colorScheme,
|
||||
maxWidth: 600,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 修改标题为图标+文字组合
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.wifi, color: colorScheme.primary, size: 22),
|
||||
const SizedBox(width: 8),
|
||||
const Text('网络信息',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildIPInfo('虚拟 IP', publicIP, Icons.public, colorScheme),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTrafficInfo(
|
||||
String label, String value, IconData icon, Color color) {
|
||||
return Column(
|
||||
|
||||
+58
-64
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:astral/utils/app_info.dart';
|
||||
import 'package:astral/utils/up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -25,11 +27,11 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
late String _currentServer;
|
||||
final _appConfig = AppConfig();
|
||||
bool _closeToTray = false; // 添加关闭进入托盘变量
|
||||
bool _pingEnabled = true; // 添加全局ping开关
|
||||
|
||||
String serverIP = "";
|
||||
// 添加 ping 相关状态
|
||||
Map<String, int?> pingResults = {};
|
||||
Map<String, bool> isPinging = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -42,55 +44,67 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
// 初始化 ping 状态
|
||||
for (var server in _serverList) {
|
||||
pingResults[server] = null;
|
||||
isPinging[server] = true; // 默认所有服务器都开启ping
|
||||
}
|
||||
|
||||
// 开始 ping 所有服务器
|
||||
for (var server in _serverList) {
|
||||
_pingServer(server);
|
||||
}
|
||||
_startPingAllServers();
|
||||
}
|
||||
|
||||
// 添加一个计时器变量来控制 ping 操作
|
||||
Timer? _pingTimer;
|
||||
|
||||
// 新增方法:开始 ping 所有服务器
|
||||
void _startPingAllServers() {
|
||||
// 取消之前的计时器(如果存在)
|
||||
_pingTimer?.cancel();
|
||||
|
||||
// 创建新的计时器,每秒执行一次 ping
|
||||
_pingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (!mounted) {
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pingEnabled) {
|
||||
for (var server in _serverList) {
|
||||
_pingServerOnce(server);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// 停止所有 ping
|
||||
for (var server in _serverList) {
|
||||
isPinging[server] = false;
|
||||
}
|
||||
// 取消计时器
|
||||
_pingTimer?.cancel();
|
||||
_pingTimer = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 简化 ping 方法,移除强制持续 ping 参数
|
||||
void _startPingServer(String server) {
|
||||
if (isPinging[server] == true) return;
|
||||
|
||||
isPinging[server] = true;
|
||||
_pingServer(server);
|
||||
}
|
||||
|
||||
// 修改停止 ping 方法 - 实际上不再需要,但保留以防将来需要
|
||||
void _stopPingServer(String server) {
|
||||
isPinging[server] = false;
|
||||
}
|
||||
|
||||
// 执行 ping 操作
|
||||
Future<void> _pingServer(String server) async {
|
||||
if (isPinging[server] != true) return;
|
||||
|
||||
// 执行单次 ping 操作
|
||||
Future<void> _pingServerOnce(String server) async {
|
||||
final pingResult = await PingUtil.ping(server);
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
pingResults[server] = pingResult;
|
||||
});
|
||||
|
||||
// 1秒后再次 ping
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
_pingServer(server);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 切换全局ping状态
|
||||
void _togglePingStatus(bool value) {
|
||||
setState(() {
|
||||
_pingEnabled = value;
|
||||
if (!_pingEnabled) {
|
||||
// 如果关闭ping,清空所有结果
|
||||
for (var server in _serverList) {
|
||||
pingResults[server] = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加服务器对话框
|
||||
Future<void> _showAddServerDialog() async {
|
||||
final controller = TextEditingController();
|
||||
@@ -123,10 +137,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
_serverList.add(result);
|
||||
_appConfig.setServerList(_serverList);
|
||||
|
||||
// 初始化新服务器的 ping 状态并立即开始 ping
|
||||
// 初始化新服务器的 ping 状态
|
||||
pingResults[result] = null;
|
||||
isPinging[result] = true;
|
||||
_pingServer(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -189,21 +201,16 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
if (confirm == true) {
|
||||
final server = _serverList[index];
|
||||
|
||||
// 停止 ping
|
||||
_stopPingServer(server);
|
||||
|
||||
setState(() {
|
||||
_serverList.removeAt(index);
|
||||
_appConfig.setServerList(_serverList);
|
||||
|
||||
// 移除 ping 状态
|
||||
pingResults.remove(server);
|
||||
isPinging.remove(server);
|
||||
|
||||
if (_currentServer == server && _serverList.isNotEmpty) {
|
||||
_currentServer = _serverList[0];
|
||||
_appConfig.setCurrentServer(_currentServer);
|
||||
_startPingServer(_currentServer);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -212,7 +219,9 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
// 添加构建 ping 显示组件的方法
|
||||
Widget _buildPingWidget(String server) {
|
||||
final pingResult = pingResults[server];
|
||||
if (pingResult == null) {
|
||||
if (!_pingEnabled) {
|
||||
return const Text('Ping已关闭', style: TextStyle(color: Colors.grey));
|
||||
} else if (pingResult == null) {
|
||||
return const Text('测试中...', style: TextStyle(color: Colors.grey));
|
||||
} else {
|
||||
return Text(
|
||||
@@ -250,9 +259,6 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
ExpansionTile(
|
||||
leading: const Icon(Icons.list),
|
||||
title: const Text('服务器列表'),
|
||||
onExpansionChanged: (expanded) {
|
||||
// 不再需要处理展开折叠时的 ping 状态,所有服务器都持续 ping
|
||||
},
|
||||
children: [
|
||||
// 在服务器列表前添加当前服务器的 ping 状态显示
|
||||
ListView.builder(
|
||||
@@ -261,22 +267,6 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
itemCount: _serverList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final server = _serverList[index];
|
||||
final pingResult = pingResults[server];
|
||||
|
||||
// 构建延迟显示组件
|
||||
Widget pingWidget;
|
||||
if (pingResult == null) {
|
||||
pingWidget = const Text('测试中...',
|
||||
style: TextStyle(color: Colors.grey));
|
||||
} else {
|
||||
pingWidget = Text('${pingResult}ms',
|
||||
style: TextStyle(
|
||||
color: pingResult < 100
|
||||
? Colors.green
|
||||
: (pingResult < 300
|
||||
? Colors.orange
|
||||
: Colors.red)));
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.computer),
|
||||
@@ -284,14 +274,13 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
children: [
|
||||
Text('服务器 ${index + 1}'),
|
||||
const SizedBox(width: 8),
|
||||
pingWidget,
|
||||
_buildPingWidget(server),
|
||||
],
|
||||
),
|
||||
subtitle: Text(server),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 移除 ping 按钮,只保留编辑和删除按钮
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () => _showEditServerDialog(index),
|
||||
@@ -305,9 +294,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_currentServer = server;
|
||||
Provider.of<KM>(context, listen: false).serverIP =
|
||||
server;
|
||||
// 不再需要特别开始 ping 新选择的服务器,因为所有服务器都在 ping
|
||||
Provider.of<KM>(context, listen: false).serverIP = server;
|
||||
_appConfig.setCurrentServer(_currentServer);
|
||||
});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('已切换到服务器: $server')),
|
||||
@@ -347,6 +335,12 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
});
|
||||
},
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('启用服务器Ping测试'),
|
||||
subtitle: const Text('定期测试所有服务器的网络延迟'),
|
||||
value: _pingEnabled,
|
||||
onChanged: _togglePingStatus,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
+2
-78
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
class FloatingCard extends StatefulWidget {
|
||||
final ColorScheme colorScheme;
|
||||
@@ -8,14 +7,8 @@ class FloatingCard extends StatefulWidget {
|
||||
final EdgeInsetsGeometry padding;
|
||||
final Duration duration;
|
||||
final double hoverElevation;
|
||||
final double? maxWidth; // 添加最大宽度参数
|
||||
final double? height; // 添加最大宽度参数
|
||||
final bool enable3DEffect; // 是否启用3D效果
|
||||
final double maxRotationDegree; // 最大旋转角度
|
||||
final bool enableTranslateEffect; // 是否启用偏移效果
|
||||
final double maxTranslateDistance; // 最大偏移距离
|
||||
final double zTranslation; // Z轴偏移距离
|
||||
final bool riseOnHover; // 控制悬浮时是升起还是降下
|
||||
final double? maxWidth;
|
||||
final double? height;
|
||||
|
||||
const FloatingCard({
|
||||
super.key,
|
||||
@@ -27,12 +20,6 @@ class FloatingCard extends StatefulWidget {
|
||||
this.hoverElevation = 8,
|
||||
this.maxWidth,
|
||||
this.height,
|
||||
this.enable3DEffect = true, // 默认启用3D效果
|
||||
this.maxRotationDegree = 10, // 默认最大旋转角度为10度
|
||||
this.enableTranslateEffect = true, // 默认启用偏移效果
|
||||
this.maxTranslateDistance = 5, // 默认最大偏移距离为5
|
||||
this.zTranslation = 10, // 默认Z轴偏移距离为20
|
||||
this.riseOnHover = true, // 默认悬浮时升起
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -41,67 +28,12 @@ class FloatingCard extends StatefulWidget {
|
||||
|
||||
class _FloatingCardState extends State<FloatingCard> {
|
||||
bool isHovered = false;
|
||||
Offset mousePosition = Offset.zero;
|
||||
final GlobalKey _cardKey = GlobalKey();
|
||||
|
||||
// 获取卡片的尺寸和位置
|
||||
Rect? _getCardRect() {
|
||||
final RenderBox? renderBox =
|
||||
_cardKey.currentContext?.findRenderObject() as RenderBox?;
|
||||
if (renderBox == null) return null;
|
||||
final position = renderBox.localToGlobal(Offset.zero);
|
||||
return Rect.fromLTWH(
|
||||
position.dx, position.dy, renderBox.size.width, renderBox.size.height);
|
||||
}
|
||||
|
||||
// 计算旋转角度
|
||||
(double, double) _calculateRotation() {
|
||||
final rect = _getCardRect();
|
||||
if (rect == null) return (0, 0);
|
||||
|
||||
// 计算鼠标相对于卡片中心的位置
|
||||
final centerX = rect.width / 2;
|
||||
final centerY = rect.height / 2;
|
||||
final deltaX = (mousePosition.dx - centerX) / centerX;
|
||||
final deltaY = (mousePosition.dy - centerY) / centerY;
|
||||
|
||||
// 计算旋转角度,鼠标在右侧时向左倾斜(Y轴正向旋转),鼠标在下方时向上倾斜(X轴负向旋转)
|
||||
final rotateY = deltaX * widget.maxRotationDegree;
|
||||
final rotateX = -deltaY * widget.maxRotationDegree;
|
||||
|
||||
return (rotateX, rotateY);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 根据是否启用3D效果计算旋转角度
|
||||
final (rotateX, rotateY) =
|
||||
isHovered && widget.enable3DEffect ? _calculateRotation() : (0.0, 0.0);
|
||||
|
||||
// 根据是否启用偏移效果计算偏移距离
|
||||
final translateX = isHovered && widget.enableTranslateEffect
|
||||
? rotateY * widget.maxTranslateDistance
|
||||
: 0.0;
|
||||
final translateY = isHovered && widget.enableTranslateEffect
|
||||
? rotateX * widget.maxTranslateDistance
|
||||
: 0.0;
|
||||
|
||||
// 根据riseOnHover决定Z轴偏移方向
|
||||
final zDirection = widget.riseOnHover ? 1.0 : -1.0;
|
||||
final translateZ = isHovered && widget.enableTranslateEffect
|
||||
? widget.zTranslation * zDirection
|
||||
: 0.0;
|
||||
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => isHovered = true),
|
||||
onExit: (_) => setState(() => isHovered = false),
|
||||
onHover: (event) {
|
||||
if (widget.enable3DEffect || widget.enableTranslateEffect) {
|
||||
setState(() {
|
||||
mousePosition = event.localPosition;
|
||||
});
|
||||
}
|
||||
},
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
@@ -109,15 +41,7 @@ class _FloatingCardState extends State<FloatingCard> {
|
||||
maxWidth: widget.maxWidth ?? double.infinity,
|
||||
),
|
||||
child: AnimatedContainer(
|
||||
key: _cardKey,
|
||||
duration: widget.duration,
|
||||
transform: Matrix4.identity()
|
||||
..setEntry(3, 2, 0.001) // 透视效果
|
||||
// 仅当启用3D效果时应用旋转
|
||||
..rotateX(widget.enable3DEffect ? rotateX * math.pi / 180 : 0)
|
||||
..rotateY(widget.enable3DEffect ? rotateY * math.pi / 180 : 0)
|
||||
// 仅当启用偏移效果时应用偏移
|
||||
..translate(translateX, translateY, translateZ),
|
||||
transformAlignment: Alignment.center,
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
+188
-175
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -42,7 +42,6 @@ dependencies:
|
||||
flutter_rust_bridge: 2.9.0
|
||||
flutter_colorpicker: ^1.1.0
|
||||
window_manager: ^0.4.3
|
||||
fl_chart: ^0.70.2
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
json_annotation: ^4.8.1
|
||||
tray_manager: ^0.3.2
|
||||
@@ -52,6 +51,7 @@ dependencies:
|
||||
yaml: ^3.1.2
|
||||
flutter_local_notifications: ^19.0.0
|
||||
windows_notification: ^1.3.0
|
||||
fl_chart: ^0.70.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
+12
-8
@@ -581,15 +581,19 @@ pub fn create_server(
|
||||
cfg.set_hostname(Option::from(username));
|
||||
cfg.set_dhcp(enable_dhcp);
|
||||
let mut flags = cfg.get_flags();
|
||||
flags.dev_name = "Astral".to_string();
|
||||
// flags.dev_name = "astral".to_string();
|
||||
cfg.set_flags(flags);
|
||||
let peer_config = PeerConfig {
|
||||
uri: ("tcp://".to_string() + &severurl).parse().unwrap(),
|
||||
};
|
||||
let peer_config2 = PeerConfig {
|
||||
uri: ("udp://".to_string() + &severurl).parse().unwrap(),
|
||||
};
|
||||
cfg.set_peers(vec![peer_config, peer_config2]);
|
||||
// 创建TCP和UDP连接配置列表
|
||||
let peer_configs = vec![
|
||||
PeerConfig {
|
||||
uri: format!("tcp://{}", severurl).parse().unwrap(),
|
||||
},
|
||||
PeerConfig {
|
||||
uri: format!("udp://{}", severurl).parse().unwrap(),
|
||||
}
|
||||
];
|
||||
|
||||
cfg.set_peers(peer_configs);
|
||||
if enable_dhcp == false {
|
||||
// 使用完整路径引用 cidr 模块的 Ipv4Inet
|
||||
// 解析IP地址和子网掩码
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 917 B |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
|
||||
For more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
|
||||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="A new Flutter project.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="astral">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>astral</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "astral",
|
||||
"short_name": "astral",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "#0175C2",
|
||||
"theme_color": "#0175C2",
|
||||
"description": "A new Flutter project.",
|
||||
"orientation": "portrait-primary",
|
||||
"prefer_related_applications": false,
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/Icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "icons/Icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "icons/Icon-maskable-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "icons/Icon-maskable-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -75,10 +75,6 @@ set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
# 添加管理员权限要求(修正路径格式)
|
||||
target_link_options(${BINARY_NAME} PRIVATE
|
||||
"LINKER:/MANIFESTUAC:level='requireAdministrator' uiAccess='false'"
|
||||
$<$<C_COMPILER_ID:MSVC>:"LINKER:/MANIFESTINPUT:${CMAKE_CURRENT_SOURCE_DIR}/runner/runner.exe.manifest">)
|
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
@@ -26,7 +26,7 @@ target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTT
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
|
||||
|
||||
SET_TARGET_PROPERTIES(${BINARY_NAME} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\" /SUBSYSTEM:WINDOWS")
|
||||
# Disable Windows macros that collide with C++ standard library functions.
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
@@ -18,4 +12,14 @@
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel
|
||||
level="requireAdministrator"
|
||||
uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
|
||||
Reference in New Issue
Block a user