refactor: enhance auto-read request management

This commit is contained in:
wanghongenpin
2026-03-25 01:29:50 +08:00
parent c706174894
commit 69cc1aff8d
6 changed files with 88 additions and 21 deletions

View File

@@ -69,6 +69,52 @@ class ExpiringCache<K, V> {
}
}
/// A simple LRU (Least Recently Used) cache implementation using LinkedHashSet.
class LruCacheSet<K> {
final int capacity;
final _cache = LinkedHashSet<K>();
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<K> 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<K, V> {
final int capacity;
final _cache = LinkedHashMap<K, V>();

View File

@@ -266,7 +266,7 @@ class DomainWidgetState extends State<DomainList> with AutomaticKeepAliveClientM
}
///清理
clean() {
void clean() {
setState(() {
containerMap.clear();
searchView.clear();

View File

@@ -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<DesktopRequestListWidget> with Autom
@override
void dispose() {
RequestWidget.removeAutoReadByIds(container.map((request) => request.requestId));
super.dispose();
}
@@ -183,12 +185,14 @@ class DesktopRequestListState extends State<DesktopRequestListWidget> with Autom
void domainListRemove(List<HttpRequest> list) {
container.removeWhere((element) => list.contains(element));
requestSequenceKey.currentState?.remove(list);
RequestWidget.removeAutoReadByIds(list.map((request) => request.requestId));
}
///全部请求删除
void sequenceRemove(List<HttpRequest> 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<DesktopRequestListWidget> 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<DesktopRequestListWidget> 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));
}
///导出

View File

@@ -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<String> requestIds) {
_RequestWidgetState.removeAutoReadByIds(requestIds);
}
}
class _RequestWidgetState extends State<RequestWidget> {
//选择的节点
static _RequestWidgetState? selectedState;
static Set<String> autoReadRequests = <String>{};
static LruCacheSet<String> autoReadRequests = LruCacheSet<String>(5000);
static bool markAutoRead(String requestId) {
return autoReadRequests.add(requestId);
}
static void removeAutoReadByIds(Iterable<String> requestIds) {
autoReadRequests.removeAll(requestIds);
}
bool selected = false;
@@ -93,12 +106,6 @@ class _RequestWidgetState extends State<RequestWidget> {
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<RequestWidget> {
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<RequestWidget> {
}
if (AppConfiguration.current?.autoReadEnabled == true) {
autoReadRequests.add(widget.request.requestId);
markAutoRead(widget.request.requestId);
}
//切换选中的节点

View File

@@ -74,7 +74,7 @@ class RequestSequenceState extends State<RequestSequence> with AutomaticKeepAliv
KeywordHighlights.addListener(highlightListener);
}
changeState() {
void changeState() {
//防止频繁刷新
if (!changing) {
changing = true;

View File

@@ -60,13 +60,13 @@ class ListenableList<T> extends Iterable<T> {
if (source != null) this.source = source;
}
addListener(ListenerListEvent<T> listener) {
void addListener(ListenerListEvent<T> listener) {
if (_listeners.contains(listener)) return;
listener.sourceAware(source);
_listeners.add(listener);
}
removeListener(ListenerListEvent<T> listener) {
void removeListener(ListenerListEvent<T> listener) {
_listeners.remove(listener);
}
@@ -85,21 +85,28 @@ class ListenableList<T> extends Iterable<T> {
return source.sublist(start, end);
}
void removeRange(start, end) {
source.removeRange(start, end > source.length ? source.length : end);
List<T> removeRange(int start, int end) {
final normalizedEnd = end > source.length ? source.length : end;
if (start < 0 || start >= normalizedEnd) {
return <T>[];
}
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<T> extends Iterable<T> {
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 = <T>[];
source.removeWhere((it) {
if (test.call(it)) {