mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-14 11:18:54 +01:00
Abstract album content provider
This commit is contained in:
parent
d4785b1f74
commit
0e7f2462b6
13 changed files with 452 additions and 149 deletions
|
@ -138,6 +138,7 @@ class AppDbAlbumEntry {
|
||||||
Album.fromJson(
|
Album.fromJson(
|
||||||
json["album"].cast<String, dynamic>(),
|
json["album"].cast<String, dynamic>(),
|
||||||
upgraderV1: AlbumUpgraderV1(),
|
upgraderV1: AlbumUpgraderV1(),
|
||||||
|
upgraderV2: AlbumUpgraderV2(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:collection';
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
@ -8,6 +7,7 @@ import 'package:idb_sqflite/idb_sqflite.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/app_db.dart';
|
import 'package:nc_photos/app_db.dart';
|
||||||
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/entity/album/upgrader.dart';
|
import 'package:nc_photos/entity/album/upgrader.dart';
|
||||||
import 'package:nc_photos/entity/file.dart';
|
import 'package:nc_photos/entity/file.dart';
|
||||||
import 'package:nc_photos/entity/file/data_source.dart';
|
import 'package:nc_photos/entity/file/data_source.dart';
|
||||||
|
@ -126,15 +126,15 @@ class Album with EquatableMixin {
|
||||||
Album({
|
Album({
|
||||||
DateTime lastUpdated,
|
DateTime lastUpdated,
|
||||||
@required String name,
|
@required String name,
|
||||||
@required List<AlbumItem> items,
|
@required this.provider,
|
||||||
this.albumFile,
|
this.albumFile,
|
||||||
}) : this.lastUpdated = (lastUpdated ?? DateTime.now()).toUtc(),
|
}) : this.lastUpdated = (lastUpdated ?? DateTime.now()).toUtc(),
|
||||||
this.name = name ?? "",
|
this.name = name ?? "";
|
||||||
this.items = UnmodifiableListView(items);
|
|
||||||
|
|
||||||
factory Album.fromJson(
|
factory Album.fromJson(
|
||||||
Map<String, dynamic> json, {
|
Map<String, dynamic> json, {
|
||||||
AlbumUpgraderV1 upgraderV1,
|
AlbumUpgraderV1 upgraderV1,
|
||||||
|
AlbumUpgraderV2 upgraderV2,
|
||||||
}) {
|
}) {
|
||||||
final jsonVersion = json["version"];
|
final jsonVersion = json["version"];
|
||||||
if (jsonVersion < 2) {
|
if (jsonVersion < 2) {
|
||||||
|
@ -144,14 +144,20 @@ class Album with EquatableMixin {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (jsonVersion < 3) {
|
||||||
|
json = upgraderV2?.call(json);
|
||||||
|
if (json == null) {
|
||||||
|
_log.info("[fromJson] Version $jsonVersion not compatible");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Album(
|
return Album(
|
||||||
lastUpdated: json["lastUpdated"] == null
|
lastUpdated: json["lastUpdated"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["lastUpdated"]),
|
: DateTime.parse(json["lastUpdated"]),
|
||||||
name: json["name"],
|
name: json["name"],
|
||||||
items: (json["items"] as List)
|
provider:
|
||||||
.map((e) => AlbumItem.fromJson(e.cast<String, dynamic>()))
|
AlbumProvider.fromJson(json["provider"].cast<String, dynamic>()),
|
||||||
.toList(),
|
|
||||||
albumFile: json["albumFile"] == null
|
albumFile: json["albumFile"] == null
|
||||||
? null
|
? null
|
||||||
: File.fromJson(json["albumFile"].cast<String, dynamic>()),
|
: File.fromJson(json["albumFile"].cast<String, dynamic>()),
|
||||||
|
@ -160,12 +166,10 @@ class Album with EquatableMixin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
toString({bool isDeep = false}) {
|
toString({bool isDeep = false}) {
|
||||||
final itemsStr =
|
|
||||||
isDeep ? items.toReadableString() : "List {length: ${items.length}}";
|
|
||||||
return "$runtimeType {"
|
return "$runtimeType {"
|
||||||
"lastUpdated: $lastUpdated, "
|
"lastUpdated: $lastUpdated, "
|
||||||
"name: $name, "
|
"name: $name, "
|
||||||
"items: $itemsStr, "
|
"provider: ${provider.toString(isDeep: isDeep)}, "
|
||||||
"albumFile: $albumFile, "
|
"albumFile: $albumFile, "
|
||||||
"}";
|
"}";
|
||||||
}
|
}
|
||||||
|
@ -178,13 +182,13 @@ class Album with EquatableMixin {
|
||||||
Album copyWith({
|
Album copyWith({
|
||||||
DateTime lastUpdated,
|
DateTime lastUpdated,
|
||||||
String name,
|
String name,
|
||||||
List<AlbumItem> items,
|
AlbumProvider provider,
|
||||||
File albumFile,
|
File albumFile,
|
||||||
}) {
|
}) {
|
||||||
return Album(
|
return Album(
|
||||||
lastUpdated: lastUpdated,
|
lastUpdated: lastUpdated,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
items: items ?? this.items,
|
provider: provider ?? this.provider,
|
||||||
albumFile: albumFile ?? this.albumFile,
|
albumFile: albumFile ?? this.albumFile,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -194,7 +198,7 @@ class Album with EquatableMixin {
|
||||||
"version": version,
|
"version": version,
|
||||||
"lastUpdated": lastUpdated.toIso8601String(),
|
"lastUpdated": lastUpdated.toIso8601String(),
|
||||||
"name": name,
|
"name": name,
|
||||||
"items": items.map((e) => e.toJson()).toList(),
|
"provider": provider.toJson(),
|
||||||
// ignore albumFile
|
// ignore albumFile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -204,7 +208,7 @@ class Album with EquatableMixin {
|
||||||
"version": version,
|
"version": version,
|
||||||
"lastUpdated": lastUpdated.toIso8601String(),
|
"lastUpdated": lastUpdated.toIso8601String(),
|
||||||
"name": name,
|
"name": name,
|
||||||
"items": items.map((e) => e.toJson()).toList(),
|
"provider": provider.toJson(),
|
||||||
if (albumFile != null) "albumFile": albumFile.toJson(),
|
if (albumFile != null) "albumFile": albumFile.toJson(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -213,15 +217,14 @@ class Album with EquatableMixin {
|
||||||
get props => [
|
get props => [
|
||||||
lastUpdated,
|
lastUpdated,
|
||||||
name,
|
name,
|
||||||
items,
|
provider,
|
||||||
albumFile,
|
albumFile,
|
||||||
];
|
];
|
||||||
|
|
||||||
final DateTime lastUpdated;
|
final DateTime lastUpdated;
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
/// Immutable list of items. Modifying the list will result in an error
|
final AlbumProvider provider;
|
||||||
final List<AlbumItem> items;
|
|
||||||
|
|
||||||
/// How is this album stored on server
|
/// How is this album stored on server
|
||||||
///
|
///
|
||||||
|
@ -229,7 +232,7 @@ class Album with EquatableMixin {
|
||||||
final File albumFile;
|
final File albumFile;
|
||||||
|
|
||||||
/// versioning of this class, use to upgrade old persisted album
|
/// versioning of this class, use to upgrade old persisted album
|
||||||
static const version = 2;
|
static const version = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumRepo {
|
class AlbumRepo {
|
||||||
|
@ -281,6 +284,7 @@ class AlbumRemoteDataSource implements AlbumDataSource {
|
||||||
return Album.fromJson(
|
return Album.fromJson(
|
||||||
jsonDecode(utf8.decode(data)),
|
jsonDecode(utf8.decode(data)),
|
||||||
upgraderV1: AlbumUpgraderV1(),
|
upgraderV1: AlbumUpgraderV1(),
|
||||||
|
upgraderV2: AlbumUpgraderV2(),
|
||||||
).copyWith(albumFile: albumFile);
|
).copyWith(albumFile: albumFile);
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
dynamic d = data;
|
dynamic d = data;
|
||||||
|
@ -343,11 +347,19 @@ class AlbumAppDbDataSource implements AlbumDataSource {
|
||||||
if (results?.isNotEmpty == true) {
|
if (results?.isNotEmpty == true) {
|
||||||
final entries = results
|
final entries = results
|
||||||
.map((e) => AppDbAlbumEntry.fromJson(e.cast<String, dynamic>()));
|
.map((e) => AppDbAlbumEntry.fromJson(e.cast<String, dynamic>()));
|
||||||
final items = entries.map((e) {
|
if (entries.length > 1) {
|
||||||
_log.info("[get] ${e.path}[${e.index}]");
|
final items = entries.map((e) {
|
||||||
return e.album.items;
|
_log.info("[get] ${e.path}[${e.index}]");
|
||||||
}).reduce((value, element) => value + element);
|
return AlbumStaticProvider.of(e.album).items;
|
||||||
return entries.first.album.copyWith(items: items);
|
}).reduce((value, element) => value + element);
|
||||||
|
return entries.first.album.copyWith(
|
||||||
|
provider: AlbumStaticProvider(
|
||||||
|
items: items,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return entries.first.album;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw CacheNotFoundException("No entry: $path");
|
throw CacheNotFoundException("No entry: $path");
|
||||||
}
|
}
|
||||||
|
@ -461,27 +473,37 @@ Future<void> _cacheAlbum(
|
||||||
final range = KeyRange.bound([path, 0], [path, int_util.int32Max]);
|
final range = KeyRange.bound([path, 0], [path, int_util.int32Max]);
|
||||||
// count number of entries for this album
|
// count number of entries for this album
|
||||||
final count = await index.count(range);
|
final count = await index.count(range);
|
||||||
int newCount = 0;
|
|
||||||
|
|
||||||
var albumItemLists =
|
// cut large album into smaller pieces, needed to workaround Android DB
|
||||||
partition(album.items, AppDbAlbumEntry.maxDataSize).toList();
|
// limitation
|
||||||
if (albumItemLists.isEmpty) {
|
final entries = <AppDbAlbumEntry>[];
|
||||||
albumItemLists = [<AlbumItem>[]];
|
if (album.provider is AlbumStaticProvider) {
|
||||||
|
var albumItemLists = partition(
|
||||||
|
AlbumStaticProvider.of(album).items, AppDbAlbumEntry.maxDataSize)
|
||||||
|
.toList();
|
||||||
|
if (albumItemLists.isEmpty) {
|
||||||
|
albumItemLists = [<AlbumItem>[]];
|
||||||
|
}
|
||||||
|
entries.addAll(albumItemLists.withIndex().map((pair) => AppDbAlbumEntry(
|
||||||
|
path,
|
||||||
|
pair.item1,
|
||||||
|
album.copyWith(
|
||||||
|
provider: AlbumStaticProvider(items: pair.item2),
|
||||||
|
))));
|
||||||
|
} else {
|
||||||
|
entries.add(AppDbAlbumEntry(path, 0, album));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final pair in albumItemLists.withIndex()) {
|
for (final e in entries) {
|
||||||
_log.info(
|
_log.info("[_cacheAlbum] Caching ${e.path}[${e.index}]");
|
||||||
"[_cacheAlbum] Caching $path[${pair.item1}], length: ${pair.item2.length}");
|
await store.put(e.toJson(),
|
||||||
await store.put(
|
AppDbAlbumEntry.toPrimaryKey(account, e.album.albumFile, e.index));
|
||||||
AppDbAlbumEntry(path, pair.item1, album.copyWith(items: pair.item2))
|
|
||||||
.toJson(),
|
|
||||||
AppDbAlbumEntry.toPrimaryKey(account, album.albumFile, pair.item1),
|
|
||||||
);
|
|
||||||
++newCount;
|
|
||||||
}
|
}
|
||||||
if (count > newCount) {
|
|
||||||
|
if (count > entries.length) {
|
||||||
// index is 0-based
|
// index is 0-based
|
||||||
final rmRange = KeyRange.bound([path, newCount], [path, int_util.int32Max]);
|
final rmRange =
|
||||||
|
KeyRange.bound([path, entries.length], [path, int_util.int32Max]);
|
||||||
final rmKeys = await index
|
final rmKeys = await index
|
||||||
.openKeyCursor(range: rmRange, autoAdvance: true)
|
.openKeyCursor(range: rmRange, autoAdvance: true)
|
||||||
.map((cursor) => cursor.primaryKey)
|
.map((cursor) => cursor.primaryKey)
|
||||||
|
|
85
lib/entity/album/provider.dart
Normal file
85
lib/entity/album/provider.dart
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
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';
|
||||||
|
import 'package:nc_photos/iterable_extension.dart';
|
||||||
|
|
||||||
|
abstract class AlbumProvider with EquatableMixin {
|
||||||
|
const AlbumProvider();
|
||||||
|
|
||||||
|
factory AlbumProvider.fromJson(Map<String, dynamic> json) {
|
||||||
|
final type = json["type"];
|
||||||
|
final content = json["content"];
|
||||||
|
switch (type) {
|
||||||
|
case AlbumStaticProvider._type:
|
||||||
|
return AlbumStaticProvider.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 AlbumStaticProvider) {
|
||||||
|
return AlbumStaticProvider._type;
|
||||||
|
} else {
|
||||||
|
throw StateError("Unknwon subtype");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"type": getType(),
|
||||||
|
"content": _toContentJson(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString({bool isDeep = false});
|
||||||
|
|
||||||
|
Map<String, dynamic> _toContentJson();
|
||||||
|
|
||||||
|
static final _log = Logger("entity.album.provider.AlbumProvider");
|
||||||
|
}
|
||||||
|
|
||||||
|
class AlbumStaticProvider extends AlbumProvider {
|
||||||
|
AlbumStaticProvider({
|
||||||
|
@required List<AlbumItem> items,
|
||||||
|
}) : this.items = UnmodifiableListView(items);
|
||||||
|
|
||||||
|
factory AlbumStaticProvider.fromJson(Map<String, dynamic> json) {
|
||||||
|
return AlbumStaticProvider(
|
||||||
|
items: (json["items"] as List)
|
||||||
|
.map((e) => AlbumItem.fromJson(e.cast<String, dynamic>()))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString({bool isDeep = false}) {
|
||||||
|
final itemsStr =
|
||||||
|
isDeep ? items.toReadableString() : "List {length: ${items.length}}";
|
||||||
|
return "$runtimeType {"
|
||||||
|
"items: $itemsStr, "
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
get props => [
|
||||||
|
items,
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
_toContentJson() {
|
||||||
|
return {
|
||||||
|
"items": items.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Immutable list of items. Modifying the list will result in an error
|
||||||
|
final List<AlbumItem> items;
|
||||||
|
|
||||||
|
static const _type = "static";
|
||||||
|
}
|
|
@ -23,3 +23,29 @@ class AlbumUpgraderV1 implements AlbumUpgrader {
|
||||||
|
|
||||||
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV1");
|
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Upgrade v2 Album to v3
|
||||||
|
class AlbumUpgraderV2 implements AlbumUpgrader {
|
||||||
|
AlbumUpgraderV2({
|
||||||
|
this.logFilePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> call(Map<String, dynamic> json) {
|
||||||
|
// move v2 items to v3 provider
|
||||||
|
_log.fine("[call] Upgrade v2 Album for file: $logFilePath");
|
||||||
|
final result = Map<String, dynamic>.from(json);
|
||||||
|
result["provider"] = <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": result["items"],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
result.remove("items");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// File path for logging only
|
||||||
|
final String logFilePath;
|
||||||
|
|
||||||
|
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV2");
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:kiwi/kiwi.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/entity/album.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.dart';
|
||||||
import 'package:nc_photos/event/event.dart';
|
import 'package:nc_photos/event/event.dart';
|
||||||
import 'package:nc_photos/use_case/list_album.dart';
|
import 'package:nc_photos/use_case/list_album.dart';
|
||||||
|
@ -23,18 +24,27 @@ class Remove {
|
||||||
|
|
||||||
Future<void> _cleanUpAlbums(Account account, File file) async {
|
Future<void> _cleanUpAlbums(Account account, File file) async {
|
||||||
final albums = await ListAlbum(fileRepo, albumRepo)(account);
|
final albums = await ListAlbum(fileRepo, albumRepo)(account);
|
||||||
for (final a in albums) {
|
// clean up only make sense for static albums
|
||||||
|
for (final a
|
||||||
|
in albums.where((element) => element.provider is AlbumStaticProvider)) {
|
||||||
try {
|
try {
|
||||||
if (a.items.any((element) =>
|
final provider = AlbumStaticProvider.of(a);
|
||||||
|
if (provider.items.any((element) =>
|
||||||
element is AlbumFileItem && element.file.path == file.path)) {
|
element is AlbumFileItem && element.file.path == file.path)) {
|
||||||
final newItems = a.items.where((element) {
|
final newItems = provider.items.where((element) {
|
||||||
if (element is AlbumFileItem) {
|
if (element is AlbumFileItem) {
|
||||||
return element.file.path != file.path;
|
return element.file.path != file.path;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}).toList();
|
}).toList();
|
||||||
await UpdateAlbum(albumRepo)(account, a.copyWith(items: newItems));
|
await UpdateAlbum(albumRepo)(
|
||||||
|
account,
|
||||||
|
a.copyWith(
|
||||||
|
provider: AlbumStaticProvider(
|
||||||
|
items: newItems,
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
_log.shout(
|
_log.shout(
|
||||||
|
|
|
@ -4,18 +4,24 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/app_db.dart';
|
import 'package:nc_photos/app_db.dart';
|
||||||
import 'package:nc_photos/entity/album.dart';
|
import 'package:nc_photos/entity/album.dart';
|
||||||
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
|
|
||||||
/// Resync files inside an album with the file db
|
/// Resync files inside an album with the file db
|
||||||
class ResyncAlbum {
|
class ResyncAlbum {
|
||||||
Future<Album> call(Account account, Album album) async {
|
Future<Album> call(Account account, Album album) async {
|
||||||
|
if (album.provider is! AlbumStaticProvider) {
|
||||||
|
_log.warning(
|
||||||
|
"[call] Resync only make sense for static albums: ${album.name}");
|
||||||
|
return album;
|
||||||
|
}
|
||||||
return await AppDb.use((db) async {
|
return await AppDb.use((db) async {
|
||||||
final transaction =
|
final transaction =
|
||||||
db.transaction(AppDb.fileDbStoreName, idbModeReadWrite);
|
db.transaction(AppDb.fileDbStoreName, idbModeReadWrite);
|
||||||
final store = transaction.objectStore(AppDb.fileDbStoreName);
|
final store = transaction.objectStore(AppDb.fileDbStoreName);
|
||||||
final index = store.index(AppDbFileDbEntry.indexName);
|
final index = store.index(AppDbFileDbEntry.indexName);
|
||||||
final newItems = <AlbumItem>[];
|
final newItems = <AlbumItem>[];
|
||||||
for (final item in album.items) {
|
for (final item in AlbumStaticProvider.of(album).items) {
|
||||||
if (item is AlbumFileItem) {
|
if (item is AlbumFileItem) {
|
||||||
try {
|
try {
|
||||||
newItems.add(await _syncOne(account, item, store, index));
|
newItems.add(await _syncOne(account, item, store, index));
|
||||||
|
@ -30,7 +36,7 @@ class ResyncAlbum {
|
||||||
newItems.add(item);
|
newItems.add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return album.copyWith(items: newItems);
|
return album.copyWith(provider: AlbumStaticProvider(items: newItems));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/bloc/list_album.dart';
|
import 'package:nc_photos/bloc/list_album.dart';
|
||||||
import 'package:nc_photos/entity/album.dart';
|
import 'package:nc_photos/entity/album.dart';
|
||||||
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||||
import 'package:nc_photos/k.dart' as k;
|
import 'package:nc_photos/k.dart' as k;
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
|
@ -139,7 +140,8 @@ class _AlbumPickerDialogState extends State<AlbumPickerDialog> {
|
||||||
|
|
||||||
void _transformItems(List<Album> albums) {
|
void _transformItems(List<Album> albums) {
|
||||||
_items.clear();
|
_items.clear();
|
||||||
_items.addAll(albums);
|
_items.addAll(
|
||||||
|
albums.where((element) => element.provider is AlbumStaticProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _reqQuery() {
|
void _reqQuery() {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/api/api.dart';
|
import 'package:nc_photos/api/api.dart';
|
||||||
import 'package:nc_photos/api/api_util.dart' as api_util;
|
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||||
import 'package:nc_photos/entity/album.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.dart';
|
||||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||||
|
@ -77,6 +78,7 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
get itemStreamListCellSize => _thumbSize;
|
get itemStreamListCellSize => _thumbSize;
|
||||||
|
|
||||||
void _initAlbum() {
|
void _initAlbum() {
|
||||||
|
assert(widget.album.provider is AlbumStaticProvider);
|
||||||
ResyncAlbum()(widget.account, widget.album).then((album) {
|
ResyncAlbum()(widget.account, widget.album).then((album) {
|
||||||
if (_shouldPropagateResyncedAlbum(album)) {
|
if (_shouldPropagateResyncedAlbum(album)) {
|
||||||
UpdateAlbum(AlbumRepo(AlbumCachedDataSource()))(widget.account, album)
|
UpdateAlbum(AlbumRepo(AlbumCachedDataSource()))(widget.account, album)
|
||||||
|
@ -247,7 +249,7 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
final selectedIndexes =
|
final selectedIndexes =
|
||||||
selectedListItems.map((e) => itemStreamListItems.indexOf(e)).toList();
|
selectedListItems.map((e) => itemStreamListItems.indexOf(e)).toList();
|
||||||
final selectedFiles = _backingFiles.takeIndex(selectedIndexes).toList();
|
final selectedFiles = _backingFiles.takeIndex(selectedIndexes).toList();
|
||||||
final newItems = _album.items.where((element) {
|
final newItems = _getAlbumItemsOf(_album).where((element) {
|
||||||
if (element is AlbumFileItem) {
|
if (element is AlbumFileItem) {
|
||||||
return !selectedFiles.any((select) => select.path == element.file.path);
|
return !selectedFiles.any((select) => select.path == element.file.path);
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,7 +258,9 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
}).toList();
|
}).toList();
|
||||||
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
||||||
final newAlbum = _album.copyWith(
|
final newAlbum = _album.copyWith(
|
||||||
items: newItems,
|
provider: AlbumStaticProvider(
|
||||||
|
items: newItems,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
UpdateAlbum(albumRepo)(widget.account, newAlbum).then((_) {
|
UpdateAlbum(albumRepo)(widget.account, newAlbum).then((_) {
|
||||||
SnackBarManager().showSnackBar(SnackBar(
|
SnackBarManager().showSnackBar(SnackBar(
|
||||||
|
@ -286,7 +290,7 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _transformItems() {
|
void _transformItems() {
|
||||||
_backingFiles = _album.items
|
_backingFiles = _getAlbumItemsOf(_album)
|
||||||
.whereType<AlbumFileItem>()
|
.whereType<AlbumFileItem>()
|
||||||
.map((e) => e.file)
|
.map((e) => e.file)
|
||||||
.where((element) => file_util.isSupportedFormat(element))
|
.where((element) => file_util.isSupportedFormat(element))
|
||||||
|
@ -320,12 +324,14 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _shouldPropagateResyncedAlbum(Album album) {
|
bool _shouldPropagateResyncedAlbum(Album album) {
|
||||||
if (widget.album.items.length != album.items.length) {
|
final origItems = _getAlbumItemsOf(widget.album);
|
||||||
|
final resyncItems = _getAlbumItemsOf(album);
|
||||||
|
if (origItems.length != resyncItems.length) {
|
||||||
_log.info(
|
_log.info(
|
||||||
"[_shouldPropagateResyncedAlbum] Item length differ: ${widget.album.items.length}, ${album.items.length}");
|
"[_shouldPropagateResyncedAlbum] Item length differ: ${origItems.length}, ${resyncItems.length}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (final z in zip([widget.album.items, album.items])) {
|
for (final z in zip([origItems, resyncItems])) {
|
||||||
final a = z[0], b = z[1];
|
final a = z[0], b = z[1];
|
||||||
bool isEqual;
|
bool isEqual;
|
||||||
if (a is AlbumFileItem && b is AlbumFileItem) {
|
if (a is AlbumFileItem && b is AlbumFileItem) {
|
||||||
|
@ -344,6 +350,9 @@ class _AlbumViewerState extends State<AlbumViewer>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<AlbumItem> _getAlbumItemsOf(Album a) =>
|
||||||
|
AlbumStaticProvider.of(a).items;
|
||||||
|
|
||||||
int get _thumbSize {
|
int get _thumbSize {
|
||||||
switch (_thumbZoomLevel) {
|
switch (_thumbZoomLevel) {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:nc_photos/api/api.dart';
|
||||||
import 'package:nc_photos/api/api_util.dart' as api_util;
|
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||||
import 'package:nc_photos/bloc/list_album.dart';
|
import 'package:nc_photos/bloc/list_album.dart';
|
||||||
import 'package:nc_photos/entity/album.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.dart';
|
||||||
import 'package:nc_photos/entity/file/data_source.dart';
|
import 'package:nc_photos/entity/file/data_source.dart';
|
||||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
|
@ -175,10 +176,15 @@ class _HomeAlbumsState extends State<HomeAlbums> {
|
||||||
|
|
||||||
Widget _buildAlbumItem(BuildContext context, int index) {
|
Widget _buildAlbumItem(BuildContext context, int index) {
|
||||||
final item = _items[index];
|
final item = _items[index];
|
||||||
|
var subtitle = "";
|
||||||
|
if (item.album.provider is AlbumStaticProvider) {
|
||||||
|
subtitle = AppLocalizations.of(context)
|
||||||
|
.albumSize(AlbumStaticProvider.of(item.album).items.length);
|
||||||
|
}
|
||||||
return AlbumGridItem(
|
return AlbumGridItem(
|
||||||
cover: _buildAlbumCover(context, item.album),
|
cover: _buildAlbumCover(context, item.album),
|
||||||
title: item.album.name,
|
title: item.album.name,
|
||||||
subtitle: AppLocalizations.of(context).albumSize(item.album.items.length),
|
subtitle: subtitle,
|
||||||
isSelected: _selectedItems.contains(item),
|
isSelected: _selectedItems.contains(item),
|
||||||
onTap: () => _onItemTap(item),
|
onTap: () => _onItemTap(item),
|
||||||
onLongPress: _isSelectionMode ? null : () => _onItemLongPress(item),
|
onLongPress: _isSelectionMode ? null : () => _onItemLongPress(item),
|
||||||
|
@ -386,7 +392,8 @@ class _HomeAlbumsState extends State<HomeAlbums> {
|
||||||
final sortedAlbums = albums.map((e) {
|
final sortedAlbums = albums.map((e) {
|
||||||
// find the latest file in this album
|
// find the latest file in this album
|
||||||
try {
|
try {
|
||||||
final lastItem = e.items
|
final lastItem = AlbumStaticProvider.of(e)
|
||||||
|
.items
|
||||||
.whereType<AlbumFileItem>()
|
.whereType<AlbumFileItem>()
|
||||||
.map((e) => e.file)
|
.map((e) => e.file)
|
||||||
.where((element) => file_util.isSupportedFormat(element))
|
.where((element) => file_util.isSupportedFormat(element))
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/api/api_util.dart' as api_util;
|
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||||
import 'package:nc_photos/bloc/scan_dir.dart';
|
import 'package:nc_photos/bloc/scan_dir.dart';
|
||||||
import 'package:nc_photos/entity/album.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.dart';
|
||||||
import 'package:nc_photos/entity/file/data_source.dart';
|
import 'package:nc_photos/entity/file/data_source.dart';
|
||||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
|
@ -311,6 +312,7 @@ class _HomePhotosState extends State<HomePhotos>
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addSelectedToAlbum(BuildContext context, Album album) async {
|
Future<void> _addSelectedToAlbum(BuildContext context, Album album) async {
|
||||||
|
assert(album.provider is AlbumStaticProvider);
|
||||||
final selected = selectedListItems
|
final selected = selectedListItems
|
||||||
.whereType<_FileListItem>()
|
.whereType<_FileListItem>()
|
||||||
.map((e) => AlbumFileItem(file: e.file))
|
.map((e) => AlbumFileItem(file: e.file))
|
||||||
|
@ -320,10 +322,12 @@ class _HomePhotosState extends State<HomePhotos>
|
||||||
await UpdateAlbum(albumRepo)(
|
await UpdateAlbum(albumRepo)(
|
||||||
widget.account,
|
widget.account,
|
||||||
album.copyWith(
|
album.copyWith(
|
||||||
items: makeDistinctAlbumItems([
|
provider: AlbumStaticProvider(
|
||||||
...album.items,
|
items: makeDistinctAlbumItems([
|
||||||
...selected,
|
...AlbumStaticProvider.of(album).items,
|
||||||
]),
|
...selected,
|
||||||
|
]),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
_log.shout(
|
_log.shout(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/entity/album.dart';
|
import 'package:nc_photos/entity/album.dart';
|
||||||
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/use_case/create_album.dart';
|
import 'package:nc_photos/use_case/create_album.dart';
|
||||||
|
|
||||||
/// Dialog to create a new album
|
/// Dialog to create a new album
|
||||||
|
@ -63,7 +64,9 @@ class _NewAlbumDialogState extends State<NewAlbumDialog> {
|
||||||
_formKey.currentState.save();
|
_formKey.currentState.save();
|
||||||
final album = Album(
|
final album = Album(
|
||||||
name: _formValue.name,
|
name: _formValue.name,
|
||||||
items: const [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: const [],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
_log.info("[_onOkPressed] Creating album: $album");
|
_log.info("[_onOkPressed] Creating album: $album");
|
||||||
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/double_extension.dart';
|
import 'package:nc_photos/double_extension.dart';
|
||||||
import 'package:nc_photos/entity/album.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.dart';
|
||||||
import 'package:nc_photos/entity/file/data_source.dart';
|
import 'package:nc_photos/entity/file/data_source.dart';
|
||||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||||
|
@ -348,10 +349,12 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addToAlbum(BuildContext context, Album album) async {
|
Future<void> _addToAlbum(BuildContext context, Album album) async {
|
||||||
|
assert(album.provider is AlbumStaticProvider);
|
||||||
try {
|
try {
|
||||||
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
final albumRepo = AlbumRepo(AlbumCachedDataSource());
|
||||||
final newItem = AlbumFileItem(file: widget.file);
|
final newItem = AlbumFileItem(file: widget.file);
|
||||||
if (album.items
|
if (AlbumStaticProvider.of(album)
|
||||||
|
.items
|
||||||
.whereType<AlbumFileItem>()
|
.whereType<AlbumFileItem>()
|
||||||
.containsIf(newItem, (a, b) => a.file.path == b.file.path)) {
|
.containsIf(newItem, (a, b) => a.file.path == b.file.path)) {
|
||||||
// already added, do nothing
|
// already added, do nothing
|
||||||
|
@ -366,7 +369,12 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
|
||||||
await UpdateAlbum(albumRepo)(
|
await UpdateAlbum(albumRepo)(
|
||||||
widget.account,
|
widget.account,
|
||||||
album.copyWith(
|
album.copyWith(
|
||||||
items: [...album.items, AlbumFileItem(file: widget.file)],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [
|
||||||
|
...AlbumStaticProvider.of(album).items,
|
||||||
|
AlbumFileItem(file: widget.file),
|
||||||
|
],
|
||||||
|
),
|
||||||
));
|
));
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
_log.shout("[_addToAlbum] Failed while updating album", e, stacktrace);
|
_log.shout("[_addToAlbum] Failed while updating album", e, stacktrace);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:nc_photos/entity/album.dart';
|
import 'package:nc_photos/entity/album.dart';
|
||||||
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/entity/album/upgrader.dart';
|
import 'package:nc_photos/entity/album/upgrader.dart';
|
||||||
import 'package:nc_photos/entity/file.dart';
|
import 'package:nc_photos/entity/file.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
@ -10,14 +11,21 @@ void main() {
|
||||||
final json = <String, dynamic>{
|
final json = <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
Album.fromJson(json),
|
Album.fromJson(json),
|
||||||
Album(
|
Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,54 +34,68 @@ void main() {
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "album",
|
"name": "album",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
Album.fromJson(json),
|
Album.fromJson(json),
|
||||||
Album(
|
Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "album",
|
name: "album",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("items", () {
|
test("AlbumStaticProvider", () {
|
||||||
final json = <String, dynamic>{
|
final json = <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [
|
"provider": <String, dynamic>{
|
||||||
<String, dynamic>{
|
"type": "static",
|
||||||
"type": "file",
|
"content": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"items": [
|
||||||
"file": <String, dynamic>{
|
<String, dynamic>{
|
||||||
"path": "remote.php/dav/files/admin/test1.jpg",
|
"type": "file",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"file": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
<String, dynamic>{
|
||||||
},
|
"type": "file",
|
||||||
<String, dynamic>{
|
"content": <String, dynamic>{
|
||||||
"type": "file",
|
"file": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"path": "remote.php/dav/files/admin/test2.jpg",
|
||||||
"file": <String, dynamic>{
|
},
|
||||||
"path": "remote.php/dav/files/admin/test2.jpg",
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
Album.fromJson(json),
|
Album.fromJson(json),
|
||||||
Album(
|
Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [
|
provider: AlbumStaticProvider(
|
||||||
AlbumFileItem(
|
items: [
|
||||||
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
||||||
AlbumFileItem(
|
),
|
||||||
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -81,7 +103,12 @@ void main() {
|
||||||
final json = <String, dynamic>{
|
final json = <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
"albumFile": <String, dynamic>{
|
"albumFile": <String, dynamic>{
|
||||||
"path": "remote.php/dav/files/admin/test1.jpg",
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
},
|
},
|
||||||
|
@ -91,7 +118,9 @@ void main() {
|
||||||
Album(
|
Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
@ -102,13 +131,20 @@ void main() {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toRemoteJson(), <String, dynamic>{
|
expect(album.toRemoteJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,51 +152,65 @@ void main() {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "album",
|
name: "album",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toRemoteJson(), <String, dynamic>{
|
expect(album.toRemoteJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "album",
|
"name": "album",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("items", () {
|
test("AlbumStaticProvider", () {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [
|
provider: AlbumStaticProvider(
|
||||||
AlbumFileItem(
|
items: [
|
||||||
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
||||||
AlbumFileItem(
|
),
|
||||||
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toRemoteJson(), <String, dynamic>{
|
expect(album.toRemoteJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [
|
"provider": <String, dynamic>{
|
||||||
<String, dynamic>{
|
"type": "static",
|
||||||
"type": "file",
|
"content": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"items": [
|
||||||
"file": <String, dynamic>{
|
<String, dynamic>{
|
||||||
"path": "remote.php/dav/files/admin/test1.jpg",
|
"type": "file",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"file": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
<String, dynamic>{
|
||||||
},
|
"type": "file",
|
||||||
<String, dynamic>{
|
"content": <String, dynamic>{
|
||||||
"type": "file",
|
"file": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"path": "remote.php/dav/files/admin/test2.jpg",
|
||||||
"file": <String, dynamic>{
|
},
|
||||||
"path": "remote.php/dav/files/admin/test2.jpg",
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -170,13 +220,20 @@ void main() {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toAppDbJson(), <String, dynamic>{
|
expect(album.toAppDbJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -184,51 +241,65 @@ void main() {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "album",
|
name: "album",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toAppDbJson(), <String, dynamic>{
|
expect(album.toAppDbJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "album",
|
"name": "album",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("items", () {
|
test("AlbumStaticProvider", () {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [
|
provider: AlbumStaticProvider(
|
||||||
AlbumFileItem(
|
items: [
|
||||||
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
||||||
AlbumFileItem(
|
),
|
||||||
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
AlbumFileItem(
|
||||||
),
|
file: File(path: "remote.php/dav/files/admin/test2.jpg"),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(album.toAppDbJson(), <String, dynamic>{
|
expect(album.toAppDbJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [
|
"provider": <String, dynamic>{
|
||||||
<String, dynamic>{
|
"type": "static",
|
||||||
"type": "file",
|
"content": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"items": [
|
||||||
"file": <String, dynamic>{
|
<String, dynamic>{
|
||||||
"path": "remote.php/dav/files/admin/test1.jpg",
|
"type": "file",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"file": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
<String, dynamic>{
|
||||||
},
|
"type": "file",
|
||||||
<String, dynamic>{
|
"content": <String, dynamic>{
|
||||||
"type": "file",
|
"file": <String, dynamic>{
|
||||||
"content": <String, dynamic>{
|
"path": "remote.php/dav/files/admin/test2.jpg",
|
||||||
"file": <String, dynamic>{
|
},
|
||||||
"path": "remote.php/dav/files/admin/test2.jpg",
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,14 +307,21 @@ void main() {
|
||||||
final album = Album(
|
final album = Album(
|
||||||
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678, 901),
|
||||||
name: "",
|
name: "",
|
||||||
items: [],
|
provider: AlbumStaticProvider(
|
||||||
|
items: [],
|
||||||
|
),
|
||||||
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
albumFile: File(path: "remote.php/dav/files/admin/test1.jpg"),
|
||||||
);
|
);
|
||||||
expect(album.toAppDbJson(), <String, dynamic>{
|
expect(album.toAppDbJson(), <String, dynamic>{
|
||||||
"version": Album.version,
|
"version": Album.version,
|
||||||
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
"name": "",
|
"name": "",
|
||||||
"items": [],
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
"albumFile": <String, dynamic>{
|
"albumFile": <String, dynamic>{
|
||||||
"path": "remote.php/dav/files/admin/test1.jpg",
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
},
|
},
|
||||||
|
@ -278,5 +356,47 @@ void main() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("AlbumUpgraderV2", () {
|
||||||
|
final json = <String, dynamic>{
|
||||||
|
"version": 2,
|
||||||
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
|
"items": [
|
||||||
|
<String, dynamic>{
|
||||||
|
"type": "file",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"file": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"albumFile": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.json",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(AlbumUpgraderV2()(json), <String, dynamic>{
|
||||||
|
"version": 2,
|
||||||
|
"lastUpdated": "2020-01-02T03:04:05.678901Z",
|
||||||
|
"provider": <String, dynamic>{
|
||||||
|
"type": "static",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"items": [
|
||||||
|
<String, dynamic>{
|
||||||
|
"type": "file",
|
||||||
|
"content": <String, dynamic>{
|
||||||
|
"file": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.jpg",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"albumFile": <String, dynamic>{
|
||||||
|
"path": "remote.php/dav/files/admin/test1.json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue