Merge branch 'main' into photo_integration

This commit is contained in:
Neeraj Gupta 2023-05-01 16:19:06 +05:30
commit b3c0ec3941
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
7 changed files with 69 additions and 43 deletions

View file

@ -4,7 +4,7 @@ ente 是一个简单的应用程序来备份和分享您的照片和视频。
我们在Android、iOS、web 和桌面上有开源应用, 和您的照片将以端到端加密方式无缝同步 (e2ee)。 我们在Android、iOS、web 和桌面上有开源应用, 和您的照片将以端到端加密方式无缝同步 (e2ee)。
即使您不是亲人,也可以轻松地与您的个人分享您的相册。 即使您不是亲人,也可以轻松地与您的个人分享您的相册。 您可以分享可公开查看的链接,他们可以通过添加照片来查看您的相册并进行协作,即使没有帐户或应用。 如果你一直在寻找一个隐私友好的可以替代Google Photos你已经来到了正确的地方。 使用 Ente它们以端到端加密 (e2ee) 的方式存储。 这意味着只有您可以查看它们。 使用 Ente它们以端到端加密 (e2ee) 的方式存储。 这意味着只有您可以查看它们。 即使您不是亲人,也可以轻松地与您的个人分享您的相册。 即使您不是亲人,也可以轻松地与您的个人分享您的相册。 您可以分享可公开查看的链接,他们可以通过添加照片来查看您的相册并进行协作,即使没有帐户或应用。
您的加密数据已复制到三个不同的地点,包括巴黎的一个铺面掩体。 我们认真对待子孙后代,并确保您回忆比您长寿。 我们认真对待子孙后代,并确保您回忆比您长寿。 您的加密数据已复制到三个不同的地点,包括巴黎的一个铺面掩体。 我们认真对待子孙后代,并确保您回忆比您长寿。 我们认真对待子孙后代,并确保您回忆比您长寿。
@ -30,7 +30,7 @@ ente 是一个简单的应用程序来备份和分享您的照片和视频。
ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/photos-app/blob/f-droid/android/permissions.md ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/photos-app/blob/f-droid/android/permissions.md
价格 价格
我们不会永远提供免费计划,因为我们必须保持可持续性,经受住时间的考验。 相反,我们提供您可以自由分享的负担得起的计划。 您可以在 ente. 相反,我们提供您可以自由分享的负担得起的计划。 您可以在 ente.io找到更多信息。 我们不会永远提供免费计划,因为我们必须保持可持续性,经受住时间的考验。 相反,我们提供您可以自由分享的负担得起的计划。 您可以在 ente. 相反,我们提供您可以自由分享的负担得起的计划。 您可以在 ente.io找到更多信息。 您可以在 ente.io找到更多信息。
支持 支持
我们对提供人的支持感到自豪。 我们对提供人的支持感到自豪。 如果您是我们的付费客户您可以联系Team@ente.io并期待我们的团队在24小时内做出回应。 我们对提供人的支持感到自豪。 我们对提供人的支持感到自豪。 如果您是我们的付费客户您可以联系Team@ente.io并期待我们的团队在24小时内做出回应。

View file

@ -3,6 +3,7 @@ import 'dart:io';
import "package:adaptive_theme/adaptive_theme.dart"; import "package:adaptive_theme/adaptive_theme.dart";
import 'package:background_fetch/background_fetch.dart'; import 'package:background_fetch/background_fetch.dart';
import "package:computer/computer.dart";
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -153,6 +154,8 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
} else { } else {
AppLifecycleService.instance.onAppInForeground('init via: $via'); AppLifecycleService.instance.onAppInForeground('init via: $via');
} }
// Start workers asynchronously. No need to wait for them to start
Computer.shared().turnOn(workersCount: 4, verbose: kDebugMode);
CryptoUtil.init(); CryptoUtil.init();
await NotificationService.instance.init(); await NotificationService.instance.init();
await NetworkClient.instance.init(); await NetworkClient.instance.init();

View file

@ -16,7 +16,6 @@ const assetFetchPageSize = 2000;
Future<Tuple2<List<LocalPathAsset>, List<File>>> getLocalPathAssetsAndFiles( Future<Tuple2<List<LocalPathAsset>, List<File>>> getLocalPathAssetsAndFiles(
int fromTime, int fromTime,
int toTime, int toTime,
Computer computer,
) async { ) async {
final pathEntities = await _getGalleryList( final pathEntities = await _getGalleryList(
updateFromTime: fromTime, updateFromTime: fromTime,
@ -31,17 +30,24 @@ Future<Tuple2<List<LocalPathAsset>, List<File>>> getLocalPathAssetsAndFiles(
final List<File> uniqueFiles = []; final List<File> uniqueFiles = [];
for (AssetPathEntity pathEntity in pathEntities) { for (AssetPathEntity pathEntity in pathEntities) {
final List<AssetEntity> assetsInPath = await _getAllAssetLists(pathEntity); final List<AssetEntity> assetsInPath = await _getAllAssetLists(pathEntity);
final Tuple2<Set<String>, List<File>> result = await computer.compute( late Tuple2<Set<String>, List<File>> result;
_getLocalIDsAndFilesFromAssets, if (assetsInPath.isEmpty) {
param: <String, dynamic>{ result = const Tuple2({}, []);
"pathEntity": pathEntity, } else {
"fromTime": fromTime, result = await Computer.shared().compute(
"alreadySeenLocalIDs": alreadySeenLocalIDs, _getLocalIDsAndFilesFromAssets,
"assetList": assetsInPath, param: <String, dynamic>{
}, "pathEntity": pathEntity,
); "fromTime": fromTime,
alreadySeenLocalIDs.addAll(result.item1); "alreadySeenLocalIDs": alreadySeenLocalIDs,
uniqueFiles.addAll(result.item2); "assetList": assetsInPath,
},
taskName:
"getLocalPathAssetsAndFiles-${pathEntity.name}-count-${assetsInPath.length}",
);
alreadySeenLocalIDs.addAll(result.item1);
uniqueFiles.addAll(result.item2);
}
localPathAssets.add( localPathAssets.add(
LocalPathAsset( LocalPathAsset(
localIDs: result.item1, localIDs: result.item1,
@ -118,15 +124,17 @@ Future<LocalDiffResult> getDiffWithLocal(
Set<String> existingIDs, // localIDs of files already imported in app Set<String> existingIDs, // localIDs of files already imported in app
Map<String, Set<String>> pathToLocalIDs, Map<String, Set<String>> pathToLocalIDs,
Set<String> invalidIDs, Set<String> invalidIDs,
Computer computer,
) async { ) async {
final Map<String, dynamic> args = <String, dynamic>{}; final Map<String, dynamic> args = <String, dynamic>{};
args['assets'] = assets; args['assets'] = assets;
args['existingIDs'] = existingIDs; args['existingIDs'] = existingIDs;
args['invalidIDs'] = invalidIDs; args['invalidIDs'] = invalidIDs;
args['pathToLocalIDs'] = pathToLocalIDs; args['pathToLocalIDs'] = pathToLocalIDs;
final LocalDiffResult diffResult = final LocalDiffResult diffResult = await Computer.shared().compute(
await computer.compute(_getLocalAssetsDiff, param: args); _getLocalAssetsDiff,
param: args,
taskName: "getLocalAssetsDiff",
);
if (diffResult.localPathAssets != null) { if (diffResult.localPathAssets != null) {
diffResult.uniqueLocalFiles = diffResult.uniqueLocalFiles =
await _convertLocalAssetsToUniqueFiles(diffResult.localPathAssets!); await _convertLocalAssetsToUniqueFiles(diffResult.localPathAssets!);

View file

@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:computer/computer.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
@ -24,7 +23,6 @@ import 'package:tuple/tuple.dart';
class LocalSyncService { class LocalSyncService {
final _logger = Logger("LocalSyncService"); final _logger = Logger("LocalSyncService");
final _db = FilesDB.instance; final _db = FilesDB.instance;
final Computer _computer = Computer();
late SharedPreferences _prefs; late SharedPreferences _prefs;
Completer<void>? _existingSync; Completer<void>? _existingSync;
@ -47,7 +45,6 @@ class LocalSyncService {
if (!AppLifecycleService.instance.isForeground) { if (!AppLifecycleService.instance.isForeground) {
await PhotoManager.setIgnorePermissionCheck(true); await PhotoManager.setIgnorePermissionCheck(true);
} }
await _computer.turnOn(workersCount: 1);
if (hasGrantedPermissions()) { if (hasGrantedPermissions()) {
_registerChangeCallback(); _registerChangeCallback();
} }
@ -164,7 +161,6 @@ class LocalSyncService {
existingLocalFileIDs, existingLocalFileIDs,
pathToLocalIDs, pathToLocalIDs,
invalidIDs, invalidIDs,
_computer,
); );
bool hasAnyMappingChanged = false; bool hasAnyMappingChanged = false;
if (localDiffResult.newPathToLocalIDs?.isNotEmpty ?? false) { if (localDiffResult.newPathToLocalIDs?.isNotEmpty ?? false) {
@ -268,17 +264,18 @@ class LocalSyncService {
required int toTime, required int toTime,
}) async { }) async {
final Tuple2<List<LocalPathAsset>, List<File>> result = final Tuple2<List<LocalPathAsset>, List<File>> result =
await getLocalPathAssetsAndFiles(fromTime, toTime, _computer); await getLocalPathAssetsAndFiles(fromTime, toTime);
// Update the mapping for device path_id to local file id. Also, keep track
// of newly discovered device paths
await FilesDB.instance.insertLocalAssets(
result.item1,
shouldAutoBackup: Configuration.instance.hasSelectedAllFoldersForBackup(),
);
final List<File> files = result.item2; final List<File> files = result.item2;
if (files.isNotEmpty) { if (files.isNotEmpty) {
// Update the mapping for device path_id to local file id. Also, keep track
// of newly discovered device paths
await FilesDB.instance.insertLocalAssets(
result.item1,
shouldAutoBackup:
Configuration.instance.hasSelectedAllFoldersForBackup(),
);
_logger.info( _logger.info(
"Loaded ${files.length} photos from " + "Loaded ${files.length} photos from " +
DateTime.fromMicrosecondsSinceEpoch(fromTime).toString() + DateTime.fromMicrosecondsSinceEpoch(fromTime).toString() +

View file

@ -166,10 +166,10 @@ Uint8List chachaDecryptData(Map<String, dynamic> args) {
} }
class CryptoUtil { class CryptoUtil {
static final Computer _computer = Computer(); // Note: workers are turned on during app startup.
static final Computer _computer = Computer.shared();
static init() { static init() {
_computer.turnOn(workersCount: 4);
Sodium.init(); Sodium.init();
} }
@ -231,7 +231,11 @@ class CryptoUtil {
args["cipher"] = cipher; args["cipher"] = cipher;
args["nonce"] = nonce; args["nonce"] = nonce;
args["key"] = key; args["key"] = key;
return _computer.compute(cryptoSecretboxOpenEasy, param: args); return _computer.compute(
cryptoSecretboxOpenEasy,
param: args,
taskName: "decrypt",
);
} }
// Decrypts the given cipher, with the given key and nonce using XSalsa20 // Decrypts the given cipher, with the given key and nonce using XSalsa20
@ -262,7 +266,11 @@ class CryptoUtil {
final args = <String, dynamic>{}; final args = <String, dynamic>{};
args["source"] = source; args["source"] = source;
args["key"] = key; args["key"] = key;
return _computer.compute(chachaEncryptData, param: args); return _computer.compute(
chachaEncryptData,
param: args,
taskName: "encryptChaCha",
);
} }
// Decrypts the given source, with the given key and header using XChaCha20 // Decrypts the given source, with the given key and header using XChaCha20
@ -277,7 +285,11 @@ class CryptoUtil {
args["source"] = source; args["source"] = source;
args["key"] = key; args["key"] = key;
args["header"] = header; args["header"] = header;
return _computer.compute(chachaDecryptData, param: args); return _computer.compute(
chachaDecryptData,
param: args,
taskName: "decryptChaCha",
);
} }
// Encrypts the file at sourceFilePath, with the key (if provided) and a // Encrypts the file at sourceFilePath, with the key (if provided) and a
@ -293,7 +305,8 @@ class CryptoUtil {
args["sourceFilePath"] = sourceFilePath; args["sourceFilePath"] = sourceFilePath;
args["destinationFilePath"] = destinationFilePath; args["destinationFilePath"] = destinationFilePath;
args["key"] = key; args["key"] = key;
return _computer.compute(chachaEncryptFile, param: args); return _computer.compute(chachaEncryptFile,
param: args, taskName: "encryptFile");
} }
// Decrypts the file at sourceFilePath, with the given key and header using // Decrypts the file at sourceFilePath, with the given key and header using
@ -309,7 +322,8 @@ class CryptoUtil {
args["destinationFilePath"] = destinationFilePath; args["destinationFilePath"] = destinationFilePath;
args["header"] = header; args["header"] = header;
args["key"] = key; args["key"] = key;
return _computer.compute(chachaDecryptFile, param: args); return _computer.compute(chachaDecryptFile,
param: args, taskName: "decryptFile");
} }
// Generates and returns a 256-bit key. // Generates and returns a 256-bit key.
@ -391,7 +405,7 @@ class CryptoUtil {
return DerivedKeyResult(key, memLimit, opsLimit); return DerivedKeyResult(key, memLimit, opsLimit);
} }
// Derives a key for a given password, salt, memLimit and opsLimit using // Derives a key for a given password, salt, memLimit and opsLimit using
// Argon2id, v1.3. // Argon2id, v1.3.
static Future<Uint8List> deriveKey( static Future<Uint8List> deriveKey(
Uint8List password, Uint8List password,
@ -407,6 +421,7 @@ class CryptoUtil {
"memLimit": memLimit, "memLimit": memLimit,
"opsLimit": opsLimit, "opsLimit": opsLimit,
}, },
taskName: "deriveKey",
); );
} }
@ -417,6 +432,7 @@ class CryptoUtil {
param: { param: {
"sourceFilePath": source.path, "sourceFilePath": source.path,
}, },
taskName: "fileHash",
); );
} }
} }

View file

@ -275,11 +275,12 @@ packages:
computer: computer:
dependency: "direct main" dependency: "direct main"
description: description:
name: computer path: "."
sha256: "3df9f1ef497aaf69e066b00f4441726eb28037dc33e97b5d56393967f92c5fe8" ref: HEAD
url: "https://pub.dev" resolved-ref: "82e365fed8a1a76f6eea0220de98389eed7b0445"
source: hosted url: "https://github.com/ente-io/computer.git"
version: "2.0.0" source: git
version: "3.2.1"
confetti: confetti:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -28,7 +28,8 @@ dependencies:
chewie: chewie:
path: thirdparty/chewie path: thirdparty/chewie
collection: # dart collection: # dart
computer: ^2.0.0 computer:
git: "https://github.com/ente-io/computer.git"
confetti: ^0.6.0 confetti: ^0.6.0
connectivity_plus: ^3.0.3 connectivity_plus: ^3.0.3
crypto: ^3.0.2 crypto: ^3.0.2