92 lines
3.0 KiB
Dart
92 lines
3.0 KiB
Dart
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<SearchFilesEntry> entries;
|
|
|
|
SearchFilesResponse({
|
|
required this.name,
|
|
required this.isPaginated,
|
|
required this.cursor,
|
|
required this.entries,
|
|
});
|
|
|
|
factory SearchFilesResponse.fromJson(Map<String, dynamic> json) =>
|
|
_$SearchFilesResponseFromJson(json);
|
|
Map<String, dynamic> toJson() => _$SearchFilesResponseToJson(this);
|
|
}
|
|
|
|
@JsonSerializable()
|
|
class SearchFilesEntry {
|
|
final String title;
|
|
final String? subline;
|
|
final String? icon;
|
|
final String? resourceUrl;
|
|
final Map<String, dynamic>? attributes;
|
|
|
|
SearchFilesEntry({
|
|
required this.title,
|
|
this.subline,
|
|
this.icon,
|
|
this.resourceUrl,
|
|
this.attributes,
|
|
});
|
|
|
|
factory SearchFilesEntry.fromJson(Map<String, dynamic> json) =>
|
|
_$SearchFilesEntryFromJson(json);
|
|
Map<String, dynamic> 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);
|
|
}
|
|
}
|