mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-25 02:48:54 +01:00
List files shared with you in Sharing
This commit is contained in:
parent
50ba293345
commit
afd859d414
8 changed files with 108 additions and 19 deletions
|
@ -538,10 +538,12 @@ class _OcsFilesSharingShares {
|
||||||
/// Get Shares from a specific file or folder
|
/// Get Shares from a specific file or folder
|
||||||
///
|
///
|
||||||
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#get-shares-from-a-specific-file-or-folder
|
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#get-shares-from-a-specific-file-or-folder
|
||||||
|
/// See: https://doc.owncloud.com/server/latest/developer_manual/core/apis/ocs-share-api.html#get-all-shares
|
||||||
Future<Response> get({
|
Future<Response> get({
|
||||||
String? path,
|
String? path,
|
||||||
bool? reshares,
|
bool? reshares,
|
||||||
bool? subfiles,
|
bool? subfiles,
|
||||||
|
bool? sharedWithMe,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
return await _filesSharing._ocs._api.request(
|
return await _filesSharing._ocs._api.request(
|
||||||
|
@ -555,6 +557,7 @@ class _OcsFilesSharingShares {
|
||||||
if (path != null) "path": path,
|
if (path != null) "path": path,
|
||||||
if (reshares != null) "reshares": reshares.toString(),
|
if (reshares != null) "reshares": reshares.toString(),
|
||||||
if (subfiles != null) "subfiles": subfiles.toString(),
|
if (subfiles != null) "subfiles": subfiles.toString(),
|
||||||
|
if (sharedWithMe != null) "shared_with_me": sharedWithMe.toString(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -174,6 +174,15 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ListSharingItem>> _query(ListSharingBlocQuery ev) async {
|
Future<List<ListSharingItem>> _query(ListSharingBlocQuery ev) async {
|
||||||
|
return (await Future.wait([
|
||||||
|
_querySharesByMe(ev),
|
||||||
|
_querySharesWithMe(ev),
|
||||||
|
]))
|
||||||
|
.reduce((value, element) => value + element);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ListSharingItem>> _querySharesByMe(
|
||||||
|
ListSharingBlocQuery ev) async {
|
||||||
final shareRepo = ShareRepo(ShareRemoteDataSource());
|
final shareRepo = ShareRepo(ShareRemoteDataSource());
|
||||||
final shares = await shareRepo.listAll(ev.account);
|
final shares = await shareRepo.listAll(ev.account);
|
||||||
final futures = shares.map((e) async {
|
final futures = shares.map((e) async {
|
||||||
|
@ -206,7 +215,32 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
|
||||||
final file = await FindFile()(ev.account, e.itemSource);
|
final file = await FindFile()(ev.account, e.itemSource);
|
||||||
return ListSharingItem(e, file);
|
return ListSharingItem(e, file);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
_log.warning("[_query] File not found: ${e.itemSource}");
|
_log.warning("[_querySharesByMe] File not found: ${e.itemSource}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (await Future.wait(futures)).whereType<ListSharingItem>().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ListSharingItem>> _querySharesWithMe(
|
||||||
|
ListSharingBlocQuery ev) async {
|
||||||
|
final shareRepo = ShareRepo(ShareRemoteDataSource());
|
||||||
|
final shares = await shareRepo.reverseListAll(ev.account);
|
||||||
|
final futures = shares.map((e) async {
|
||||||
|
if (!file_util.isSupportedMime(e.mimeType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ev.account.roots
|
||||||
|
.every((r) => r.isNotEmpty && !e.path.startsWith("/$r/"))) {
|
||||||
|
// ignore files not under root dirs
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final file = await FindFile()(ev.account, e.itemSource);
|
||||||
|
return ListSharingItem(e, file);
|
||||||
|
} catch (_) {
|
||||||
|
_log.warning("[_querySharesWithMe] File not found: ${e.itemSource}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -88,6 +88,8 @@ class Share with EquatableMixin {
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.shareType,
|
required this.shareType,
|
||||||
required this.stime,
|
required this.stime,
|
||||||
|
required this.uidOwner,
|
||||||
|
required this.displaynameOwner,
|
||||||
required String path,
|
required String path,
|
||||||
required this.itemType,
|
required this.itemType,
|
||||||
required this.mimeType,
|
required this.mimeType,
|
||||||
|
@ -103,6 +105,8 @@ class Share with EquatableMixin {
|
||||||
"id: $id, "
|
"id: $id, "
|
||||||
"shareType: $shareType, "
|
"shareType: $shareType, "
|
||||||
"stime: $stime, "
|
"stime: $stime, "
|
||||||
|
"uidOwner: $uidOwner, "
|
||||||
|
"displaynameOwner: $displaynameOwner, "
|
||||||
"path: $path, "
|
"path: $path, "
|
||||||
"itemType: $itemType, "
|
"itemType: $itemType, "
|
||||||
"mimeType: $mimeType, "
|
"mimeType: $mimeType, "
|
||||||
|
@ -118,6 +122,8 @@ class Share with EquatableMixin {
|
||||||
id,
|
id,
|
||||||
shareType,
|
shareType,
|
||||||
stime,
|
stime,
|
||||||
|
uidOwner,
|
||||||
|
displaynameOwner,
|
||||||
path,
|
path,
|
||||||
itemType,
|
itemType,
|
||||||
mimeType,
|
mimeType,
|
||||||
|
@ -131,6 +137,8 @@ class Share with EquatableMixin {
|
||||||
final String id;
|
final String id;
|
||||||
final ShareType shareType;
|
final ShareType shareType;
|
||||||
final DateTime stime;
|
final DateTime stime;
|
||||||
|
final String uidOwner;
|
||||||
|
final String displaynameOwner;
|
||||||
final String path;
|
final String path;
|
||||||
final ShareItemType itemType;
|
final ShareItemType itemType;
|
||||||
final String mimeType;
|
final String mimeType;
|
||||||
|
@ -158,6 +166,10 @@ class ShareRepo {
|
||||||
/// See [ShareDataSource.listAll]
|
/// See [ShareDataSource.listAll]
|
||||||
Future<List<Share>> listAll(Account account) => dataSrc.listAll(account);
|
Future<List<Share>> listAll(Account account) => dataSrc.listAll(account);
|
||||||
|
|
||||||
|
/// See [ShareDataSource.reverseListAll]
|
||||||
|
Future<List<Share>> reverseListAll(Account account) =>
|
||||||
|
dataSrc.reverseListAll(account);
|
||||||
|
|
||||||
/// See [ShareDataSource.create]
|
/// See [ShareDataSource.create]
|
||||||
Future<Share> create(Account account, File file, String shareWith) =>
|
Future<Share> create(Account account, File file, String shareWith) =>
|
||||||
dataSrc.create(account, file, shareWith);
|
dataSrc.create(account, file, shareWith);
|
||||||
|
@ -187,6 +199,9 @@ abstract class ShareDataSource {
|
||||||
/// List all shares from a given user
|
/// List all shares from a given user
|
||||||
Future<List<Share>> listAll(Account account);
|
Future<List<Share>> listAll(Account account);
|
||||||
|
|
||||||
|
/// List all shares by other users with a given user
|
||||||
|
Future<List<Share>> reverseListAll(Account account);
|
||||||
|
|
||||||
/// Share a file/folder with a user
|
/// Share a file/folder with a user
|
||||||
Future<Share> create(Account account, File file, String shareWith);
|
Future<Share> create(Account account, File file, String shareWith);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:nc_photos/api/api.dart';
|
||||||
import 'package:nc_photos/entity/file.dart';
|
import 'package:nc_photos/entity/file.dart';
|
||||||
import 'package:nc_photos/entity/share.dart';
|
import 'package:nc_photos/entity/share.dart';
|
||||||
import 'package:nc_photos/exception.dart';
|
import 'package:nc_photos/exception.dart';
|
||||||
|
import 'package:nc_photos/iterable_extension.dart';
|
||||||
import 'package:nc_photos/type.dart';
|
import 'package:nc_photos/type.dart';
|
||||||
|
|
||||||
class ShareRemoteDataSource implements ShareDataSource {
|
class ShareRemoteDataSource implements ShareDataSource {
|
||||||
|
@ -35,6 +36,15 @@ class ShareRemoteDataSource implements ShareDataSource {
|
||||||
return _onListResult(response);
|
return _onListResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
reverseListAll(Account account) async {
|
||||||
|
_log.info("[reverseListAll] $account");
|
||||||
|
final response = await Api(account).ocs().filesSharing().shares().get(
|
||||||
|
sharedWithMe: true,
|
||||||
|
);
|
||||||
|
return _onListResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
create(Account account, File file, String shareWith) async {
|
create(Account account, File file, String shareWith) async {
|
||||||
_log.info("[create] Share '${file.path}' with '$shareWith'");
|
_log.info("[create] Share '${file.path}' with '$shareWith'");
|
||||||
|
@ -127,8 +137,9 @@ class _ShareParser {
|
||||||
return Share(
|
return Share(
|
||||||
id: json["id"],
|
id: json["id"],
|
||||||
shareType: shareType,
|
shareType: shareType,
|
||||||
stime:
|
stime: DateTime.fromMillisecondsSinceEpoch(json["stime"] * 1000),
|
||||||
DateTime.fromMillisecondsSinceEpoch(json["stime"] * 1000),
|
uidOwner: json["uid_owner"],
|
||||||
|
displaynameOwner: json["displayname_owner"],
|
||||||
path: json["path"],
|
path: json["path"],
|
||||||
itemType: itemType,
|
itemType: itemType,
|
||||||
mimeType: json["mimetype"],
|
mimeType: json["mimetype"],
|
||||||
|
|
|
@ -869,6 +869,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fileLastSharedByOthersDescription": "{user} shared with you on {date}",
|
||||||
|
"@fileLastSharedByOthersDescription": {
|
||||||
|
"description": "The date when this file was shared with you",
|
||||||
|
"placeholders": {
|
||||||
|
"user": {
|
||||||
|
"example": "Alice"
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"example": "Jan 1, 2021",
|
||||||
|
"description": "The date string is formatted according to the current locale"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sharedWithLabel": "Shared with",
|
"sharedWithLabel": "Shared with",
|
||||||
"@sharedWithLabel": {
|
"@sharedWithLabel": {
|
||||||
"description": "A list of users or links where this file is sharing with"
|
"description": "A list of users or links where this file is sharing with"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"sortOptionManualLabel",
|
"sortOptionManualLabel",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
"shareMethodPasswordLinkDescription",
|
"shareMethodPasswordLinkDescription",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
@ -137,6 +139,7 @@
|
||||||
"shareMethodPasswordLinkDescription",
|
"shareMethodPasswordLinkDescription",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
@ -160,6 +163,7 @@
|
||||||
"sortOptionManualLabel",
|
"sortOptionManualLabel",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
@ -232,6 +236,7 @@
|
||||||
"shareMethodPasswordLinkDescription",
|
"shareMethodPasswordLinkDescription",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
@ -277,6 +282,7 @@
|
||||||
"shareMethodPasswordLinkDescription",
|
"shareMethodPasswordLinkDescription",
|
||||||
"collectionSharingLabel",
|
"collectionSharingLabel",
|
||||||
"fileLastSharedDescription",
|
"fileLastSharedDescription",
|
||||||
|
"fileLastSharedByOthersDescription",
|
||||||
"sharedWithLabel",
|
"sharedWithLabel",
|
||||||
"unshareTooltip",
|
"unshareTooltip",
|
||||||
"unshareSuccessNotification",
|
"unshareSuccessNotification",
|
||||||
|
|
|
@ -127,23 +127,25 @@ class _SharedFileViewerState extends State<SharedFileViewer> {
|
||||||
title: Text(widget.file.strippedPath),
|
title: Text(widget.file.strippedPath),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
if (widget.shares.first.uidOwner == widget.account.username) ...[
|
||||||
child: Padding(
|
SliverToBoxAdapter(
|
||||||
padding: const EdgeInsets.all(16),
|
child: Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(16),
|
||||||
L10n.global().sharedWithLabel,
|
child: Text(
|
||||||
style: TextStyle(
|
L10n.global().sharedWithLabel,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SliverList(
|
||||||
SliverList(
|
delegate: SliverChildBuilderDelegate(
|
||||||
delegate: SliverChildBuilderDelegate(
|
(context, index) => _buildShareItem(context, _shares[index]),
|
||||||
(context, index) => _buildShareItem(context, _shares[index]),
|
childCount: _shares.length,
|
||||||
childCount: _shares.length,
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,10 @@ class _SharingBrowserState extends State<SharingBrowser> {
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
L10n.global().fileLastSharedDescription(dateStr),
|
shares.first.share.uidOwner == widget.account.username
|
||||||
|
? L10n.global().fileLastSharedDescription(dateStr)
|
||||||
|
: L10n.global().fileLastSharedByOthersDescription(
|
||||||
|
shares.first.share.displaynameOwner, dateStr),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppTheme.getSecondaryTextColor(context),
|
color: AppTheme.getSecondaryTextColor(context),
|
||||||
),
|
),
|
||||||
|
@ -238,8 +241,10 @@ class _SharingBrowserState extends State<SharingBrowser> {
|
||||||
// group shares of the same file
|
// group shares of the same file
|
||||||
final map = <String, List<ListSharingItem>>{};
|
final map = <String, List<ListSharingItem>>{};
|
||||||
for (final i in items) {
|
for (final i in items) {
|
||||||
map[i.share.path] ??= <ListSharingItem>[];
|
final isSharedByMe = i.share.uidOwner == widget.account.username;
|
||||||
map[i.share.path]!.add(i);
|
final groupKey = "${i.share.path}?$isSharedByMe";
|
||||||
|
map[groupKey] ??= <ListSharingItem>[];
|
||||||
|
map[groupKey]!.add(i);
|
||||||
}
|
}
|
||||||
// sort the sub-lists
|
// sort the sub-lists
|
||||||
for (final list in map.values) {
|
for (final list in map.values) {
|
||||||
|
|
Loading…
Reference in a new issue