Compare commits

...

11 Commits

Author SHA1 Message Date
Neeraj Gupta
fa361904f6 [mob] Misc bug fixes (#3522)
## Description

## Tests
2024-09-29 11:17:51 +05:30
Neeraj Gupta
00e75c0fb2 [mob] Lint 2024-09-29 09:54:20 +05:30
Neeraj Gupta
026ab8dcc6 [mob] Bump version: v0.9.46 2024-09-29 09:53:15 +05:30
Neeraj Gupta
7d42ed37e1 Merge remote-tracking branch 'origin/main' into bug_fixes 2024-09-29 09:52:49 +05:30
Neeraj Gupta
a5d01a9ffe [mob] Fix avatar faceID 2024-09-29 09:52:41 +05:30
Neeraj Gupta
675b7f6cea [mob] Sync cgroup as part of ML 2024-09-29 09:45:48 +05:30
Neeraj Gupta
772373580a [mob] Stop consuming errors for trash 2024-09-29 09:42:25 +05:30
Neeraj Gupta
f0a19e38aa [mob] Fix hide cluster property 2024-09-29 09:41:35 +05:30
Manav Rathi
d1d6590547 [web] Sync locations only once on app start if there are pending uploads (#3521) 2024-09-29 05:52:32 +05:30
Manav Rathi
03da960c33 Start with a idle state
Not sure why it was true - there is a possibility that this was intentional, but
I can't think why. The reason for changing it is to fix our "isForced" logic
(otherwise the non-file-related sync doesn't run on app start), without
introducing _another_ flag to track if the sync was initiated from a gallery
useEffect or by the preUploadSync.
2024-09-29 05:40:37 +05:30
Manav Rathi
2bdc010849 [web] Do not perform multiple non-file-syncs in parallel
e.g. this might cause multiple requests to getOrCreate a location tag entity
key. Remote will reject the second one, so no harm will come of it, but still
its better to enforce serialization to make the mental model of the code easier
to reason about.
2024-09-29 05:20:12 +05:30
8 changed files with 45 additions and 16 deletions

View File

@@ -107,6 +107,14 @@ class EntityService {
}
}
Future<void> syncEntity(EntityType type) async {
try {
await _remoteToLocalSync(type);
} catch (e) {
_logger.severe("Failed to sync entities", e);
}
}
Future<void> _remoteToLocalSync(EntityType type) async {
final int lastSyncTime =
_prefs.getInt(_getEntityLastSyncTimePrefix(type)) ?? 0;
@@ -116,7 +124,6 @@ class EntityService {
limit: fetchLimit,
);
if (result.isEmpty) {
debugPrint("No $type entries to sync");
return;
}
final bool hasMoreItems = result.length == fetchLimit;

View File

@@ -6,6 +6,8 @@ import "package:logging/logging.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/diff_sync_complete_event.dart";
import "package:photos/events/people_changed_event.dart";
import "package:photos/models/api/entity/type.dart";
import "package:photos/services/entity_service.dart";
import "package:photos/services/machine_learning/face_ml/face_detection/detection.dart";
import "package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart";
import "package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart";
@@ -59,6 +61,7 @@ class FaceRecognitionService {
return;
}
_isSyncing = true;
await EntityService.instance.syncEntity(EntityType.cgroup);
if (_shouldSyncPeople) {
await PersonService.instance.reconcileClusters();
Bus.instance.fire(PeopleChangedEvent(type: PeopleEventType.syncDone));

View File

@@ -335,7 +335,7 @@ class ClusterFeedbackService {
}
Future<void> ignoreCluster(String clusterID) async {
await PersonService.instance.addPerson('', clusterID);
await PersonService.instance.addPerson('', clusterID, isHidden: true);
Bus.instance.fire(PeopleChangedEvent());
return;
}

View File

@@ -8,6 +8,8 @@ import "package:photos/db/ml/db.dart";
import "package:photos/events/people_changed_event.dart";
import "package:photos/extensions/stop_watch.dart";
import "package:photos/models/api/entity/type.dart";
import "package:photos/models/file/file.dart";
import 'package:photos/models/ml/face/face.dart';
import "package:photos/models/ml/face/person.dart";
import "package:photos/service_locator.dart";
import "package:photos/services/entity_service.dart";
@@ -292,6 +294,24 @@ class PersonService {
await faceMLDataDB.bulkAssignClusterToPersonID(clusterToPersonID);
}
Future<void> updateAvatar(PersonEntity p, EnteFile file) async {
final Face? face = await MLDataDB.instance.getCoverFaceForPerson(
recentFileID: file.uploadedFileID!,
personID: p.remoteID,
);
if (face == null) {
throw Exception(
"No face found for person ${p.remoteID} in file ${file.uploadedFileID}",
);
}
final person = (await getPerson(p.remoteID))!;
final updatedPerson = person.copyWith(
data: person.data.copyWith(avatarFaceId: face.faceID),
);
await _updatePerson(updatedPerson);
}
Future<void> updateAttributes(
String id, {
String? name,

View File

@@ -121,13 +121,7 @@ class RemoteSyncService {
await syncDeviceCollectionFilesForUpload();
}
await _pullDiff();
// sync trash but consume error during initial launch.
// this is to ensure that we don't pause upload due to any error during
// the trash sync. Impact: We may end up re-uploading a file which was
// recently trashed.
await TrashSyncService.instance
.syncTrash()
.onError((e, s) => _logger.severe('trash sync failed', e, s));
await TrashSyncService.instance.syncTrash();
if (!hasSyncedBefore) {
await _prefs.setBool(_isFirstRemoteSyncDone, true);
await syncDeviceCollectionFilesForUpload();

View File

@@ -696,10 +696,7 @@ class _FileSelectionActionsWidgetState
Future<void> _setPersonCover() async {
final EnteFile file = widget.selectedFiles.files.first;
await PersonService.instance.updateAttributes(
widget.person!.remoteID,
avatarFaceId: file.uploadedFileID.toString(),
);
await PersonService.instance.updateAvatar(widget.person!, file);
widget.selectedFiles.clearAll();
if (mounted) {
setState(() => {});

View File

@@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.9.45+945
version: 0.9.46+946
publish_to: none
environment:

View File

@@ -255,7 +255,7 @@ export default function Gallery() {
accept: ".zip",
});
const syncInProgress = useRef(true);
const syncInProgress = useRef(false);
const syncInterval = useRef<NodeJS.Timeout>();
const resync = useRef<{ force: boolean; silent: boolean }>();
@@ -785,6 +785,7 @@ export default function Gallery() {
resync.current = { force, silent };
return;
}
const isForced = syncInProgress.current && force;
syncInProgress.current = true;
try {
const token = getToken();
@@ -805,7 +806,14 @@ export default function Gallery() {
await syncFiles("normal", normalCollections, setFiles);
await syncFiles("hidden", hiddenCollections, setHiddenFiles);
await syncTrash(collections, setTrashedFiles);
await sync();
// syncWithRemote is called with the force flag set to true before
// doing an upload. So it is possible, say when resuming a pending
// upload, that we get two syncWithRemotes happening in parallel.
//
// Do the non-file-related sync only for one of these parallel ones.
if (!isForced) {
await sync();
}
} catch (e) {
switch (e.message) {
case CustomError.SESSION_EXPIRED: