Fix windows tun issues
Optimize android get system dns Optimize more details
This commit is contained in:
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@@ -75,7 +75,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
cache: true
|
cache: true
|
||||||
flutter-version: 3.29.3
|
# flutter-version: 3.29.3
|
||||||
|
|
||||||
- name: Get Flutter Dependency
|
- name: Get Flutter Dependency
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ fun ConnectivityManager.resolveDns(network: Network?): List<String> {
|
|||||||
fun InetAddress.asSocketAddressText(port: Int): String {
|
fun InetAddress.asSocketAddressText(port: Int): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Inet6Address ->
|
is Inet6Address ->
|
||||||
"[${numericToTextFormat(this.address)}]:$port"
|
"[${numericToTextFormat(this)}]:$port"
|
||||||
|
|
||||||
is Inet4Address ->
|
is Inet4Address ->
|
||||||
"${this.hostAddress}:$port"
|
"${this.hostAddress}:$port"
|
||||||
@@ -141,7 +141,8 @@ fun Context.getActionPendingIntent(action: String): PendingIntent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun numericToTextFormat(src: ByteArray): String {
|
private fun numericToTextFormat(address: Inet6Address): String {
|
||||||
|
val src = address.address
|
||||||
val sb = StringBuilder(39)
|
val sb = StringBuilder(39)
|
||||||
for (i in 0 until 8) {
|
for (i in 0 until 8) {
|
||||||
sb.append(
|
sb.append(
|
||||||
@@ -154,6 +155,10 @@ private fun numericToTextFormat(src: ByteArray): String {
|
|||||||
sb.append(":")
|
sb.append(":")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (address.scopeId > 0) {
|
||||||
|
sb.append("%")
|
||||||
|
sb.append(address.scopeId)
|
||||||
|
}
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun handleStart(options: VpnOptions): Boolean {
|
fun handleStart(options: VpnOptions): Boolean {
|
||||||
|
onUpdateNetwork();
|
||||||
if (options.enable != this.options?.enable) {
|
if (options.enable != this.options?.enable) {
|
||||||
this.flClashService = null
|
this.flClashService = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
@@ -90,37 +91,37 @@ class Request {
|
|||||||
"https://ipinfo.io/json/": IpInfo.fromIpInfoIoJson,
|
"https://ipinfo.io/json/": IpInfo.fromIpInfoIoJson,
|
||||||
};
|
};
|
||||||
|
|
||||||
Future<IpInfo?> checkIp({CancelToken? cancelToken}) async {
|
Future<Result<IpInfo?>> checkIp({CancelToken? cancelToken}) async {
|
||||||
for (final source in _ipInfoSources.entries) {
|
var failureCount = 0;
|
||||||
try {
|
final futures = _ipInfoSources.entries.map((source) async {
|
||||||
final response = await Dio()
|
final Completer<Result<IpInfo?>> completer = Completer();
|
||||||
.get<Map<String, dynamic>>(
|
final future = Dio().get<Map<String, dynamic>>(
|
||||||
source.key,
|
source.key,
|
||||||
cancelToken: cancelToken,
|
cancelToken: cancelToken,
|
||||||
options: Options(
|
options: Options(
|
||||||
responseType: ResponseType.json,
|
responseType: ResponseType.json,
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
.timeout(
|
future.then((res) {
|
||||||
Duration(
|
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||||
seconds: 30,
|
completer.complete(Result.success(source.value(res.data!)));
|
||||||
),
|
} else {
|
||||||
);
|
failureCount++;
|
||||||
if (response.statusCode != 200 || response.data == null) {
|
if (failureCount == _ipInfoSources.length) {
|
||||||
continue;
|
completer.complete(Result.success(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (response.data == null) {
|
}).catchError((e) {
|
||||||
continue;
|
failureCount++;
|
||||||
|
if (e == DioExceptionType.cancel) {
|
||||||
|
completer.complete(Result.error("cancelled"));
|
||||||
}
|
}
|
||||||
return source.value(response.data!);
|
});
|
||||||
} catch (e) {
|
return completer.future;
|
||||||
commonPrint.log("checkIp error ===> $e");
|
});
|
||||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
final res = await Future.any(futures);
|
||||||
throw "cancelled";
|
cancelToken?.cancel();
|
||||||
}
|
return res;
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> pingHelper() async {
|
Future<bool> pingHelper() async {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Future<void> _service(List<String> flags) async {
|
|||||||
vpn?.addListener(
|
vpn?.addListener(
|
||||||
_VpnListenerWithService(
|
_VpnListenerWithService(
|
||||||
onDnsChanged: (String dns) {
|
onDnsChanged: (String dns) {
|
||||||
|
print("handle dns $dns");
|
||||||
clashLibHandler.updateDns(dns);
|
clashLibHandler.updateDns(dns);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class MessageManagerState extends State<MessageManager> {
|
|||||||
key: Key(messages.last.id),
|
key: Key(messages.last.id),
|
||||||
builder: (_, constraints) {
|
builder: (_, constraints) {
|
||||||
return Card(
|
return Card(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedSuperellipseBorder(
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(12.0),
|
Radius.circular(12.0),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -200,6 +200,24 @@ class Tun with _$Tun {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TunExt on Tun {
|
||||||
|
Tun getRealTun(RouteMode routeMode) {
|
||||||
|
final mRouteAddress = routeMode == RouteMode.bypassPrivate
|
||||||
|
? defaultBypassPrivateRouteAddress
|
||||||
|
: routeAddress;
|
||||||
|
return switch (system.isDesktop) {
|
||||||
|
true => copyWith(
|
||||||
|
autoRoute: true,
|
||||||
|
routeAddress: [],
|
||||||
|
),
|
||||||
|
false => copyWith(
|
||||||
|
autoRoute: mRouteAddress.isEmpty ? true : false,
|
||||||
|
routeAddress: mRouteAddress,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class FallbackFilter with _$FallbackFilter {
|
class FallbackFilter with _$FallbackFilter {
|
||||||
const factory FallbackFilter({
|
const factory FallbackFilter({
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ final coreStateProvider = AutoDisposeProvider<CoreState>.internal(
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef CoreStateRef = AutoDisposeProviderRef<CoreState>;
|
typedef CoreStateRef = AutoDisposeProviderRef<CoreState>;
|
||||||
String _$updateParamsHash() => r'79fd7a5a8650fabac3a2ca7ce903c1d9eb363ed2';
|
String _$updateParamsHash() => r'012df72ab0e769a51c573f4692031506d7b1f1b4';
|
||||||
|
|
||||||
/// See also [updateParams].
|
/// See also [updateParams].
|
||||||
@ProviderFor(updateParams)
|
@ProviderFor(updateParams)
|
||||||
@@ -126,7 +126,7 @@ final proxyStateProvider = AutoDisposeProvider<ProxyState>.internal(
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef ProxyStateRef = AutoDisposeProviderRef<ProxyState>;
|
typedef ProxyStateRef = AutoDisposeProviderRef<ProxyState>;
|
||||||
String _$trayStateHash() => r'39ff84c50ad9c9cc666fa2538fe13ec0d7236b2e';
|
String _$trayStateHash() => r'61c99bbae2cb7ed69dc9ee0f2149510eb6a87df4';
|
||||||
|
|
||||||
/// See also [trayState].
|
/// See also [trayState].
|
||||||
@ProviderFor(trayState)
|
@ProviderFor(trayState)
|
||||||
|
|||||||
@@ -105,10 +105,15 @@ CoreState coreState(Ref ref) {
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
UpdateParams updateParams(Ref ref) {
|
UpdateParams updateParams(Ref ref) {
|
||||||
|
final routeMode = ref.watch(
|
||||||
|
networkSettingProvider.select(
|
||||||
|
(state) => state.routeMode,
|
||||||
|
),
|
||||||
|
);
|
||||||
return ref.watch(
|
return ref.watch(
|
||||||
patchClashConfigProvider.select(
|
patchClashConfigProvider.select(
|
||||||
(state) => UpdateParams(
|
(state) => UpdateParams(
|
||||||
tun: state.tun,
|
tun: state.tun.getRealTun(routeMode),
|
||||||
allowLan: state.allowLan,
|
allowLan: state.allowLan,
|
||||||
findProcessMode: state.findProcessMode,
|
findProcessMode: state.findProcessMode,
|
||||||
mode: state.mode,
|
mode: state.mode,
|
||||||
@@ -153,9 +158,11 @@ TrayState trayState(Ref ref) {
|
|||||||
final appSetting = ref.watch(
|
final appSetting = ref.watch(
|
||||||
appSettingProvider,
|
appSettingProvider,
|
||||||
);
|
);
|
||||||
final groups = ref.watch(
|
final groups = ref
|
||||||
groupsProvider,
|
.watch(
|
||||||
);
|
currentGroupsStateProvider,
|
||||||
|
)
|
||||||
|
.value;
|
||||||
final brightness = ref.watch(
|
final brightness = ref.watch(
|
||||||
appBrightnessProvider,
|
appBrightnessProvider,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -315,19 +315,9 @@ class GlobalState {
|
|||||||
final profileId = profile.id;
|
final profileId = profile.id;
|
||||||
final configMap = await getProfileConfig(profileId);
|
final configMap = await getProfileConfig(profileId);
|
||||||
final rawConfig = await handleEvaluate(configMap);
|
final rawConfig = await handleEvaluate(configMap);
|
||||||
final routeAddress =
|
final realPatchConfig = patchConfig.copyWith(
|
||||||
config.networkProps.routeMode == RouteMode.bypassPrivate
|
tun: patchConfig.tun.getRealTun(config.networkProps.routeMode),
|
||||||
? defaultBypassPrivateRouteAddress
|
);
|
||||||
: patchConfig.tun.routeAddress;
|
|
||||||
final realPatchConfig = !system.isDesktop
|
|
||||||
? patchConfig.copyWith.tun(
|
|
||||||
autoRoute: routeAddress.isEmpty ? true : false,
|
|
||||||
routeAddress: routeAddress,
|
|
||||||
)
|
|
||||||
: patchConfig.copyWith.tun(
|
|
||||||
autoRoute: true,
|
|
||||||
routeAddress: [],
|
|
||||||
);
|
|
||||||
rawConfig["external-controller"] = realPatchConfig.externalController.value;
|
rawConfig["external-controller"] = realPatchConfig.externalController.value;
|
||||||
rawConfig["external-ui"] = "";
|
rawConfig["external-ui"] = "";
|
||||||
rawConfig["interface-name"] = "";
|
rawConfig["interface-name"] = "";
|
||||||
@@ -411,21 +401,23 @@ class GlobalState {
|
|||||||
for (final host in realPatchConfig.hosts.entries) {
|
for (final host in realPatchConfig.hosts.entries) {
|
||||||
rawConfig["hosts"][host.key] = host.value.splitByMultipleSeparators;
|
rawConfig["hosts"][host.key] = host.value.splitByMultipleSeparators;
|
||||||
}
|
}
|
||||||
|
if (rawConfig["dns"] == null) {
|
||||||
|
rawConfig["dns"] = {};
|
||||||
|
}
|
||||||
|
final isEnableDns = rawConfig["dns"]["enable"] == true;
|
||||||
final overrideDns = globalState.config.overrideDns;
|
final overrideDns = globalState.config.overrideDns;
|
||||||
if (overrideDns) {
|
if (overrideDns || !isEnableDns) {
|
||||||
rawConfig["dns"] = realPatchConfig.dns.toJson();
|
final dns = switch (!isEnableDns) {
|
||||||
|
true => realPatchConfig.dns.copyWith(
|
||||||
|
nameserver: [...realPatchConfig.dns.nameserver, "system://"]),
|
||||||
|
false => realPatchConfig.dns,
|
||||||
|
};
|
||||||
|
rawConfig["dns"] = dns.toJson();
|
||||||
rawConfig["dns"]["nameserver-policy"] = {};
|
rawConfig["dns"]["nameserver-policy"] = {};
|
||||||
for (final entry in realPatchConfig.dns.nameserverPolicy.entries) {
|
for (final entry in dns.nameserverPolicy.entries) {
|
||||||
rawConfig["dns"]["nameserver-policy"][entry.key] =
|
rawConfig["dns"]["nameserver-policy"][entry.key] =
|
||||||
entry.value.splitByMultipleSeparators;
|
entry.value.splitByMultipleSeparators;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (rawConfig["dns"] == null) {
|
|
||||||
rawConfig["dns"] = {};
|
|
||||||
}
|
|
||||||
if (rawConfig["dns"]["enable"] != false) {
|
|
||||||
rawConfig["dns"]["enable"] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var rules = [];
|
var rules = [];
|
||||||
if (rawConfig["rules"] != null) {
|
if (rawConfig["rules"] != null) {
|
||||||
@@ -509,6 +501,9 @@ class DetectionState {
|
|||||||
debouncer.call(
|
debouncer.call(
|
||||||
FunctionTag.checkIp,
|
FunctionTag.checkIp,
|
||||||
_checkIp,
|
_checkIp,
|
||||||
|
duration: Duration(
|
||||||
|
milliseconds: 1200,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,36 +528,35 @@ class DetectionState {
|
|||||||
cancelToken = null;
|
cancelToken = null;
|
||||||
}
|
}
|
||||||
cancelToken = CancelToken();
|
cancelToken = CancelToken();
|
||||||
try {
|
state.value = state.value.copyWith(
|
||||||
|
isTesting: true,
|
||||||
|
);
|
||||||
|
final res = await request.checkIp(cancelToken: cancelToken);
|
||||||
|
if (res.isError) {
|
||||||
state.value = state.value.copyWith(
|
state.value = state.value.copyWith(
|
||||||
isTesting: true,
|
isLoading: true,
|
||||||
|
ipInfo: null,
|
||||||
);
|
);
|
||||||
final ipInfo = await request.checkIp(cancelToken: cancelToken);
|
return;
|
||||||
state.value = state.value.copyWith(
|
|
||||||
isTesting: false,
|
|
||||||
);
|
|
||||||
if (ipInfo != null) {
|
|
||||||
state.value = state.value.copyWith(
|
|
||||||
isLoading: false,
|
|
||||||
ipInfo: ipInfo,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_clearSetTimeoutTimer();
|
|
||||||
_setTimeoutTimer = Timer(const Duration(milliseconds: 300), () {
|
|
||||||
state.value = state.value.copyWith(
|
|
||||||
isLoading: false,
|
|
||||||
ipInfo: null,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (e.toString() == "cancelled") {
|
|
||||||
state.value = state.value.copyWith(
|
|
||||||
isLoading: true,
|
|
||||||
ipInfo: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
final ipInfo = res.data;
|
||||||
|
state.value = state.value.copyWith(
|
||||||
|
isTesting: false,
|
||||||
|
);
|
||||||
|
if (ipInfo != null) {
|
||||||
|
state.value = state.value.copyWith(
|
||||||
|
isLoading: false,
|
||||||
|
ipInfo: ipInfo,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_clearSetTimeoutTimer();
|
||||||
|
_setTimeoutTimer = Timer(const Duration(milliseconds: 300), () {
|
||||||
|
state.value = state.value.copyWith(
|
||||||
|
isLoading: false,
|
||||||
|
ipInfo: null,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearSetTimeoutTimer() {
|
_clearSetTimeoutTimer() {
|
||||||
|
|||||||
@@ -135,10 +135,12 @@ class TrafficUsage extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 8,
|
height: 8,
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: primaryColor,
|
color: primaryColor,
|
||||||
borderRadius:
|
shape: RoundedSuperellipseBorder(
|
||||||
BorderRadius.circular(2),
|
borderRadius:
|
||||||
|
BorderRadius.circular(3),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -161,10 +163,12 @@ class TrafficUsage extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 8,
|
height: 8,
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: secondaryColor,
|
color: secondaryColor,
|
||||||
borderRadius:
|
shape: RoundedSuperellipseBorder(
|
||||||
BorderRadius.circular(2),
|
borderRadius:
|
||||||
|
BorderRadius.circular(3),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
|||||||
@@ -418,9 +418,11 @@ class _ListHeaderState extends State<ListHeader> {
|
|||||||
width: constraints.maxWidth,
|
width: constraints.maxWidth,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: EdgeInsets.all(6.ap),
|
padding: EdgeInsets.all(6.ap),
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
|
shape: RoundedSuperellipseBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
color: context.colorScheme.secondaryContainer,
|
color: context.colorScheme.secondaryContainer,
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
),
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: CommonTargetIcon(
|
child: CommonTargetIcon(
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class CommonCard extends StatelessWidget {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
|
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
|
||||||
shape: WidgetStatePropertyAll(
|
shape: WidgetStatePropertyAll(
|
||||||
RoundedRectangleBorder(
|
RoundedSuperellipseBorder(
|
||||||
borderRadius: BorderRadius.circular(radius),
|
borderRadius: BorderRadius.circular(radius),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:fl_clash/providers/providers.dart';
|
import 'package:fl_clash/providers/providers.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'card.dart';
|
import 'card.dart';
|
||||||
import 'grid.dart';
|
import 'grid.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ class CommonPopupMenu extends StatelessWidget {
|
|||||||
elevation: 12,
|
elevation: 12,
|
||||||
color: context.colorScheme.surfaceContainer,
|
color: context.colorScheme.surfaceContainer,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedSuperellipseBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -148,9 +148,11 @@ class _AdaptiveSheetScaffoldState extends State<AdaptiveSheetScaffold> {
|
|||||||
final handleSize = Size(32, 4);
|
final handleSize = Size(32, 4);
|
||||||
return Container(
|
return Container(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28.0)),
|
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
|
shape: RoundedSuperellipseBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(28.0)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -161,8 +163,10 @@ class _AdaptiveSheetScaffoldState extends State<AdaptiveSheetScaffold> {
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
height: handleSize.height,
|
height: handleSize.height,
|
||||||
width: handleSize.width,
|
width: handleSize.width,
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
borderRadius: BorderRadius.circular(handleSize.height / 2),
|
shape: RoundedSuperellipseBorder(
|
||||||
|
borderRadius: BorderRadius.circular(handleSize.height / 2),
|
||||||
|
),
|
||||||
color: context.colorScheme.onSurfaceVariant,
|
color: context.colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class _SideSheetState extends State<SideSheet> {
|
|||||||
final Color shadowColor = widget.shadowColor ?? Colors.transparent;
|
final Color shadowColor = widget.shadowColor ?? Colors.transparent;
|
||||||
final double elevation = widget.elevation ?? 0;
|
final double elevation = widget.elevation ?? 0;
|
||||||
final ShapeBorder shape = widget.shape ??
|
final ShapeBorder shape = widget.shape ??
|
||||||
RoundedRectangleBorder(
|
RoundedSuperellipseBorder(
|
||||||
borderRadius: BorderRadius.circular(0),
|
borderRadius: BorderRadius.circular(0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -373,8 +373,10 @@ class _CommonTabBarState<T extends Object> extends State<CommonTabBar<T>>
|
|||||||
child: Container(
|
child: Container(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
padding: widget.padding.resolve(Directionality.of(context)),
|
padding: widget.padding.resolve(Directionality.of(context)),
|
||||||
decoration: BoxDecoration(
|
decoration: ShapeDecoration(
|
||||||
borderRadius: const BorderRadius.all(_kCornerRadius),
|
shape: RoundedSuperellipseBorder(
|
||||||
|
borderRadius: const BorderRadius.all(_kCornerRadius),
|
||||||
|
),
|
||||||
color: widget.backgroundColor,
|
color: widget.backgroundColor,
|
||||||
),
|
),
|
||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
|
|||||||
29
pubspec.lock
29
pubspec.lock
@@ -85,10 +85,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.12.0"
|
version: "2.13.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -373,10 +373,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.3"
|
||||||
ffi:
|
ffi:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -706,10 +706,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: intl
|
name: intl
|
||||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.19.0"
|
version: "0.20.2"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -770,10 +770,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.8"
|
version: "10.0.9"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1024,10 +1024,11 @@ packages:
|
|||||||
re_editor:
|
re_editor:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: re_editor
|
path: "."
|
||||||
sha256: "17e430f0591dd361992ec2dd6f69191c1853fa46e05432e095310a8f82ee820e"
|
ref: main
|
||||||
url: "https://pub.dev"
|
resolved-ref: "7cda330fc33d5ef9e00333048b70ce65a5f5d550"
|
||||||
source: hosted
|
url: "https://github.com/chen08209/re-editor.git"
|
||||||
|
source: git
|
||||||
version: "0.7.0"
|
version: "0.7.0"
|
||||||
re_highlight:
|
re_highlight:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
@@ -1494,10 +1495,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.3.1"
|
version: "15.0.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: fl_clash
|
name: fl_clash
|
||||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 0.8.85+202506071
|
version: 0.8.86+2025061501
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.1.0 <4.0.0'
|
sdk: '>=3.1.0 <4.0.0'
|
||||||
|
|
||||||
@@ -37,7 +37,10 @@ dependencies:
|
|||||||
dio: ^5.8.0+1
|
dio: ^5.8.0+1
|
||||||
win32: ^5.5.1
|
win32: ^5.5.1
|
||||||
ffi: ^2.1.2
|
ffi: ^2.1.2
|
||||||
re_editor: ^0.7.0
|
re_editor:
|
||||||
|
git:
|
||||||
|
url: https://github.com/chen08209/re-editor.git
|
||||||
|
ref: main
|
||||||
re_highlight: ^0.0.3
|
re_highlight: ^0.0.3
|
||||||
archive: ^3.6.1
|
archive: ^3.6.1
|
||||||
lpinyin: ^2.0.3
|
lpinyin: ^2.0.3
|
||||||
|
|||||||
Reference in New Issue
Block a user