diff --git a/lib/services/sync/webdav_service.dart b/lib/services/sync/webdav_service.dart index ec872b2..3c38a0c 100644 --- a/lib/services/sync/webdav_service.dart +++ b/lib/services/sync/webdav_service.dart @@ -53,6 +53,9 @@ class WebDAVService { // 默认自动同步间隔(分钟) static const int _defaultAutoSyncInterval = 5; + // HTTP 请求超时 + static const Duration _httpTimeout = Duration(seconds: 30); + Map? _cachedConfig; Timer? _autoSyncTimer; bool _isAutoSyncEnabled = false; @@ -426,7 +429,7 @@ class WebDAVService { request.headers['Content-Type'] = 'application/zip'; request.bodyBytes = bytes; - var response = await client.send(request); + var response = await client.send(request).timeout(_httpTimeout); // 处理重定向 if (response.statusCode == 301 || response.statusCode == 302 || @@ -437,7 +440,7 @@ class WebDAVService { request.headers['Authorization'] = _basicAuth(username, password); request.headers['Content-Type'] = 'application/zip'; request.bodyBytes = bytes; - response = await client.send(request); + response = await client.send(request).timeout(_httpTimeout); } } @@ -461,7 +464,7 @@ class WebDAVService { var request = http.Request('GET', Uri.parse(url)); request.headers['Authorization'] = _basicAuth(username, password); - var response = await client.send(request); + var response = await client.send(request).timeout(_httpTimeout); // 处理重定向 if (response.statusCode == 301 || response.statusCode == 302 || @@ -470,7 +473,7 @@ class WebDAVService { if (location != null) { request = http.Request('GET', Uri.parse(location)); request.headers['Authorization'] = _basicAuth(username, password); - response = await client.send(request); + response = await client.send(request).timeout(_httpTimeout); } } @@ -508,7 +511,7 @@ class WebDAVService { var request = http.Request('HEAD', Uri.parse(zipUrl)); request.headers['Authorization'] = _basicAuth(username, password); - var response = await client.send(request); + var response = await client.send(request).timeout(_httpTimeout); // 处理重定向 if (response.statusCode == 301 || response.statusCode == 302 || @@ -517,7 +520,7 @@ class WebDAVService { if (location != null) { request = http.Request('HEAD', Uri.parse(location)); request.headers['Authorization'] = _basicAuth(username, password); - response = await client.send(request); + response = await client.send(request).timeout(_httpTimeout); } } @@ -551,7 +554,7 @@ class WebDAVService { var request = http.Request('HEAD', Uri.parse(url)); request.headers['Authorization'] = _basicAuth(username, password); - var response = await client.send(request); + var response = await client.send(request).timeout(_httpTimeout); // 处理重定向 if (response.statusCode == 301 || response.statusCode == 302 || @@ -560,7 +563,7 @@ class WebDAVService { if (location != null) { request = http.Request('HEAD', Uri.parse(location)); request.headers['Authorization'] = _basicAuth(username, password); - response = await client.send(request); + response = await client.send(request).timeout(_httpTimeout); } } diff --git a/lib/widgets/custom_drawer.dart b/lib/widgets/custom_drawer.dart index 2e8f37e..13d0713 100644 --- a/lib/widgets/custom_drawer.dart +++ b/lib/widgets/custom_drawer.dart @@ -30,16 +30,40 @@ class _CustomDrawerState extends State { String _version = '0.1.5'; // 热力图缓存 - List? _cachedMovies; - List? _cachedBooks; - List? _cachedNotes; - List? _cachedGames; + int _cachedMoviesHash = 0; + int _cachedBooksHash = 0; + int _cachedNotesHash = 0; + int _cachedGamesHash = 0; Map? _cachedDailyCounts; int? _cachedMaxCount; // 最近添加缓存 List<_RecentItem>? _cachedRecentItems; + /// 用列表长度 + 首末元素ID生成轻量哈希,避免 identical() 在 Provider 返回新实例时永远失败 + int _listHash(List list) { + if (list.isEmpty) return 0; + final first = list.first; + final last = list.last; + return Object.hash(list.length, first, last); + } + + bool _isHeatmapCacheValid(List movies, List books, List notes, List games) { + return _cachedDailyCounts != null && + _cachedMoviesHash == _listHash(movies) && + _cachedBooksHash == _listHash(books) && + _cachedNotesHash == _listHash(notes) && + _cachedGamesHash == _listHash(games); + } + + bool _isRecentCacheValid(List movies, List books, List notes, List games) { + return _cachedRecentItems != null && + _cachedMoviesHash == _listHash(movies) && + _cachedBooksHash == _listHash(books) && + _cachedNotesHash == _listHash(notes) && + _cachedGamesHash == _listHash(games); + } + @override void initState() { super.initState(); @@ -264,11 +288,7 @@ class _CustomDrawerState extends State { // ─── 热力图缓存计算 ─── (int, Map) _computeDailyCounts(List movies, List books, List notes, List games) { - if (identical(movies, _cachedMovies) && - identical(books, _cachedBooks) && - identical(notes, _cachedNotes) && - identical(games, _cachedGames) && - _cachedDailyCounts != null) { + if (_isHeatmapCacheValid(movies, books, notes, games)) { return (_cachedMaxCount!, _cachedDailyCounts!); } @@ -296,21 +316,17 @@ class _CustomDrawerState extends State { } if (maxCount == 0) maxCount = 1; - _cachedMovies = movies; - _cachedBooks = books; - _cachedNotes = notes; - _cachedGames = games; + _cachedMoviesHash = _listHash(movies); + _cachedBooksHash = _listHash(books); + _cachedNotesHash = _listHash(notes); + _cachedGamesHash = _listHash(games); _cachedDailyCounts = dailyCounts; _cachedMaxCount = maxCount; return (maxCount, dailyCounts); } List<_RecentItem> _computeRecentItems(List movies, List books, List notes, List games) { - if (identical(movies, _cachedMovies) && - identical(books, _cachedBooks) && - identical(notes, _cachedNotes) && - identical(games, _cachedGames) && - _cachedRecentItems != null) { + if (_isRecentCacheValid(movies, books, notes, games)) { return _cachedRecentItems!; } @@ -329,6 +345,10 @@ class _CustomDrawerState extends State { } items.sort((a, b) => b.date.compareTo(a.date)); + _cachedMoviesHash = _listHash(movies); + _cachedBooksHash = _listHash(books); + _cachedNotesHash = _listHash(notes); + _cachedGamesHash = _listHash(games); _cachedRecentItems = items; return items; }