Optimize performance
Update core Optimize core stability Fix linux tun authority check error Fix some issues
This commit is contained in:
281
lib/state.dart
281
lib/state.dart
@@ -1,9 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:fl_clash/clash/clash.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/l10n/l10n.dart';
|
||||
import 'package:fl_clash/plugins/service.dart';
|
||||
import 'package:fl_clash/widgets/scaffold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -17,9 +17,12 @@ import 'models/models.dart';
|
||||
typedef UpdateTasks = List<FutureOr Function()>;
|
||||
|
||||
class GlobalState {
|
||||
static GlobalState? _instance;
|
||||
bool isService = false;
|
||||
Timer? timer;
|
||||
Timer? groupsUpdateTimer;
|
||||
late Config config;
|
||||
late AppState appState;
|
||||
late PackageInfo packageInfo;
|
||||
Function? updateCurrentDelayDebounce;
|
||||
PageController? pageController;
|
||||
@@ -30,11 +33,43 @@ class GlobalState {
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
late AppController appController;
|
||||
GlobalKey<CommonScaffoldState> homeScaffoldKey = GlobalKey();
|
||||
bool lastTunEnable = false;
|
||||
int? lastProfileModified;
|
||||
|
||||
bool get isStart => startTime != null && startTime!.isBeforeNow;
|
||||
|
||||
GlobalState._internal();
|
||||
|
||||
factory GlobalState() {
|
||||
_instance ??= GlobalState._internal();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
initApp(int version) async {
|
||||
appState = AppState(
|
||||
version: version,
|
||||
viewWidth: other.getScreenSize().width,
|
||||
requests: FixedList(1000),
|
||||
logs: FixedList(1000),
|
||||
traffics: FixedList(30),
|
||||
totalTraffic: Traffic(),
|
||||
);
|
||||
await init();
|
||||
}
|
||||
|
||||
init() async {
|
||||
packageInfo = await PackageInfo.fromPlatform();
|
||||
config = await preferences.getConfig() ??
|
||||
Config(
|
||||
themeProps: defaultThemeProps,
|
||||
);
|
||||
await globalState.migrateOldData(config);
|
||||
await AppLocalizations.load(
|
||||
other.getLocaleForString(config.appSetting.locale) ??
|
||||
WidgetsBinding.instance.platformDispatcher.locale,
|
||||
);
|
||||
}
|
||||
|
||||
String get ua => config.patchClashConfig.globalUa ?? packageInfo.ua;
|
||||
|
||||
startUpdateTasks([UpdateTasks? tasks]) async {
|
||||
if (timer != null && timer!.isActive == true) return;
|
||||
if (tasks != null) {
|
||||
@@ -47,10 +82,10 @@ class GlobalState {
|
||||
}
|
||||
|
||||
executorUpdateTask() async {
|
||||
if (timer != null && timer!.isActive == true) return;
|
||||
for (final task in tasks) {
|
||||
await task();
|
||||
}
|
||||
timer = null;
|
||||
}
|
||||
|
||||
stopUpdateTasks() {
|
||||
@@ -59,88 +94,11 @@ class GlobalState {
|
||||
timer = null;
|
||||
}
|
||||
|
||||
Future<void> initCore({
|
||||
required AppState appState,
|
||||
required ClashConfig clashConfig,
|
||||
required Config config,
|
||||
}) async {
|
||||
await globalState.init(
|
||||
appState: appState,
|
||||
config: config,
|
||||
clashConfig: clashConfig,
|
||||
);
|
||||
await applyProfile(
|
||||
appState: appState,
|
||||
config: config,
|
||||
clashConfig: clashConfig,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateClashConfig({
|
||||
required AppState appState,
|
||||
required ClashConfig clashConfig,
|
||||
required Config config,
|
||||
bool isPatch = true,
|
||||
}) async {
|
||||
await config.currentProfile?.checkAndUpdate();
|
||||
final useClashConfig = clashConfig.copyWith();
|
||||
if (clashConfig.tun.enable != lastTunEnable &&
|
||||
lastTunEnable == false &&
|
||||
!Platform.isAndroid) {
|
||||
final code = await system.authorizeCore();
|
||||
switch (code) {
|
||||
case AuthorizeCode.none:
|
||||
break;
|
||||
case AuthorizeCode.success:
|
||||
lastTunEnable = useClashConfig.tun.enable;
|
||||
await restartCore(
|
||||
appState: appState,
|
||||
clashConfig: clashConfig,
|
||||
config: config,
|
||||
);
|
||||
return;
|
||||
case AuthorizeCode.error:
|
||||
useClashConfig.tun = useClashConfig.tun.copyWith(
|
||||
enable: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (config.appSetting.openLogs) {
|
||||
clashCore.startLog();
|
||||
} else {
|
||||
clashCore.stopLog();
|
||||
}
|
||||
final res = await clashCore.updateConfig(
|
||||
getUpdateConfigParams(config, clashConfig, isPatch),
|
||||
);
|
||||
if (res.isNotEmpty) throw res;
|
||||
lastTunEnable = useClashConfig.tun.enable;
|
||||
lastProfileModified = await config.getCurrentProfile()?.profileLastModified;
|
||||
}
|
||||
|
||||
handleStart([UpdateTasks? tasks]) async {
|
||||
startTime ??= DateTime.now();
|
||||
await clashCore.startListener();
|
||||
await service?.startVpn();
|
||||
startUpdateTasks(tasks);
|
||||
startTime ??= DateTime.now();
|
||||
}
|
||||
|
||||
restartCore({
|
||||
required AppState appState,
|
||||
required ClashConfig clashConfig,
|
||||
required Config config,
|
||||
bool isPatch = true,
|
||||
}) async {
|
||||
await clashService?.reStart();
|
||||
await initCore(
|
||||
appState: appState,
|
||||
clashConfig: clashConfig,
|
||||
config: config,
|
||||
);
|
||||
|
||||
if (isStart) {
|
||||
await handleStart();
|
||||
}
|
||||
}
|
||||
|
||||
Future updateStartTime() async {
|
||||
@@ -150,85 +108,16 @@ class GlobalState {
|
||||
Future handleStop() async {
|
||||
startTime = null;
|
||||
await clashCore.stopListener();
|
||||
clashLib?.stopTun();
|
||||
await clashLib?.stopTun();
|
||||
await service?.stopVpn();
|
||||
stopUpdateTasks();
|
||||
}
|
||||
|
||||
Future applyProfile({
|
||||
required AppState appState,
|
||||
required Config config,
|
||||
required ClashConfig clashConfig,
|
||||
}) async {
|
||||
clashCore.requestGc();
|
||||
await updateClashConfig(
|
||||
appState: appState,
|
||||
clashConfig: clashConfig,
|
||||
config: config,
|
||||
isPatch: false,
|
||||
);
|
||||
await updateGroups(appState);
|
||||
await updateProviders(appState);
|
||||
}
|
||||
|
||||
updateProviders(AppState appState) async {
|
||||
appState.providers = await clashCore.getExternalProviders();
|
||||
}
|
||||
|
||||
CoreState getCoreState(Config config, ClashConfig clashConfig) {
|
||||
return CoreState(
|
||||
enable: config.vpnProps.enable,
|
||||
accessControl: config.isAccessControl ? config.accessControl : null,
|
||||
ipv6: config.vpnProps.ipv6,
|
||||
allowBypass: config.vpnProps.allowBypass,
|
||||
bypassDomain: config.networkProps.bypassDomain,
|
||||
systemProxy: config.vpnProps.systemProxy,
|
||||
currentProfileName:
|
||||
config.currentProfile?.label ?? config.currentProfileId ?? "",
|
||||
routeAddress: clashConfig.routeAddress,
|
||||
);
|
||||
}
|
||||
|
||||
getUpdateConfigParams(Config config, ClashConfig clashConfig, bool isPatch) {
|
||||
return UpdateConfigParams(
|
||||
profileId: config.currentProfileId ?? "",
|
||||
config: clashConfig,
|
||||
params: ConfigExtendedParams(
|
||||
isPatch: isPatch,
|
||||
isCompatible: true,
|
||||
selectedMap: config.currentSelectedMap,
|
||||
overrideDns: config.overrideDns,
|
||||
testUrl: config.appSetting.testUrl,
|
||||
onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
init({
|
||||
required AppState appState,
|
||||
required Config config,
|
||||
required ClashConfig clashConfig,
|
||||
}) async {
|
||||
appState.isInit = await clashCore.isInit;
|
||||
if (!appState.isInit) {
|
||||
appState.isInit = await clashCore.init(
|
||||
config: config,
|
||||
clashConfig: clashConfig,
|
||||
);
|
||||
clashLib?.setState(
|
||||
getCoreState(config, clashConfig),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateGroups(AppState appState) async {
|
||||
appState.groups = await clashCore.getProxiesGroups();
|
||||
}
|
||||
|
||||
Future<bool?> showMessage<bool>({
|
||||
Future<bool?> showMessage({
|
||||
required String title,
|
||||
required InlineSpan message,
|
||||
String? confirmText,
|
||||
bool cancelable = true,
|
||||
}) async {
|
||||
return await showCommonDialog<bool>(
|
||||
child: Builder(
|
||||
@@ -251,12 +140,13 @@ class GlobalState {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(appLocalizations.cancel),
|
||||
),
|
||||
if (cancelable)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(appLocalizations.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
@@ -270,22 +160,6 @@ class GlobalState {
|
||||
);
|
||||
}
|
||||
|
||||
changeProxy({
|
||||
required Config config,
|
||||
required String groupName,
|
||||
required String proxyName,
|
||||
}) async {
|
||||
await clashCore.changeProxy(
|
||||
ChangeProxyParams(
|
||||
groupName: groupName,
|
||||
proxyName: proxyName,
|
||||
),
|
||||
);
|
||||
if (config.appSetting.closeConnections) {
|
||||
clashCore.closeConnections();
|
||||
}
|
||||
}
|
||||
|
||||
Future<T?> showCommonDialog<T>({
|
||||
required Widget child,
|
||||
bool dismissible = true,
|
||||
@@ -301,17 +175,6 @@ class GlobalState {
|
||||
);
|
||||
}
|
||||
|
||||
updateTraffic({
|
||||
required Config config,
|
||||
AppFlowingState? appFlowingState,
|
||||
}) async {
|
||||
final traffic = await clashCore.getTraffic();
|
||||
if (appFlowingState != null) {
|
||||
appFlowingState.addTraffic(traffic);
|
||||
appFlowingState.totalTraffic = await clashCore.getTotalTraffic();
|
||||
}
|
||||
}
|
||||
|
||||
Future<T?> safeRun<T>(
|
||||
FutureOr<T> Function() futureFunction, {
|
||||
String? title,
|
||||
@@ -321,6 +184,7 @@ class GlobalState {
|
||||
final res = await futureFunction();
|
||||
return res;
|
||||
} catch (e) {
|
||||
commonPrint.log("$e");
|
||||
if (silence) {
|
||||
showNotifier(e.toString());
|
||||
} else {
|
||||
@@ -353,6 +217,49 @@ class GlobalState {
|
||||
}
|
||||
launchUrl(Uri.parse(url));
|
||||
}
|
||||
|
||||
Future<void> migrateOldData(Config config) async {
|
||||
final clashConfig = await preferences.getClashConfig();
|
||||
if (clashConfig != null) {
|
||||
config = config.copyWith(
|
||||
patchClashConfig: clashConfig,
|
||||
);
|
||||
preferences.clearClashConfig();
|
||||
preferences.saveConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
CoreState getCoreState() {
|
||||
final currentProfile = config.currentProfile;
|
||||
return CoreState(
|
||||
vpnProps: config.vpnProps,
|
||||
onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy,
|
||||
currentProfileName: currentProfile?.label ?? currentProfile?.id ?? "",
|
||||
bypassDomain: config.networkProps.bypassDomain,
|
||||
);
|
||||
}
|
||||
|
||||
getUpdateConfigParams([bool? isPatch]) {
|
||||
final currentProfile = config.currentProfile;
|
||||
final clashConfig = config.patchClashConfig;
|
||||
return UpdateConfigParams(
|
||||
profileId: config.currentProfileId ?? "",
|
||||
config: clashConfig.copyWith(
|
||||
globalUa: ua,
|
||||
tun: clashConfig.tun.copyWith(
|
||||
routeAddress: config.networkProps.routeMode == RouteMode.bypassPrivate
|
||||
? defaultBypassPrivateRouteAddress
|
||||
: clashConfig.tun.routeAddress,
|
||||
),
|
||||
),
|
||||
params: ConfigExtendedParams(
|
||||
isPatch: isPatch ?? false,
|
||||
selectedMap: currentProfile?.selectedMap ?? {},
|
||||
overrideDns: config.overrideDns,
|
||||
testUrl: config.appSetting.testUrl,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final globalState = GlobalState();
|
||||
|
||||
Reference in New Issue
Block a user