Update ProxyGroup Sort

This commit is contained in:
chen08209
2024-05-03 14:31:10 +08:00
parent 91faed35c0
commit 453c7c98d0
9 changed files with 224 additions and 76 deletions

View File

@@ -21,7 +21,7 @@ import (
"unsafe" "unsafe"
) )
var currentConfig *config.RawConfig var currentConfig = config.DefaultRawConfig()
var isInit = false var isInit = false
@@ -235,6 +235,7 @@ func getProviders() *C.char {
return C.CString(string(data)) return C.CString(string(data))
} }
//export getProvider //export getProvider
func getProvider(name *C.char) *C.char { func getProvider(name *C.char) *C.char {
providerName := C.GoString(name) providerName := C.GoString(name)

View File

@@ -69,43 +69,30 @@ class ClashCore {
1; 1;
} }
List<Group> getProxiesGroups() { Future<List<Group>> getProxiesGroups() {
final proxiesRaw = clashFFI.getProxies(); final proxiesRaw = clashFFI.getProxies();
final proxies = json.decode(proxiesRaw.cast<Utf8>().toDartString()); final proxiesRawString = proxiesRaw.cast<Utf8>().toDartString();
final groupsRaw = List.from(proxies.values).where((e) { return Isolate.run<List<Group>>(() {
final excludeName = !UsedProxyExtension.valueList final proxies = json.decode(proxiesRawString);
.where((element) => element != UsedProxy.GLOBAL.name) final groupsRaw = (proxies[UsedProxy.GLOBAL.name]["all"] as List)
.contains(e['name']); .where((e) {
final validType = GroupTypeExtension.valueList.contains(e['type']); final proxy = proxies[e];
return excludeName && validType; final excludeName = !UsedProxyExtension.valueList
}).map( .where((element) => element != UsedProxy.GLOBAL.name)
(e) { .contains(proxy['name']);
e["all"] = ((e["all"] ?? []) as List) final validType = GroupTypeExtension.valueList.contains(proxy['type']);
return excludeName && validType;
}).map((groupName) {
final group = proxies[groupName];
group["all"] = ((group["all"] ?? []) as List)
.map( .map(
(name) => proxies[name], (name) => proxies[name],
) )
.toList(); .toList();
return e; return group;
}, }).toList();
).toList() return groupsRaw.map((e) => Group.fromJson(e)).toList();
..sort( });
(a, b) {
final aIndex = GroupTypeExtension.getGroupType(a['type'])?.index;
final bIndex = GroupTypeExtension.getGroupType(b['type'])?.index;
if (a == null && b == null) {
return 0;
}
if (a == null) {
return 1;
}
if (b == null) {
return -1;
}
return aIndex! - bIndex!;
},
);
final groups = groupsRaw.map((e) => Group.fromJson(e)).toList();
return groups;
} }
bool changeProxy(ChangeProxyParams changeProxyParams) { bool changeProxy(ChangeProxyParams changeProxyParams) {

View File

@@ -127,7 +127,7 @@ class AppController {
if (value == config.currentProfileId) return; if (value == config.currentProfileId) return;
config.currentProfileId = value; config.currentProfileId = value;
await updateClashConfig(isPatch: false); await updateClashConfig(isPatch: false);
updateGroups(); await updateGroups();
changeProxy(); changeProxy();
appState.delayMap = {}; appState.delayMap = {};
saveConfigPreferences(); saveConfigPreferences();
@@ -144,13 +144,13 @@ class AppController {
if (isNotNeedUpdate == false) continue; if (isNotNeedUpdate == false) continue;
final result = await profile.update(); final result = await profile.update();
if (result.type == ResultType.error) continue; if (result.type == ResultType.error) continue;
updateGroups(); await updateGroups();
changeProxy(); changeProxy();
} }
} }
updateGroups() { Future<void> updateGroups() async {
globalState.updateGroups(appState); await globalState.updateGroups(appState);
} }
updateSystemColorSchemes(SystemColorSchemes systemColorSchemes) { updateSystemColorSchemes(SystemColorSchemes systemColorSchemes) {

View File

@@ -9,8 +9,7 @@ extension GroupTypeExtension on GroupType {
) )
.toList(); .toList();
static GroupType? getGroupType(String? value) { static GroupType? getGroupType(String value) {
if (value == null) return null;
final index = GroupTypeExtension.valueList.indexOf(value); final index = GroupTypeExtension.valueList.indexOf(value);
if (index == -1) return null; if (index == -1) return null;
return GroupType.values[index]; return GroupType.values[index];

View File

@@ -1,4 +1,3 @@
import 'package:collection/collection.dart';
import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/clash/clash.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart'; import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
@@ -57,26 +56,6 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
}); });
} }
_updateTabController(length) {
if (_tabController != null) {
_tabController!.dispose();
_tabController = null;
}
_tabController = TabController(
length: length,
vsync: this,
);
}
@override
void dispose() {
if (_tabController != null) {
_tabController!.dispose();
_tabController = null;
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Selector<AppState, bool>( return Selector<AppState, bool>(
@@ -87,14 +66,32 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
} }
return child!; return child!;
}, },
child: Selector2<AppState, ClashConfig, List<Group>>( child: Selector3<AppState, Config, ClashConfig, ProxiesSelectorState>(
selector: (_, appState, clashConfig) => selector: (_, appState, config, clashConfig) {
appState.getCurrentGroups(clashConfig.mode), final currentGroups = appState.getCurrentGroups(clashConfig.mode);
shouldRebuild: (prev, next) => final currentProxyName = appState.getCurrentGroupNameWithGroups(
!const ListEquality<Group>().equals(prev, next), currentGroups,
builder: (_, groups, __) { config.currentGroupName,
clashConfig.mode,
);
final currentIndex = currentGroups
.indexWhere((element) => element.name == currentProxyName);
return ProxiesSelectorState(
currentIndex: currentIndex != -1 ? currentIndex : 0,
groups: currentGroups,
);
},
builder: (_, state, __) {
if (_tabController != null) {
_tabController!.dispose();
_tabController = null;
}
_tabController = TabController(
length: state.groups.length,
vsync: this,
initialIndex: state.currentIndex,
);
debugPrint("[Proxies] update===>"); debugPrint("[Proxies] update===>");
_updateTabController(groups.length);
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -108,7 +105,7 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
overlayColor: overlayColor:
const MaterialStatePropertyAll(Colors.transparent), const MaterialStatePropertyAll(Colors.transparent),
tabs: [ tabs: [
for (final group in groups) for (final group in state.groups)
Tab( Tab(
text: group.name, text: group.name,
), ),
@@ -118,7 +115,7 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
child: TabBarView( child: TabBarView(
controller: _tabController, controller: _tabController,
children: [ children: [
for (final group in groups) for (final group in state.groups)
KeepContainer( KeepContainer(
child: ProxiesTabView( child: ProxiesTabView(
group: group, group: group,

View File

@@ -165,19 +165,26 @@ class AppState with ChangeNotifier {
} }
} }
String? getCurrentGroupName(String? groupName, Mode mode) { String? getCurrentGroupNameWithGroups(
final currentGroups = getCurrentGroups(mode); List<Group> groups,
String? groupName,
Mode mode,
) {
switch (mode) { switch (mode) {
case Mode.direct: case Mode.direct:
return null; return null;
case Mode.global: case Mode.global:
return UsedProxy.GLOBAL.name; return UsedProxy.GLOBAL.name;
case Mode.rule: case Mode.rule:
return groupName ?? return groupName ?? (groups.isNotEmpty ? groups.first.name : null);
(currentGroups.isNotEmpty ? currentGroups.first.name : null);
} }
} }
String? getCurrentGroupName(String? groupName, Mode mode) {
final currentGroups = getCurrentGroups(mode);
return getCurrentGroupNameWithGroups(currentGroups, groupName, mode);
}
String? getCurrentProxyName(String? proxyName, Mode mode) { String? getCurrentProxyName(String? proxyName, Mode mode) {
final currentGroups = getCurrentGroups(mode); final currentGroups = getCurrentGroups(mode);
switch (mode) { switch (mode) {

View File

@@ -1740,3 +1740,150 @@ abstract class _HomeNavigationSelectorState
_$$HomeNavigationSelectorStateImplCopyWith<_$HomeNavigationSelectorStateImpl> _$$HomeNavigationSelectorStateImplCopyWith<_$HomeNavigationSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError; get copyWith => throw _privateConstructorUsedError;
} }
/// @nodoc
mixin _$ProxiesSelectorState {
int get currentIndex => throw _privateConstructorUsedError;
List<Group> get groups => 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<Group> groups});
}
/// @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? groups = null,
}) {
return _then(_value.copyWith(
currentIndex: null == currentIndex
? _value.currentIndex
: currentIndex // ignore: cast_nullable_to_non_nullable
as int,
groups: null == groups
? _value.groups
: groups // ignore: cast_nullable_to_non_nullable
as List<Group>,
) 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<Group> groups});
}
/// @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? groups = null,
}) {
return _then(_$ProxiesSelectorStateImpl(
currentIndex: null == currentIndex
? _value.currentIndex
: currentIndex // ignore: cast_nullable_to_non_nullable
as int,
groups: null == groups
? _value._groups
: groups // ignore: cast_nullable_to_non_nullable
as List<Group>,
));
}
}
/// @nodoc
class _$ProxiesSelectorStateImpl implements _ProxiesSelectorState {
const _$ProxiesSelectorStateImpl(
{required this.currentIndex, required final List<Group> groups})
: _groups = groups;
@override
final int currentIndex;
final List<Group> _groups;
@override
List<Group> get groups {
if (_groups is EqualUnmodifiableListView) return _groups;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_groups);
}
@override
String toString() {
return 'ProxiesSelectorState(currentIndex: $currentIndex, groups: $groups)';
}
@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._groups, _groups));
}
@override
int get hashCode => Object.hash(
runtimeType, currentIndex, const DeepCollectionEquality().hash(_groups));
@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<Group> groups}) = _$ProxiesSelectorStateImpl;
@override
int get currentIndex;
@override
List<Group> get groups;
@override
@JsonKey(ignore: true)
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@@ -5,6 +5,7 @@ import 'config.dart';
import 'navigation.dart'; import 'navigation.dart';
import 'package.dart'; import 'package.dart';
import 'profile.dart'; import 'profile.dart';
import 'proxy.dart';
part 'generated/selector.freezed.dart'; part 'generated/selector.freezed.dart';
@@ -101,3 +102,12 @@ class HomeNavigationSelectorState with _$HomeNavigationSelectorState{
required String? locale, required String? locale,
}) = _HomeNavigationSelectorState; }) = _HomeNavigationSelectorState;
} }
@freezed
class ProxiesSelectorState with _$ProxiesSelectorState{
const factory ProxiesSelectorState({
required int currentIndex,
required List<Group> groups,
}) = _ProxiesSelectorState;
}

View File

@@ -166,8 +166,8 @@ class GlobalState {
); );
} }
updateGroups(AppState appState) { Future<void> updateGroups(AppState appState) async {
appState.groups = clashCore.getProxiesGroups(); appState.groups = await clashCore.getProxiesGroups();
} }
showMessage({ showMessage({