feat(client): 自动连接开关 + Windows 开机自启改任务计划程序
- 新增「自动连接」设置开关(默认关,持久化):启动 app 进登录态主界面后,等节点就绪 自动连一次(_RootFlowState 一次性 listenManual nodesProvider → toggle())。全平台生效。 - Windows 开机自启改用 schtasks /rl highest 登录触发任务:本应用 requireAdministrator, 原注册表 Run 键(非提权)开机会弹 UAC/起不来 → 任务计划静默提权拉起。macOS/Linux 仍用 launch_at_startup 登录项。 - 设置页功能组加「自动连接」行;新增 autoConnect/autoConnectSub 文案。 - _load 加 mounted 守卫(异步初始化期间已 dispose 不再写 state)。 - 测试:autoConnect 默认关 / _load 读持久化 / setAutoConnect 落盘。 注:移动端真·常连(Android Always-on + iOS/iPad On-Demand,无 UI 自连)是更大的原生活, 已单列 todo #14 后续做;本轮移动端只有「打开 app 自动连接」。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,9 @@ import 'services/token_store.dart';
|
||||
import 'shell/home_shell.dart';
|
||||
import 'state/app_providers.dart';
|
||||
import 'state/auth_provider.dart';
|
||||
import 'state/connection_provider.dart';
|
||||
import 'state/nodes_provider.dart';
|
||||
import 'state/settings_provider.dart';
|
||||
import 'system_tray.dart';
|
||||
import 'widgets/auth_screen.dart';
|
||||
import 'widgets/onboarding_screen.dart';
|
||||
@@ -113,6 +116,25 @@ class RootFlow extends ConsumerStatefulWidget {
|
||||
class _RootFlowState extends ConsumerState<RootFlow> {
|
||||
final _store = const TokenStore();
|
||||
bool _forceOnboarding = false;
|
||||
bool _autoConnectArmed = false; // 自动连接每进程只尝试一次
|
||||
|
||||
// 进入登录态主界面后:若开了「自动连接」且当前未连接,等节点就绪后自动连一次。
|
||||
void _maybeAutoConnect() {
|
||||
if (_autoConnectArmed) return;
|
||||
_autoConnectArmed = true;
|
||||
if (!ref.read(settingsProvider).autoConnect) return;
|
||||
if (ref.read(connectionProvider).phase != VpnPhase.off) return;
|
||||
// 节点列表异步加载,等出现可用(uuid 非空)节点再连,避免「节点未就绪」直接失败。
|
||||
late final ProviderSubscription sub;
|
||||
sub = ref.listenManual(nodesProvider, (prev, next) {
|
||||
final ready = (next.valueOrNull ?? const []).any((n) => n.uuid.isNotEmpty);
|
||||
if (!ready) return;
|
||||
sub.close();
|
||||
if (ref.read(connectionProvider).phase == VpnPhase.off) {
|
||||
ref.read(connectionProvider.notifier).toggle();
|
||||
}
|
||||
}, fireImmediately: true);
|
||||
}
|
||||
|
||||
// 登录/注册成功后:未看过引导才进引导,否则直接主界面。
|
||||
Future<void> _afterAuth() async {
|
||||
@@ -139,6 +161,9 @@ class _RootFlowState extends ConsumerState<RootFlow> {
|
||||
if (_forceOnboarding) {
|
||||
return OnboardingScreen(t: t, onDone: () { _afterOnboarding(); });
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) _maybeAutoConnect();
|
||||
});
|
||||
return const HomeShell();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user