Abstract album cover provider

This commit is contained in:
Ming Ming 2021-06-26 19:51:13 +08:00
parent 0e7f2462b6
commit 8e46c604a8
6 changed files with 287 additions and 10 deletions

View file

@ -7,6 +7,7 @@ import 'package:idb_sqflite/idb_sqflite.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/entity/album/cover_provider.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/album/upgrader.dart';
import 'package:nc_photos/entity/file.dart';
@ -127,6 +128,7 @@ class Album with EquatableMixin {
DateTime lastUpdated,
@required String name,
@required this.provider,
@required this.coverProvider,
this.albumFile,
}) : this.lastUpdated = (lastUpdated ?? DateTime.now()).toUtc(),
this.name = name ?? "";
@ -158,6 +160,8 @@ class Album with EquatableMixin {
name: json["name"],
provider:
AlbumProvider.fromJson(json["provider"].cast<String, dynamic>()),
coverProvider: AlbumCoverProvider.fromJson(
json["coverProvider"].cast<String, dynamic>()),
albumFile: json["albumFile"] == null
? null
: File.fromJson(json["albumFile"].cast<String, dynamic>()),
@ -170,6 +174,7 @@ class Album with EquatableMixin {
"lastUpdated: $lastUpdated, "
"name: $name, "
"provider: ${provider.toString(isDeep: isDeep)}, "
"coverProvider: $coverProvider, "
"albumFile: $albumFile, "
"}";
}
@ -183,12 +188,14 @@ class Album with EquatableMixin {
DateTime lastUpdated,
String name,
AlbumProvider provider,
AlbumCoverProvider coverProvider,
File albumFile,
}) {
return Album(
lastUpdated: lastUpdated,
name: name ?? this.name,
provider: provider ?? this.provider,
coverProvider: coverProvider ?? this.coverProvider,
albumFile: albumFile ?? this.albumFile,
);
}
@ -199,6 +206,7 @@ class Album with EquatableMixin {
"lastUpdated": lastUpdated.toIso8601String(),
"name": name,
"provider": provider.toJson(),
"coverProvider": coverProvider.toJson(),
// ignore albumFile
};
}
@ -209,6 +217,7 @@ class Album with EquatableMixin {
"lastUpdated": lastUpdated.toIso8601String(),
"name": name,
"provider": provider.toJson(),
"coverProvider": coverProvider.toJson(),
if (albumFile != null) "albumFile": albumFile.toJson(),
};
}
@ -218,6 +227,7 @@ class Album with EquatableMixin {
lastUpdated,
name,
provider,
coverProvider,
albumFile,
];
@ -225,6 +235,7 @@ class Album with EquatableMixin {
final String name;
final AlbumProvider provider;
final AlbumCoverProvider coverProvider;
/// How is this album stored on server
///

View file

@ -0,0 +1,105 @@
import 'package:equatable/equatable.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/iterable_extension.dart' as iterable_extension;
abstract class AlbumCoverProvider with EquatableMixin {
const AlbumCoverProvider();
factory AlbumCoverProvider.fromJson(Map<String, dynamic> json) {
final type = json["type"];
final content = json["content"];
switch (type) {
case AlbumAutoCoverProvider._type:
return AlbumAutoCoverProvider.fromJson(content.cast<String, dynamic>());
default:
_log.shout("[fromJson] Unknown type: $type");
throw ArgumentError.value(type, "type");
}
}
Map<String, dynamic> toJson() {
String getType() {
if (this is AlbumAutoCoverProvider) {
return AlbumAutoCoverProvider._type;
} else {
throw StateError("Unknwon subtype");
}
}
return {
"type": getType(),
"content": _toContentJson(),
};
}
@override
toString();
File getCover(Album album);
Map<String, dynamic> _toContentJson();
static final _log = Logger("entity.album.cover_provider.AlbumCoverProvider");
}
/// Cover selected automatically by us
class AlbumAutoCoverProvider extends AlbumCoverProvider {
AlbumAutoCoverProvider({
this.coverFile,
});
factory AlbumAutoCoverProvider.fromJson(Map<String, dynamic> json) {
return AlbumAutoCoverProvider(
coverFile: json["coverFile"] == null
? null
: File.fromJson(json["coverFile"].cast<String, dynamic>()),
);
}
@override
toString() {
return "$runtimeType {"
"coverFile: '${coverFile?.path}', "
"}";
}
File getCover(Album album) {
if (coverFile == null) {
try {
// use the latest file as cover
return AlbumStaticProvider.of(album)
.items
.whereType<AlbumFileItem>()
.map((e) => e.file)
.where((element) =>
file_util.isSupportedFormat(element) && element.hasPreview)
.sorted(compareFileDateTimeDescending)
.first;
} catch (_) {
return null;
}
} else {
return coverFile;
}
}
@override
get props => [
coverFile,
];
@override
_toContentJson() {
return {
if (coverFile != null) "coverFile": coverFile.toJson(),
};
}
final File coverFile;
static const _type = "auto";
}

View file

@ -41,6 +41,12 @@ class AlbumUpgraderV2 implements AlbumUpgrader {
}
};
result.remove("items");
// add the auto cover provider
result["coverProvider"] = <String, dynamic>{
"type": "auto",
"content": {},
};
return result;
}

View file

@ -194,16 +194,8 @@ class _HomeAlbumsState extends State<HomeAlbums> {
Widget _buildAlbumCover(BuildContext context, Album album) {
Widget cover;
try {
// use the latest file as cover
final latestFile = album.items
.whereType<AlbumFileItem>()
.map((e) => e.file)
.where((element) =>
file_util.isSupportedFormat(element) && element.hasPreview)
.sorted(compareFileDateTimeDescending)
.first;
final previewUrl = api_util.getFilePreviewUrl(widget.account, latestFile,
final coverFile = album.coverProvider.getCover(album);
final previewUrl = api_util.getFilePreviewUrl(widget.account, coverFile,
width: 512, height: 512);
cover = FittedBox(
clipBehavior: Clip.hardEdge,

View file

@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/cover_provider.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/use_case/create_album.dart';
@ -67,6 +68,7 @@ class _NewAlbumDialogState extends State<NewAlbumDialog> {
provider: AlbumStaticProvider(
items: const [],
),
coverProvider: AlbumAutoCoverProvider(),
);
_log.info("[_onOkPressed] Creating album: $album");
final albumRepo = AlbumRepo(AlbumCachedDataSource());

View file

@ -1,4 +1,5 @@
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/cover_provider.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/album/upgrader.dart';
import 'package:nc_photos/entity/file.dart';
@ -17,6 +18,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
};
expect(
Album.fromJson(json),
@ -26,6 +31,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
));
});
@ -40,6 +46,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
};
expect(
Album.fromJson(json),
@ -49,6 +59,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
));
});
@ -80,6 +91,10 @@ void main() {
],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
};
expect(
Album.fromJson(json),
@ -96,6 +111,43 @@ void main() {
),
],
),
coverProvider: AlbumAutoCoverProvider(),
));
});
test("AlbumAutoCoverProvider", () {
final json = <String, dynamic>{
"version": Album.version,
"lastUpdated": "2020-01-02T03:04:05.678901Z",
"name": "",
"provider": <String, dynamic>{
"type": "static",
"content": <String, dynamic>{
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{
"coverFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.jpg",
},
},
},
};
expect(
Album.fromJson(json),
Album(
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
name: "",
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(
coverFile: File(
path: "remote.php/dav/files/admin/test1.jpg",
),
),
));
});
@ -109,6 +161,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
"albumFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.jpg",
},
@ -121,6 +177,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
));
});
@ -134,6 +191,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toRemoteJson(), <String, dynamic>{
"version": Album.version,
@ -145,6 +203,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
@ -155,6 +217,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toRemoteJson(), <String, dynamic>{
"version": Album.version,
@ -166,6 +229,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
@ -183,6 +250,7 @@ void main() {
),
],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toRemoteJson(), <String, dynamic>{
"version": Album.version,
@ -211,6 +279,41 @@ void main() {
],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
test("AlbumAutoCoverProvider", () {
final album = Album(
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
name: "",
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(
coverFile: File(path: "remote.php/dav/files/admin/test1.jpg")),
);
expect(album.toRemoteJson(), <String, dynamic>{
"version": Album.version,
"lastUpdated": "2020-01-02T03:04:05.678901Z",
"name": "",
"provider": <String, dynamic>{
"type": "static",
"content": <String, dynamic>{
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{
"coverFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.jpg",
},
},
},
});
});
});
@ -223,6 +326,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toAppDbJson(), <String, dynamic>{
"version": Album.version,
@ -234,6 +338,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
@ -244,6 +352,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toAppDbJson(), <String, dynamic>{
"version": Album.version,
@ -255,6 +364,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
@ -272,6 +385,7 @@ void main() {
),
],
),
coverProvider: AlbumAutoCoverProvider(),
);
expect(album.toAppDbJson(), <String, dynamic>{
"version": Album.version,
@ -300,6 +414,44 @@ void main() {
],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
});
});
test("AlbumAutoCoverProvider", () {
final album = Album(
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
name: "",
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(
coverFile: File(
path: "remote.php/dav/files/admin/test1.jpg",
),
),
);
expect(album.toAppDbJson(), <String, dynamic>{
"version": Album.version,
"lastUpdated": "2020-01-02T03:04:05.678901Z",
"name": "",
"provider": <String, dynamic>{
"type": "static",
"content": <String, dynamic>{
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{
"coverFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.jpg",
},
},
},
});
});
@ -310,6 +462,7 @@ void main() {
provider: AlbumStaticProvider(
items: [],
),
coverProvider: AlbumAutoCoverProvider(),
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
);
expect(album.toAppDbJson(), <String, dynamic>{
@ -322,6 +475,10 @@ void main() {
"items": [],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
"albumFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.jpg",
},
@ -393,6 +550,10 @@ void main() {
],
},
},
"coverProvider": <String, dynamic>{
"type": "auto",
"content": <String, dynamic>{},
},
"albumFile": <String, dynamic>{
"path": "remote.php/dav/files/admin/test1.json",
},