From 69cc1aff8d64817244a8e5c4bbd3d66f2ecfbc04 Mon Sep 17 00:00:00 2001 From: wanghongenpin Date: Wed, 25 Mar 2026 01:29:50 +0800 Subject: [PATCH] refactor: enhance auto-read request management --- lib/network/util/cache.dart | 46 ++++++++++++++++++++ lib/ui/desktop/request/domians.dart | 2 +- lib/ui/desktop/request/list.dart | 9 +++- lib/ui/desktop/request/request.dart | 27 +++++++----- lib/ui/desktop/request/request_sequence.dart | 2 +- lib/utils/listenable_list.dart | 23 ++++++---- 6 files changed, 88 insertions(+), 21 deletions(-) diff --git a/lib/network/util/cache.dart b/lib/network/util/cache.dart index 338a396..3cbc6d1 100644 --- a/lib/network/util/cache.dart +++ b/lib/network/util/cache.dart @@ -69,6 +69,52 @@ class ExpiringCache { } } +/// A simple LRU (Least Recently Used) cache implementation using LinkedHashSet. +class LruCacheSet { + final int capacity; + final _cache = LinkedHashSet(); + + LruCacheSet(this.capacity); + + bool add(K key) { + bool newEntry = !_cache.contains(key); + if (!newEntry) { + // Move the accessed key to the end to show that it was recently used + _cache.remove(key); + } else if (_cache.length == capacity) { + // Remove the first key (least recently used) + _cache.remove(_cache.first); + } + _cache.add(key); + return newEntry; + } + + bool contains(K key) { + return _cache.contains(key); + } + + void remove(K key) { + _cache.remove(key); + } + + void removeAll(Iterable keys) { + for (var key in keys) { + _cache.remove(key); + } + } + + void removeWhere(bool Function(K key) test) { + _cache.removeWhere(test); + } + + int get length => _cache.length; + + void clear() { + _cache.clear(); + } +} + +/// A simple LRU (Least Recently Used) cache implementation using LinkedHashMap. class LruCache { final int capacity; final _cache = LinkedHashMap(); diff --git a/lib/ui/desktop/request/domians.dart b/lib/ui/desktop/request/domians.dart index 826a9fd..d4902c4 100644 --- a/lib/ui/desktop/request/domians.dart +++ b/lib/ui/desktop/request/domians.dart @@ -266,7 +266,7 @@ class DomainWidgetState extends State with AutomaticKeepAliveClientM } ///清理 - clean() { + void clean() { setState(() { containerMap.clear(); searchView.clear(); diff --git a/lib/ui/desktop/request/list.dart b/lib/ui/desktop/request/list.dart index f746b5e..a692b95 100644 --- a/lib/ui/desktop/request/list.dart +++ b/lib/ui/desktop/request/list.dart @@ -28,6 +28,7 @@ import 'package:proxypin/network/http/http_client.dart'; import 'package:proxypin/ui/component/widgets.dart'; import 'package:proxypin/ui/content/panel.dart'; import 'package:proxypin/ui/desktop/request/request_sequence.dart'; +import 'package:proxypin/ui/desktop/request/request.dart'; import 'package:proxypin/ui/desktop/request/search.dart'; import 'package:proxypin/utils/har.dart'; import 'package:proxypin/utils/lang.dart'; @@ -76,6 +77,7 @@ class DesktopRequestListState extends State with Autom @override void dispose() { + RequestWidget.removeAutoReadByIds(container.map((request) => request.requestId)); super.dispose(); } @@ -183,12 +185,14 @@ class DesktopRequestListState extends State with Autom void domainListRemove(List list) { container.removeWhere((element) => list.contains(element)); requestSequenceKey.currentState?.remove(list); + RequestWidget.removeAutoReadByIds(list.map((request) => request.requestId)); } ///全部请求删除 void sequenceRemove(List list) { container.removeWhere((element) => list.contains(element)); domainListKey.currentState?.remove(list); + RequestWidget.removeAutoReadByIds(list.map((request) => request.requestId)); } void search(SearchModel searchModel) { @@ -203,6 +207,7 @@ class DesktopRequestListState extends State with Autom ///清理 void clean() { setState(() { + RequestWidget.removeAutoReadByIds(container.map((request) => request.requestId)); container.clear(); domainListKey.currentState?.clean(); requestSequenceKey.currentState?.clean(); @@ -216,10 +221,12 @@ class DesktopRequestListState extends State with Autom return; } - container.removeRange(0, list.length - retain); + var removeRange = container.removeRange(0, list.length - retain); domainListKey.currentState?.clean(); requestSequenceKey.currentState?.clean(); + + RequestWidget.removeAutoReadByIds(removeRange.map((request) => request.requestId)); } ///导出 diff --git a/lib/ui/desktop/request/request.dart b/lib/ui/desktop/request/request.dart index 8d4e00c..afe489c 100644 --- a/lib/ui/desktop/request/request.dart +++ b/lib/ui/desktop/request/request.dart @@ -28,8 +28,8 @@ import 'package:proxypin/network/components/manager/script_manager.dart'; import 'package:proxypin/network/channel/host_port.dart'; import 'package:proxypin/network/http/http.dart'; import 'package:proxypin/network/http/http_client.dart'; +import 'package:proxypin/network/util/cache.dart'; import 'package:proxypin/storage/favorites.dart'; -import 'package:proxypin/ui/component/app_dialog.dart'; import 'package:proxypin/ui/component/multi_window.dart'; import 'package:proxypin/ui/component/utils.dart'; import 'package:proxypin/ui/component/widgets.dart'; @@ -74,13 +74,26 @@ class RequestWidget extends StatefulWidget { var state = key as GlobalKey<_RequestWidgetState>; state.currentState?.changeState(); } + + static void removeAutoReadByIds(Iterable requestIds) { + _RequestWidgetState.removeAutoReadByIds(requestIds); + } + } class _RequestWidgetState extends State { //选择的节点 static _RequestWidgetState? selectedState; - static Set autoReadRequests = {}; + static LruCacheSet autoReadRequests = LruCacheSet(5000); + + static bool markAutoRead(String requestId) { + return autoReadRequests.add(requestId); + } + + static void removeAutoReadByIds(Iterable requestIds) { + autoReadRequests.removeAll(requestIds); + } bool selected = false; @@ -93,12 +106,6 @@ class _RequestWidgetState extends State { super.initState(); } - @override - void dispose() { - autoReadRequests.remove(widget.request.requestId); - super.dispose(); - } - @override Widget build(BuildContext context) { var request = widget.request; @@ -118,7 +125,7 @@ class _RequestWidgetState extends State { minLeadingWidth: 5, textColor: requestColor, selectedColor: requestColor, - selectedTileColor: Theme.of(context).colorScheme.primary.withOpacity(0.1), + selectedTileColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1), leading: getIcon(widget.response.get() ?? widget.request.response, color: requestColor), trailing: widget.trailing, title: Text(title.fixAutoLines(), overflow: TextOverflow.ellipsis, maxLines: 2), @@ -408,7 +415,7 @@ class _RequestWidgetState extends State { } if (AppConfiguration.current?.autoReadEnabled == true) { - autoReadRequests.add(widget.request.requestId); + markAutoRead(widget.request.requestId); } //切换选中的节点 diff --git a/lib/ui/desktop/request/request_sequence.dart b/lib/ui/desktop/request/request_sequence.dart index 02928b6..5e58fa2 100644 --- a/lib/ui/desktop/request/request_sequence.dart +++ b/lib/ui/desktop/request/request_sequence.dart @@ -74,7 +74,7 @@ class RequestSequenceState extends State with AutomaticKeepAliv KeywordHighlights.addListener(highlightListener); } - changeState() { + void changeState() { //防止频繁刷新 if (!changing) { changing = true; diff --git a/lib/utils/listenable_list.dart b/lib/utils/listenable_list.dart index 30e7ac5..615b99c 100644 --- a/lib/utils/listenable_list.dart +++ b/lib/utils/listenable_list.dart @@ -60,13 +60,13 @@ class ListenableList extends Iterable { if (source != null) this.source = source; } - addListener(ListenerListEvent listener) { + void addListener(ListenerListEvent listener) { if (_listeners.contains(listener)) return; listener.sourceAware(source); _listeners.add(listener); } - removeListener(ListenerListEvent listener) { + void removeListener(ListenerListEvent listener) { _listeners.remove(listener); } @@ -85,21 +85,28 @@ class ListenableList extends Iterable { return source.sublist(start, end); } - void removeRange(start, end) { - source.removeRange(start, end > source.length ? source.length : end); + List removeRange(int start, int end) { + final normalizedEnd = end > source.length ? source.length : end; + if (start < 0 || start >= normalizedEnd) { + return []; + } + + final removed = source.sublist(start, normalizedEnd); + source.removeRange(start, normalizedEnd); for (var element in _listeners) { element.clear(); } + return removed; } - update(int index, T item) { + void update(int index, T item) { source[index] = item; for (var element in _listeners) { element.onUpdate(item); } } - add(T item) { + void add(T item) { source.add(item); for (var element in _listeners) { element.onAdd(item); @@ -126,14 +133,14 @@ class ListenableList extends Iterable { return item; } - clear() { + void clear() { source.clear(); for (var element in _listeners) { element.clear(); } } - removeWhere(bool Function(T element) test) { + void removeWhere(bool Function(T element) test) { var list = []; source.removeWhere((it) { if (test.call(it)) {