2020-10-09 18:43:59 +00:00
|
|
|
import 'dart:convert';
|
2022-03-21 09:32:24 +00:00
|
|
|
import 'dart:core';
|
2020-10-09 18:43:59 +00:00
|
|
|
|
2022-12-20 09:32:57 +00:00
|
|
|
import 'package:flutter/foundation.dart';
|
2022-03-21 09:32:24 +00:00
|
|
|
import 'package:photos/models/magic_metadata.dart';
|
2020-11-02 14:38:59 +00:00
|
|
|
|
2020-10-09 18:43:59 +00:00
|
|
|
class Collection {
|
|
|
|
final int id;
|
2022-09-20 06:12:35 +00:00
|
|
|
final User? owner;
|
2020-10-09 18:43:59 +00:00
|
|
|
final String encryptedKey;
|
2022-09-20 06:12:35 +00:00
|
|
|
final String? keyDecryptionNonce;
|
2022-09-21 01:07:08 +00:00
|
|
|
final 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;
|
2022-09-21 10:47:50 +00:00
|
|
|
final CollectionAttributes attributes;
|
2022-09-20 06:12:35 +00:00
|
|
|
final List<User?>? sharees;
|
|
|
|
final List<PublicURL?>? publicURLs;
|
2020-10-31 12:48:41 +00:00
|
|
|
final int updationTime;
|
|
|
|
final bool isDeleted;
|
2022-09-20 06:12:35 +00:00
|
|
|
String? mMdEncodedJson;
|
2022-03-21 09:32:24 +00:00
|
|
|
int mMdVersion = 0;
|
2022-09-20 06:12:35 +00:00
|
|
|
CollectionMagicMetadata? _mmd;
|
2022-03-21 09:32:24 +00:00
|
|
|
|
|
|
|
CollectionMagicMetadata get magicMetadata =>
|
|
|
|
_mmd ?? CollectionMagicMetadata.fromEncodedJson(mMdEncodedJson ?? '{}');
|
|
|
|
|
|
|
|
set magicMetadata(val) => _mmd = val;
|
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,
|
2021-01-22 08:17:22 +00:00
|
|
|
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,
|
2022-01-23 06:04:39 +00:00
|
|
|
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() {
|
2022-09-19 11:52:20 +00:00
|
|
|
return mMdVersion > 0 && magicMetadata.visibility == visibilityArchive;
|
2022-03-21 09:32:24 +00:00
|
|
|
}
|
|
|
|
|
2022-10-14 08:35:20 +00:00
|
|
|
bool isHidden() {
|
|
|
|
if (isDefaultHidden()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return mMdVersion > 0 && (magicMetadata.visibility == visibilityHidden);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDefaultHidden() {
|
|
|
|
return (magicMetadata.subType ?? 0) == subTypeDefaultHidden;
|
|
|
|
}
|
|
|
|
|
2022-12-22 17:55:09 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-12-17 09:28:16 +00:00
|
|
|
bool isOwner(int userID) {
|
|
|
|
return (owner?.id ?? 0) == userID;
|
|
|
|
}
|
|
|
|
|
2022-11-25 11:04:35 +00:00
|
|
|
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;
|
2022-12-20 09:32:57 +00:00
|
|
|
case "uncategorized":
|
|
|
|
return CollectionType.uncategorized;
|
|
|
|
case "album":
|
|
|
|
return CollectionType.album;
|
|
|
|
case "unknown":
|
|
|
|
return CollectionType.unknown;
|
2020-10-21 22:22:09 +00:00
|
|
|
}
|
2022-12-20 09:32:57 +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";
|
2022-12-20 09:32:57 +00:00
|
|
|
case CollectionType.album:
|
2020-10-21 22:22:09 +00:00
|
|
|
return "album";
|
2022-12-20 09:32:57 +00:00
|
|
|
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({
|
2022-09-20 06:12:35 +00:00
|
|
|
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,
|
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,
|
2021-01-22 08:17:22 +00:00
|
|
|
encryptedName ?? this.encryptedName,
|
|
|
|
nameDecryptionNonce ?? this.nameDecryptionNonce,
|
2020-11-02 14:38:59 +00:00
|
|
|
type ?? this.type,
|
|
|
|
attributes ?? this.attributes,
|
|
|
|
sharees ?? this.sharees,
|
2022-01-23 06:04:39 +00:00
|
|
|
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;
|
|
|
|
return result;
|
2020-11-02 14:38:59 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 18:43:59 +00:00
|
|
|
Map<String, dynamic> toMap() {
|
|
|
|
return {
|
|
|
|
'id': id,
|
2020-10-31 16:11:43 +00:00
|
|
|
'owner': owner?.toMap(),
|
2020-10-09 18:43:59 +00:00
|
|
|
'encryptedKey': encryptedKey,
|
|
|
|
'keyDecryptionNonce': keyDecryptionNonce,
|
|
|
|
'name': name,
|
2021-01-22 08:17:22 +00:00
|
|
|
'encryptedName': encryptedName,
|
|
|
|
'nameDecryptionNonce': nameDecryptionNonce,
|
2020-10-12 19:14:23 +00:00
|
|
|
'type': typeToString(type),
|
2022-09-21 10:47:50 +00:00
|
|
|
'attributes': attributes.toMap(),
|
2022-09-20 06:12:35 +00:00
|
|
|
'sharees': sharees?.map((x) => x?.toMap()).toList(),
|
|
|
|
'publicURLs': publicURLs?.map((x) => x?.toMap()).toList(),
|
2020-10-31 12:48:41 +00:00
|
|
|
'updationTime': updationTime,
|
2020-11-02 14:38:59 +00:00
|
|
|
'isDeleted': isDeleted,
|
2020-10-09 18:43:59 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-09-21 08:55:00 +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)));
|
2022-01-23 06:04:39 +00:00
|
|
|
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'],
|
2021-01-22 08:17:22 +00:00
|
|
|
map['encryptedName'],
|
|
|
|
map['nameDecryptionNonce'],
|
2020-10-12 19:14:23 +00:00
|
|
|
typeFromString(map['type']),
|
2020-10-21 22:22:09 +00:00
|
|
|
CollectionAttributes.fromMap(map['attributes']),
|
2020-11-02 14:38:59 +00:00
|
|
|
sharees,
|
2022-01-23 06:04:39 +00:00
|
|
|
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-12 19:14:23 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 18:43:59 +00:00
|
|
|
enum CollectionType {
|
|
|
|
folder,
|
|
|
|
favorites,
|
2022-12-20 09:32:57 +00:00
|
|
|
uncategorized,
|
2020-10-09 18:43:59 +00:00
|
|
|
album,
|
2022-12-20 09:32:57 +00:00
|
|
|
unknown,
|
2020-10-09 18:43:59 +00:00
|
|
|
}
|
2020-10-21 22:22:09 +00:00
|
|
|
|
2023-01-12 04:26:01 +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 {
|
2022-09-20 06:12:35 +00:00
|
|
|
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,
|
2021-01-24 14:05:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-02-14 18:15:38 +00:00
|
|
|
map['version'] = version ?? 0;
|
2020-10-21 22:22:09 +00:00
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2022-09-21 08:55:00 +00:00
|
|
|
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'],
|
2021-01-24 14:05:18 +00:00
|
|
|
version: map['version'] ?? 0,
|
2020-10-21 22:22:09 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-10-31 16:11:43 +00:00
|
|
|
|
2020-11-02 14:38:59 +00:00
|
|
|
class User {
|
2022-09-20 06:12:35 +00:00
|
|
|
int? id;
|
2020-10-31 16:11:43 +00:00
|
|
|
String email;
|
2022-09-20 06:12:35 +00:00
|
|
|
String? name;
|
2022-11-21 02:10:42 +00:00
|
|
|
String? role;
|
2020-10-31 16:11:43 +00:00
|
|
|
|
2020-11-02 14:38:59 +00:00
|
|
|
User({
|
2020-10-31 16:11:43 +00:00
|
|
|
this.id,
|
2022-09-20 06:12:35 +00:00
|
|
|
required this.email,
|
2020-10-31 16:11:43 +00:00
|
|
|
this.name,
|
2022-11-20 11:54:10 +00:00
|
|
|
this.role,
|
2020-10-31 16:11:43 +00:00
|
|
|
});
|
|
|
|
|
2022-11-21 02:10:42 +00:00
|
|
|
bool get isViewer => role == null || role?.toUpperCase() == 'VIEWER';
|
|
|
|
|
|
|
|
bool get isCollaborator =>
|
|
|
|
role != null && role?.toUpperCase() == 'COLLABORATOR';
|
|
|
|
|
2020-10-31 16:11:43 +00:00
|
|
|
Map<String, dynamic> toMap() {
|
2022-11-20 11:54:10 +00:00
|
|
|
return {'id': id, 'email': email, 'name': name, 'role': role};
|
2020-10-31 16:11:43 +00:00
|
|
|
}
|
|
|
|
|
2022-09-21 08:55:00 +00:00
|
|
|
static fromMap(Map<String, dynamic>? map) {
|
|
|
|
if (map == null) return null;
|
2020-10-31 16:11:43 +00:00
|
|
|
|
2020-11-02 14:38:59 +00:00
|
|
|
return User(
|
2020-10-31 16:11:43 +00:00
|
|
|
id: map['id'],
|
|
|
|
email: map['email'],
|
|
|
|
name: map['name'],
|
2022-11-20 11:54:10 +00:00
|
|
|
role: map['role'] ?? 'VIEWER',
|
2020-10-31 16:11:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
|
2020-11-02 14:38:59 +00:00
|
|
|
factory User.fromJson(String source) => User.fromMap(json.decode(source));
|
2020-10-31 16:11:43 +00:00
|
|
|
}
|
2022-01-23 06:04:39 +00:00
|
|
|
|
|
|
|
class PublicURL {
|
|
|
|
String url;
|
|
|
|
int deviceLimit;
|
|
|
|
int validTill;
|
2022-09-20 06:12:35 +00:00
|
|
|
bool enableDownload;
|
2022-12-11 13:06:36 +00:00
|
|
|
bool enableCollect;
|
2022-09-20 06:12:35 +00:00
|
|
|
bool passwordEnabled;
|
2022-01-23 06:04:39 +00:00
|
|
|
|
2022-06-11 08:23:52 +00:00
|
|
|
PublicURL({
|
2022-09-20 06:12:35 +00:00
|
|
|
required this.url,
|
|
|
|
required this.deviceLimit,
|
|
|
|
required this.validTill,
|
|
|
|
this.enableDownload = true,
|
|
|
|
this.passwordEnabled = false,
|
2022-12-11 13:06:36 +00:00
|
|
|
this.enableCollect = false,
|
2022-06-11 08:23:52 +00:00
|
|
|
});
|
2022-01-23 06:04:39 +00:00
|
|
|
|
|
|
|
Map<String, dynamic> toMap() {
|
|
|
|
return {
|
|
|
|
'url': url,
|
|
|
|
'deviceLimit': deviceLimit,
|
|
|
|
'validTill': validTill,
|
2022-02-22 06:08:27 +00:00
|
|
|
'enableDownload': enableDownload,
|
2022-02-21 02:13:10 +00:00
|
|
|
'passwordEnabled': passwordEnabled,
|
2022-12-11 13:06:36 +00:00
|
|
|
'enableCollect': enableCollect,
|
2022-01-23 06:04:39 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-11-21 09:28:17 +00:00
|
|
|
bool get hasExpiry => validTill != 0;
|
|
|
|
|
|
|
|
// isExpired indicates whether the link has expired or not
|
|
|
|
bool get isExpired =>
|
|
|
|
hasExpiry && validTill < DateTime.now().microsecondsSinceEpoch;
|
|
|
|
|
2022-09-21 08:55:00 +00:00
|
|
|
static fromMap(Map<String, dynamic>? map) {
|
|
|
|
if (map == null) return null;
|
2022-01-23 06:04:39 +00:00
|
|
|
|
|
|
|
return PublicURL(
|
|
|
|
url: map['url'],
|
|
|
|
deviceLimit: map['deviceLimit'],
|
2022-02-21 02:13:10 +00:00
|
|
|
validTill: map['validTill'] ?? 0,
|
2022-02-22 06:08:27 +00:00
|
|
|
enableDownload: map['enableDownload'] ?? true,
|
2022-02-21 02:13:10 +00:00
|
|
|
passwordEnabled: map['passwordEnabled'] ?? false,
|
2022-12-11 13:06:36 +00:00
|
|
|
enableCollect: map['enableCollect'] ?? false,
|
2022-01-23 06:04:39 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|