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> 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 buildLocalCacheIndex(List payloads) { final byPath = {}; for (final json in payloads) { final ListFilesResponse listing; try { listing = ListFilesResponse.fromJson( jsonDecode(json) as Map, ); } 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 searchLocalCacheIndex( List index, String query, { List? 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, ]; }