improved performance and battery usage on older devices
This commit is contained in:
@@ -1,49 +1,29 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:localstore/localstore.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../../../../api/cache_store.dart';
|
||||
import '../../../../api/marianumcloud/webdav/queries/list_files/cacheable_file.dart';
|
||||
import '../../../../api/marianumcloud/webdav/queries/list_files/list_files_response.dart';
|
||||
import '../../../../api/request_cache.dart';
|
||||
|
||||
/// Document key prefix used by `ListFilesCache._documentId`.
|
||||
const String _folderCachePrefix = 'wd-folder-';
|
||||
|
||||
/// Scans every cached folder listing in Localstore and returns files/folders
|
||||
/// whose name contains [query] (case-insensitive).
|
||||
///
|
||||
/// [pathScope] restricts results to entries whose WebDAV path starts with
|
||||
/// the given folder. Pass an empty list (or null) to search globally.
|
||||
///
|
||||
/// [docs] is an injection seam for tests — production callers leave it null
|
||||
/// so the helper reads from the real Localstore.
|
||||
Future<List<CacheableFile>> searchLocalCaches(
|
||||
String query, {
|
||||
List<String>? pathScope,
|
||||
Map<String, dynamic>? docs,
|
||||
}) async {
|
||||
final trimmed = query.trim();
|
||||
if (trimmed.isEmpty) return const [];
|
||||
final needle = trimmed.toLowerCase();
|
||||
final scopePrefix = pathScope == null || pathScope.isEmpty
|
||||
? ''
|
||||
: '${pathScope.join('/')}/';
|
||||
|
||||
final raw =
|
||||
docs ??
|
||||
await Localstore.instance.collection(RequestCache.collection).get();
|
||||
if (raw == null || raw.isEmpty) return const [];
|
||||
|
||||
final results = <String, CacheableFile>{};
|
||||
for (final entry in raw.entries) {
|
||||
final docKey = entry.key.split('/').last;
|
||||
if (!docKey.startsWith(_folderCachePrefix)) continue;
|
||||
|
||||
final value = entry.value;
|
||||
if (value is! Map) continue;
|
||||
final json = value['json'];
|
||||
if (json is! String) continue;
|
||||
/// Every file and folder from the cached folder listings, deduplicated by
|
||||
/// path. Built once per search session: reading and parsing all listings on
|
||||
/// each keystroke used to stall typing.
|
||||
Future<List<CacheableFile>> loadLocalCacheIndex() async {
|
||||
final entries = await CacheStore.instance.readAll(prefix: _folderCachePrefix);
|
||||
if (entries.isEmpty) return const [];
|
||||
final payloads = [for (final entry in entries.values) entry.json];
|
||||
return compute(buildLocalCacheIndex, payloads);
|
||||
}
|
||||
|
||||
/// Parses cached `ListFilesResponse` payloads into a deduplicated file list.
|
||||
/// Unparsable payloads are skipped.
|
||||
List<CacheableFile> buildLocalCacheIndex(List<String> payloads) {
|
||||
final byPath = <String, CacheableFile>{};
|
||||
for (final json in payloads) {
|
||||
final ListFilesResponse listing;
|
||||
try {
|
||||
listing = ListFilesResponse.fromJson(
|
||||
@@ -52,14 +32,32 @@ Future<List<CacheableFile>> searchLocalCaches(
|
||||
} on Object {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final file in listing.files) {
|
||||
if (!file.name.toLowerCase().contains(needle)) continue;
|
||||
if (scopePrefix.isNotEmpty && !file.path.startsWith(scopePrefix)) {
|
||||
continue;
|
||||
}
|
||||
results[file.path] ??= file;
|
||||
byPath[file.path] ??= file;
|
||||
}
|
||||
}
|
||||
return results.values.toList();
|
||||
return byPath.values.toList();
|
||||
}
|
||||
|
||||
/// Files in [index] whose name contains [query] (case-insensitive).
|
||||
///
|
||||
/// [pathScope] restricts results to entries whose WebDAV path starts with
|
||||
/// the given folder. Pass an empty list (or null) to search globally.
|
||||
List<CacheableFile> searchLocalCacheIndex(
|
||||
List<CacheableFile> index,
|
||||
String query, {
|
||||
List<String>? pathScope,
|
||||
}) {
|
||||
final trimmed = query.trim();
|
||||
if (trimmed.isEmpty) return const [];
|
||||
final needle = trimmed.toLowerCase();
|
||||
final scopePrefix = pathScope == null || pathScope.isEmpty
|
||||
? ''
|
||||
: '${pathScope.join('/')}/';
|
||||
return [
|
||||
for (final file in index)
|
||||
if (file.lowerName.contains(needle) &&
|
||||
(scopePrefix.isEmpty || file.path.startsWith(scopePrefix)))
|
||||
file,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user