Skip to content

Commit

Permalink
Add windows storage corruption detection
Browse files Browse the repository at this point in the history
Fix core crash caused by windows resource manager restart

Optimize logs, requests, access to pages

Fix macos bypass domain issues
  • Loading branch information
chen08209 committed Feb 9, 2025
1 parent 6c27f2e commit c6266b7
Show file tree
Hide file tree
Showing 65 changed files with 3,070 additions and 3,571 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ data class Package(
val packageName: String,
val label: String,
val isSystem: Boolean,
val firstInstallTime: Long,
val lastUpdateTime: Long,
)
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -302,7 +301,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
packageName = it.packageName,
label = it.applicationInfo.loadLabel(packageManager).toString(),
isSystem = (it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 1,
firstInstallTime = it.firstInstallTime
lastUpdateTime = it.lastUpdateTime
)
}?.let { packages.addAll(it) }
return packages
Expand Down
4 changes: 2 additions & 2 deletions lib/clash/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ClashCore {
}

static Future<void> initGeo() async {
final homePath = await appPath.getHomeDirPath();
final homePath = await appPath.homeDirPath;
final homeDir = Directory(homePath);
final isExists = await homeDir.exists();
if (!isExists) {
Expand Down Expand Up @@ -68,7 +68,7 @@ class ClashCore {
required Config config,
}) async {
await initGeo();
final homeDirPath = await appPath.getHomeDirPath();
final homeDirPath = await appPath.homeDirPath;
return await clashInterface.init(homeDirPath);
}

Expand Down
7 changes: 4 additions & 3 deletions lib/clash/interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,9 @@ abstract class ClashHandlerInterface with ClashInterface {
@override
Future<String> updateGeoData(UpdateGeoDataParams params) {
return invoke<String>(
method: ActionMethod.updateGeoData,
data: json.encode(params),
);
method: ActionMethod.updateGeoData,
data: json.encode(params),
timeout: Duration(minutes: 1));
}

@override
Expand All @@ -292,6 +292,7 @@ abstract class ClashHandlerInterface with ClashInterface {
return invoke<String>(
method: ActionMethod.updateExternalProvider,
data: providerName,
timeout: Duration(minutes: 1),
);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/common/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ export 'text.dart';
export 'tray.dart';
export 'window.dart';
export 'windows.dart';
export 'render.dart';
export 'render.dart';
export 'view.dart';
19 changes: 19 additions & 0 deletions lib/common/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,23 @@ extension BuildContextExtension on BuildContext {
ColorScheme get colorScheme => Theme.of(this).colorScheme;

TextTheme get textTheme => Theme.of(this).textTheme;

T? findLastStateOfType<T extends State>() {
T? state;

visitor(Element element) {
if(!element.mounted){
return;
}
if(element is StatefulElement){
if (element.state is T) {
state = element.state as T;
}
}
element.visitChildren(visitor);
}

visitor(this as Element);
return state;
}
}
46 changes: 41 additions & 5 deletions lib/common/function.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import 'dart:async';

class Debouncer {
Map<dynamic, Timer> operators = {};
final Map<dynamic, Timer> _operations = {};

call(
dynamic tag,
Function func, {
List<dynamic>? args,
Duration duration = const Duration(milliseconds: 600),
}) {
final timer = operators[tag];
final timer = _operations[tag];
if (timer != null) {
timer.cancel();
}
operators[tag] = Timer(
_operations[tag] = Timer(
duration,
() {
operators.remove(tag);
_operations[tag]?.cancel();
_operations.remove(tag);
Function.apply(
func,
args,
Expand All @@ -26,8 +27,43 @@ class Debouncer {
}

cancel(dynamic tag) {
operators[tag]?.cancel();
_operations[tag]?.cancel();
}
}

class Throttler {
final Map<dynamic, Timer> _operations = {};

call(
String tag,
Function func, {
List<dynamic>? args,
Duration duration = const Duration(milliseconds: 600),
}) {
final timer = _operations[tag];
if (timer != null) {
return true;
}
_operations[tag] = Timer(
duration,
() {
_operations[tag]?.cancel();
_operations.remove(tag);
Function.apply(
func,
args,
);
},
);
return false;
}

cancel(dynamic tag) {
_operations[tag]?.cancel();
}
}


final debouncer = Debouncer();

final throttler = Throttler();
56 changes: 54 additions & 2 deletions lib/common/list.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
import 'dart:collection';

class FixedList<T> {
final int maxLength;
final List<T> _list = [];

FixedList(this.maxLength);

add(T item) {
if (_list.length == maxLength) {
_list.removeAt(0);
}
_list.add(item);
}

List<T> get list => List.unmodifiable(_list);

int get length => _list.length;

T operator [](int index) => _list[index];
}

class FixedMap<K, V> {
final int maxSize;
final Map<K, V> _map = {};
final Queue<K> _queue = Queue<K>();

FixedMap(this.maxSize);

put(K key, V value) {
if (_map.length == maxSize) {
final oldestKey = _queue.removeFirst();
_map.remove(oldestKey);
}
_map[key] = value;
_queue.add(key);
}

clear(){
_map.clear();
_queue.clear();
}

V? get(K key) => _map[key];

bool containsKey(K key) => _map.containsKey(key);

int get length => _map.length;

Map<K, V> get map => Map.unmodifiable(_map);
}

extension ListExtension<T> on List<T> {
List<T> intersection(List<T> list) {
return where((item) => list.contains(item)).toList();
Expand All @@ -17,8 +69,8 @@ extension ListExtension<T> on List<T> {
}

List<T> safeSublist(int start) {
if(start <= 0) return this;
if(start > length) return [];
if (start <= 0) return this;
if (start > length) return [];
return sublist(start);
}
}
2 changes: 1 addition & 1 deletion lib/common/lock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SingleInstanceLock {

Future<bool> acquire() async {
try {
final lockFilePath = await appPath.getLockFilePath();
final lockFilePath = await appPath.lockFilePath;
final lockFile = File(lockFilePath);
await lockFile.create();
_accessFile = await lockFile.open(mode: FileMode.write);
Expand Down
9 changes: 7 additions & 2 deletions lib/common/measure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ class Measure {
WidgetsBinding.instance.platformDispatcher.textScaleFactor,
);

Size computeTextSize(Text text) {
Size computeTextSize(
Text text, {
double maxWidth = double.infinity,
}) {
final textPainter = TextPainter(
text: TextSpan(text: text.data, style: text.style),
maxLines: text.maxLines,
textScaler: _textScale,
textDirection: text.textDirection ?? TextDirection.ltr,
)..layout();
)..layout(
maxWidth: maxWidth,
);
return textPainter.size;
}

Expand Down
10 changes: 5 additions & 5 deletions lib/common/navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ class Navigation {
fragment: ProfilesFragment(),
),
const NavigationItem(
icon: Icon(Icons.view_timeline),
icon: Icon(Icons.view_timeline),
label: "requests",
fragment: RequestsFragment(),
fragment: RequestsFragment(),
description: "requestsDesc",
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
),
const NavigationItem(
icon: Icon(Icons.ballot),
icon: Icon(Icons.ballot),
label: "connections",
fragment: ConnectionsFragment(),
fragment: ConnectionsFragment(),
description: "connectionsDesc",
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
),
Expand All @@ -49,7 +49,7 @@ class Navigation {
description: "resourcesDesc",
keep: false,
fragment: Resources(),
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
modes: [NavigationItemMode.more],
),
NavigationItem(
icon: const Icon(Icons.adb),
Expand Down
48 changes: 20 additions & 28 deletions lib/common/other.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'package:lpinyin/lpinyin.dart';
import 'package:zxing2/qrcode.dart';

class Other {
Color? getDelayColor(int? delay) {
Expand All @@ -34,6 +30,26 @@ class Other {
);
}

String generateRandomString({int minLength = 10, int maxLength = 100}) {
const latinChars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
final random = Random();

int length = minLength + random.nextInt(maxLength - minLength + 1);

String result = '';
for (int i = 0; i < length; i++) {
if (random.nextBool()) {
result +=
String.fromCharCode(0x4E00 + random.nextInt(0x9FA5 - 0x4E00 + 1));
} else {
result += latinChars[random.nextInt(latinChars.length)];
}
}

return result;
}

String get uuidV4 {
final Random random = Random();
final bytes = List.generate(16, (_) => random.nextInt(256));
Expand Down Expand Up @@ -165,30 +181,6 @@ class Other {
: "";
}

Future<String?> parseQRCode(Uint8List? bytes) {
return Isolate.run<String?>(() {
if (bytes == null) return null;
img.Image? image = img.decodeImage(bytes);
LuminanceSource source = RGBLuminanceSource(
image!.width,
image.height,
image
.convert(numChannels: 4)
.getBytes(order: img.ChannelOrder.abgr)
.buffer
.asInt32List(),
);
final bitmap = BinaryBitmap(GlobalHistogramBinarizer(source));
final reader = QRCodeReader();
try {
final result = reader.decode(bitmap);
return result.text;
} catch (_) {
return null;
}
});
}

String? getFileNameForDisposition(String? disposition) {
if (disposition == null) return null;
final parseValue = HeaderValue.parse(disposition);
Expand Down
Loading

0 comments on commit c6266b7

Please sign in to comment.