Compare commits
5 Commits
v0.8.83-pr
...
v0.8.84
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76c9f08d4a | ||
|
|
f83a8e0cce | ||
|
|
f5544f1af7 | ||
|
|
eeb543780a | ||
|
|
676f2d058a |
40
CHANGELOG.md
40
CHANGELOG.md
@@ -1,3 +1,43 @@
|
||||
## v0.8.84
|
||||
|
||||
- Fix windows service verify issues
|
||||
|
||||
- Update changelog
|
||||
|
||||
## v0.8.83
|
||||
|
||||
- Add windows server mode start process verify
|
||||
|
||||
- Add linux deb dependencies
|
||||
|
||||
- Add backup recovery strategy select
|
||||
|
||||
- Support custom text scaling
|
||||
|
||||
- Optimize the display of different text scale
|
||||
|
||||
- Optimize windows setup experience
|
||||
|
||||
- Optimize startTun performance
|
||||
|
||||
- Optimize android tv experience
|
||||
|
||||
- Optimize default option
|
||||
|
||||
- Optimize computed text size
|
||||
|
||||
- Optimize hyperOS freeform window
|
||||
|
||||
- Add developer mode
|
||||
|
||||
- Update core
|
||||
|
||||
- Optimize more details
|
||||
|
||||
- Add issues template
|
||||
|
||||
- Update changelog
|
||||
|
||||
## v0.8.82
|
||||
|
||||
- Optimize android vpn performance
|
||||
|
||||
Submodule core/Clash.Meta updated: 88a1848dfb...6eac0e5d3d
@@ -12,7 +12,7 @@ export 'iterable.dart';
|
||||
export 'keyboard.dart';
|
||||
export 'launch.dart';
|
||||
export 'link.dart';
|
||||
export 'list.dart';
|
||||
export 'fixed.dart';
|
||||
export 'lock.dart';
|
||||
export 'measure.dart';
|
||||
export 'navigation.dart';
|
||||
|
||||
@@ -76,22 +76,24 @@ const viewModeColumnsMap = {
|
||||
ViewMode.desktop: [4, 3],
|
||||
};
|
||||
|
||||
const defaultPrimaryColor = 0xFF795548;
|
||||
const defaultPrimaryColor = 0XFFD8C0C3;
|
||||
|
||||
double getWidgetHeight(num lines) {
|
||||
return max(lines * 84 + (lines - 1) * 16, 0).ap;
|
||||
}
|
||||
|
||||
const maxLength = 150;
|
||||
|
||||
final mainIsolate = "FlClashMainIsolate";
|
||||
|
||||
final serviceIsolate = "FlClashServiceIsolate";
|
||||
|
||||
const defaultPrimaryColors = [
|
||||
defaultPrimaryColor,
|
||||
0xFF795548,
|
||||
0xFF03A9F4,
|
||||
0xFFFFFF00,
|
||||
0XFFBBC9CC,
|
||||
0XFFABD397,
|
||||
0XFFD8C0C3,
|
||||
defaultPrimaryColor,
|
||||
0XFF665390,
|
||||
];
|
||||
|
||||
79
lib/common/fixed.dart
Normal file
79
lib/common/fixed.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'iterable.dart';
|
||||
|
||||
class FixedList<T> {
|
||||
final int maxLength;
|
||||
final List<T> _list;
|
||||
|
||||
FixedList(this.maxLength, {List<T>? list})
|
||||
: _list = (list ?? [])..truncate(maxLength);
|
||||
|
||||
add(T item) {
|
||||
_list.add(item);
|
||||
_list.truncate(maxLength);
|
||||
}
|
||||
|
||||
clear() {
|
||||
_list.clear();
|
||||
}
|
||||
|
||||
List<T> get list => List.unmodifiable(_list);
|
||||
|
||||
int get length => _list.length;
|
||||
|
||||
T operator [](int index) => _list[index];
|
||||
|
||||
FixedList<T> copyWith() {
|
||||
return FixedList(
|
||||
maxLength,
|
||||
list: _list,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FixedMap<K, V> {
|
||||
int maxLength;
|
||||
late Map<K, V> _map;
|
||||
|
||||
FixedMap(this.maxLength, {Map<K, V>? map}) {
|
||||
_map = map ?? {};
|
||||
}
|
||||
|
||||
updateCacheValue(K key, V Function() callback) {
|
||||
final realValue = _map.updateCacheValue(
|
||||
key,
|
||||
callback,
|
||||
);
|
||||
_adjustMap();
|
||||
return realValue;
|
||||
}
|
||||
|
||||
clear() {
|
||||
_map.clear();
|
||||
}
|
||||
|
||||
updateMaxLength(int size) {
|
||||
maxLength = size;
|
||||
_adjustMap();
|
||||
}
|
||||
|
||||
updateMap(Map<K, V> map) {
|
||||
_map = map;
|
||||
_adjustMap();
|
||||
}
|
||||
|
||||
_adjustMap() {
|
||||
if (_map.length > maxLength) {
|
||||
_map = Map.fromEntries(
|
||||
map.entries.toList()..truncate(maxLength),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -38,6 +38,43 @@ extension IterableExt<T> on Iterable<T> {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<T> takeLast({int count = 50}) {
|
||||
if (count <= 0) return Iterable.empty();
|
||||
return count >= length ? this : toList().skip(length - count);
|
||||
}
|
||||
}
|
||||
|
||||
extension ListExt<T> on List<T> {
|
||||
void truncate(int maxLength) {
|
||||
assert(maxLength > 0);
|
||||
if (length > maxLength) {
|
||||
removeRange(0, length - maxLength);
|
||||
}
|
||||
}
|
||||
|
||||
List<T> intersection(List<T> list) {
|
||||
return where((item) => list.contains(item)).toList();
|
||||
}
|
||||
|
||||
List<List<T>> batch(int maxConcurrent) {
|
||||
final batches = (length / maxConcurrent).ceil();
|
||||
final List<List<T>> res = [];
|
||||
for (int i = 0; i < batches; i++) {
|
||||
if (i != batches - 1) {
|
||||
res.add(sublist(i * maxConcurrent, maxConcurrent * (i + 1)));
|
||||
} else {
|
||||
res.add(sublist(i * maxConcurrent, length));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
List<T> safeSublist(int start) {
|
||||
if (start <= 0) return this;
|
||||
if (start > length) return [];
|
||||
return sublist(start);
|
||||
}
|
||||
}
|
||||
|
||||
extension DoubleListExt on List<double> {
|
||||
@@ -67,9 +104,9 @@ extension DoubleListExt on List<double> {
|
||||
}
|
||||
|
||||
extension MapExt<K, V> on Map<K, V> {
|
||||
getCacheValue(K key, V defaultValue) {
|
||||
updateCacheValue(K key, V Function() callback) {
|
||||
if (this[key] == null) {
|
||||
this[key] = defaultValue;
|
||||
this[key] = callback();
|
||||
}
|
||||
return this[key];
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import 'dart:collection';
|
||||
|
||||
class FixedList<T> {
|
||||
final int maxLength;
|
||||
final List<T> _list;
|
||||
|
||||
FixedList(this.maxLength, {List<T>? list}) : _list = list ?? [];
|
||||
|
||||
add(T item) {
|
||||
if (_list.length == maxLength) {
|
||||
_list.removeAt(0);
|
||||
}
|
||||
_list.add(item);
|
||||
}
|
||||
|
||||
clear() {
|
||||
_list.clear();
|
||||
}
|
||||
|
||||
List<T> get list => List.unmodifiable(_list);
|
||||
|
||||
int get length => _list.length;
|
||||
|
||||
T operator [](int index) => _list[index];
|
||||
|
||||
FixedList<T> copyWith() {
|
||||
return FixedList(
|
||||
maxLength,
|
||||
list: _list,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FixedMap<K, V> {
|
||||
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);
|
||||
return value;
|
||||
}
|
||||
|
||||
clear() {
|
||||
_map.clear();
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
updateMaxSize(int size){
|
||||
maxSize = size;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
List<List<T>> batch(int maxConcurrent) {
|
||||
final batches = (length / maxConcurrent).ceil();
|
||||
final List<List<T>> res = [];
|
||||
for (int i = 0; i < batches; i++) {
|
||||
if (i != batches - 1) {
|
||||
res.add(sublist(i * maxConcurrent, maxConcurrent * (i + 1)));
|
||||
} else {
|
||||
res.add(sublist(i * maxConcurrent, length));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
List<T> safeSublist(int start) {
|
||||
if (start <= 0) return this;
|
||||
if (start > length) return [];
|
||||
return sublist(start);
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get bodyMediumHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"bodyMediumHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.bodyMedium,
|
||||
@@ -44,9 +44,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get bodyLargeHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"bodyLargeHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.bodyLarge,
|
||||
@@ -56,9 +56,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get bodySmallHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"bodySmallHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.bodySmall,
|
||||
@@ -68,9 +68,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get labelSmallHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"labelSmallHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.labelSmall,
|
||||
@@ -80,9 +80,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get labelMediumHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"labelMediumHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.labelMedium,
|
||||
@@ -92,9 +92,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get titleLargeHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"titleLargeHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.titleLarge,
|
||||
@@ -104,9 +104,9 @@ class Measure {
|
||||
}
|
||||
|
||||
double get titleMediumHeight {
|
||||
return _measureMap.getCacheValue(
|
||||
return _measureMap.updateCacheValue(
|
||||
"titleMediumHeight",
|
||||
computeTextSize(
|
||||
() => computeTextSize(
|
||||
Text(
|
||||
"X",
|
||||
style: context.textTheme.titleMedium,
|
||||
|
||||
@@ -14,7 +14,6 @@ class Navigation {
|
||||
const NavigationItem(
|
||||
icon: Icon(Icons.space_dashboard),
|
||||
label: PageLabel.dashboard,
|
||||
keep: false,
|
||||
fragment: DashboardFragment(
|
||||
key: GlobalObjectKey(PageLabel.dashboard),
|
||||
),
|
||||
|
||||
@@ -12,32 +12,35 @@ class CommonTheme {
|
||||
) : _colorMap = {};
|
||||
|
||||
Color get darkenSecondaryContainer {
|
||||
return _colorMap.getCacheValue(
|
||||
return _colorMap.updateCacheValue(
|
||||
"darkenSecondaryContainer",
|
||||
context.colorScheme.secondaryContainer.blendDarken(context, factor: 0.1),
|
||||
() => context.colorScheme.secondaryContainer
|
||||
.blendDarken(context, factor: 0.1),
|
||||
);
|
||||
}
|
||||
|
||||
Color get darkenSecondaryContainerLighter {
|
||||
return _colorMap.getCacheValue(
|
||||
return _colorMap.updateCacheValue(
|
||||
"darkenSecondaryContainerLighter",
|
||||
context.colorScheme.secondaryContainer
|
||||
() => context.colorScheme.secondaryContainer
|
||||
.blendDarken(context, factor: 0.1)
|
||||
.opacity60,
|
||||
);
|
||||
}
|
||||
|
||||
Color get darken2SecondaryContainer {
|
||||
return _colorMap.getCacheValue(
|
||||
return _colorMap.updateCacheValue(
|
||||
"darken2SecondaryContainer",
|
||||
context.colorScheme.secondaryContainer.blendDarken(context, factor: 0.2),
|
||||
() => context.colorScheme.secondaryContainer
|
||||
.blendDarken(context, factor: 0.2),
|
||||
);
|
||||
}
|
||||
|
||||
Color get darken3PrimaryContainer {
|
||||
return _colorMap.getCacheValue(
|
||||
return _colorMap.updateCacheValue(
|
||||
"darken3PrimaryContainer",
|
||||
context.colorScheme.primaryContainer.blendDarken(context, factor: 0.3),
|
||||
() => context.colorScheme.primaryContainer
|
||||
.blendDarken(context, factor: 0.3),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,6 +312,10 @@ class AppController {
|
||||
handleChangeProfile() {
|
||||
_ref.read(delayDataSourceProvider.notifier).value = {};
|
||||
applyProfile();
|
||||
_ref.read(logsProvider.notifier).value = FixedList(500);
|
||||
_ref.read(requestsProvider.notifier).value = FixedList(500);
|
||||
globalState.cacheHeightMap = {};
|
||||
globalState.cacheScrollPosition = {};
|
||||
}
|
||||
|
||||
updateBrightness(Brightness brightness) {
|
||||
|
||||
@@ -472,8 +472,13 @@ enum RuleTarget {
|
||||
REJECT,
|
||||
}
|
||||
|
||||
|
||||
enum RecoveryStrategy {
|
||||
compatible,
|
||||
override,
|
||||
}
|
||||
|
||||
enum CacheTag {
|
||||
logs,
|
||||
rules,
|
||||
requests,
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class AboutFragment extends StatelessWidget {
|
||||
title: Text(appLocalizations.contactMe),
|
||||
onTap: () {
|
||||
globalState.showMessage(
|
||||
title: appLocalizations.contactMe,
|
||||
message: TextSpan(text: "chen08209@gmail.com"),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -20,12 +20,13 @@ class RequestsFragment extends ConsumerStatefulWidget {
|
||||
|
||||
class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
with PageMixin {
|
||||
final GlobalKey<CacheItemExtentListViewState> _key = GlobalKey();
|
||||
final _requestsStateNotifier =
|
||||
ValueNotifier<ConnectionsState>(const ConnectionsState());
|
||||
final _requestsStateNotifier = ValueNotifier<ConnectionsState>(
|
||||
const ConnectionsState(loading: true),
|
||||
);
|
||||
List<Connection> _requests = [];
|
||||
final _cacheKey = ValueKey("requests_list");
|
||||
final _tag = CacheTag.requests;
|
||||
late ScrollController _scrollController;
|
||||
bool _isLoad = false;
|
||||
|
||||
double _currentMaxWidth = 0;
|
||||
|
||||
@@ -45,12 +46,13 @@ class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final preOffset = globalState.cacheScrollPosition[_cacheKey] ?? -1;
|
||||
final preOffset = globalState.cacheScrollPosition[_tag] ?? -1;
|
||||
_scrollController = ScrollController(
|
||||
initialScrollOffset: preOffset > 0 ? preOffset : double.maxFinite,
|
||||
);
|
||||
_requests = globalState.appState.requests.list;
|
||||
_requestsStateNotifier.value = _requestsStateNotifier.value.copyWith(
|
||||
connections: globalState.appState.requests.list,
|
||||
connections: _requests,
|
||||
);
|
||||
ref.listenManual(
|
||||
isCurrentPageProvider(
|
||||
@@ -97,14 +99,7 @@ class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
final lines = (chainSize.height / baseHeight).round();
|
||||
final computerHeight =
|
||||
size.height + chainSize.height + 24 + 24 * (lines - 1);
|
||||
return computerHeight;
|
||||
}
|
||||
|
||||
_handleTryClearCache(double maxWidth) {
|
||||
if (_currentMaxWidth != maxWidth) {
|
||||
_currentMaxWidth = maxWidth;
|
||||
_key.currentState?.clearCache();
|
||||
}
|
||||
return computerHeight + 8 + 32 + globalState.measure.bodyMediumHeight;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -132,6 +127,42 @@ class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
}, duration: commonDuration);
|
||||
}
|
||||
|
||||
_preLoad() {
|
||||
if (_isLoad == true) {
|
||||
return;
|
||||
}
|
||||
_isLoad = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final isMobileView = ref.read(isMobileViewProvider);
|
||||
if (isMobileView) {
|
||||
await Future.delayed(Duration(milliseconds: 300));
|
||||
}
|
||||
final parts = _requests.batch(10);
|
||||
globalState.cacheHeightMap[_tag] ??= FixedMap(
|
||||
_requests.length,
|
||||
);
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
final part = parts[i];
|
||||
await Future(
|
||||
() {
|
||||
for (final request in part) {
|
||||
globalState.cacheHeightMap[_tag]?.updateCacheValue(
|
||||
request.id,
|
||||
() => _calcCacheHeight(request),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
_requestsStateNotifier.value = _requestsStateNotifier.value.copyWith(
|
||||
loading: false,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
@@ -145,13 +176,14 @@ class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
Platform.isAndroid,
|
||||
),
|
||||
);
|
||||
_handleTryClearCache(constraints.maxWidth - 40 - (value ? 60 : 0));
|
||||
_currentMaxWidth = constraints.maxWidth - 40 - (value ? 60 : 0);
|
||||
return child!;
|
||||
},
|
||||
child: TextScaleNotification(
|
||||
child: ValueListenableBuilder<ConnectionsState>(
|
||||
valueListenable: _requestsStateNotifier,
|
||||
builder: (_, state, __) {
|
||||
_preLoad();
|
||||
final connections = state.list;
|
||||
if (connections.isEmpty) {
|
||||
return NullStatus(
|
||||
@@ -174,51 +206,56 @@ class _RequestsFragmentState extends ConsumerState<RequestsFragment>
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ScrollToEndBox(
|
||||
controller: _scrollController,
|
||||
cacheKey: _cacheKey,
|
||||
dataSource: connections,
|
||||
child: CommonScrollBar(
|
||||
controller: _scrollController,
|
||||
child: CacheItemExtentListView(
|
||||
key: _key,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
physics: NextClampingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
itemExtentBuilder: (index) {
|
||||
final widget = items[index];
|
||||
if (widget.runtimeType == Divider) {
|
||||
return 0;
|
||||
}
|
||||
final measure = globalState.measure;
|
||||
final bodyMediumHeight = measure.bodyMediumHeight;
|
||||
final connection = connections[(index / 2).floor()];
|
||||
final height = _calcCacheHeight(connection);
|
||||
return height + bodyMediumHeight + 32;
|
||||
},
|
||||
itemBuilder: (_, index) {
|
||||
return items[index];
|
||||
},
|
||||
itemCount: items.length,
|
||||
keyBuilder: (int index) {
|
||||
final widget = items[index];
|
||||
if (widget.runtimeType == Divider) {
|
||||
return "divider";
|
||||
}
|
||||
final connection = connections[(index / 2).floor()];
|
||||
return connection.id;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
final content = connections.isEmpty
|
||||
? NullStatus(
|
||||
label: appLocalizations.nullRequestsDesc,
|
||||
)
|
||||
: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ScrollToEndBox(
|
||||
controller: _scrollController,
|
||||
tag: _tag,
|
||||
dataSource: connections,
|
||||
child: CommonScrollBar(
|
||||
controller: _scrollController,
|
||||
child: CacheItemExtentListView(
|
||||
tag: _tag,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
physics: NextClampingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
itemExtentBuilder: (index) {
|
||||
if (index.isOdd) {
|
||||
return 0;
|
||||
}
|
||||
return _calcCacheHeight(
|
||||
connections[index ~/ 2]);
|
||||
},
|
||||
itemBuilder: (_, index) {
|
||||
return items[index];
|
||||
},
|
||||
itemCount: items.length,
|
||||
keyBuilder: (int index) {
|
||||
if (index.isOdd) {
|
||||
return "divider";
|
||||
}
|
||||
return connections[index ~/ 2].id;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return FadeBox(
|
||||
child: state.loading
|
||||
? Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: content,
|
||||
);
|
||||
},
|
||||
),
|
||||
onNotification: (_) {
|
||||
_key.currentState?.clearCache();
|
||||
globalState.cacheHeightMap[_tag]?.clear();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -8,10 +8,12 @@ import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../providers/app.dart';
|
||||
|
||||
class DeveloperView extends ConsumerWidget {
|
||||
const DeveloperView({super.key});
|
||||
|
||||
Widget _getDeveloperList(BuildContext context) {
|
||||
Widget _getDeveloperList(BuildContext context, WidgetRef ref) {
|
||||
return generateSectionV2(
|
||||
title: appLocalizations.options,
|
||||
items: [
|
||||
@@ -27,10 +29,29 @@ class DeveloperView extends ConsumerWidget {
|
||||
title: Text(appLocalizations.logsTest),
|
||||
onTap: () {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
ref.read(requestsProvider.notifier).addRequest(Connection(
|
||||
id: utils.id,
|
||||
start: DateTime.now(),
|
||||
metadata: Metadata(
|
||||
uid: i * i,
|
||||
network: utils.generateRandomString(
|
||||
maxLength: 1000,
|
||||
minLength: 20,
|
||||
),
|
||||
sourceIP: '',
|
||||
sourcePort: '',
|
||||
destinationIP: '',
|
||||
destinationPort: '',
|
||||
host: '',
|
||||
process: '',
|
||||
remoteDestination: "",
|
||||
),
|
||||
chains: ["chains"],
|
||||
));
|
||||
globalState.appController.addLog(
|
||||
Log.app(
|
||||
utils.generateRandomString(
|
||||
maxLength: 1000,
|
||||
maxLength: 200,
|
||||
minLength: 20,
|
||||
),
|
||||
),
|
||||
@@ -91,7 +112,7 @@ class DeveloperView extends ConsumerWidget {
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
_getDeveloperList(context)
|
||||
_getDeveloperList(context, ref)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
@@ -16,25 +18,27 @@ class LogsFragment extends ConsumerStatefulWidget {
|
||||
}
|
||||
|
||||
class _LogsFragmentState extends ConsumerState<LogsFragment> with PageMixin {
|
||||
final _logsStateNotifier = ValueNotifier<LogsState>(LogsState());
|
||||
final _cacheKey = ValueKey("logs_list");
|
||||
final _logsStateNotifier = ValueNotifier<LogsState>(
|
||||
LogsState(loading: true),
|
||||
);
|
||||
late ScrollController _scrollController;
|
||||
|
||||
double _currentMaxWidth = 0;
|
||||
final GlobalKey<CacheItemExtentListViewState> _key = GlobalKey();
|
||||
final _tag = CacheTag.rules;
|
||||
bool _isLoad = false;
|
||||
|
||||
List<Log> _logs = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final preOffset = globalState.cacheScrollPosition[_cacheKey] ?? -1;
|
||||
final position = globalState.cacheScrollPosition[_tag] ?? -1;
|
||||
_scrollController = ScrollController(
|
||||
initialScrollOffset: preOffset > 0
|
||||
? preOffset
|
||||
: double.maxFinite,
|
||||
initialScrollOffset: position > 0 ? position : double.maxFinite,
|
||||
);
|
||||
_logs = globalState.appState.logs.list;
|
||||
_logsStateNotifier.value = _logsStateNotifier.value.copyWith(
|
||||
logs: globalState.appState.logs.list,
|
||||
logs: _logs,
|
||||
);
|
||||
ref.listenManual(
|
||||
isCurrentPageProvider(
|
||||
@@ -95,13 +99,6 @@ class _LogsFragmentState extends ConsumerState<LogsFragment> with PageMixin {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
_handleTryClearCache(double maxWidth) {
|
||||
if (_currentMaxWidth != maxWidth) {
|
||||
_currentMaxWidth = maxWidth;
|
||||
_key.currentState?.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
_handleExport() async {
|
||||
final commonScaffoldState = context.commonScaffoldState;
|
||||
final res = await commonScaffoldState?.loadingRun<bool>(
|
||||
@@ -125,12 +122,12 @@ class _LogsFragmentState extends ConsumerState<LogsFragment> with PageMixin {
|
||||
.computeTextSize(
|
||||
Text(
|
||||
log.payload,
|
||||
style: globalState.appController.context.textTheme.bodyLarge,
|
||||
style: context.textTheme.bodyLarge,
|
||||
),
|
||||
maxWidth: _currentMaxWidth,
|
||||
)
|
||||
.height;
|
||||
return height + bodySmallHeight + 8 + bodyMediumHeight + 40;
|
||||
return height + bodySmallHeight + 8 + bodyMediumHeight + 40 + 8;
|
||||
}
|
||||
|
||||
updateLogsThrottler() {
|
||||
@@ -143,86 +140,122 @@ class _LogsFragmentState extends ConsumerState<LogsFragment> with PageMixin {
|
||||
return;
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_logsStateNotifier.value = _logsStateNotifier.value.copyWith(
|
||||
logs: _logs,
|
||||
);
|
||||
if (mounted) {
|
||||
_logsStateNotifier.value = _logsStateNotifier.value.copyWith(
|
||||
logs: _logs,
|
||||
);
|
||||
}
|
||||
});
|
||||
}, duration: commonDuration);
|
||||
}
|
||||
|
||||
_preLoad() {
|
||||
if (_isLoad == true) {
|
||||
return;
|
||||
}
|
||||
_isLoad = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final isMobileView = ref.read(isMobileViewProvider);
|
||||
if (isMobileView) {
|
||||
await Future.delayed(Duration(milliseconds: 300));
|
||||
}
|
||||
final parts = _logs.batch(10);
|
||||
globalState.cacheHeightMap[_tag] ??= FixedMap(
|
||||
_logs.length,
|
||||
);
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
final part = parts[i];
|
||||
await Future(
|
||||
() {
|
||||
for (final log in part) {
|
||||
globalState.cacheHeightMap[_tag]?.updateCacheValue(
|
||||
log.payload,
|
||||
() => _getItemHeight(log),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
_logsStateNotifier.value = _logsStateNotifier.value.copyWith(
|
||||
loading: false,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
_handleTryClearCache(constraints.maxWidth - 40);
|
||||
return TextScaleNotification(
|
||||
child: ValueListenableBuilder<LogsState>(
|
||||
valueListenable: _logsStateNotifier,
|
||||
builder: (_, state, __) {
|
||||
final logs = state.list;
|
||||
if (logs.isEmpty) {
|
||||
return NullStatus(
|
||||
label: appLocalizations.nullLogsDesc,
|
||||
);
|
||||
}
|
||||
final items = logs
|
||||
.map<Widget>(
|
||||
(log) => LogItem(
|
||||
key: Key(log.dateTime),
|
||||
log: log,
|
||||
onClick: (value) {
|
||||
context.commonScaffoldState?.addKeyword(value);
|
||||
},
|
||||
),
|
||||
)
|
||||
.separated(
|
||||
const Divider(
|
||||
height: 0,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ScrollToEndBox<Log>(
|
||||
controller: _scrollController,
|
||||
cacheKey: _cacheKey,
|
||||
dataSource: logs,
|
||||
child: CommonScrollBar(
|
||||
controller: _scrollController,
|
||||
child: CacheItemExtentListView(
|
||||
key: _key,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
physics: NextClampingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
itemBuilder: (_, index) {
|
||||
return items[index];
|
||||
},
|
||||
itemExtentBuilder: (index) {
|
||||
final item = items[index];
|
||||
if (item.runtimeType == Divider) {
|
||||
return 0;
|
||||
}
|
||||
final log = logs[(index / 2).floor()];
|
||||
return _getItemHeight(log);
|
||||
},
|
||||
itemCount: items.length,
|
||||
keyBuilder: (int index) {
|
||||
final item = items[index];
|
||||
if (item.runtimeType == Divider) {
|
||||
return "divider";
|
||||
}
|
||||
final log = logs[(index / 2).floor()];
|
||||
return log.payload;
|
||||
},
|
||||
),
|
||||
_currentMaxWidth = constraints.maxWidth - 40;
|
||||
return ValueListenableBuilder<LogsState>(
|
||||
valueListenable: _logsStateNotifier,
|
||||
builder: (_, state, __) {
|
||||
_preLoad();
|
||||
final logs = state.list;
|
||||
final items = logs
|
||||
.map<Widget>(
|
||||
(log) => LogItem(
|
||||
key: Key(log.dateTime),
|
||||
log: log,
|
||||
onClick: (value) {
|
||||
context.commonScaffoldState?.addKeyword(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
onNotification: (_) {
|
||||
_key.currentState?.clearCache();
|
||||
)
|
||||
.separated(
|
||||
const Divider(
|
||||
height: 0,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
final content = logs.isEmpty
|
||||
? NullStatus(
|
||||
label: appLocalizations.nullLogsDesc,
|
||||
)
|
||||
: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: CommonScrollBar(
|
||||
controller: _scrollController,
|
||||
child: ScrollToEndBox(
|
||||
controller: _scrollController,
|
||||
tag: _tag,
|
||||
dataSource: logs,
|
||||
child: CacheItemExtentListView(
|
||||
tag: _tag,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
physics: NextClampingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
itemBuilder: (_, index) {
|
||||
return items[index];
|
||||
},
|
||||
itemExtentBuilder: (index) {
|
||||
if (index.isOdd) {
|
||||
return 0;
|
||||
}
|
||||
return _getItemHeight(logs[index ~/ 2]);
|
||||
},
|
||||
itemCount: items.length,
|
||||
keyBuilder: (int index) {
|
||||
if (index.isOdd) {
|
||||
return "divider";
|
||||
}
|
||||
return logs[index ~/ 2].payload;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return FadeBox(
|
||||
child: state.loading
|
||||
? Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: content,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -23,7 +23,6 @@ class OverrideProfile extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _OverrideProfileState extends State<OverrideProfile> {
|
||||
final GlobalKey<CacheItemExtentListViewState> _ruleListKey = GlobalKey();
|
||||
final _controller = ScrollController();
|
||||
double _currentMaxWidth = 0;
|
||||
|
||||
@@ -86,13 +85,6 @@ class _OverrideProfileState extends State<OverrideProfile> {
|
||||
);
|
||||
}
|
||||
|
||||
_handleTryClearCache(double maxWidth) {
|
||||
if (_currentMaxWidth != maxWidth) {
|
||||
_currentMaxWidth = maxWidth;
|
||||
_ruleListKey.currentState?.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
_buildContent() {
|
||||
return Consumer(
|
||||
builder: (_, ref, child) {
|
||||
@@ -116,7 +108,7 @@ class _OverrideProfileState extends State<OverrideProfile> {
|
||||
},
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
_handleTryClearCache(constraints.maxWidth - 104);
|
||||
_currentMaxWidth = constraints.maxWidth - 104;
|
||||
return CommonAutoHiddenScrollBar(
|
||||
controller: _controller,
|
||||
child: CustomScrollView(
|
||||
@@ -148,7 +140,6 @@ class _OverrideProfileState extends State<OverrideProfile> {
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 0),
|
||||
sliver: RuleContent(
|
||||
maxWidth: _currentMaxWidth,
|
||||
ruleListKey: _ruleListKey,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
@@ -449,12 +440,10 @@ class RuleTitle extends ConsumerWidget {
|
||||
}
|
||||
|
||||
class RuleContent extends ConsumerWidget {
|
||||
final Key ruleListKey;
|
||||
final double maxWidth;
|
||||
|
||||
const RuleContent({
|
||||
super.key,
|
||||
required this.ruleListKey,
|
||||
required this.maxWidth,
|
||||
});
|
||||
|
||||
@@ -602,7 +591,7 @@ class RuleContent extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
return CacheItemExtentSliverReorderableList(
|
||||
key: ruleListKey,
|
||||
tag: CacheTag.rules,
|
||||
itemBuilder: (context, index) {
|
||||
final rule = rules[index];
|
||||
return GestureDetector(
|
||||
|
||||
@@ -370,7 +370,7 @@ class ProfileItem extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
title: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
||||
@@ -21,13 +21,14 @@ import 'common/common.dart';
|
||||
Future<void> main() async {
|
||||
globalState.isService = false;
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
FlutterError.onError = (details) {
|
||||
commonPrint.log(details.stack.toString());
|
||||
};
|
||||
final version = await system.version;
|
||||
await clashCore.preload();
|
||||
await globalState.initApp(version);
|
||||
await android?.init();
|
||||
await window?.init(version);
|
||||
globalState.isPre = const String.fromEnvironment("APP_ENV") != 'stable';
|
||||
globalState.coreSHA256 = const String.fromEnvironment("CORE_SHA256");
|
||||
HttpOverrides.global = FlClashHttpOverrides();
|
||||
runApp(ProviderScope(
|
||||
child: const Application(),
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class AppStateManager extends StatefulWidget {
|
||||
class AppStateManager extends ConsumerStatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const AppStateManager({
|
||||
@@ -14,15 +16,22 @@ class AppStateManager extends StatefulWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
State<AppStateManager> createState() => _AppStateManagerState();
|
||||
ConsumerState<AppStateManager> createState() => _AppStateManagerState();
|
||||
}
|
||||
|
||||
class _AppStateManagerState extends State<AppStateManager>
|
||||
class _AppStateManagerState extends ConsumerState<AppStateManager>
|
||||
with WidgetsBindingObserver {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
ref.listenManual(layoutChangeProvider, (prev, next) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (prev != next) {
|
||||
globalState.cacheHeightMap = {};
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -71,7 +71,7 @@ class _ClashContainerState extends ConsumerState<ClashManager>
|
||||
|
||||
@override
|
||||
void onLog(Log log) {
|
||||
ref.watch(logsProvider.notifier).addLog(log);
|
||||
ref.read(logsProvider.notifier).addLog(log);
|
||||
if (log.logLevel == LogLevel.error) {
|
||||
globalState.showNotifier(log.payload);
|
||||
}
|
||||
@@ -80,13 +80,13 @@ class _ClashContainerState extends ConsumerState<ClashManager>
|
||||
|
||||
@override
|
||||
void onRequest(Connection connection) async {
|
||||
ref.watch(requestsProvider.notifier).addRequest(connection);
|
||||
ref.read(requestsProvider.notifier).addRequest(connection);
|
||||
super.onRequest(connection);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoaded(String providerName) async {
|
||||
ref.watch(providersProvider.notifier).setProvider(
|
||||
ref.read(providersProvider.notifier).setProvider(
|
||||
await clashCore.getExternalProvider(
|
||||
providerName,
|
||||
),
|
||||
|
||||
@@ -148,7 +148,7 @@ class Tun with _$Tun {
|
||||
@Default(false) bool enable,
|
||||
@Default(appName) String device,
|
||||
@JsonKey(name: "auto-route") @Default(false) bool autoRoute,
|
||||
@Default(TunStack.gvisor) TunStack stack,
|
||||
@Default(TunStack.mixed) TunStack stack,
|
||||
@JsonKey(name: "dns-hijack") @Default(["any:53"]) List<String> dnsHijack,
|
||||
@JsonKey(name: "route-address") @Default([]) List<String> routeAddress,
|
||||
}) = _Tun;
|
||||
|
||||
@@ -120,6 +120,7 @@ class LogsState with _$LogsState {
|
||||
@Default([]) List<Log> logs,
|
||||
@Default([]) List<String> keywords,
|
||||
@Default("") String query,
|
||||
@Default(false) bool loading,
|
||||
}) = _LogsState;
|
||||
}
|
||||
|
||||
@@ -143,6 +144,7 @@ class ConnectionsState with _$ConnectionsState {
|
||||
@Default([]) List<Connection> connections,
|
||||
@Default([]) List<String> keywords,
|
||||
@Default("") String query,
|
||||
@Default(false) bool loading,
|
||||
}) = _ConnectionsState;
|
||||
}
|
||||
|
||||
@@ -512,3 +514,17 @@ class PopupMenuItemData {
|
||||
final IconData? icon;
|
||||
final PopupMenuItemType? type;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class TextPainterParams with _$TextPainterParams {
|
||||
const factory TextPainterParams({
|
||||
required String? text,
|
||||
required double? fontSize,
|
||||
required double textScaleFactor,
|
||||
@Default(double.infinity) double maxWidth,
|
||||
int? maxLines,
|
||||
}) = _TextPainterParams;
|
||||
|
||||
factory TextPainterParams.fromJson(Map<String, Object?> json) =>
|
||||
_$TextPainterParamsFromJson(json);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class AppSettingProps with _$AppSettingProps {
|
||||
@Default(false) bool autoLaunch,
|
||||
@Default(false) bool silentLaunch,
|
||||
@Default(false) bool autoRun,
|
||||
@Default(true) bool openLogs,
|
||||
@Default(false) bool openLogs,
|
||||
@Default(true) bool closeConnections,
|
||||
@Default(defaultTestUrl) String testUrl,
|
||||
@Default(true) bool isAnimateToPage,
|
||||
@@ -192,7 +192,7 @@ class ThemeProps with _$ThemeProps {
|
||||
int? primaryColor,
|
||||
@Default(defaultPrimaryColors) List<int> primaryColors,
|
||||
@Default(ThemeMode.dark) ThemeMode themeMode,
|
||||
@Default(DynamicSchemeVariant.tonalSpot) DynamicSchemeVariant schemeVariant,
|
||||
@Default(DynamicSchemeVariant.content) DynamicSchemeVariant schemeVariant,
|
||||
@Default(false) bool pureBlack,
|
||||
@Default(TextScale()) TextScale textScale,
|
||||
}) = _ThemeProps;
|
||||
|
||||
@@ -810,7 +810,7 @@ class _$TunImpl implements _Tun {
|
||||
{this.enable = false,
|
||||
this.device = appName,
|
||||
@JsonKey(name: "auto-route") this.autoRoute = false,
|
||||
this.stack = TunStack.gvisor,
|
||||
this.stack = TunStack.mixed,
|
||||
@JsonKey(name: "dns-hijack")
|
||||
final List<String> dnsHijack = const ["any:53"],
|
||||
@JsonKey(name: "route-address")
|
||||
|
||||
@@ -68,7 +68,7 @@ _$TunImpl _$$TunImplFromJson(Map<String, dynamic> json) => _$TunImpl(
|
||||
device: json['device'] as String? ?? appName,
|
||||
autoRoute: json['auto-route'] as bool? ?? false,
|
||||
stack: $enumDecodeNullable(_$TunStackEnumMap, json['stack']) ??
|
||||
TunStack.gvisor,
|
||||
TunStack.mixed,
|
||||
dnsHijack: (json['dns-hijack'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
|
||||
@@ -1320,6 +1320,7 @@ mixin _$LogsState {
|
||||
List<Log> get logs => throw _privateConstructorUsedError;
|
||||
List<String> get keywords => throw _privateConstructorUsedError;
|
||||
String get query => throw _privateConstructorUsedError;
|
||||
bool get loading => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LogsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1333,7 +1334,8 @@ abstract class $LogsStateCopyWith<$Res> {
|
||||
factory $LogsStateCopyWith(LogsState value, $Res Function(LogsState) then) =
|
||||
_$LogsStateCopyWithImpl<$Res, LogsState>;
|
||||
@useResult
|
||||
$Res call({List<Log> logs, List<String> keywords, String query});
|
||||
$Res call(
|
||||
{List<Log> logs, List<String> keywords, String query, bool loading});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1354,6 +1356,7 @@ class _$LogsStateCopyWithImpl<$Res, $Val extends LogsState>
|
||||
Object? logs = null,
|
||||
Object? keywords = null,
|
||||
Object? query = null,
|
||||
Object? loading = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
logs: null == logs
|
||||
@@ -1368,6 +1371,10 @@ class _$LogsStateCopyWithImpl<$Res, $Val extends LogsState>
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
loading: null == loading
|
||||
? _value.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -1380,7 +1387,8 @@ abstract class _$$LogsStateImplCopyWith<$Res>
|
||||
__$$LogsStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({List<Log> logs, List<String> keywords, String query});
|
||||
$Res call(
|
||||
{List<Log> logs, List<String> keywords, String query, bool loading});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1399,6 +1407,7 @@ class __$$LogsStateImplCopyWithImpl<$Res>
|
||||
Object? logs = null,
|
||||
Object? keywords = null,
|
||||
Object? query = null,
|
||||
Object? loading = null,
|
||||
}) {
|
||||
return _then(_$LogsStateImpl(
|
||||
logs: null == logs
|
||||
@@ -1413,6 +1422,10 @@ class __$$LogsStateImplCopyWithImpl<$Res>
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
loading: null == loading
|
||||
? _value.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1423,7 +1436,8 @@ class _$LogsStateImpl implements _LogsState {
|
||||
const _$LogsStateImpl(
|
||||
{final List<Log> logs = const [],
|
||||
final List<String> keywords = const [],
|
||||
this.query = ""})
|
||||
this.query = "",
|
||||
this.loading = false})
|
||||
: _logs = logs,
|
||||
_keywords = keywords;
|
||||
|
||||
@@ -1448,10 +1462,13 @@ class _$LogsStateImpl implements _LogsState {
|
||||
@override
|
||||
@JsonKey()
|
||||
final String query;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool loading;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LogsState(logs: $logs, keywords: $keywords, query: $query)';
|
||||
return 'LogsState(logs: $logs, keywords: $keywords, query: $query, loading: $loading)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1461,7 +1478,8 @@ class _$LogsStateImpl implements _LogsState {
|
||||
other is _$LogsStateImpl &&
|
||||
const DeepCollectionEquality().equals(other._logs, _logs) &&
|
||||
const DeepCollectionEquality().equals(other._keywords, _keywords) &&
|
||||
(identical(other.query, query) || other.query == query));
|
||||
(identical(other.query, query) || other.query == query) &&
|
||||
(identical(other.loading, loading) || other.loading == loading));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1469,7 +1487,8 @@ class _$LogsStateImpl implements _LogsState {
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_logs),
|
||||
const DeepCollectionEquality().hash(_keywords),
|
||||
query);
|
||||
query,
|
||||
loading);
|
||||
|
||||
/// Create a copy of LogsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1484,7 +1503,8 @@ abstract class _LogsState implements LogsState {
|
||||
const factory _LogsState(
|
||||
{final List<Log> logs,
|
||||
final List<String> keywords,
|
||||
final String query}) = _$LogsStateImpl;
|
||||
final String query,
|
||||
final bool loading}) = _$LogsStateImpl;
|
||||
|
||||
@override
|
||||
List<Log> get logs;
|
||||
@@ -1492,6 +1512,8 @@ abstract class _LogsState implements LogsState {
|
||||
List<String> get keywords;
|
||||
@override
|
||||
String get query;
|
||||
@override
|
||||
bool get loading;
|
||||
|
||||
/// Create a copy of LogsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1506,6 +1528,7 @@ mixin _$ConnectionsState {
|
||||
List<Connection> get connections => throw _privateConstructorUsedError;
|
||||
List<String> get keywords => throw _privateConstructorUsedError;
|
||||
String get query => throw _privateConstructorUsedError;
|
||||
bool get loading => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConnectionsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1521,7 +1544,10 @@ abstract class $ConnectionsStateCopyWith<$Res> {
|
||||
_$ConnectionsStateCopyWithImpl<$Res, ConnectionsState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{List<Connection> connections, List<String> keywords, String query});
|
||||
{List<Connection> connections,
|
||||
List<String> keywords,
|
||||
String query,
|
||||
bool loading});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1542,6 +1568,7 @@ class _$ConnectionsStateCopyWithImpl<$Res, $Val extends ConnectionsState>
|
||||
Object? connections = null,
|
||||
Object? keywords = null,
|
||||
Object? query = null,
|
||||
Object? loading = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
connections: null == connections
|
||||
@@ -1556,6 +1583,10 @@ class _$ConnectionsStateCopyWithImpl<$Res, $Val extends ConnectionsState>
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
loading: null == loading
|
||||
? _value.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -1569,7 +1600,10 @@ abstract class _$$ConnectionsStateImplCopyWith<$Res>
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{List<Connection> connections, List<String> keywords, String query});
|
||||
{List<Connection> connections,
|
||||
List<String> keywords,
|
||||
String query,
|
||||
bool loading});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1588,6 +1622,7 @@ class __$$ConnectionsStateImplCopyWithImpl<$Res>
|
||||
Object? connections = null,
|
||||
Object? keywords = null,
|
||||
Object? query = null,
|
||||
Object? loading = null,
|
||||
}) {
|
||||
return _then(_$ConnectionsStateImpl(
|
||||
connections: null == connections
|
||||
@@ -1602,6 +1637,10 @@ class __$$ConnectionsStateImplCopyWithImpl<$Res>
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
loading: null == loading
|
||||
? _value.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1651,8 @@ class _$ConnectionsStateImpl implements _ConnectionsState {
|
||||
const _$ConnectionsStateImpl(
|
||||
{final List<Connection> connections = const [],
|
||||
final List<String> keywords = const [],
|
||||
this.query = ""})
|
||||
this.query = "",
|
||||
this.loading = false})
|
||||
: _connections = connections,
|
||||
_keywords = keywords;
|
||||
|
||||
@@ -1637,10 +1677,13 @@ class _$ConnectionsStateImpl implements _ConnectionsState {
|
||||
@override
|
||||
@JsonKey()
|
||||
final String query;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool loading;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConnectionsState(connections: $connections, keywords: $keywords, query: $query)';
|
||||
return 'ConnectionsState(connections: $connections, keywords: $keywords, query: $query, loading: $loading)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1651,7 +1694,8 @@ class _$ConnectionsStateImpl implements _ConnectionsState {
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._connections, _connections) &&
|
||||
const DeepCollectionEquality().equals(other._keywords, _keywords) &&
|
||||
(identical(other.query, query) || other.query == query));
|
||||
(identical(other.query, query) || other.query == query) &&
|
||||
(identical(other.loading, loading) || other.loading == loading));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1659,7 +1703,8 @@ class _$ConnectionsStateImpl implements _ConnectionsState {
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_connections),
|
||||
const DeepCollectionEquality().hash(_keywords),
|
||||
query);
|
||||
query,
|
||||
loading);
|
||||
|
||||
/// Create a copy of ConnectionsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1675,7 +1720,8 @@ abstract class _ConnectionsState implements ConnectionsState {
|
||||
const factory _ConnectionsState(
|
||||
{final List<Connection> connections,
|
||||
final List<String> keywords,
|
||||
final String query}) = _$ConnectionsStateImpl;
|
||||
final String query,
|
||||
final bool loading}) = _$ConnectionsStateImpl;
|
||||
|
||||
@override
|
||||
List<Connection> get connections;
|
||||
@@ -1683,6 +1729,8 @@ abstract class _ConnectionsState implements ConnectionsState {
|
||||
List<String> get keywords;
|
||||
@override
|
||||
String get query;
|
||||
@override
|
||||
bool get loading;
|
||||
|
||||
/// Create a copy of ConnectionsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -3178,3 +3226,243 @@ abstract class _Field implements Field {
|
||||
_$$FieldImplCopyWith<_$FieldImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
TextPainterParams _$TextPainterParamsFromJson(Map<String, dynamic> json) {
|
||||
return _TextPainterParams.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$TextPainterParams {
|
||||
String? get text => throw _privateConstructorUsedError;
|
||||
double? get fontSize => throw _privateConstructorUsedError;
|
||||
double get textScaleFactor => throw _privateConstructorUsedError;
|
||||
double get maxWidth => throw _privateConstructorUsedError;
|
||||
int? get maxLines => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this TextPainterParams to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of TextPainterParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$TextPainterParamsCopyWith<TextPainterParams> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TextPainterParamsCopyWith<$Res> {
|
||||
factory $TextPainterParamsCopyWith(
|
||||
TextPainterParams value, $Res Function(TextPainterParams) then) =
|
||||
_$TextPainterParamsCopyWithImpl<$Res, TextPainterParams>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? text,
|
||||
double? fontSize,
|
||||
double textScaleFactor,
|
||||
double maxWidth,
|
||||
int? maxLines});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TextPainterParamsCopyWithImpl<$Res, $Val extends TextPainterParams>
|
||||
implements $TextPainterParamsCopyWith<$Res> {
|
||||
_$TextPainterParamsCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TextPainterParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? text = freezed,
|
||||
Object? fontSize = freezed,
|
||||
Object? textScaleFactor = null,
|
||||
Object? maxWidth = null,
|
||||
Object? maxLines = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
text: freezed == text
|
||||
? _value.text
|
||||
: text // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fontSize: freezed == fontSize
|
||||
? _value.fontSize
|
||||
: fontSize // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
textScaleFactor: null == textScaleFactor
|
||||
? _value.textScaleFactor
|
||||
: textScaleFactor // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
maxWidth: null == maxWidth
|
||||
? _value.maxWidth
|
||||
: maxWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
maxLines: freezed == maxLines
|
||||
? _value.maxLines
|
||||
: maxLines // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$TextPainterParamsImplCopyWith<$Res>
|
||||
implements $TextPainterParamsCopyWith<$Res> {
|
||||
factory _$$TextPainterParamsImplCopyWith(_$TextPainterParamsImpl value,
|
||||
$Res Function(_$TextPainterParamsImpl) then) =
|
||||
__$$TextPainterParamsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? text,
|
||||
double? fontSize,
|
||||
double textScaleFactor,
|
||||
double maxWidth,
|
||||
int? maxLines});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$TextPainterParamsImplCopyWithImpl<$Res>
|
||||
extends _$TextPainterParamsCopyWithImpl<$Res, _$TextPainterParamsImpl>
|
||||
implements _$$TextPainterParamsImplCopyWith<$Res> {
|
||||
__$$TextPainterParamsImplCopyWithImpl(_$TextPainterParamsImpl _value,
|
||||
$Res Function(_$TextPainterParamsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of TextPainterParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? text = freezed,
|
||||
Object? fontSize = freezed,
|
||||
Object? textScaleFactor = null,
|
||||
Object? maxWidth = null,
|
||||
Object? maxLines = freezed,
|
||||
}) {
|
||||
return _then(_$TextPainterParamsImpl(
|
||||
text: freezed == text
|
||||
? _value.text
|
||||
: text // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fontSize: freezed == fontSize
|
||||
? _value.fontSize
|
||||
: fontSize // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
textScaleFactor: null == textScaleFactor
|
||||
? _value.textScaleFactor
|
||||
: textScaleFactor // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
maxWidth: null == maxWidth
|
||||
? _value.maxWidth
|
||||
: maxWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
maxLines: freezed == maxLines
|
||||
? _value.maxLines
|
||||
: maxLines // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$TextPainterParamsImpl implements _TextPainterParams {
|
||||
const _$TextPainterParamsImpl(
|
||||
{required this.text,
|
||||
required this.fontSize,
|
||||
required this.textScaleFactor,
|
||||
this.maxWidth = double.infinity,
|
||||
this.maxLines});
|
||||
|
||||
factory _$TextPainterParamsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$TextPainterParamsImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String? text;
|
||||
@override
|
||||
final double? fontSize;
|
||||
@override
|
||||
final double textScaleFactor;
|
||||
@override
|
||||
@JsonKey()
|
||||
final double maxWidth;
|
||||
@override
|
||||
final int? maxLines;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TextPainterParams(text: $text, fontSize: $fontSize, textScaleFactor: $textScaleFactor, maxWidth: $maxWidth, maxLines: $maxLines)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$TextPainterParamsImpl &&
|
||||
(identical(other.text, text) || other.text == text) &&
|
||||
(identical(other.fontSize, fontSize) ||
|
||||
other.fontSize == fontSize) &&
|
||||
(identical(other.textScaleFactor, textScaleFactor) ||
|
||||
other.textScaleFactor == textScaleFactor) &&
|
||||
(identical(other.maxWidth, maxWidth) ||
|
||||
other.maxWidth == maxWidth) &&
|
||||
(identical(other.maxLines, maxLines) ||
|
||||
other.maxLines == maxLines));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, text, fontSize, textScaleFactor, maxWidth, maxLines);
|
||||
|
||||
/// Create a copy of TextPainterParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$TextPainterParamsImplCopyWith<_$TextPainterParamsImpl> get copyWith =>
|
||||
__$$TextPainterParamsImplCopyWithImpl<_$TextPainterParamsImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$TextPainterParamsImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _TextPainterParams implements TextPainterParams {
|
||||
const factory _TextPainterParams(
|
||||
{required final String? text,
|
||||
required final double? fontSize,
|
||||
required final double textScaleFactor,
|
||||
final double maxWidth,
|
||||
final int? maxLines}) = _$TextPainterParamsImpl;
|
||||
|
||||
factory _TextPainterParams.fromJson(Map<String, dynamic> json) =
|
||||
_$TextPainterParamsImpl.fromJson;
|
||||
|
||||
@override
|
||||
String? get text;
|
||||
@override
|
||||
double? get fontSize;
|
||||
@override
|
||||
double get textScaleFactor;
|
||||
@override
|
||||
double get maxWidth;
|
||||
@override
|
||||
int? get maxLines;
|
||||
|
||||
/// Create a copy of TextPainterParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$TextPainterParamsImplCopyWith<_$TextPainterParamsImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@@ -198,3 +198,23 @@ const _$KeyboardModifierEnumMap = {
|
||||
KeyboardModifier.meta: 'meta',
|
||||
KeyboardModifier.shift: 'shift',
|
||||
};
|
||||
|
||||
_$TextPainterParamsImpl _$$TextPainterParamsImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$TextPainterParamsImpl(
|
||||
text: json['text'] as String?,
|
||||
fontSize: (json['fontSize'] as num?)?.toDouble(),
|
||||
textScaleFactor: (json['textScaleFactor'] as num).toDouble(),
|
||||
maxWidth: (json['maxWidth'] as num?)?.toDouble() ?? double.infinity,
|
||||
maxLines: (json['maxLines'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$TextPainterParamsImplToJson(
|
||||
_$TextPainterParamsImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'text': instance.text,
|
||||
'fontSize': instance.fontSize,
|
||||
'textScaleFactor': instance.textScaleFactor,
|
||||
'maxWidth': instance.maxWidth,
|
||||
'maxLines': instance.maxLines,
|
||||
};
|
||||
|
||||
@@ -327,7 +327,7 @@ class _$AppSettingPropsImpl implements _AppSettingProps {
|
||||
this.autoLaunch = false,
|
||||
this.silentLaunch = false,
|
||||
this.autoRun = false,
|
||||
this.openLogs = true,
|
||||
this.openLogs = false,
|
||||
this.closeConnections = true,
|
||||
this.testUrl = defaultTestUrl,
|
||||
this.isAnimateToPage = true,
|
||||
@@ -2127,7 +2127,7 @@ class _$ThemePropsImpl implements _ThemeProps {
|
||||
{this.primaryColor,
|
||||
final List<int> primaryColors = defaultPrimaryColors,
|
||||
this.themeMode = ThemeMode.dark,
|
||||
this.schemeVariant = DynamicSchemeVariant.tonalSpot,
|
||||
this.schemeVariant = DynamicSchemeVariant.content,
|
||||
this.pureBlack = false,
|
||||
this.textScale = const TextScale()})
|
||||
: _primaryColors = primaryColors;
|
||||
|
||||
@@ -17,7 +17,7 @@ _$AppSettingPropsImpl _$$AppSettingPropsImplFromJson(
|
||||
autoLaunch: json['autoLaunch'] as bool? ?? false,
|
||||
silentLaunch: json['silentLaunch'] as bool? ?? false,
|
||||
autoRun: json['autoRun'] as bool? ?? false,
|
||||
openLogs: json['openLogs'] as bool? ?? true,
|
||||
openLogs: json['openLogs'] as bool? ?? false,
|
||||
closeConnections: json['closeConnections'] as bool? ?? true,
|
||||
testUrl: json['testUrl'] as String? ?? defaultTestUrl,
|
||||
isAnimateToPage: json['isAnimateToPage'] as bool? ?? true,
|
||||
@@ -257,7 +257,7 @@ _$ThemePropsImpl _$$ThemePropsImplFromJson(Map<String, dynamic> json) =>
|
||||
ThemeMode.dark,
|
||||
schemeVariant: $enumDecodeNullable(
|
||||
_$DynamicSchemeVariantEnumMap, json['schemeVariant']) ??
|
||||
DynamicSchemeVariant.tonalSpot,
|
||||
DynamicSchemeVariant.content,
|
||||
pureBlack: json['pureBlack'] as bool? ?? false,
|
||||
textScale: json['textScale'] == null
|
||||
? const TextScale()
|
||||
|
||||
@@ -1765,6 +1765,22 @@ class _GetProfileOverrideDataProviderElement
|
||||
String get profileId => (origin as GetProfileOverrideDataProvider).profileId;
|
||||
}
|
||||
|
||||
String _$layoutChangeHash() => r'f25182e1dfaf3c70000404d7635bb1e1db09efbb';
|
||||
|
||||
/// See also [layoutChange].
|
||||
@ProviderFor(layoutChange)
|
||||
final layoutChangeProvider = AutoDisposeProvider<VM2?>.internal(
|
||||
layoutChange,
|
||||
name: r'layoutChangeProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$layoutChangeHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef LayoutChangeRef = AutoDisposeProviderRef<VM2?>;
|
||||
String _$genColorSchemeHash() => r'b18f15c938a8132ee4ed02cdfc02f3b9f01724e2';
|
||||
|
||||
/// See also [genColorScheme].
|
||||
|
||||
@@ -510,6 +510,17 @@ OverrideData? getProfileOverrideData(Ref ref, String profileId) {
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
VM2? layoutChange(Ref ref) {
|
||||
final viewWidth = ref.watch(viewWidthProvider);
|
||||
final textScale =
|
||||
ref.watch(themeSettingProvider.select((state) => state.textScale));
|
||||
return VM2(
|
||||
a: viewWidth,
|
||||
b: textScale,
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
ColorScheme genColorScheme(
|
||||
Ref ref,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:fl_clash/clash/clash.dart';
|
||||
@@ -22,8 +21,8 @@ typedef UpdateTasks = List<FutureOr Function()>;
|
||||
|
||||
class GlobalState {
|
||||
static GlobalState? _instance;
|
||||
Map<Key, double> cacheScrollPosition = {};
|
||||
Map<Key, FixedMap<String, double>> cacheHeightMap = {};
|
||||
Map<CacheTag, double> cacheScrollPosition = {};
|
||||
Map<CacheTag, FixedMap<String, double>> cacheHeightMap = {};
|
||||
bool isService = false;
|
||||
Timer? timer;
|
||||
Timer? groupsUpdateTimer;
|
||||
@@ -53,11 +52,13 @@ class GlobalState {
|
||||
}
|
||||
|
||||
initApp(int version) async {
|
||||
coreSHA256 = const String.fromEnvironment("CORE_SHA256");
|
||||
isPre = const String.fromEnvironment("APP_ENV") != 'stable';
|
||||
appState = AppState(
|
||||
version: version,
|
||||
viewSize: Size.zero,
|
||||
requests: FixedList(500),
|
||||
logs: FixedList(500),
|
||||
requests: FixedList(maxLength),
|
||||
logs: FixedList(maxLength),
|
||||
traffics: FixedList(30),
|
||||
totalTraffic: Traffic(),
|
||||
);
|
||||
|
||||
@@ -257,7 +257,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
leading: leading ?? this.leading,
|
||||
horizontalTitleGap: horizontalTitleGap,
|
||||
title: title,
|
||||
minTileHeight: 52,
|
||||
minVerticalPadding: 12,
|
||||
subtitle: subtitle,
|
||||
titleAlignment: tileTitleAlignment,
|
||||
onTap: onTap,
|
||||
|
||||
@@ -16,7 +16,7 @@ class TextScaleNotification extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer(
|
||||
builder: (_, ref, __) {
|
||||
builder: (_, ref, child) {
|
||||
ref.listen(
|
||||
themeSettingProvider.select((state) => state.textScale),
|
||||
(prev, next) {
|
||||
@@ -25,7 +25,7 @@ class TextScaleNotification extends StatelessWidget {
|
||||
}
|
||||
},
|
||||
);
|
||||
return child;
|
||||
return child!;
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -53,13 +54,13 @@ class ScrollToEndBox<T> extends StatefulWidget {
|
||||
final ScrollController controller;
|
||||
final List<T> dataSource;
|
||||
final Widget child;
|
||||
final Key cacheKey;
|
||||
final CacheTag tag;
|
||||
|
||||
const ScrollToEndBox({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.controller,
|
||||
required this.cacheKey,
|
||||
required this.tag,
|
||||
required this.dataSource,
|
||||
});
|
||||
|
||||
@@ -72,8 +73,7 @@ class _ScrollToEndBoxState<T> extends State<ScrollToEndBox<T>> {
|
||||
|
||||
_handleTryToEnd() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final double offset =
|
||||
globalState.cacheScrollPosition[widget.cacheKey] ?? -1;
|
||||
final double offset = globalState.cacheScrollPosition[widget.tag] ?? -1;
|
||||
if (offset < 0) {
|
||||
widget.controller.animateTo(
|
||||
duration: kThemeAnimationDuration,
|
||||
@@ -94,13 +94,12 @@ class _ScrollToEndBoxState<T> extends State<ScrollToEndBox<T>> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NotificationListener<ScrollNotification>(
|
||||
return NotificationListener<UserScrollNotification>(
|
||||
onNotification: (details) {
|
||||
double offset =
|
||||
globalState.cacheScrollPosition[widget.tag] =
|
||||
details.metrics.pixels == details.metrics.maxScrollExtent
|
||||
? -1
|
||||
: details.metrics.pixels;
|
||||
globalState.cacheScrollPosition[widget.cacheKey] = offset;
|
||||
return false;
|
||||
},
|
||||
child: widget.child,
|
||||
@@ -117,6 +116,7 @@ class CacheItemExtentListView extends StatefulWidget {
|
||||
final bool shrinkWrap;
|
||||
final bool reverse;
|
||||
final ScrollController controller;
|
||||
final CacheTag tag;
|
||||
|
||||
const CacheItemExtentListView({
|
||||
super.key,
|
||||
@@ -128,6 +128,7 @@ class CacheItemExtentListView extends StatefulWidget {
|
||||
required this.keyBuilder,
|
||||
required this.itemCount,
|
||||
required this.itemExtentBuilder,
|
||||
required this.tag,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -136,21 +137,19 @@ class CacheItemExtentListView extends StatefulWidget {
|
||||
}
|
||||
|
||||
class CacheItemExtentListViewState extends State<CacheItemExtentListView> {
|
||||
late final FixedMap<String, double> _cacheHeightMap;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_cacheHeightMap = FixedMap(widget.itemCount);
|
||||
_updateCacheHeightMap();
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
_cacheHeightMap.clear();
|
||||
_updateCacheHeightMap() {
|
||||
globalState.cacheHeightMap[widget.tag]?.updateMaxLength(widget.itemCount);
|
||||
globalState.cacheHeightMap[widget.tag] ??= FixedMap(widget.itemCount);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_cacheHeightMap.updateMaxSize(widget.itemCount);
|
||||
return ListView.builder(
|
||||
itemBuilder: widget.itemBuilder,
|
||||
itemCount: widget.itemCount,
|
||||
@@ -159,20 +158,14 @@ class CacheItemExtentListViewState extends State<CacheItemExtentListView> {
|
||||
shrinkWrap: widget.shrinkWrap,
|
||||
controller: widget.controller,
|
||||
itemExtentBuilder: (index, __) {
|
||||
final key = widget.keyBuilder(index);
|
||||
if (_cacheHeightMap.containsKey(key)) {
|
||||
return _cacheHeightMap.get(key);
|
||||
}
|
||||
return _cacheHeightMap.put(key, widget.itemExtentBuilder(index));
|
||||
_updateCacheHeightMap();
|
||||
return globalState.cacheHeightMap[widget.tag]?.updateCacheValue(
|
||||
widget.keyBuilder(index),
|
||||
() => widget.itemExtentBuilder(index),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cacheHeightMap.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class CacheItemExtentSliverReorderableList extends StatefulWidget {
|
||||
@@ -182,6 +175,7 @@ class CacheItemExtentSliverReorderableList extends StatefulWidget {
|
||||
final double Function(int index) itemExtentBuilder;
|
||||
final ReorderCallback onReorder;
|
||||
final ReorderItemProxyDecorator? proxyDecorator;
|
||||
final CacheTag tag;
|
||||
|
||||
const CacheItemExtentSliverReorderableList({
|
||||
super.key,
|
||||
@@ -191,6 +185,7 @@ class CacheItemExtentSliverReorderableList extends StatefulWidget {
|
||||
required this.itemExtentBuilder,
|
||||
required this.onReorder,
|
||||
this.proxyDecorator,
|
||||
required this.tag,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -200,30 +195,24 @@ class CacheItemExtentSliverReorderableList extends StatefulWidget {
|
||||
|
||||
class CacheItemExtentSliverReorderableListState
|
||||
extends State<CacheItemExtentSliverReorderableList> {
|
||||
late final FixedMap<String, double> _cacheHeightMap;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_cacheHeightMap = FixedMap(widget.itemCount);
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
_cacheHeightMap.clear();
|
||||
globalState.cacheHeightMap[widget.tag]?.updateMaxLength(widget.itemCount);
|
||||
globalState.cacheHeightMap[widget.tag] ??= FixedMap(widget.itemCount);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_cacheHeightMap.updateMaxSize(widget.itemCount);
|
||||
globalState.cacheHeightMap[widget.tag]?.updateMaxLength(widget.itemCount);
|
||||
return SliverReorderableList(
|
||||
itemBuilder: widget.itemBuilder,
|
||||
itemCount: widget.itemCount,
|
||||
itemExtentBuilder: (index, __) {
|
||||
final key = widget.keyBuilder(index);
|
||||
if (_cacheHeightMap.containsKey(key)) {
|
||||
return _cacheHeightMap.get(key);
|
||||
}
|
||||
return _cacheHeightMap.put(key, widget.itemExtentBuilder(index));
|
||||
return globalState.cacheHeightMap[widget.tag]?.updateCacheValue(
|
||||
widget.keyBuilder(index),
|
||||
() => widget.itemExtentBuilder(index),
|
||||
);
|
||||
},
|
||||
onReorder: widget.onReorder,
|
||||
proxyDecorator: widget.proxyDecorator,
|
||||
@@ -232,7 +221,6 @@ class CacheItemExtentSliverReorderableListState
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cacheHeightMap.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Submodule plugins/flutter_distributor updated: 9daab581b0...cdeeef2d8f
@@ -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.8.83+202504281
|
||||
version: 0.8.84+202505013
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@ static PROCESS: Lazy<Arc<Mutex<Option<std::process::Child>>>> =
|
||||
Lazy::new(|| Arc::new(Mutex::new(None)));
|
||||
|
||||
fn start(start_params: StartParams) -> impl Reply {
|
||||
if sha256_file(start_params.path.as_str()).unwrap_or("".to_string()) != env!("TOKEN") {
|
||||
return "Only FlClashCore is allowed to run.".to_string();
|
||||
let sha256 = sha256_file(start_params.path.as_str()).unwrap_or("".to_string());
|
||||
if sha256 != env!("TOKEN") {
|
||||
return format!("The SHA256 hash of the program requesting execution is: {}. The helper program only allows execution of applications with the SHA256 hash: {}.", sha256, env!("TOKEN"),);
|
||||
}
|
||||
stop();
|
||||
let mut process = PROCESS.lock().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user