nc-photos/app/lib/use_case/list_sharing.dart
2023-09-12 01:31:29 +08:00

206 lines
6.1 KiB
Dart

import 'dart:async';
import 'package:collection/collection.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/use_case/find_file.dart';
import 'package:nc_photos/use_case/ls.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:path/path.dart' as path_lib;
part 'list_sharing.g.dart';
abstract class ListSharingData {}
class ListSharingFileData implements ListSharingData {
const ListSharingFileData(this.share, this.file);
final Share share;
final File file;
}
class ListSharingAlbumData implements ListSharingData {
const ListSharingAlbumData(this.share, this.album);
final Share share;
final Album album;
}
@npLog
class ListSharing {
ListSharing(this._c);
Stream<List<ListSharingData>> call(Account account) async* {
final sharedAlbumFiles = await Ls(_c.fileRepo)(
account,
File(
path: remote_storage_util.getRemoteAlbumsDir(account),
),
);
final controller = StreamController<List<ListSharingData>>();
var byMe = <ListSharingData>[];
var isByMeDone = false;
var withMe = <ListSharingData>[];
var isWithMeDone = false;
void notify() {
controller.add([
...byMe,
...withMe,
]);
}
void onDone() {
if (isByMeDone && isWithMeDone) {
controller.close();
}
}
unawaited(_querySharesByMe(account, sharedAlbumFiles).then((value) {
byMe = value;
notify();
}).catchError((e, stackTrace) {
controller.addError(e, stackTrace);
}).whenComplete(() {
isByMeDone = true;
onDone();
}));
unawaited(_querySharesWithMe(account, sharedAlbumFiles).then((value) {
withMe = value;
notify();
}).catchError((e, stackTrace) {
controller.addError(e, stackTrace);
}).whenComplete(() {
isWithMeDone = true;
onDone();
}));
yield* controller.stream;
}
Future<List<ListSharingData>> _querySharesByMe(
Account account, List<File> sharedAlbumFiles) async {
final shares = await _c.shareRepo.listAll(account);
final futures = shares.map((s) async {
final webdavPath = file_util.unstripPath(account, s.path);
// include link share dirs
if (s.itemType == ShareItemType.folder) {
if (webdavPath
.startsWith(remote_storage_util.getRemoteLinkSharesDir(account))) {
return ListSharingFileData(
s,
File(
path: webdavPath,
fileId: s.itemSource,
isCollection: true,
),
);
}
}
// include shared albums
if (path_lib.dirname(webdavPath) ==
remote_storage_util.getRemoteAlbumsDir(account)) {
try {
final file = sharedAlbumFiles
.firstWhere((element) => element.fileId == s.itemSource);
return await _querySharedAlbum(account, s, file);
} catch (e, stackTrace) {
_log.severe(
"[_querySharesWithMe] Shared album not found: ${s.itemSource}",
e,
stackTrace);
return null;
}
}
if (!file_util.isSupportedMime(s.mimeType)) {
return null;
}
// show only link shares
if (s.url == null) {
return null;
}
if (account.roots
.every((r) => r.isNotEmpty && !s.path.startsWith("$r/"))) {
// ignore files not under root dirs
return null;
}
try {
final file = (await FindFile(_c)(account, [s.itemSource])).first;
return ListSharingFileData(s, file);
} catch (e, stackTrace) {
_log.severe("[_querySharesByMe] File not found: ${s.itemSource}", e,
stackTrace);
return null;
}
});
return (await Future.wait(futures)).whereNotNull().toList();
}
Future<List<ListSharingData>> _querySharesWithMe(
Account account, List<File> sharedAlbumFiles) async {
final pendingSharedAlbumFiles = await Ls(_c.fileRepo)(
account,
File(
path: remote_storage_util.getRemotePendingSharedAlbumsDir(account),
),
);
final shares = await _c.shareRepo.reverseListAll(account);
final futures = shares.map((s) async {
final webdavPath = file_util.unstripPath(account, s.path);
// include pending shared albums
if (path_lib.dirname(webdavPath) ==
remote_storage_util.getRemotePendingSharedAlbumsDir(account)) {
try {
final file = pendingSharedAlbumFiles
.firstWhere((element) => element.fileId == s.itemSource);
return await _querySharedAlbum(account, s, file);
} catch (e, stackTrace) {
_log.severe(
"[_querySharesWithMe] Pending shared album not found: ${s.itemSource}",
e,
stackTrace);
return null;
}
}
// include shared albums
if (path_lib.dirname(webdavPath) ==
remote_storage_util.getRemoteAlbumsDir(account)) {
try {
final file = sharedAlbumFiles
.firstWhere((element) => element.fileId == s.itemSource);
return await _querySharedAlbum(account, s, file);
} catch (e, stackTrace) {
_log.severe(
"[_querySharesWithMe] Shared album not found: ${s.itemSource}",
e,
stackTrace);
return null;
}
}
});
return (await Future.wait(futures)).whereNotNull().toList();
}
Future<ListSharingData?> _querySharedAlbum(
Account account, Share share, File albumFile) async {
try {
final album = await _c.albumRepo.get(account, albumFile);
return ListSharingAlbumData(share, album);
} catch (e, stackTrace) {
_log.shout(
"[_querySharedAlbum] Failed while getting album", e, stackTrace);
return null;
}
}
final DiContainer _c;
}