64 lines
2.1 KiB
Dart
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,
|
|
];
|
|
}
|