Track shared assets separately
This commit is contained in:
@@ -16,7 +16,6 @@ import 'package:photos/models/file_load_result.dart';
|
||||
import 'package:photos/models/location/location.dart';
|
||||
import "package:photos/models/metadata/common_keys.dart";
|
||||
import "package:photos/services/filter/db_filters.dart";
|
||||
import 'package:photos/utils/file_uploader_util.dart';
|
||||
import 'package:sqlite_async/sqlite_async.dart';
|
||||
|
||||
class FilesDB with SqlDbBase {
|
||||
|
||||
@@ -141,14 +141,19 @@ class LocalDBMigration {
|
||||
''',
|
||||
'''
|
||||
CREATE TABLE shared_assets (
|
||||
id TEXT PRIMARY KEY,
|
||||
dest_collection_id INTEGER NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
duration_in_sec INTEGER DEFAULT 0,
|
||||
dest_collection_id INTEGER NOT NULL,
|
||||
owner_id INTEGER NOT NULL
|
||||
owner_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (dest_collection_id, id),
|
||||
);
|
||||
''',
|
||||
'''
|
||||
CREATE INDEX IF NOT EXISTS sa_collection_owner ON shared_assets(dest_collection_id, owner_id);
|
||||
''',
|
||||
'''
|
||||
CREATE TABLE device_path (
|
||||
path_id TEXT PRIMARY KEY,
|
||||
|
||||
56
mobile/lib/db/local/table/shared_assets.dart
Normal file
56
mobile/lib/db/local/table/shared_assets.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import "package:collection/collection.dart";
|
||||
import "package:photos/db/local/db.dart";
|
||||
import "package:photos/models/local/shared_asset.dart";
|
||||
|
||||
extension SharedAssetsTable on LocalDB {
|
||||
Future<Set<String>> getSharedAssetsID() async {
|
||||
final result = await sqliteDB.getAll('SELECT id FROM shared_assets');
|
||||
return Set.unmodifiable(result.map<String>((row) => row['id'] as String));
|
||||
}
|
||||
|
||||
Future<void> insertSharedAssets(List<SharedAsset> assets) async {
|
||||
if (assets.isEmpty) return;
|
||||
await Future.forEach(
|
||||
assets.slices(LocalDB.batchInsertMaxCount),
|
||||
(slice) async {
|
||||
final List<List<Object?>> values =
|
||||
slice.map((e) => e.rowProps).toList();
|
||||
await sqliteDB.executeBatch(
|
||||
'INSERT INTO shared_assets (id, name, type, creation_time, duration_in_seconds, dest_collection_id, owner_id) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
values,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<SharedAsset>> getSharedAssets() async {
|
||||
final result = await sqliteDB.getAll(
|
||||
'SELECT * FROM shared_assets ORDER BY creation_time DESC',
|
||||
);
|
||||
return result.map((row) => SharedAsset.fromRow(row)).toList();
|
||||
}
|
||||
|
||||
Future<List<SharedAsset>> getSharedAssetsByCollection(
|
||||
int collectionID,
|
||||
) async {
|
||||
final result = await sqliteDB.getAll(
|
||||
'SELECT * FROM shared_assets WHERE dest_collection_id = ? ORDER BY creation_time DESC',
|
||||
[collectionID],
|
||||
);
|
||||
return result.map((row) => SharedAsset.fromRow(row)).toList();
|
||||
}
|
||||
|
||||
Future<void> deleteSharedAssetsByCollection(int collectionID) async {
|
||||
await sqliteDB.execute(
|
||||
'DELETE FROM shared_assets WHERE dest_collection_id = ?',
|
||||
[collectionID],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteSharedAsset(String assetID) async {
|
||||
await sqliteDB.execute(
|
||||
'DELETE FROM shared_assets WHERE id = ?',
|
||||
[assetID],
|
||||
);
|
||||
}
|
||||
}
|
||||
43
mobile/lib/models/local/shared_asset.dart
Normal file
43
mobile/lib/models/local/shared_asset.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import "package:photos/models/file/file_type.dart";
|
||||
|
||||
class SharedAsset {
|
||||
final String id;
|
||||
final String name;
|
||||
final FileType type;
|
||||
final int creationTime;
|
||||
final int durationInSeconds;
|
||||
final int destCollectionID;
|
||||
final int ownerID;
|
||||
|
||||
SharedAsset({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.creationTime,
|
||||
required this.durationInSeconds,
|
||||
required this.destCollectionID,
|
||||
required this.ownerID,
|
||||
});
|
||||
|
||||
List<Object?> get rowProps => [
|
||||
id,
|
||||
name,
|
||||
getInt(type),
|
||||
creationTime,
|
||||
durationInSeconds,
|
||||
destCollectionID,
|
||||
ownerID,
|
||||
];
|
||||
|
||||
factory SharedAsset.fromRow(Map<String, dynamic> map) {
|
||||
return SharedAsset(
|
||||
id: map['id'] as String,
|
||||
name: map['name'] as String,
|
||||
type: getFileType(['type'] as int),
|
||||
creationTime: map['creation_time'] as int,
|
||||
durationInSeconds: map['duration_in_seconds'] as int,
|
||||
destCollectionID: map['dest_collection_id'] as int,
|
||||
ownerID: map['owner_id'] as int,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import "package:photo_manager/photo_manager.dart";
|
||||
import "package:photos/core/configuration.dart";
|
||||
import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/db/files_db.dart";
|
||||
import "package:photos/db/local/table/shared_assets.dart";
|
||||
import "package:photos/events/collection_updated_event.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/collection/collection.dart';
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/collections_service.dart";
|
||||
import 'package:photos/services/favorites_service.dart';
|
||||
import "package:photos/services/hidden_service.dart";
|
||||
@@ -203,12 +205,12 @@ extension CollectionFileActions on CollectionActions {
|
||||
final List<EnteFile> filesPendingUpload = [];
|
||||
final int currentUserID = Configuration.instance.getUserID()!;
|
||||
if (sharedFiles != null) {
|
||||
filesPendingUpload.addAll(
|
||||
await convertIncomingSharedMediaToFile(
|
||||
sharedFiles,
|
||||
collectionID,
|
||||
),
|
||||
final sharedAssets = await convertIncomingSharedMediaToFile(
|
||||
sharedFiles,
|
||||
collectionID,
|
||||
Configuration.instance.getUserID()!,
|
||||
);
|
||||
await localDB.insertSharedAssets(sharedAssets);
|
||||
} else if (picketAssets != null) {
|
||||
filesPendingUpload.addAll(
|
||||
await convertPicketAssets(
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:photos/core/errors.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/core/network/network.dart';
|
||||
import 'package:photos/db/files_db.dart';
|
||||
import "package:photos/db/local/table/shared_assets.dart";
|
||||
import 'package:photos/db/upload_locks_db.dart';
|
||||
import "package:photos/events/backup_updated_event.dart";
|
||||
import "package:photos/events/file_uploaded_event.dart";
|
||||
@@ -394,9 +395,7 @@ class FileUploader {
|
||||
final sharedFiles = await Directory(sharedMediaDir).list().toList();
|
||||
if (sharedFiles.isNotEmpty) {
|
||||
_logger.info('Shared media directory cleanup ${sharedFiles.length}');
|
||||
final int ownerID = Configuration.instance.getUserID()!;
|
||||
final existingLocalFileIDs =
|
||||
await FilesDB.instance.getExistingLocalFileIDs(ownerID);
|
||||
final existingLocalFileIDs = await localDB.getSharedAssetsID();
|
||||
final Set<String> trackedSharedFilePaths = {};
|
||||
for (String localID in existingLocalFileIDs) {
|
||||
if (localID.contains(sharedMediaIdentifier)) {
|
||||
|
||||
@@ -8,12 +8,12 @@ import 'package:path/path.dart';
|
||||
import "package:photo_manager/photo_manager.dart";
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import "package:photos/db/files_db.dart";
|
||||
import "package:photos/db/remote/schema.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/collection/collection.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/file/file_type.dart';
|
||||
import "package:photos/models/local/shared_asset.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/ui/sharing/show_images_prevew.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
@@ -113,11 +113,12 @@ Future<ShareResult> shareText(
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<EnteFile>> convertIncomingSharedMediaToFile(
|
||||
Future<List<SharedAsset>> convertIncomingSharedMediaToFile(
|
||||
List<SharedMediaFile> sharedMedia,
|
||||
int collectionID,
|
||||
int ownerID,
|
||||
) async {
|
||||
final List<EnteFile> localFiles = [];
|
||||
final List<SharedAsset> sharedAssets = [];
|
||||
for (var media in sharedMedia) {
|
||||
if (!(media.type == SharedMediaType.image ||
|
||||
media.type == SharedMediaType.video)) {
|
||||
@@ -129,7 +130,11 @@ Future<List<EnteFile>> convertIncomingSharedMediaToFile(
|
||||
final enteFile = EnteFile();
|
||||
final sharedLocalId = const Uuid().v4();
|
||||
// fileName: img_x.jpg
|
||||
enteFile.title = basename(media.path);
|
||||
final String name = basename(media.path);
|
||||
int creationTime = 0;
|
||||
int durationInSeconds = 0;
|
||||
final fileType =
|
||||
media.type == SharedMediaType.image ? FileType.image : FileType.video;
|
||||
var ioFile = File(media.path);
|
||||
try {
|
||||
ioFile = ioFile.renameSync(
|
||||
@@ -156,32 +161,37 @@ Future<List<EnteFile>> convertIncomingSharedMediaToFile(
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
enteFile.localID = sharedMediaIdentifier + sharedLocalId;
|
||||
enteFile.collectionID = collectionID;
|
||||
enteFile.fileType =
|
||||
media.type == SharedMediaType.image ? FileType.image : FileType.video;
|
||||
if (enteFile.fileType == FileType.image) {
|
||||
|
||||
if (fileType == FileType.image) {
|
||||
final dateResult = await tryParseExifDateTime(ioFile, null);
|
||||
if (dateResult != null && dateResult.time != null) {
|
||||
enteFile.creationTime = dateResult.time!.microsecondsSinceEpoch;
|
||||
creationTime = dateResult.time!.microsecondsSinceEpoch;
|
||||
}
|
||||
} else if (enteFile.fileType == FileType.video) {
|
||||
enteFile.duration = (media.duration ?? 0) ~/ 1000;
|
||||
} else if (fileType == FileType.video) {
|
||||
durationInSeconds = (media.duration ?? 0) ~/ 1000;
|
||||
}
|
||||
if (enteFile.creationTime == null || enteFile.creationTime == 0) {
|
||||
if (creationTime == 0) {
|
||||
final parsedDateTime =
|
||||
parseDateTimeFromFileNameV2(basenameWithoutExtension(media.path));
|
||||
if (parsedDateTime != null) {
|
||||
enteFile.creationTime = parsedDateTime.microsecondsSinceEpoch;
|
||||
creationTime = parsedDateTime.microsecondsSinceEpoch;
|
||||
} else {
|
||||
enteFile.creationTime = DateTime.now().microsecondsSinceEpoch;
|
||||
creationTime = DateTime.now().microsecondsSinceEpoch;
|
||||
}
|
||||
}
|
||||
enteFile.modificationTime = enteFile.creationTime;
|
||||
enteFile.metadataVersion = EnteFile.kCurrentMetadataVersion;
|
||||
localFiles.add(enteFile);
|
||||
sharedAssets.add(
|
||||
SharedAsset(
|
||||
id: sharedLocalId,
|
||||
name: name,
|
||||
type: fileType,
|
||||
creationTime: creationTime,
|
||||
durationInSeconds: durationInSeconds,
|
||||
destCollectionID: collectionID,
|
||||
ownerID: ownerID,
|
||||
),
|
||||
);
|
||||
}
|
||||
return localFiles;
|
||||
return sharedAssets;
|
||||
}
|
||||
|
||||
Future<List<EnteFile>> convertPicketAssets(
|
||||
|
||||
Reference in New Issue
Block a user