Files
Client/lib/view/pages/files/search/local_cache_search.dart
T

64 lines
2.1 KiB
Dart

import 'dart:convert';
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';
/// Document key prefix used by `ListFilesCache._documentId`.
const String _folderCachePrefix = 'wd-folder-';
/// 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(
jsonDecode(json) as Map<String, dynamic>,
);
} on Object {
continue;
}
for (final file in listing.files) {
byPath[file.path] ??= file;
}
}
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,
];
}