diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-20 14:05:21 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-20 14:05:21 +0300 |
| commit | b7b2d404d035f4d83a5f3a2dc66055551dd022d3 (patch) | |
| tree | fee3ac53bab0ed6fa294bb90334022393e97e624 /player-android/lib | |
| parent | 67c90f9b9a7a861e0f6ab0f199d66cd411948fab (diff) | |
Fix PlayerApiClient const constructor and Media.tags deserialization (d9+e9)
- Remove const from PlayerApiClient constructor (Uri is not const-constructable)
- Replace .cast<String>() with .whereType<String>().toList() in Media.fromJson
to silently drop non-string and null tag elements instead of throwing TypeError
- Add regression test: tags [1, 'valid', null] deserialized as ['valid']
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diffstat (limited to 'player-android/lib')
| -rw-r--r-- | player-android/lib/api/player_api_client.dart | 4 | ||||
| -rw-r--r-- | player-android/lib/models/media.dart | 5 |
2 files changed, 7 insertions, 2 deletions
diff --git a/player-android/lib/api/player_api_client.dart b/player-android/lib/api/player_api_client.dart index 3031c73..eb438f4 100644 --- a/player-android/lib/api/player_api_client.dart +++ b/player-android/lib/api/player_api_client.dart @@ -6,7 +6,9 @@ class PlayerApiClient { final Uri baseUrl; final String bearerToken; - const PlayerApiClient({required this.baseUrl, required this.bearerToken}); + // Normal (non-const) constructor: Uri is not const-constructable, so the + // constructor must not be declared const. + PlayerApiClient({required this.baseUrl, required this.bearerToken}); Future<User> bootstrap({required String username, required String password}) => throw UnimplementedError(); Future<User> login({required String username, required String password}) => throw UnimplementedError(); diff --git a/player-android/lib/models/media.dart b/player-android/lib/models/media.dart index 7330bca..19c57b8 100644 --- a/player-android/lib/models/media.dart +++ b/player-android/lib/models/media.dart @@ -10,7 +10,10 @@ class Media { const Media({required this.id, required this.setId, required this.relPath, required this.fileName, required this.absPath, required this.type, required this.duration, required this.codec, required this.resolution, required this.bitrate, required this.fileSizeBytes, required this.width, required this.height, required this.thumbnailPath, required this.playCount, this.favorite = false, this.tags = const [], this.deletedAt, this.createdAt}); - factory Media.fromJson(Map<String, dynamic> json) => Media(id: json['id'] as int? ?? 0, setId: json['set_id'] as int? ?? 0, relPath: json['rel_path'] as String? ?? '', fileName: json['file_name'] as String? ?? '', absPath: json['abs_path'] as String? ?? '', type: json['type'] as String? ?? '', duration: (json['duration'] as num?)?.toDouble() ?? 0, codec: json['codec'] as String? ?? '', resolution: json['resolution'] as String? ?? '', bitrate: json['bitrate'] as int? ?? 0, fileSizeBytes: json['file_size_bytes'] as int? ?? 0, width: json['width'] as int? ?? 0, height: json['height'] as int? ?? 0, thumbnailPath: json['thumbnail_path'] as String? ?? '', playCount: json['play_count'] as int? ?? 0, favorite: json['favorite'] as bool? ?? false, tags: (json['tags'] as List<dynamic>? ?? const []).cast<String>(), deletedAt: dateTimeFromJson(json['deleted_at']), createdAt: dateTimeFromJson(json['created_at'])); + factory Media.fromJson(Map<String, dynamic> json) => Media(id: json['id'] as int? ?? 0, setId: json['set_id'] as int? ?? 0, relPath: json['rel_path'] as String? ?? '', fileName: json['file_name'] as String? ?? '', absPath: json['abs_path'] as String? ?? '', type: json['type'] as String? ?? '', duration: (json['duration'] as num?)?.toDouble() ?? 0, codec: json['codec'] as String? ?? '', resolution: json['resolution'] as String? ?? '', bitrate: json['bitrate'] as int? ?? 0, fileSizeBytes: json['file_size_bytes'] as int? ?? 0, width: json['width'] as int? ?? 0, height: json['height'] as int? ?? 0, thumbnailPath: json['thumbnail_path'] as String? ?? '', playCount: json['play_count'] as int? ?? 0, favorite: json['favorite'] as bool? ?? false, // Safe tag deserialization: keep only elements that are already Strings, +// silently dropping ints, nulls, or other unexpected types. This tolerates +// malformed server responses without throwing a TypeError at runtime. +tags: (json['tags'] as List<dynamic>? ?? []).whereType<String>().toList(), deletedAt: dateTimeFromJson(json['deleted_at']), createdAt: dateTimeFromJson(json['created_at'])); Map<String, dynamic> toJson() => {'id': id, 'set_id': setId, 'rel_path': relPath, 'file_name': fileName, 'abs_path': absPath, 'type': type, 'duration': duration, 'codec': codec, 'resolution': resolution, 'bitrate': bitrate, 'file_size_bytes': fileSizeBytes, 'width': width, 'height': height, 'thumbnail_path': thumbnailPath, 'play_count': playCount, 'favorite': favorite, 'tags': tags, 'deleted_at': dateTimeToJson(deletedAt), 'created_at': dateTimeToJson(createdAt)}; } |
