nc-photos/app/lib/entity/album/provider.dart

312 lines
7.7 KiB
Dart
Raw Normal View History

2021-06-24 18:26:56 +02:00
import 'dart:collection';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/entity/album.dart';
2021-07-05 09:54:01 +02:00
import 'package:nc_photos/entity/album/item.dart';
import 'package:nc_photos/entity/file.dart';
2022-01-29 12:31:32 +01:00
import 'package:nc_photos/entity/tag.dart';
2021-06-24 18:26:56 +02:00
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/or_null.dart';
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
import 'package:np_common/type.dart';
2022-12-08 16:39:13 +01:00
import 'package:to_string/to_string.dart';
part 'provider.g.dart';
2021-06-24 18:26:56 +02:00
2022-12-16 16:01:04 +01:00
@npLog
2021-06-24 18:26:56 +02:00
abstract class AlbumProvider with EquatableMixin {
const AlbumProvider();
2021-08-06 19:11:00 +02:00
factory AlbumProvider.fromJson(JsonObj json) {
2021-06-24 18:26:56 +02:00
final type = json["type"];
final content = json["content"];
switch (type) {
case AlbumStaticProvider._type:
return AlbumStaticProvider.fromJson(content.cast<String, dynamic>());
case AlbumDirProvider._type:
return AlbumDirProvider.fromJson(content.cast<String, dynamic>());
2022-01-29 12:31:32 +01:00
case AlbumTagProvider._type:
return AlbumTagProvider.fromJson(content.cast<String, dynamic>());
2021-06-24 18:26:56 +02:00
default:
_log.shout("[fromJson] Unknown type: $type");
throw ArgumentError.value(type, "type");
}
}
2021-08-06 19:11:00 +02:00
JsonObj toJson() {
2021-06-24 18:26:56 +02:00
String getType() {
if (this is AlbumStaticProvider) {
return AlbumStaticProvider._type;
} else if (this is AlbumDirProvider) {
return AlbumDirProvider._type;
2022-01-29 12:31:32 +01:00
} else if (this is AlbumTagProvider) {
return AlbumTagProvider._type;
2021-06-24 18:26:56 +02:00
} else {
throw StateError("Unknwon subtype");
}
}
return {
"type": getType(),
2021-06-27 17:35:40 +02:00
"content": toContentJson(),
2021-06-24 18:26:56 +02:00
};
}
2021-06-27 17:35:40 +02:00
@protected
2021-08-06 19:11:00 +02:00
JsonObj toContentJson();
2021-06-27 17:35:40 +02:00
2021-06-24 18:26:56 +02:00
@override
2022-12-08 16:39:13 +01:00
String toString({bool isDeep = false});
2021-06-24 18:26:56 +02:00
2021-06-27 17:35:40 +02:00
/// Return the date time associated with the latest item, or null
2021-07-23 22:05:57 +02:00
DateTime? get latestItemTime;
2021-06-27 17:35:40 +02:00
AlbumProvider copyWith();
2021-06-24 18:26:56 +02:00
2022-12-20 17:49:14 +01:00
static final _log = _$AlbumProviderNpLog.log;
2021-06-24 18:26:56 +02:00
}
abstract class AlbumProviderBase extends AlbumProvider {
AlbumProviderBase({
DateTime? latestItemTime,
}) : latestItemTime = latestItemTime?.toUtc();
@override
toContentJson() {
return {
if (latestItemTime != null)
"latestItemTime": latestItemTime!.toUtc().toIso8601String(),
};
}
@override
AlbumProviderBase copyWith({
OrNull<DateTime>? latestItemTime,
});
@override
get props => [
latestItemTime,
];
@override
final DateTime? latestItemTime;
}
2022-12-08 16:39:13 +01:00
@ToString(extraParams: r"{bool isDeep = false}")
class AlbumStaticProvider extends AlbumProviderBase {
2021-06-24 18:26:56 +02:00
AlbumStaticProvider({
DateTime? latestItemTime,
2021-07-23 22:05:57 +02:00
required List<AlbumItem> items,
}) : items = UnmodifiableListView(items),
super(
latestItemTime: latestItemTime,
);
2021-06-24 18:26:56 +02:00
2021-08-06 19:11:00 +02:00
factory AlbumStaticProvider.fromJson(JsonObj json) {
2021-06-24 18:26:56 +02:00
return AlbumStaticProvider(
latestItemTime: json["latestItemTime"] == null
? null
: DateTime.parse(json["latestItemTime"]),
2021-06-24 18:26:56 +02:00
items: (json["items"] as List)
.map((e) => AlbumItem.fromJson(e.cast<String, dynamic>()))
.toList(),
);
}
factory AlbumStaticProvider.of(Album parent) =>
(parent.provider as AlbumStaticProvider);
2021-06-24 18:26:56 +02:00
@override
2022-12-08 16:39:13 +01:00
String toString({bool isDeep = false}) => _$toString(isDeep: isDeep);
2021-06-24 18:26:56 +02:00
2021-06-27 17:35:40 +02:00
@override
toContentJson() {
return {
...super.toContentJson(),
2021-06-27 17:35:40 +02:00
"items": items.map((e) => e.toJson()).toList(),
};
}
@override
2021-07-23 22:05:57 +02:00
AlbumStaticProvider copyWith({
OrNull<DateTime>? latestItemTime,
2021-07-23 22:05:57 +02:00
List<AlbumItem>? items,
}) {
2021-06-27 17:35:40 +02:00
return AlbumStaticProvider(
latestItemTime:
latestItemTime == null ? this.latestItemTime : latestItemTime.obj,
items: items ?? List.of(this.items),
2021-06-27 17:35:40 +02:00
);
}
2021-06-24 18:26:56 +02:00
@override
get props => [
...super.props,
2021-06-24 18:26:56 +02:00
items,
];
2021-06-27 17:35:40 +02:00
/// Immutable list of items. Modifying the list will result in an error
2022-12-08 16:39:13 +01:00
@Format(r"${isDeep ? $?.toReadableString() : '[length: ${$?.length}]'}")
2021-06-27 17:35:40 +02:00
final List<AlbumItem> items;
static const _type = "static";
}
abstract class AlbumDynamicProvider extends AlbumProviderBase {
AlbumDynamicProvider({
2021-07-23 22:05:57 +02:00
DateTime? latestItemTime,
}) : super(latestItemTime: latestItemTime);
2021-06-24 18:26:56 +02:00
}
2022-12-08 16:39:13 +01:00
@ToString(extraParams: r"{bool isDeep = false}")
2021-06-27 17:35:40 +02:00
class AlbumDirProvider extends AlbumDynamicProvider {
AlbumDirProvider({
2021-07-23 22:05:57 +02:00
required this.dirs,
DateTime? latestItemTime,
}) : super(
latestItemTime: latestItemTime,
);
2021-08-06 19:11:00 +02:00
factory AlbumDirProvider.fromJson(JsonObj json) {
return AlbumDirProvider(
2021-06-27 17:35:40 +02:00
latestItemTime: json["latestItemTime"] == null
? null
: DateTime.parse(json["latestItemTime"]),
dirs: (json["dirs"] as List)
.map((e) => File.fromJson(e.cast<String, dynamic>()))
.toList(),
);
}
@override
2022-12-08 16:39:13 +01:00
String toString({bool isDeep = false}) => _$toString(isDeep: isDeep);
@override
2021-06-27 17:35:40 +02:00
toContentJson() {
return {
2021-06-27 17:35:40 +02:00
...super.toContentJson(),
"dirs": dirs.map((e) => e.toJson()).toList(),
};
}
2021-06-27 17:35:40 +02:00
@override
AlbumDirProvider copyWith({
OrNull<DateTime>? latestItemTime,
List<File>? dirs,
2021-06-27 17:35:40 +02:00
}) {
return AlbumDirProvider(
latestItemTime:
latestItemTime == null ? this.latestItemTime : latestItemTime.obj,
dirs: dirs ?? List.of(this.dirs),
2021-06-27 17:35:40 +02:00
);
}
@override
get props => [
...super.props,
dirs,
];
2022-12-08 16:39:13 +01:00
@Format(r"${$?.map((e) => e.path).toReadableString()}")
final List<File> dirs;
static const _type = "dir";
}
2022-01-15 11:35:15 +01:00
2022-12-08 16:39:13 +01:00
@ToString(extraParams: r"{bool isDeep = false}")
2022-01-29 12:31:32 +01:00
class AlbumTagProvider extends AlbumDynamicProvider {
AlbumTagProvider({
required this.tags,
DateTime? latestItemTime,
}) : super(latestItemTime: latestItemTime);
factory AlbumTagProvider.fromJson(JsonObj json) => AlbumTagProvider(
latestItemTime: json["latestItemTime"] == null
? null
: DateTime.parse(json["latestItemTime"]),
tags: (json["tags"] as List)
.map((e) => Tag.fromJson(e.cast<String, dynamic>()))
.toList(),
);
@override
2022-12-08 16:39:13 +01:00
String toString({bool isDeep = false}) => _$toString(isDeep: isDeep);
2022-01-29 12:31:32 +01:00
@override
toContentJson() => {
...super.toContentJson(),
"tags": tags.map((t) => t.toJson()).toList(),
};
@override
AlbumTagProvider copyWith({
OrNull<DateTime>? latestItemTime,
List<Tag>? tags,
}) =>
AlbumTagProvider(
latestItemTime:
latestItemTime == null ? this.latestItemTime : latestItemTime.obj,
tags: tags ?? List.of(this.tags),
);
@override
get props => [
...super.props,
tags,
];
2022-12-08 16:39:13 +01:00
@Format(r"${$?.map((t) => t.displayName).toReadableString()}")
2022-01-29 12:31:32 +01:00
final List<Tag> tags;
static const _type = "tag";
}
2022-01-15 11:35:15 +01:00
/// Smart albums are created only by the app and not the user
abstract class AlbumSmartProvider extends AlbumProviderBase {
AlbumSmartProvider({
DateTime? latestItemTime,
}) : super(latestItemTime: latestItemTime);
@override
AlbumSmartProvider copyWith({
2022-01-15 11:35:15 +01:00
OrNull<DateTime>? latestItemTime,
}) {
// Smart albums do not support copying
throw UnimplementedError();
}
@override
toContentJson() {
// Smart albums do not support saving
throw UnimplementedError();
}
}
/// Memory album is created based on dates
2022-12-08 16:39:13 +01:00
@ToString(extraParams: r"{bool isDeep = false}")
2022-01-15 11:35:15 +01:00
class AlbumMemoryProvider extends AlbumSmartProvider {
AlbumMemoryProvider({
required this.year,
required this.month,
required this.day,
}) : super(latestItemTime: DateTime(year, month, day));
@override
2022-12-08 16:39:13 +01:00
String toString({bool isDeep = false}) => _$toString(isDeep: isDeep);
2022-01-15 11:35:15 +01:00
@override
get props => [
...super.props,
year,
month,
day,
];
final int year;
final int month;
final int day;
}