import 'package:json_annotation/json_annotation.dart'; import '../webdav/queries/list_files/cacheable_file.dart'; part 'search_files_response.g.dart'; /// Subset of the OCS Search Provider API response we actually consume. /// The provider (`files`) returns one object per match plus pagination state. @JsonSerializable(explicitToJson: true) class SearchFilesResponse { final String name; final bool isPaginated; final int? cursor; final List entries; SearchFilesResponse({ required this.name, required this.isPaginated, required this.cursor, required this.entries, }); factory SearchFilesResponse.fromJson(Map json) => _$SearchFilesResponseFromJson(json); Map toJson() => _$SearchFilesResponseToJson(this); } @JsonSerializable() class SearchFilesEntry { final String title; final String? subline; final String? icon; final String? resourceUrl; final Map? attributes; SearchFilesEntry({ required this.title, this.subline, this.icon, this.resourceUrl, this.attributes, }); factory SearchFilesEntry.fromJson(Map json) => _$SearchFilesEntryFromJson(json); Map toJson() => _$SearchFilesEntryToJson(this); /// Heuristic — the files provider sets icon classes containing "folder" for /// directories. Falls back to false when missing or unrecognised. bool get isDirectory => (icon ?? '').toLowerCase().contains('folder'); String? _stringAttribute(String key) { final raw = attributes?[key]; return raw is String && raw.isNotEmpty ? raw : null; } String? _dirFromResourceUrl() { final url = resourceUrl; if (url == null) return null; return Uri.tryParse(url)?.queryParameters['dir']; } /// Reconstructs the WebDAV-relative path used elsewhere (matching /// [CacheableFile.path] — no leading slash, trailing slash for /// directories). Prefers the explicit `path` attribute set by Nextcloud's /// files search provider (28+); falls back to the `dir` query parameter /// in [resourceUrl]. Returns `null` when neither is available — `subline` /// is intentionally **not** parsed because it is localized UI text /// ("in {folder}"), not a path, and using it produced bogus duplicate /// folder headers like "/in Alte-Notebooks". String? get webdavPath { final attrPath = _stringAttribute('path'); if (attrPath != null) { final stripped = attrPath.replaceAll(RegExp(r'^/+|/+$'), ''); return isDirectory ? '$stripped/' : stripped; } final dir = _dirFromResourceUrl(); if (dir != null) { final stripped = dir.replaceAll(RegExp(r'^/+|/+$'), ''); final base = stripped.isEmpty ? title : '$stripped/$title'; return isDirectory ? '$base/' : base; } return null; } CacheableFile? toCacheable() { final path = webdavPath; if (path == null) return null; return CacheableFile(path: path, isDirectory: isDirectory, name: title); } }