Compare commits

..

4 Commits

Author SHA1 Message Date
chen08209
08d07498b9 update Version 2024-05-07 18:32:21 +08:00
chen08209
d5aa09949a Reconstruction application proxy logic 2024-05-07 18:31:14 +08:00
chen08209
fd1dfe5c60 Fix Tab destroy error 2024-05-06 19:05:27 +08:00
chen08209
9f89fe8b29 Optimize repeat healthcheck 2024-05-06 17:17:26 +08:00
23 changed files with 506 additions and 625 deletions

View File

@@ -17,6 +17,7 @@ import (
"os"
"os/exec"
"runtime"
"strings"
"sync"
"syscall"
)
@@ -114,6 +115,152 @@ func decorationConfig(profilePath *string, cfg config.RawConfig) *config.RawConf
return prof
}
func Reduce[T any, U any](s []T, initVal U, f func(U, T) U) U {
for _, v := range s {
initVal = f(initVal, v)
}
return initVal
}
func Map[T, U any](slice []T, fn func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = fn(v)
}
return result
}
func replaceFromMap(s string, m map[string]string) string {
for k, v := range m {
s = strings.ReplaceAll(s, k, v)
}
return s
}
func removeDuplicateFromSlice[T any](slice []T) []T {
result := make([]T, 0)
seen := make(map[any]struct{})
for _, value := range slice {
if _, ok := seen[value]; !ok {
result = append(result, value)
seen[value] = struct{}{}
}
}
return result
}
func generateProxyGroupAndRule(proxyGroup *[]map[string]any, rule *[]string) {
var replacements = map[string]string{}
var selectArr []map[string]any
var urlTestArr []map[string]any
var fallbackArr []map[string]any
for _, group := range *proxyGroup {
switch group["type"] {
case "select":
selectArr = append(selectArr, group)
replacements[group["name"].(string)] = "Proxy"
break
case "url-test":
urlTestArr = append(urlTestArr, group)
replacements[group["name"].(string)] = "Auto"
break
case "fallback":
fallbackArr = append(fallbackArr, group)
replacements[group["name"].(string)] = "Fallback"
break
default:
break
}
}
ProxyProxies := Reduce(selectArr, []string{}, func(res []string, cur map[string]any) []string {
if cur["proxies"] == nil {
return res
}
for _, proxyName := range cur["proxies"].([]interface{}) {
if str, ok := proxyName.(string); ok {
str = replaceFromMap(str, replacements)
if str != "Proxy" {
res = append(res, str)
}
}
}
return res
})
ProxyProxies = removeDuplicateFromSlice(ProxyProxies)
AutoProxies := Reduce(urlTestArr, []string{}, func(res []string, cur map[string]any) []string {
if cur["proxies"] == nil {
return res
}
for _, proxyName := range cur["proxies"].([]interface{}) {
if str, ok := proxyName.(string); ok {
str = replaceFromMap(str, replacements)
if str != "Auto" {
res = append(res, str)
}
}
}
return res
})
AutoProxies = removeDuplicateFromSlice(AutoProxies)
FallbackProxies := Reduce(fallbackArr, []string{}, func(res []string, cur map[string]any) []string {
if cur["proxies"] == nil {
return res
}
for _, proxyName := range cur["proxies"].([]interface{}) {
if str, ok := proxyName.(string); ok {
str = replaceFromMap(str, replacements)
if str != "Fallback" {
res = append(res, str)
}
}
}
return res
})
FallbackProxies = removeDuplicateFromSlice(FallbackProxies)
var computedProxyGroup []map[string]any
if len(ProxyProxies) > 0 {
computedProxyGroup = append(computedProxyGroup,
map[string]any{
"name": "Proxy",
"type": "select",
"proxies": ProxyProxies,
})
}
if len(AutoProxies) > 0 {
computedProxyGroup = append(computedProxyGroup,
map[string]any{
"name": "Auto",
"type": "url-test",
"proxies": AutoProxies,
})
}
if len(FallbackProxies) > 0 {
computedProxyGroup = append(computedProxyGroup,
map[string]any{
"name": "Fallback",
"type": "fallback",
"proxies": FallbackProxies,
})
}
computedRule := Map(*rule, func(value string) string {
return replaceFromMap(value, replacements)
})
*proxyGroup = computedProxyGroup
*rule = computedRule
}
func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfig) {
targetConfig.ExternalController = ""
targetConfig.ExternalUI = ""
@@ -129,23 +276,19 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi
targetConfig.Tun.Device = patchConfig.Tun.Device
targetConfig.Tun.DNSHijack = patchConfig.Tun.DNSHijack
targetConfig.Tun.Stack = patchConfig.Tun.Stack
targetConfig.GeodataLoader = "standard"
targetConfig.Profile.StoreSelected = false
if targetConfig.DNS.Enable == false {
targetConfig.DNS = patchConfig.DNS
} else {
targetConfig.DNS.UseHosts = patchConfig.DNS.UseHosts
targetConfig.DNS.EnhancedMode = patchConfig.DNS.EnhancedMode
targetConfig.DNS.IPv6 = patchConfig.DNS.IPv6
targetConfig.DNS.DefaultNameserver = append(patchConfig.DNS.DefaultNameserver, targetConfig.DNS.DefaultNameserver...)
targetConfig.DNS.NameServer = append(patchConfig.DNS.NameServer, targetConfig.DNS.NameServer...)
targetConfig.DNS.FakeIPFilter = append(patchConfig.DNS.FakeIPFilter, targetConfig.DNS.FakeIPFilter...)
targetConfig.DNS.Fallback = append(patchConfig.DNS.Fallback, targetConfig.DNS.Fallback...)
if runtime.GOOS == "android" {
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder)
} else if runtime.GOOS == "windows" {
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, dns.SystemDNSPlaceholder)
}
}
if runtime.GOOS == "android" {
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder)
} else if runtime.GOOS == "windows" {
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, dns.SystemDNSPlaceholder)
}
targetConfig.ProxyProvider = make(map[string]map[string]any)
targetConfig.RuleProvider = make(map[string]map[string]any)
generateProxyGroupAndRule(&targetConfig.ProxyGroup, &targetConfig.Rule)
}
func patchConfig(general *config.General) {
@@ -193,7 +336,6 @@ func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) {
}
}
}
func applyConfig(isPatch bool) {
@@ -205,5 +347,6 @@ func applyConfig(isPatch bool) {
patchConfig(cfg.General)
} else {
executor.ApplyConfig(cfg, true)
healthcheck()
}
}

View File

@@ -19,11 +19,11 @@ type Message struct {
Data interface{} `json:"data"`
}
func (message *Message) toJson() string {
func (message *Message) Json() string {
data, _ := json.Marshal(message)
return string(data)
}
func SendMessage(message Message) {
SendToPort(*Port, message.toJson())
SendToPort(*Port, message.Json())
}

View File

@@ -96,27 +96,28 @@ func getProxies() *C.char {
//export changeProxy
func changeProxy(s *C.char) bool {
paramsString := C.GoString(s)
var params = &ChangeProxyParams{}
err := json.Unmarshal([]byte(paramsString), params)
if err != nil {
log.Infoln("Unmarshal ChangeProxyParams %v", err)
return false
}
proxies := tunnel.ProxiesWithProviders()
proxy := proxies[*params.GroupName]
if proxy == nil {
return false
}
log.Infoln("change proxy %s", proxy.Name())
adapterProxy := proxy.(*adapter.Proxy)
selector, ok := adapterProxy.ProxyAdapter.(*outboundgroup.Selector)
if !ok {
return false
}
if err := selector.Set(*params.ProxyName); err != nil {
return false
}
go func() {
paramsString := C.GoString(s)
var params = &ChangeProxyParams{}
err := json.Unmarshal([]byte(paramsString), params)
if err != nil {
log.Infoln("Unmarshal ChangeProxyParams %v", err)
}
proxies := tunnel.ProxiesWithProviders()
proxy := proxies[*params.GroupName]
if proxy == nil {
return
}
log.Infoln("change proxy %s", proxy.Name())
adapterProxy := proxy.(*adapter.Proxy)
selector, ok := adapterProxy.ProxyAdapter.(*outboundgroup.Selector)
if !ok {
return
}
if err := selector.Set(*params.ProxyName); err != nil {
return
}
}()
return true
}
@@ -136,7 +137,8 @@ func getTraffic() *C.char {
}
//export asyncTestDelay
func asyncTestDelay(s *C.char) {
func asyncTestDelay(s *C.char, port C.longlong) {
i := int64(port)
go func() {
paramsString := C.GoString(s)
var params = &TestDelayParams{}
@@ -144,42 +146,34 @@ func asyncTestDelay(s *C.char) {
if err != nil {
return
}
expectedStatus, err := utils.NewUnsignedRanges[uint16]("")
if err != nil {
return
}
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(params.Timeout))
defer cancel()
proxies := tunnel.ProxiesWithProviders()
proxy := proxies[params.ProxyName]
delayData := &Delay{
Name: params.ProxyName,
}
message := bridge.Message{
Type: bridge.Delay,
Data: delayData,
}
if proxy == nil {
delayData.Value = -1
bridge.SendMessage(message)
bridge.SendToPort(i, message.Json())
return
}
delay, err := proxy.URLTest(ctx, constant.DefaultTestURL, expectedStatus)
if err != nil || delay == 0 {
delayData.Value = -1
bridge.SendMessage(message)
bridge.SendToPort(i, message.Json())
return
}
delayData.Value = int32(delay)
bridge.SendMessage(message)
bridge.SendToPort(i, message.Json())
}()
}

View File

@@ -27,8 +27,13 @@ runAppWithPreferences(
ChangeNotifierProvider<Config>(
create: (_) => config,
),
ChangeNotifierProvider<AppState>(
ChangeNotifierProxyProvider2<Config, ClashConfig, AppState>(
create: (_) => appState,
update: (_, config, clashConfig, appState) {
appState?.mode = clashConfig.mode;
appState?.currentProxyName = config.currentProxyName;
return appState!;
},
)
],
child: child,

View File

@@ -100,9 +100,6 @@ class ClashCore {
.map(
(name) => proxies[name],
)
.where(
(proxy) => proxy["type"] != GroupType.Selector.value,
)
.toList();
return group;
}).toList();
@@ -115,13 +112,38 @@ class ClashCore {
return clashFFI.changeProxy(params.toNativeUtf8().cast()) == 1;
}
bool delay(String proxyName) {
Future<Delay> delay(String proxyName) {
final completer = Completer<Delay>();
final receiver = ReceivePort();
receiver.listen((message) {
if (!completer.isCompleted) {
final m = Message.fromJson(json.decode(message));
final delay = Delay.fromJson(m.data);
completer.complete(delay);
receiver.close();
}
});
final delayParams = {
"proxy-name": proxyName,
"timeout": appConstant.httpTimeoutDuration.inMilliseconds,
};
clashFFI.asyncTestDelay(json.encode(delayParams).toNativeUtf8().cast());
return true;
clashFFI.asyncTestDelay(
json.encode(delayParams).toNativeUtf8().cast(),
receiver.sendPort.nativePort,
);
Future.delayed(appConstant.httpTimeoutDuration + appConstant.moreDuration,
() {
if (!completer.isCompleted) {
receiver.close();
completer.complete(
Delay(
name: proxyName,
value: -1,
),
);
}
});
return completer.future;
}
healthcheck() {

View File

@@ -960,17 +960,20 @@ class ClashFFI {
void asyncTestDelay(
ffi.Pointer<ffi.Char> s,
int port,
) {
return _asyncTestDelay(
s,
port,
);
}
late final _asyncTestDelayPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>(
'asyncTestDelay');
late final _asyncTestDelay =
_asyncTestDelayPtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>();
late final _asyncTestDelayPtr = _lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Pointer<ffi.Char>, ffi.LongLong)>>('asyncTestDelay');
late final _asyncTestDelay = _asyncTestDelayPtr
.asFunction<void Function(ffi.Pointer<ffi.Char>, int)>();
ffi.Pointer<ffi.Char> getVersionInfo() {
return _getVersionInfo();

View File

@@ -172,13 +172,6 @@ class AppController {
appState.systemColorSchemes = systemColorSchemes;
}
clearCurrentDelay() {
final currentProxyName =
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
if (currentProxyName == null) return;
appState.setDelay(Delay(name: currentProxyName, value: null));
}
savePreferences() async {
await saveConfigPreferences();
await saveClashConfigPreferences();

View File

@@ -2,6 +2,8 @@
enum GroupType { Selector, URLTest, Fallback }
enum GroupName { GLOBAL, Proxy, Auto, Fallback }
extension GroupTypeExtension on GroupType {
static List<String> get valueList => GroupType.values
.map(

View File

@@ -88,12 +88,8 @@ class _NetworkDetectionState extends State<NetworkDetection> {
child: Selector3<AppState, Config, ClashConfig,
NetworkDetectionSelectorState>(
selector: (_, appState, config, clashConfig) {
final proxyName = appState.getCurrentProxyName(
config.currentProxyName,
clashConfig.mode,
);
final proxyName = appState.currentProxyName;
return NetworkDetectionSelectorState(
isInit: appState.isInit,
currentProxyName: proxyName,
delay: appState.getDelay(
proxyName,

View File

@@ -1,5 +1,7 @@
import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@@ -50,9 +52,6 @@ class _StartButtonState extends State<StartButton>
updateSystemProxy() async {
final appController = context.appController;
await appController.updateSystemProxy(isStart);
if (isStart && mounted) {
appController.healthcheck();
}
}
@override
@@ -66,14 +65,17 @@ class _StartButtonState extends State<StartButton>
if (!state.isInit || !state.hasProfile) {
return Container();
}
final textWidth = context.appController.measure.computeTextSize(
Text(
Other.getTimeDifference(
DateTime.now(),
),
style: Theme.of(context).textTheme.titleMedium?.toSoftBold(),
),
).width +
final textWidth = context.appController.measure
.computeTextSize(
Text(
Other.getTimeDifference(
DateTime.now(),
),
style:
Theme.of(context).textTheme.titleMedium?.toSoftBold(),
),
)
.width +
16;
return AnimatedBuilder(
animation: _controller.view,

View File

@@ -1,4 +1,3 @@
import 'package:fl_clash/clash/clash.dart';
import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
import 'package:provider/provider.dart';
@@ -17,8 +16,6 @@ class ProxiesFragment extends StatefulWidget {
class _ProxiesFragmentState extends State<ProxiesFragment>
with TickerProviderStateMixin {
TabController? _tabController;
_initActions() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final commonScaffoldState =
@@ -56,89 +53,6 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
});
}
@override
Widget build(BuildContext context) {
return DelayTestButtonContainer(
child: Selector<AppState, bool>(
selector: (_, appState) => appState.currentLabel == 'proxies',
builder: (_, isCurrent, child) {
if (isCurrent) {
_initActions();
}
return child!;
},
child: Selector3<AppState, Config, ClashConfig, ProxiesSelectorState>(
selector: (_, appState, config, clashConfig) {
final currentGroups = appState.getCurrentGroups(clashConfig.mode);
final groupNames = currentGroups.map((e) => e.name).toList();
final currentProxyName = appState.getCurrentGroupNameWithGroups(
currentGroups,
config.currentGroupName,
clashConfig.mode,
);
final currentIndex = currentGroups
.indexWhere((element) => element.name == currentProxyName);
return ProxiesSelectorState(
currentIndex: currentIndex,
groupNames: groupNames,
);
},
builder: (_, state, __) {
_tabController ??= TabController(
length: state.groupNames.length,
vsync: this,
initialIndex: state.currentIndex,
);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
controller: _tabController,
padding: const EdgeInsets.symmetric(horizontal: 16),
dividerColor: Colors.transparent,
isScrollable: true,
tabAlignment: TabAlignment.start,
overlayColor:
const MaterialStatePropertyAll(Colors.transparent),
tabs: [
for (final groupName in state.groupNames)
Tab(
text: groupName,
),
],
),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
for (final groupName in state.groupNames)
KeepContainer(
key: ObjectKey(groupName),
child: ProxiesTabView(
groupName: groupName,
),
),
],
),
)
],
);
},
),
),
);
}
}
class ProxiesTabView extends StatelessWidget {
final String groupName;
const ProxiesTabView({
super.key,
required this.groupName,
});
List<Proxy> _sortOfName(List<Proxy> proxies) {
return List.of(proxies)
..sort(
@@ -169,7 +83,6 @@ class ProxiesTabView extends StatelessWidget {
}
_getProxies(
BuildContext context,
List<Proxy> proxies,
ProxiesSortType proxiesSortType,
) {
@@ -189,8 +102,7 @@ class ProxiesTabView extends StatelessWidget {
8 * 2;
}
_card(
BuildContext context, {
_card({
required void Function() onPressed,
required bool isSelected,
required Proxy proxy,
@@ -232,12 +144,22 @@ class ProxiesTabView extends StatelessWidget {
),
SizedBox(
height: measure.bodySmallHeight,
child: Text(
proxy.type,
style: context.textTheme.bodySmall?.copyWith(
overflow: TextOverflow.ellipsis,
color: context.textTheme.bodySmall?.color?.toLight(),
child: Selector<AppState, String>(
selector: (context, appState) => appState.getDesc(
proxy.type,
proxy.name,
),
builder: (_, desc, __) {
return TooltipText(
text: Text(
desc,
style: context.textTheme.bodySmall?.copyWith(
overflow: TextOverflow.ellipsis,
color: context.textTheme.bodySmall?.color?.toLight(),
),
),
);
},
),
),
const SizedBox(
@@ -300,42 +222,14 @@ class ProxiesTabView extends StatelessWidget {
itemCount: proxies.length,
itemBuilder: (_, index) {
final proxy = proxies[index];
return Selector3<AppState, Config, ClashConfig,
ProxiesCardSelectorState>(
selector: (_, appState, config, clashConfig) {
final currentGroupName = appState.getCurrentGroupName(
config.currentGroupName,
clashConfig.mode,
);
final currentProxyName = appState.getCurrentProxyName(
config.currentProxyName,
clashConfig.mode,
);
final group = appState.getGroupWithName(groupName);
final isSelected = group.type == GroupType.Selector
? group.name == currentGroupName &&
proxy.name == currentProxyName
: group.now == proxy.name;
return ProxiesCardSelectorState(
isSelected: isSelected,
currentGroupName: currentGroupName,
currentProxyName: currentProxyName,
);
},
builder: (_, state, __) {
return Selector<AppState, bool>(
selector: (_, appState) => proxy.name == appState.currentProxyName,
builder: (_, isSelected, __) {
return _card(
context,
isSelected: state.isSelected,
isSelected: isSelected,
onPressed: () {
final group =
context.appController.appState.getGroupWithName(groupName);
if (group.type == GroupType.Selector) {
final config = context.read<Config>();
config.currentProfile?.groupName = group.name;
config.currentProfile?.proxyName = proxy.name;
config.update();
context.appController.changeProxy();
}
context.appController.config.currentProxyName = proxy.name;
context.appController.changeProxy();
},
proxy: proxy,
);
@@ -347,52 +241,63 @@ class ProxiesTabView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Selector2<AppState, Config, ProxiesTabViewSelectorState>(
selector: (_, appState, config) {
return ProxiesTabViewSelectorState(
proxiesSortType: config.proxiesSortType,
sortNum: appState.sortNum,
group: appState.getGroupWithName(groupName),
);
},
builder: (_, state, __) {
final proxies = _getProxies(
context,
state.group.all,
state.proxiesSortType,
);
return Align(
alignment: Alignment.topCenter,
child: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(
key: const Key('proxies_grid_small'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 2,
),
return DelayTestButtonContainer(
child: Selector<AppState, bool>(
selector: (_, appState) => appState.currentLabel == 'proxies',
builder: (_, isCurrent, child) {
if (isCurrent) {
_initActions();
}
return child!;
},
child: Selector2<AppState, Config, ProxiesSelectorState>(
selector: (_, appState, config) {
return ProxiesSelectorState(
proxiesSortType: config.proxiesSortType,
sortNum: appState.sortNum,
group: appState.currentGroup,
);
},
builder: (_, state, __) {
if (state.group == null) return Container();
final proxies = _getProxies(
state.group!.all,
state.proxiesSortType,
);
return Align(
alignment: Alignment.topCenter,
child: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(
key: const Key('proxies_grid_small'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 2,
),
),
Breakpoints.medium: SlotLayout.from(
key: const Key('proxies_grid_medium'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 3,
),
),
Breakpoints.large: SlotLayout.from(
key: const Key('proxies_grid_large'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 4,
),
),
},
),
Breakpoints.medium: SlotLayout.from(
key: const Key('proxies_grid_medium'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 3,
),
),
Breakpoints.large: SlotLayout.from(
key: const Key('proxies_grid_large'),
builder: (_) => _buildGrid(
context,
proxies: proxies,
columns: 4,
),
),
},
),
);
},
);
},
),
),
);
}
}

View File

@@ -17,7 +17,10 @@ Future<void> main() async {
await window?.init();
final config = await preferences.getConfig() ?? Config();
final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
final appState = AppState();
final appState = AppState(
mode: clashConfig.mode,
currentProxyName: config.currentProxyName,
);
await globalState.init(
appState: appState,
config: config,
@@ -41,7 +44,10 @@ Future<void> vpnService() async {
WidgetsFlutterBinding.ensureInitialized();
final config = await preferences.getConfig() ?? Config();
final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
final appState = AppState();
final appState = AppState(
mode: clashConfig.mode,
currentProxyName: config.currentProxyName,
);
clashMessage.addListener(ClashMessageListenerWithVpn(onTun: (String fd) {
proxyManager.setProtect(
int.parse(fd),

View File

@@ -23,8 +23,10 @@ class AppState with ChangeNotifier {
SystemColorSchemes _systemColorSchemes;
List<Group> _groups;
num _sortNum;
Mode _mode;
String? _currentProxyName;
AppState()
AppState({required Mode mode, required currentProxyName})
: _navigationItems = [],
_delayMap = {},
_isInit = false,
@@ -34,6 +36,8 @@ class AppState with ChangeNotifier {
_groups = [],
_packages = [],
_sortNum = 0,
_mode = mode,
_currentProxyName = currentProxyName,
_systemColorSchemes = SystemColorSchemes();
String get currentLabel => _currentLabel;
@@ -81,6 +85,17 @@ class AppState with ChangeNotifier {
}
}
String getDesc(String type, String? proxyName) {
final groupTypeNamesList = GroupType.values.map((e) => e.name).toList();
if (!groupTypeNamesList.contains(type)) {
return type;
}else{
final index = groups.indexWhere((element) => element.name == proxyName);
if(index == -1) return type;
return "$type(${groups[index].now})";
}
}
int? getDelay(String? proxyName) {
if (proxyName == null) return null;
final index = groups.indexWhere((element) => element.name == proxyName);
@@ -90,6 +105,15 @@ class AppState with ChangeNotifier {
return _delayMap[group.now];
}
String? get realCurrentProxyName {
if (currentProxyName == null) return null;
final index = groups.indexWhere((element) => element.name == currentProxyName);
if (index == -1) return currentProxyName;
final group = groups[index];
if (group.now == null) return null;
return group.now;
}
setDelay(Delay delay) {
if (_delayMap[delay.name] != delay.value) {
_delayMap = Map.from(_delayMap)..[delay.name] = delay.value;
@@ -170,53 +194,48 @@ class AppState with ChangeNotifier {
}
}
List<Group> getCurrentGroups(Mode mode) {
switch (mode) {
case Mode.direct:
return [];
case Mode.global:
return groups
.where((element) => element.name == UsedProxy.GLOBAL.name)
.toList();
case Mode.rule:
return groups
.where((element) => element.name != UsedProxy.GLOBAL.name)
.toList();
Mode get mode => _mode;
set mode(Mode value) {
if (_mode != value) {
_mode = value;
notifyListeners();
}
}
String? getCurrentGroupNameWithGroups(
List<Group> groups,
String? groupName,
Mode mode,
) {
String? get currentProxyName {
if (mode == Mode.direct) return UsedProxy.DIRECT.name;
if (_currentProxyName != null) return _currentProxyName!;
return currentGroup?.now;
}
set currentProxyName(String? value) {
if (_currentProxyName != value) {
_currentProxyName = value;
notifyListeners();
}
}
Group? get currentGroup {
switch (mode) {
case Mode.direct:
return null;
case Mode.global:
return UsedProxy.GLOBAL.name;
return globalGroup;
case Mode.rule:
return groupName ?? (groups.isNotEmpty ? groups.first.name : null);
return ruleGroup;
}
}
String? getCurrentGroupName(String? groupName, Mode mode) {
final currentGroups = getCurrentGroups(mode);
return getCurrentGroupNameWithGroups(currentGroups, groupName, mode);
Group? get globalGroup {
final index =
groups.indexWhere((element) => element.name == GroupName.GLOBAL.name);
return index != -1 ? groups[index] : null;
}
Group getGroupWithName(String groupName) {
return groups.firstWhere((e) => e.name == groupName);
}
String? getCurrentProxyName(String? proxyName, Mode mode) {
final currentGroups = getCurrentGroups(mode);
switch (mode) {
case Mode.direct:
return UsedProxy.DIRECT.name;
case Mode.global || Mode.rule:
return proxyName ??
(currentGroups.isNotEmpty ? currentGroups.first.now : null);
}
Group? get ruleGroup {
final index =
groups.indexWhere((element) => element.name == GroupName.Proxy.name);
return index != -1 ? groups[index] : null;
}
}

View File

@@ -161,7 +161,12 @@ class Config extends ChangeNotifier {
String? get currentProxyName => currentProfile?.proxyName;
String? get currentGroupName => currentProfile?.groupName;
set currentProxyName(String? value){
if (currentProfile?.proxyName != value) {
currentProfile?.proxyName = value;
notifyListeners();
}
}
@JsonKey(defaultValue: false)
bool get autoLaunch {

View File

@@ -27,7 +27,6 @@ Profile _$ProfileFromJson(Map<String, dynamic> json) => Profile(
userInfo: json['userInfo'] == null
? null
: UserInfo.fromJson(json['userInfo'] as Map<String, dynamic>),
groupName: json['groupName'] as String?,
proxyName: json['proxyName'] as String?,
lastUpdateDate: json['lastUpdateDate'] == null
? null
@@ -41,7 +40,6 @@ Profile _$ProfileFromJson(Map<String, dynamic> json) => Profile(
Map<String, dynamic> _$ProfileToJson(Profile instance) => <String, dynamic>{
'id': instance.id,
'label': instance.label,
'groupName': instance.groupName,
'proxyName': instance.proxyName,
'url': instance.url,
'lastUpdateDate': instance.lastUpdateDate?.toIso8601String(),

View File

@@ -349,7 +349,6 @@ abstract class _UpdateCurrentDelaySelectorState
mixin _$NetworkDetectionSelectorState {
String? get currentProxyName => throw _privateConstructorUsedError;
int? get delay => throw _privateConstructorUsedError;
bool get isInit => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$NetworkDetectionSelectorStateCopyWith<NetworkDetectionSelectorState>
@@ -364,7 +363,7 @@ abstract class $NetworkDetectionSelectorStateCopyWith<$Res> {
_$NetworkDetectionSelectorStateCopyWithImpl<$Res,
NetworkDetectionSelectorState>;
@useResult
$Res call({String? currentProxyName, int? delay, bool isInit});
$Res call({String? currentProxyName, int? delay});
}
/// @nodoc
@@ -383,7 +382,6 @@ class _$NetworkDetectionSelectorStateCopyWithImpl<$Res,
$Res call({
Object? currentProxyName = freezed,
Object? delay = freezed,
Object? isInit = null,
}) {
return _then(_value.copyWith(
currentProxyName: freezed == currentProxyName
@@ -394,10 +392,6 @@ class _$NetworkDetectionSelectorStateCopyWithImpl<$Res,
? _value.delay
: delay // ignore: cast_nullable_to_non_nullable
as int?,
isInit: null == isInit
? _value.isInit
: isInit // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}
@@ -411,7 +405,7 @@ abstract class _$$NetworkDetectionSelectorStateImplCopyWith<$Res>
__$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String? currentProxyName, int? delay, bool isInit});
$Res call({String? currentProxyName, int? delay});
}
/// @nodoc
@@ -429,7 +423,6 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
$Res call({
Object? currentProxyName = freezed,
Object? delay = freezed,
Object? isInit = null,
}) {
return _then(_$NetworkDetectionSelectorStateImpl(
currentProxyName: freezed == currentProxyName
@@ -440,10 +433,6 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
? _value.delay
: delay // ignore: cast_nullable_to_non_nullable
as int?,
isInit: null == isInit
? _value.isInit
: isInit // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
@@ -453,20 +442,16 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
class _$NetworkDetectionSelectorStateImpl
implements _NetworkDetectionSelectorState {
const _$NetworkDetectionSelectorStateImpl(
{required this.currentProxyName,
required this.delay,
required this.isInit});
{required this.currentProxyName, required this.delay});
@override
final String? currentProxyName;
@override
final int? delay;
@override
final bool isInit;
@override
String toString() {
return 'NetworkDetectionSelectorState(currentProxyName: $currentProxyName, delay: $delay, isInit: $isInit)';
return 'NetworkDetectionSelectorState(currentProxyName: $currentProxyName, delay: $delay)';
}
@override
@@ -476,12 +461,11 @@ class _$NetworkDetectionSelectorStateImpl
other is _$NetworkDetectionSelectorStateImpl &&
(identical(other.currentProxyName, currentProxyName) ||
other.currentProxyName == currentProxyName) &&
(identical(other.delay, delay) || other.delay == delay) &&
(identical(other.isInit, isInit) || other.isInit == isInit));
(identical(other.delay, delay) || other.delay == delay));
}
@override
int get hashCode => Object.hash(runtimeType, currentProxyName, delay, isInit);
int get hashCode => Object.hash(runtimeType, currentProxyName, delay);
@JsonKey(ignore: true)
@override
@@ -496,16 +480,13 @@ abstract class _NetworkDetectionSelectorState
implements NetworkDetectionSelectorState {
const factory _NetworkDetectionSelectorState(
{required final String? currentProxyName,
required final int? delay,
required final bool isInit}) = _$NetworkDetectionSelectorStateImpl;
required final int? delay}) = _$NetworkDetectionSelectorStateImpl;
@override
String? get currentProxyName;
@override
int? get delay;
@override
bool get isInit;
@override
@JsonKey(ignore: true)
_$$NetworkDetectionSelectorStateImplCopyWith<
_$NetworkDetectionSelectorStateImpl>
@@ -1741,157 +1722,8 @@ abstract class _HomeNavigationSelectorState
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ProxiesSelectorState {
int get currentIndex => throw _privateConstructorUsedError;
List<String> get groupNames => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ProxiesSelectorStateCopyWith<ProxiesSelectorState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProxiesSelectorStateCopyWith<$Res> {
factory $ProxiesSelectorStateCopyWith(ProxiesSelectorState value,
$Res Function(ProxiesSelectorState) then) =
_$ProxiesSelectorStateCopyWithImpl<$Res, ProxiesSelectorState>;
@useResult
$Res call({int currentIndex, List<String> groupNames});
}
/// @nodoc
class _$ProxiesSelectorStateCopyWithImpl<$Res,
$Val extends ProxiesSelectorState>
implements $ProxiesSelectorStateCopyWith<$Res> {
_$ProxiesSelectorStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? currentIndex = null,
Object? groupNames = null,
}) {
return _then(_value.copyWith(
currentIndex: null == currentIndex
? _value.currentIndex
: currentIndex // ignore: cast_nullable_to_non_nullable
as int,
groupNames: null == groupNames
? _value.groupNames
: groupNames // ignore: cast_nullable_to_non_nullable
as List<String>,
) as $Val);
}
}
/// @nodoc
abstract class _$$ProxiesSelectorStateImplCopyWith<$Res>
implements $ProxiesSelectorStateCopyWith<$Res> {
factory _$$ProxiesSelectorStateImplCopyWith(_$ProxiesSelectorStateImpl value,
$Res Function(_$ProxiesSelectorStateImpl) then) =
__$$ProxiesSelectorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({int currentIndex, List<String> groupNames});
}
/// @nodoc
class __$$ProxiesSelectorStateImplCopyWithImpl<$Res>
extends _$ProxiesSelectorStateCopyWithImpl<$Res, _$ProxiesSelectorStateImpl>
implements _$$ProxiesSelectorStateImplCopyWith<$Res> {
__$$ProxiesSelectorStateImplCopyWithImpl(_$ProxiesSelectorStateImpl _value,
$Res Function(_$ProxiesSelectorStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? currentIndex = null,
Object? groupNames = null,
}) {
return _then(_$ProxiesSelectorStateImpl(
currentIndex: null == currentIndex
? _value.currentIndex
: currentIndex // ignore: cast_nullable_to_non_nullable
as int,
groupNames: null == groupNames
? _value._groupNames
: groupNames // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// @nodoc
class _$ProxiesSelectorStateImpl implements _ProxiesSelectorState {
const _$ProxiesSelectorStateImpl(
{required this.currentIndex, required final List<String> groupNames})
: _groupNames = groupNames;
@override
final int currentIndex;
final List<String> _groupNames;
@override
List<String> get groupNames {
if (_groupNames is EqualUnmodifiableListView) return _groupNames;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_groupNames);
}
@override
String toString() {
return 'ProxiesSelectorState(currentIndex: $currentIndex, groupNames: $groupNames)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProxiesSelectorStateImpl &&
(identical(other.currentIndex, currentIndex) ||
other.currentIndex == currentIndex) &&
const DeepCollectionEquality()
.equals(other._groupNames, _groupNames));
}
@override
int get hashCode => Object.hash(runtimeType, currentIndex,
const DeepCollectionEquality().hash(_groupNames));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
get copyWith =>
__$$ProxiesSelectorStateImplCopyWithImpl<_$ProxiesSelectorStateImpl>(
this, _$identity);
}
abstract class _ProxiesSelectorState implements ProxiesSelectorState {
const factory _ProxiesSelectorState(
{required final int currentIndex,
required final List<String> groupNames}) = _$ProxiesSelectorStateImpl;
@override
int get currentIndex;
@override
List<String> get groupNames;
@override
@JsonKey(ignore: true)
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ProxiesCardSelectorState {
String? get currentGroupName => throw _privateConstructorUsedError;
String? get currentProxyName => throw _privateConstructorUsedError;
bool get isSelected => throw _privateConstructorUsedError;
@@ -1906,8 +1738,7 @@ abstract class $ProxiesCardSelectorStateCopyWith<$Res> {
$Res Function(ProxiesCardSelectorState) then) =
_$ProxiesCardSelectorStateCopyWithImpl<$Res, ProxiesCardSelectorState>;
@useResult
$Res call(
{String? currentGroupName, String? currentProxyName, bool isSelected});
$Res call({String? currentProxyName, bool isSelected});
}
/// @nodoc
@@ -1924,15 +1755,10 @@ class _$ProxiesCardSelectorStateCopyWithImpl<$Res,
@pragma('vm:prefer-inline')
@override
$Res call({
Object? currentGroupName = freezed,
Object? currentProxyName = freezed,
Object? isSelected = null,
}) {
return _then(_value.copyWith(
currentGroupName: freezed == currentGroupName
? _value.currentGroupName
: currentGroupName // ignore: cast_nullable_to_non_nullable
as String?,
currentProxyName: freezed == currentProxyName
? _value.currentProxyName
: currentProxyName // ignore: cast_nullable_to_non_nullable
@@ -1954,8 +1780,7 @@ abstract class _$$ProxiesCardSelectorStateImplCopyWith<$Res>
__$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String? currentGroupName, String? currentProxyName, bool isSelected});
$Res call({String? currentProxyName, bool isSelected});
}
/// @nodoc
@@ -1971,15 +1796,10 @@ class __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>
@pragma('vm:prefer-inline')
@override
$Res call({
Object? currentGroupName = freezed,
Object? currentProxyName = freezed,
Object? isSelected = null,
}) {
return _then(_$ProxiesCardSelectorStateImpl(
currentGroupName: freezed == currentGroupName
? _value.currentGroupName
: currentGroupName // ignore: cast_nullable_to_non_nullable
as String?,
currentProxyName: freezed == currentProxyName
? _value.currentProxyName
: currentProxyName // ignore: cast_nullable_to_non_nullable
@@ -1996,12 +1816,8 @@ class __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>
class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
const _$ProxiesCardSelectorStateImpl(
{required this.currentGroupName,
required this.currentProxyName,
required this.isSelected});
{required this.currentProxyName, required this.isSelected});
@override
final String? currentGroupName;
@override
final String? currentProxyName;
@override
@@ -2009,7 +1825,7 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
@override
String toString() {
return 'ProxiesCardSelectorState(currentGroupName: $currentGroupName, currentProxyName: $currentProxyName, isSelected: $isSelected)';
return 'ProxiesCardSelectorState(currentProxyName: $currentProxyName, isSelected: $isSelected)';
}
@override
@@ -2017,8 +1833,6 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProxiesCardSelectorStateImpl &&
(identical(other.currentGroupName, currentGroupName) ||
other.currentGroupName == currentGroupName) &&
(identical(other.currentProxyName, currentProxyName) ||
other.currentProxyName == currentProxyName) &&
(identical(other.isSelected, isSelected) ||
@@ -2026,8 +1840,7 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
}
@override
int get hashCode =>
Object.hash(runtimeType, currentGroupName, currentProxyName, isSelected);
int get hashCode => Object.hash(runtimeType, currentProxyName, isSelected);
@JsonKey(ignore: true)
@override
@@ -2039,12 +1852,9 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState {
const factory _ProxiesCardSelectorState(
{required final String? currentGroupName,
required final String? currentProxyName,
{required final String? currentProxyName,
required final bool isSelected}) = _$ProxiesCardSelectorStateImpl;
@override
String? get currentGroupName;
@override
String? get currentProxyName;
@override
@@ -2056,34 +1866,32 @@ abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState {
}
/// @nodoc
mixin _$ProxiesTabViewSelectorState {
mixin _$ProxiesSelectorState {
ProxiesSortType get proxiesSortType => throw _privateConstructorUsedError;
num get sortNum => throw _privateConstructorUsedError;
Group get group => throw _privateConstructorUsedError;
Group? get group => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ProxiesTabViewSelectorStateCopyWith<ProxiesTabViewSelectorState>
get copyWith => throw _privateConstructorUsedError;
$ProxiesSelectorStateCopyWith<ProxiesSelectorState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProxiesTabViewSelectorStateCopyWith<$Res> {
factory $ProxiesTabViewSelectorStateCopyWith(
ProxiesTabViewSelectorState value,
$Res Function(ProxiesTabViewSelectorState) then) =
_$ProxiesTabViewSelectorStateCopyWithImpl<$Res,
ProxiesTabViewSelectorState>;
abstract class $ProxiesSelectorStateCopyWith<$Res> {
factory $ProxiesSelectorStateCopyWith(ProxiesSelectorState value,
$Res Function(ProxiesSelectorState) then) =
_$ProxiesSelectorStateCopyWithImpl<$Res, ProxiesSelectorState>;
@useResult
$Res call({ProxiesSortType proxiesSortType, num sortNum, Group group});
$Res call({ProxiesSortType proxiesSortType, num sortNum, Group? group});
$GroupCopyWith<$Res> get group;
$GroupCopyWith<$Res>? get group;
}
/// @nodoc
class _$ProxiesTabViewSelectorStateCopyWithImpl<$Res,
$Val extends ProxiesTabViewSelectorState>
implements $ProxiesTabViewSelectorStateCopyWith<$Res> {
_$ProxiesTabViewSelectorStateCopyWithImpl(this._value, this._then);
class _$ProxiesSelectorStateCopyWithImpl<$Res,
$Val extends ProxiesSelectorState>
implements $ProxiesSelectorStateCopyWith<$Res> {
_$ProxiesSelectorStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
@@ -2095,7 +1903,7 @@ class _$ProxiesTabViewSelectorStateCopyWithImpl<$Res,
$Res call({
Object? proxiesSortType = null,
Object? sortNum = null,
Object? group = null,
Object? group = freezed,
}) {
return _then(_value.copyWith(
proxiesSortType: null == proxiesSortType
@@ -2106,45 +1914,46 @@ class _$ProxiesTabViewSelectorStateCopyWithImpl<$Res,
? _value.sortNum
: sortNum // ignore: cast_nullable_to_non_nullable
as num,
group: null == group
group: freezed == group
? _value.group
: group // ignore: cast_nullable_to_non_nullable
as Group,
as Group?,
) as $Val);
}
@override
@pragma('vm:prefer-inline')
$GroupCopyWith<$Res> get group {
return $GroupCopyWith<$Res>(_value.group, (value) {
$GroupCopyWith<$Res>? get group {
if (_value.group == null) {
return null;
}
return $GroupCopyWith<$Res>(_value.group!, (value) {
return _then(_value.copyWith(group: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$ProxiesTabViewSelectorStateImplCopyWith<$Res>
implements $ProxiesTabViewSelectorStateCopyWith<$Res> {
factory _$$ProxiesTabViewSelectorStateImplCopyWith(
_$ProxiesTabViewSelectorStateImpl value,
$Res Function(_$ProxiesTabViewSelectorStateImpl) then) =
__$$ProxiesTabViewSelectorStateImplCopyWithImpl<$Res>;
abstract class _$$ProxiesSelectorStateImplCopyWith<$Res>
implements $ProxiesSelectorStateCopyWith<$Res> {
factory _$$ProxiesSelectorStateImplCopyWith(_$ProxiesSelectorStateImpl value,
$Res Function(_$ProxiesSelectorStateImpl) then) =
__$$ProxiesSelectorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({ProxiesSortType proxiesSortType, num sortNum, Group group});
$Res call({ProxiesSortType proxiesSortType, num sortNum, Group? group});
@override
$GroupCopyWith<$Res> get group;
$GroupCopyWith<$Res>? get group;
}
/// @nodoc
class __$$ProxiesTabViewSelectorStateImplCopyWithImpl<$Res>
extends _$ProxiesTabViewSelectorStateCopyWithImpl<$Res,
_$ProxiesTabViewSelectorStateImpl>
implements _$$ProxiesTabViewSelectorStateImplCopyWith<$Res> {
__$$ProxiesTabViewSelectorStateImplCopyWithImpl(
_$ProxiesTabViewSelectorStateImpl _value,
$Res Function(_$ProxiesTabViewSelectorStateImpl) _then)
class __$$ProxiesSelectorStateImplCopyWithImpl<$Res>
extends _$ProxiesSelectorStateCopyWithImpl<$Res, _$ProxiesSelectorStateImpl>
implements _$$ProxiesSelectorStateImplCopyWith<$Res> {
__$$ProxiesSelectorStateImplCopyWithImpl(_$ProxiesSelectorStateImpl _value,
$Res Function(_$ProxiesSelectorStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@@ -2152,9 +1961,9 @@ class __$$ProxiesTabViewSelectorStateImplCopyWithImpl<$Res>
$Res call({
Object? proxiesSortType = null,
Object? sortNum = null,
Object? group = null,
Object? group = freezed,
}) {
return _then(_$ProxiesTabViewSelectorStateImpl(
return _then(_$ProxiesSelectorStateImpl(
proxiesSortType: null == proxiesSortType
? _value.proxiesSortType
: proxiesSortType // ignore: cast_nullable_to_non_nullable
@@ -2163,19 +1972,18 @@ class __$$ProxiesTabViewSelectorStateImplCopyWithImpl<$Res>
? _value.sortNum
: sortNum // ignore: cast_nullable_to_non_nullable
as num,
group: null == group
group: freezed == group
? _value.group
: group // ignore: cast_nullable_to_non_nullable
as Group,
as Group?,
));
}
}
/// @nodoc
class _$ProxiesTabViewSelectorStateImpl
implements _ProxiesTabViewSelectorState {
const _$ProxiesTabViewSelectorStateImpl(
class _$ProxiesSelectorStateImpl implements _ProxiesSelectorState {
const _$ProxiesSelectorStateImpl(
{required this.proxiesSortType,
required this.sortNum,
required this.group});
@@ -2185,18 +1993,18 @@ class _$ProxiesTabViewSelectorStateImpl
@override
final num sortNum;
@override
final Group group;
final Group? group;
@override
String toString() {
return 'ProxiesTabViewSelectorState(proxiesSortType: $proxiesSortType, sortNum: $sortNum, group: $group)';
return 'ProxiesSelectorState(proxiesSortType: $proxiesSortType, sortNum: $sortNum, group: $group)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProxiesTabViewSelectorStateImpl &&
other is _$ProxiesSelectorStateImpl &&
(identical(other.proxiesSortType, proxiesSortType) ||
other.proxiesSortType == proxiesSortType) &&
(identical(other.sortNum, sortNum) || other.sortNum == sortNum) &&
@@ -2209,26 +2017,26 @@ class _$ProxiesTabViewSelectorStateImpl
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ProxiesTabViewSelectorStateImplCopyWith<_$ProxiesTabViewSelectorStateImpl>
get copyWith => __$$ProxiesTabViewSelectorStateImplCopyWithImpl<
_$ProxiesTabViewSelectorStateImpl>(this, _$identity);
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
get copyWith =>
__$$ProxiesSelectorStateImplCopyWithImpl<_$ProxiesSelectorStateImpl>(
this, _$identity);
}
abstract class _ProxiesTabViewSelectorState
implements ProxiesTabViewSelectorState {
const factory _ProxiesTabViewSelectorState(
abstract class _ProxiesSelectorState implements ProxiesSelectorState {
const factory _ProxiesSelectorState(
{required final ProxiesSortType proxiesSortType,
required final num sortNum,
required final Group group}) = _$ProxiesTabViewSelectorStateImpl;
required final Group? group}) = _$ProxiesSelectorStateImpl;
@override
ProxiesSortType get proxiesSortType;
@override
num get sortNum;
@override
Group get group;
Group? get group;
@override
@JsonKey(ignore: true)
_$$ProxiesTabViewSelectorStateImplCopyWith<_$ProxiesTabViewSelectorStateImpl>
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@@ -62,7 +62,6 @@ class UserInfo {
class Profile {
String id;
String? label;
String? groupName;
String? proxyName;
String? url;
DateTime? lastUpdateDate;
@@ -75,7 +74,6 @@ class Profile {
this.label,
this.url,
this.userInfo,
this.groupName,
this.proxyName,
this.lastUpdateDate,
Duration? autoUpdateDuration,
@@ -158,7 +156,6 @@ class Profile {
runtimeType == other.runtimeType &&
id == other.id &&
label == other.label &&
groupName == other.groupName &&
proxyName == other.proxyName &&
url == other.url &&
lastUpdateDate == other.lastUpdateDate &&
@@ -170,7 +167,6 @@ class Profile {
int get hashCode =>
id.hashCode ^
label.hashCode ^
groupName.hashCode ^
proxyName.hashCode ^
url.hashCode ^
lastUpdateDate.hashCode ^
@@ -180,7 +176,7 @@ class Profile {
@override
String toString() {
return 'Profile{id: $id, label: $label, groupName: $groupName, proxyName: $proxyName, url: $url, lastUpdateDate: $lastUpdateDate, autoUpdateDuration: $autoUpdateDuration, userInfo: $userInfo, autoUpdate: $autoUpdate}';
return 'Profile{id: $id, label: $label, proxyName: $proxyName, url: $url, lastUpdateDate: $lastUpdateDate, autoUpdateDuration: $autoUpdateDuration, userInfo: $userInfo, autoUpdate: $autoUpdate}';
}
Profile copyWith({
@@ -197,7 +193,6 @@ class Profile {
id: id,
label: label ?? this.label,
url: url ?? this.url,
groupName: groupName ?? this.groupName,
proxyName: proxyName ?? this.proxyName,
userInfo: userInfo ?? this.userInfo,
lastUpdateDate: lastUpdateDate ?? this.lastUpdateDate,

View File

@@ -32,7 +32,6 @@ class NetworkDetectionSelectorState with _$NetworkDetectionSelectorState {
const factory NetworkDetectionSelectorState({
required String? currentProxyName,
required int? delay,
required bool isInit,
}) = _NetworkDetectionSelectorState;
}
@@ -103,28 +102,19 @@ class HomeNavigationSelectorState with _$HomeNavigationSelectorState{
}) = _HomeNavigationSelectorState;
}
@freezed
class ProxiesSelectorState with _$ProxiesSelectorState{
const factory ProxiesSelectorState({
required int currentIndex,
required List<String> groupNames,
}) = _ProxiesSelectorState;
}
@freezed
class ProxiesCardSelectorState with _$ProxiesCardSelectorState{
const factory ProxiesCardSelectorState({
required String? currentGroupName,
required String? currentProxyName,
required bool isSelected,
}) = _ProxiesCardSelectorState;
}
@freezed
class ProxiesTabViewSelectorState with _$ProxiesTabViewSelectorState{
const factory ProxiesTabViewSelectorState({
class ProxiesSelectorState with _$ProxiesSelectorState{
const factory ProxiesSelectorState({
required ProxiesSortType proxiesSortType,
required num sortNum,
required Group group,
}) = _ProxiesTabViewSelectorState;
required Group? group,
}) = _ProxiesSelectorState;
}

View File

@@ -14,7 +14,6 @@ import 'common/common.dart';
class GlobalState {
Timer? timer;
Function? updateCurrentDelayDebounce;
Function? updateSortNumDebounce;
PageController? pageController;
final navigatorKey = GlobalKey<NavigatorState>();
@@ -75,18 +74,6 @@ class GlobalState {
stopListenUpdate();
}
void updateCurrentDelay(
String? proxyName,
) {
updateCurrentDelayDebounce ??= debounce<Function(String?)>((proxyName) {
if (proxyName != null) {
clashCore.delay(
proxyName,
);
}
});
updateCurrentDelayDebounce!([proxyName]);
}
applyProfile({
required AppState appState,
@@ -133,29 +120,36 @@ class GlobalState {
required Config config,
required ClashConfig clashConfig,
}) {
final currentGroupName =
appState.getCurrentGroupName(config.currentGroupName, clashConfig.mode);
final currentProxyName =
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
if (config.profiles.isEmpty || currentProxyName == null) {
stopSystemProxy();
return;
}
if (currentGroupName == null) return;
final groupIndex = appState.groups.indexWhere(
(element) => element.name == currentGroupName,
);
if (groupIndex == -1) return;
final proxyIndex = appState.groups[groupIndex].all.indexWhere(
(element) => element.name == currentProxyName,
);
if (proxyIndex == -1) return;
clashCore.changeProxy(
ChangeProxyParams(
groupName: currentGroupName,
proxyName: currentProxyName,
),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (config.profiles.isEmpty) {
stopSystemProxy();
return;
}
final currentProxyName = appState.currentProxyName;
if (currentProxyName == null) return;
final index1 = appState.globalGroup?.all.indexWhere(
(element) => element.name == currentProxyName,
);
if (index1 != null && index1 != -1) {
clashCore.changeProxy(
ChangeProxyParams(
groupName: GroupName.GLOBAL.name,
proxyName: currentProxyName,
),
);
}
final index2 = appState.ruleGroup?.all.indexWhere(
(element) => element.name == currentProxyName,
);
if (index2 != null && index2 != -1) {
clashCore.changeProxy(
ChangeProxyParams(
groupName: GroupName.Proxy.name,
proxyName: currentProxyName,
),
);
}
});
}
updatePackages(AppState appState) async {
@@ -171,11 +165,11 @@ class GlobalState {
required Config config,
required ClashConfig clashConfig,
}) {
final hasGroups = appState.getCurrentGroups(clashConfig.mode).isNotEmpty;
final group = appState.currentGroup;
final hasProfile = config.profiles.isNotEmpty;
appState.navigationItems = navigation.getItems(
openLogs: config.openLogs,
hasProxies: hasGroups && hasProfile,
hasProxies: group != null && hasProfile,
);
}

View File

@@ -23,14 +23,13 @@ class AppStateContainer extends StatelessWidget {
}
_updateNavigationsContainer(Widget child) {
return Selector3<AppState, Config, ClashConfig, UpdateNavigationsSelector>(
selector: (_, appState, config, clashConfig) {
final hasGroups =
appState.getCurrentGroups(clashConfig.mode).isNotEmpty;
return Selector2<AppState, Config, UpdateNavigationsSelector>(
selector: (_, appState, config) {
final group = appState.currentGroup;
final hasProfile = config.profiles.isNotEmpty;
return UpdateNavigationsSelector(
openLogs: config.openLogs,
hasProxies: hasGroups && hasProfile,
hasProxies: group != null && hasProfile,
);
},
builder: (context, state, child) {

View File

@@ -38,13 +38,14 @@ class _ClashMessageContainerState extends State<ClashMessageContainer>
@override
void onDelay(Delay delay) {
final appController = context.appController;
appController.setDelay(delay);
globalState.healthcheckLock = true;
context.appController.setDelay(delay);
WidgetsBinding.instance.addPostFrameCallback((_) {
globalState.updateSortNumDebounce ??= debounce<Function()>(
() {
context.appController.updateGroups();
context.appController.appState.sortNum++;
() async {
await appController.updateGroups();
appController.appState.sortNum++;
globalState.healthcheckLock = false;
},
milliseconds: 5000,
@@ -56,6 +57,7 @@ class _ClashMessageContainerState extends State<ClashMessageContainer>
@override
void onLog(Log log) {
print("$log");
context.appController.appState.addLog(log);
super.onLog(log);
}

View File

@@ -1,7 +1,7 @@
name: fl_clash
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
publish_to: 'none'
version: 0.7.11
version: 0.7.14
environment:
sdk: '>=3.1.0 <4.0.0'