ente/lib/models/collection.dart

341 lines
9.5 KiB
Dart
Raw Normal View History

2022-03-21 09:32:24 +00:00
import 'dart:core';
2020-10-09 18:43:59 +00:00
import 'package:flutter/foundation.dart';
import "package:photos/models/api/collection/public_url.dart";
import "package:photos/models/api/collection/user.dart";
import "package:photos/models/metadata/collection_magic.dart";
import "package:photos/models/metadata/common_keys.dart";
2020-11-02 14:38:59 +00:00
2020-10-09 18:43:59 +00:00
class Collection {
final int id;
final User? owner;
2020-10-09 18:43:59 +00:00
final String encryptedKey;
final String? keyDecryptionNonce;
@Deprecated("Use collectionName instead")
2023-05-23 09:24:39 +00:00
String? name;
2022-12-30 09:44:52 +00:00
// encryptedName & nameDecryptionNonce will be null for collections
// created before we started encrypting collection name
final String? encryptedName;
final String? nameDecryptionNonce;
2020-10-09 18:43:59 +00:00
final CollectionType type;
final CollectionAttributes attributes;
final List<User?>? sharees;
final List<PublicURL?>? publicURLs;
2020-10-31 12:48:41 +00:00
final int updationTime;
final bool isDeleted;
// In early days before public launch, we used to store collection name
// un-encrypted. decryptName will be value either decrypted value for
// encryptedName or name itself.
String? decryptedName;
// decryptedPath will be null for collections now owned by user, deleted
// collections, && collections which don't have a path. The path is used
// to map local on-device album on mobile to remote collection on ente.
String? decryptedPath;
String? mMdEncodedJson;
String? mMdPubEncodedJson;
String? sharedMmdJson;
2022-03-21 09:32:24 +00:00
int mMdVersion = 0;
int mMbPubVersion = 0;
int sharedMmdVersion = 0;
CollectionMagicMetadata? _mmd;
CollectionPubMagicMetadata? _pubMmd;
ShareeMagicMetadata? _sharedMmd;
2022-03-21 09:32:24 +00:00
CollectionMagicMetadata get magicMetadata =>
_mmd ?? CollectionMagicMetadata.fromEncodedJson(mMdEncodedJson ?? '{}');
CollectionPubMagicMetadata get pubMagicMetadata =>
_pubMmd ??
CollectionPubMagicMetadata.fromEncodedJson(mMdPubEncodedJson ?? '{}');
ShareeMagicMetadata get sharedMagicMetadata =>
_sharedMmd ?? ShareeMagicMetadata.fromEncodedJson(sharedMmdJson ?? '{}');
set magicMetadata(CollectionMagicMetadata? val) => _mmd = val;
2020-10-09 18:43:59 +00:00
set pubMagicMetadata(CollectionPubMagicMetadata? val) => _pubMmd = val;
set sharedMagicMetadata(ShareeMagicMetadata? val) => _sharedMmd = val;
2020-10-09 18:43:59 +00:00
2023-05-23 09:24:39 +00:00
String get displayName => decryptedName ?? name ?? "Unnamed Album";
2023-05-23 20:13:12 +00:00
// set the value for both name and decryptedName till we finish migration
void setName(String newName) {
name = newName;
decryptedName = newName;
}
2020-10-09 18:43:59 +00:00
Collection(
this.id,
2020-10-31 16:11:43 +00:00
this.owner,
2020-10-09 18:43:59 +00:00
this.encryptedKey,
this.keyDecryptionNonce,
this.name,
this.encryptedName,
this.nameDecryptionNonce,
2020-10-09 18:43:59 +00:00
this.type,
2020-10-21 22:22:09 +00:00
this.attributes,
2020-11-02 14:38:59 +00:00
this.sharees,
this.publicURLs,
2020-10-31 12:48:41 +00:00
this.updationTime, {
this.isDeleted = false,
});
2020-10-09 18:43:59 +00:00
2022-03-21 09:32:24 +00:00
bool isArchived() {
return mMdVersion > 0 && magicMetadata.visibility == archiveVisibility;
2022-03-21 09:32:24 +00:00
}
bool hasShareeArchived() {
return sharedMmdVersion > 0 &&
sharedMagicMetadata.visibility == archiveVisibility;
}
2023-01-25 11:02:08 +00:00
// hasLink returns true if there's any link attached to the collection
// including expired links
bool get hasLink => publicURLs != null && publicURLs!.isNotEmpty;
// hasSharees returns true if the collection is shared with other ente users
bool get hasSharees => sharees != null && sharees!.isNotEmpty;
bool isHidden() {
if (isDefaultHidden()) {
return true;
}
return mMdVersion > 0 && (magicMetadata.visibility == hiddenVisibility);
}
bool isDefaultHidden() {
return (magicMetadata.subType ?? 0) == subTypeDefaultHidden;
}
bool isSharedFilesCollection() {
return (magicMetadata.subType ?? 0) == subTypeSharedFilesCollection;
}
2022-11-22 10:21:44 +00:00
List<User> getSharees() {
final List<User> result = [];
if (sharees == null) {
return result;
}
for (final User? u in sharees!) {
if (u != null) {
result.add(u);
}
}
return result;
}
bool isOwner(int userID) {
return (owner?.id ?? 0) == userID;
}
2023-06-19 10:28:15 +00:00
CollectionParticipantRole getRole(int userID) {
if (isOwner(userID)) {
return CollectionParticipantRole.owner;
}
if (sharees == null) {
return CollectionParticipantRole.unknown;
}
for (final User? u in sharees!) {
if (u != null && u.id == userID) {
if (u.isViewer) {
return CollectionParticipantRole.viewer;
} else if (u.isCollaborator) {
return CollectionParticipantRole.collaborator;
}
}
}
return CollectionParticipantRole.unknown;
}
2023-05-23 13:12:28 +00:00
// canLinkToDevicePath returns true if the collection can be linked to local
// device album based on path. The path is nothing but the name of the device
// album.
bool canLinkToDevicePath(int userID) {
return isOwner(userID) && !isDeleted && attributes.encryptedPath != null;
}
void updateSharees(List<User> newSharees) {
sharees?.clear();
sharees?.addAll(newSharees);
}
2020-10-21 22:22:09 +00:00
static CollectionType typeFromString(String type) {
switch (type) {
case "folder":
return CollectionType.folder;
case "favorites":
return CollectionType.favorites;
case "uncategorized":
return CollectionType.uncategorized;
case "album":
return CollectionType.album;
case "unknown":
return CollectionType.unknown;
2020-10-21 22:22:09 +00:00
}
debugPrint("unexpected collection type $type");
return CollectionType.unknown;
2020-10-21 22:22:09 +00:00
}
static String typeToString(CollectionType type) {
switch (type) {
case CollectionType.folder:
return "folder";
case CollectionType.favorites:
return "favorites";
case CollectionType.album:
2020-10-21 22:22:09 +00:00
return "album";
case CollectionType.uncategorized:
return "uncategorized";
case CollectionType.unknown:
return "unknown";
2020-10-21 22:22:09 +00:00
}
}
2022-06-11 08:23:52 +00:00
Collection copyWith({
int? id,
User? owner,
String? encryptedKey,
String? keyDecryptionNonce,
String? name,
String? encryptedName,
String? nameDecryptionNonce,
CollectionType? type,
CollectionAttributes? attributes,
List<User>? sharees,
List<PublicURL>? publicURLs,
int? updationTime,
bool? isDeleted,
String? mMdEncodedJson,
int? mMdVersion,
String? decryptedName,
String? decryptedPath,
2022-06-11 08:23:52 +00:00
}) {
2022-08-29 14:43:31 +00:00
final Collection result = Collection(
2020-11-02 14:38:59 +00:00
id ?? this.id,
owner ?? this.owner,
encryptedKey ?? this.encryptedKey,
keyDecryptionNonce ?? this.keyDecryptionNonce,
name ?? this.name,
encryptedName ?? this.encryptedName,
nameDecryptionNonce ?? this.nameDecryptionNonce,
2020-11-02 14:38:59 +00:00
type ?? this.type,
attributes ?? this.attributes,
sharees ?? this.sharees,
publicURLs ?? this.publicURLs,
2020-11-02 14:38:59 +00:00
updationTime ?? this.updationTime,
isDeleted: isDeleted ?? this.isDeleted,
);
2022-03-21 09:32:24 +00:00
result.mMdVersion = mMdVersion ?? this.mMdVersion;
result.mMdEncodedJson = mMdEncodedJson ?? this.mMdEncodedJson;
result.decryptedName = decryptedName ?? this.decryptedName;
result.decryptedPath = decryptedPath ?? this.decryptedPath;
2023-05-26 03:05:06 +00:00
result.mMbPubVersion = mMbPubVersion;
result.mMdPubEncodedJson = mMdPubEncodedJson;
result.sharedMmdVersion = sharedMmdVersion;
result.sharedMmdJson = sharedMmdJson;
2022-03-21 09:32:24 +00:00
return result;
2020-11-02 14:38:59 +00:00
}
static fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
2020-11-02 14:38:59 +00:00
final sharees = (map['sharees'] == null || map['sharees'].length == 0)
2021-07-22 18:41:58 +00:00
? <User>[]
2020-11-02 14:38:59 +00:00
: List<User>.from(map['sharees'].map((x) => User.fromMap(x)));
final publicURLs =
(map['publicURLs'] == null || map['publicURLs'].length == 0)
? <PublicURL>[]
: List<PublicURL>.from(
2022-06-11 08:23:52 +00:00
map['publicURLs'].map((x) => PublicURL.fromMap(x)),
);
2020-10-09 18:43:59 +00:00
return Collection(
map['id'],
2020-11-02 14:38:59 +00:00
User.fromMap(map['owner']),
2020-10-09 18:43:59 +00:00
map['encryptedKey'],
map['keyDecryptionNonce'],
map['name'],
map['encryptedName'],
map['nameDecryptionNonce'],
typeFromString(map['type']),
2020-10-21 22:22:09 +00:00
CollectionAttributes.fromMap(map['attributes']),
2020-11-02 14:38:59 +00:00
sharees,
publicURLs,
2020-10-31 12:48:41 +00:00
map['updationTime'],
isDeleted: map['isDeleted'] ?? false,
2020-10-09 18:43:59 +00:00
);
}
}
2020-10-09 18:43:59 +00:00
enum CollectionType {
folder,
favorites,
uncategorized,
2020-10-09 18:43:59 +00:00
album,
unknown,
2020-10-09 18:43:59 +00:00
}
2020-10-21 22:22:09 +00:00
extension CollectionTypeExtn on CollectionType {
bool get canDelete =>
this != CollectionType.favorites && this != CollectionType.uncategorized;
}
2022-11-22 15:53:50 +00:00
enum CollectionParticipantRole {
unknown,
viewer,
collaborator,
owner,
}
extension CollectionParticipantRoleExtn on CollectionParticipantRole {
static CollectionParticipantRole fromString(String? val) {
if ((val ?? '') == '') {
return CollectionParticipantRole.viewer;
}
for (var x in CollectionParticipantRole.values) {
if (x.name.toUpperCase() == val!.toUpperCase()) {
return x;
}
}
return CollectionParticipantRole.unknown;
}
String toStringVal() {
return name.toUpperCase();
}
}
2020-10-21 22:22:09 +00:00
class CollectionAttributes {
final String? encryptedPath;
final String? pathDecryptionNonce;
final int? version;
2021-01-24 06:12:10 +00:00
2020-10-21 22:22:09 +00:00
CollectionAttributes({
this.encryptedPath,
this.pathDecryptionNonce,
this.version,
2020-10-21 22:22:09 +00:00
});
Map<String, dynamic> toMap() {
2021-07-22 18:41:58 +00:00
final map = <String, dynamic>{};
2020-10-21 22:22:09 +00:00
if (encryptedPath != null) {
map['encryptedPath'] = encryptedPath;
}
if (pathDecryptionNonce != null) {
map['pathDecryptionNonce'] = pathDecryptionNonce;
}
map['version'] = version ?? 0;
2020-10-21 22:22:09 +00:00
return map;
}
static fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
2020-10-21 22:22:09 +00:00
return CollectionAttributes(
encryptedPath: map['encryptedPath'],
pathDecryptionNonce: map['pathDecryptionNonce'],
version: map['version'] ?? 0,
2020-10-21 22:22:09 +00:00
);
}
}