import 'package:equatable/equatable.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/type.dart'; abstract class AlbumItem with EquatableMixin { AlbumItem({ required this.addedBy, required DateTime addedAt, }) : addedAt = addedAt.toUtc(); factory AlbumItem.fromJson(JsonObj json) { final addedBy = CiString(json["addedBy"]); final addedAt = DateTime.parse(json["addedAt"]); final type = json["type"]; final content = json["content"]; switch (type) { case AlbumFileItem._type: return AlbumFileItem.fromJson( content.cast(), addedBy, addedAt); case AlbumLabelItem._type: return AlbumLabelItem.fromJson( content.cast(), addedBy, addedAt); default: _log.shout("[fromJson] Unknown type: $type"); throw ArgumentError.value(type, "type"); } } JsonObj toJson() { String getType() { if (this is AlbumFileItem) { return AlbumFileItem._type; } else if (this is AlbumLabelItem) { return AlbumLabelItem._type; } else { throw StateError("Unknwon subtype"); } } return { "type": getType(), "content": toContentJson(), "addedBy": addedBy.toString(), "addedAt": addedAt.toIso8601String(), }; } JsonObj toContentJson(); @override toString() { return "$runtimeType {" "addedBy: '$addedBy', " "addedAt: $addedAt, " "}"; } @override get props => [ addedBy, addedAt, ]; final CiString addedBy; final DateTime addedAt; static final _log = Logger("entity.album.AlbumItem"); } class AlbumFileItem extends AlbumItem { AlbumFileItem({ required CiString addedBy, required DateTime addedAt, required this.file, }) : super(addedBy: addedBy, addedAt: addedAt); @override // ignore: hash_and_equals bool operator ==(Object? other) => equals(other, isDeep: true); bool equals(Object? other, {bool isDeep = false}) { if (other is AlbumFileItem) { return super == other && (file.equals(other.file, isDeep: isDeep)); } else { return false; } } factory AlbumFileItem.fromJson( JsonObj json, CiString addedBy, DateTime addedAt) { return AlbumFileItem( addedBy: addedBy, addedAt: addedAt, file: File.fromJson(json["file"].cast()), ); } @override toString() { return "$runtimeType {" "super: ${super.toString()}, " "file: $file, " "}"; } @override toContentJson() { return { "file": file.toJson(), }; } AlbumFileItem copyWith({ CiString? addedBy, DateTime? addedAt, File? file, }) { return AlbumFileItem( addedBy: addedBy ?? this.addedBy, addedAt: addedAt ?? this.addedAt, file: file ?? this.file, ); } AlbumFileItem minimize() => AlbumFileItem( addedBy: addedBy, addedAt: addedAt, file: file.copyWith(metadata: OrNull(null)), ); @override get props => [ ...super.props, // file is handled separately, see [equals] ]; final File file; static const _type = "file"; } class AlbumLabelItem extends AlbumItem { AlbumLabelItem({ required CiString addedBy, required DateTime addedAt, required this.text, }) : super(addedBy: addedBy, addedAt: addedAt); factory AlbumLabelItem.fromJson( JsonObj json, CiString addedBy, DateTime addedAt) { return AlbumLabelItem( addedBy: addedBy, addedAt: addedAt, text: json["text"], ); } @override toString() { return "$runtimeType {" "super: ${super.toString()}, " "text: '$text', " "}"; } @override toContentJson() { return { "text": text, }; } AlbumLabelItem copyWith({ CiString? addedBy, DateTime? addedAt, String? text, }) { return AlbumLabelItem( addedBy: addedBy ?? this.addedBy, addedAt: addedAt ?? this.addedAt, text: text ?? this.text, ); } @override get props => [ ...super.props, text, ]; final String text; static const _type = "label"; }