Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
4bbc9ea
[mob][photos] Add social actions to memories
ashilkn Jul 16, 2026
4cc77d0
[mob][photos] Harden memories social interactions
ashilkn Jul 16, 2026
1af1f79
[mob][photos] Redesign memories viewer
ashilkn Jul 16, 2026
03c2fd5
[mobile][photos] fix missing media management hint sheet call in dele…
aspizu Jul 17, 2026
e4ad6f8
[mob][photos] Refine memories viewer visuals
ashilkn Jul 17, 2026
7044a0d
[mob][photos] Adapt memories viewer scrim
ashilkn Jul 17, 2026
d61ce03
feat(photos): refine memories viewer interactions
ashilkn Jul 17, 2026
068bbab
[mobile][photos] Fix media management hint flow
aspizu Jul 17, 2026
679c6ec
fix(photos): address memories viewer review findings
ashilkn Jul 17, 2026
eecf8af
refactor(photos): clarify latest comment query scope
ashilkn Jul 20, 2026
11ce8ce
refactor(photos): defer memory social collection resolution
ashilkn Jul 20, 2026
474febb
refactor(photos): clarify non-hidden collection lookup
ashilkn Jul 20, 2026
49357f0
refactor(photos): preserve shared collection order
ashilkn Jul 20, 2026
23642b4
refactor(photos): rename memory top overlay
ashilkn Jul 20, 2026
395ae27
fix(photos): start memory progress with video playback
ashilkn Jul 20, 2026
dbd1387
refactor(photos): clarify social refresh guards
ashilkn Jul 20, 2026
36e2481
Reuse social overlay in gallery viewer
ashilkn Jul 20, 2026
0cb783c
Remove social overlay event refresh
ashilkn Jul 20, 2026
c12dfcd
Simplify social overlay refresh guards
ashilkn Jul 20, 2026
cb8fc3c
Simplify social viewer async flow
ashilkn Jul 20, 2026
74922e0
Remove redundant social action guards
ashilkn Jul 20, 2026
c9bc687
Clarify reaction update tracking name
ashilkn Jul 20, 2026
92a0fe3
Lower social action failure log severity
ashilkn Jul 20, 2026
0ca9981
Limit like failure toast visibility
ashilkn Jul 20, 2026
e7ff9fc
Prefer latest comment collection in comment sheet
ashilkn Jul 21, 2026
18e21c8
Increase social control touch targets
ashilkn Jul 21, 2026
976fbeb
Clarify hidden social collection context
ashilkn Jul 21, 2026
0f9bef9
Extract social overlay widgets
ashilkn Jul 21, 2026
47cb611
Size latest comment by viewer width
ashilkn Jul 21, 2026
0b8b98a
Constrain latest comment overlay width
ashilkn Jul 21, 2026
4ef8521
Avoid social overlay flicker on file changes
ashilkn Jul 21, 2026
930a775
Limit recovery sheet scanner resource use
ua741 Jul 20, 2026
2daed05
Merge branch 'main' into np/legacy-recovery-scan-limits
ua741 Jul 21, 2026
eccad3b
Avoid redundant sensitive key derivations
mnvr Jul 21, 2026
9b83d8e
Use cargo test for Rust CI
mnvr Jul 21, 2026
1ab9e9c
Animate social comment updates
ashilkn Jul 21, 2026
ec826f7
Speed up paste password tests
mnvr Jul 21, 2026
551b5ba
Remove redundant sensitive KEK test
mnvr Jul 21, 2026
a376745
Animate latest comment bubble width
ashilkn Jul 21, 2026
e7fd278
Check recovery image dimensions before decode
ua741 Jul 21, 2026
b00ded9
Use test-strength KDF in password change flow
mnvr Jul 21, 2026
c6f6af6
Crossfade latest comment text
ashilkn Jul 21, 2026
fc58345
Stop highlighting latest comment in sheet
ashilkn Jul 21, 2026
b65bd01
Refine latest comment transitions
ashilkn Jul 21, 2026
641ad23
Preserve recovery image aspect ratio
ua741 Jul 21, 2026
3143272
Refine latest comment resize animation
ashilkn Jul 21, 2026
60695f8
[mobile][photos] fix missing media management hint sheet call in dele…
aspizu Jul 21, 2026
6525de8
Align latest comment bubble animation
ashilkn Jul 21, 2026
126ac17
Preserve coverage in faster Rust tests
mnvr Jul 21, 2026
5ee2435
Raise gallery social overlay
ashilkn Jul 21, 2026
8f29c53
Adjust social overlay spacing
ashilkn Jul 21, 2026
628d1df
[rust] Speed up Rust CI tests (#11591)
mnvr Jul 21, 2026
a15e44d
Update CODEOWNERS to include mnvr-sudo
mnvr Jul 21, 2026
430d9b2
Compact gallery video controls
ashilkn Jul 21, 2026
cca99c2
Update CODEOWNERS to include mnvr-sudo (#11592)
mnvr Jul 21, 2026
b49c92e
Polish memories overlay contrast
ashilkn Jul 21, 2026
0eb97d6
[web] Handle large recovery sheets (#11573)
ua741 Jul 21, 2026
262fc9c
Show add to album in shared viewer
ashilkn Jul 21, 2026
7326b31
Update social overlay icons
ashilkn Jul 21, 2026
505a66b
Refine social overlay shadows
ashilkn Jul 21, 2026
05be462
Balance social icon sizing
ashilkn Jul 21, 2026
21b10b4
Harden CLI export and passkey handling
mnvr Jul 21, 2026
35a8809
Guard date picker bounds
ua741 Jul 21, 2026
bd53934
Improve account deletion recovery
ua741 Jul 21, 2026
4f9265e
Update golang.org/x/text
ua741 Jul 22, 2026
06dc4cd
[mobile] Guard date picker bounds (#11596)
ua741 Jul 22, 2026
8967f98
[auth] Optimization of Capcom and Warner Bros. custom icons (#11598)
millia-rage Jul 22, 2026
062c706
[server][web] Improve account deletion recovery (#11590)
ua741 Jul 22, 2026
57f1e3b
New Crowdin translations by GitHub Action
crowdin-bot Jul 22, 2026
635067e
Scope social state to visible collections
ashilkn Jul 22, 2026
46e868d
Trim memories viewer tests
ashilkn Jul 22, 2026
7926408
Consolidate memories change note
ashilkn Jul 22, 2026
0831bd7
Target Android API 36
mnvr Jul 22, 2026
712d601
Add Ensu API 36 change note
mnvr Jul 22, 2026
55a4799
[ensu][mobile] Target Android API 36 (#11603)
mnvr Jul 22, 2026
6962c73
[web] New translations (#11484)
AswinAsok Jul 22, 2026
d50f968
Add checksum verification to the model downloader and use it for ML t…
mnvr Jul 17, 2026
0a38ad6
Fetch ML test fixtures as a single verified batch
mnvr Jul 17, 2026
f9a5052
Adopt checksum-only validation across the model downloader and its co…
mnvr Jul 17, 2026
0bebfa5
Select models by preset id and drop custom model URLs
mnvr Jul 20, 2026
b7d81c1
Hash download files off the heap and group the migration inputs
mnvr Jul 20, 2026
e7456e4
Drop the vestigial completed-download metadata sidecar
mnvr Jul 20, 2026
53b9b08
Collapse the Gguf target variant into Files
mnvr Jul 20, 2026
cf28197
Download files sequentially and preserve resumable state on failures
mnvr Jul 21, 2026
2a5c907
Promote the transport to a public async Downloader with token cancell…
mnvr Jul 21, 2026
356622f
Format social overlay
ashilkn Jul 22, 2026
d75d642
Merge remote-tracking branch 'origin' into comments_and_reactions_on_…
ashilkn Jul 22, 2026
b8a94b3
Validate stored export filenames
mnvr Jul 22, 2026
e8dea98
Complete the token and id-based selection sweep across the app layers
mnvr Jul 22, 2026
17e7b03
[rust] Harden CLI export and passkey handling (#11595)
mnvr Jul 22, 2026
66f5465
[mob][photos] Comments and reactions on memories (#11539)
ashilkn Jul 22, 2026
4c3403b
Resolve model presets against a single canonical catalog
mnvr Jul 22, 2026
0a20b3f
Add network-state permission and move transcription assets to models.…
mnvr Jul 22, 2026
cfa93c6
Fix family admin detection
mnvr Jul 22, 2026
3a0d0dd
fix(Favoriting):fix-first-favoriting-sync-issue
AswinAsok Jul 22, 2026
756ef0e
Update referral share copy
ua741 Jul 22, 2026
525952c
[mobile] Update referral share copy (#11608)
ua741 Jul 22, 2026
50107cc
[web][photos] Fix first file unfavouriting without indexedDB synced (…
AswinAsok Jul 22, 2026
2d04a62
[web] Fix family admin detection (#11605)
mnvr Jul 22, 2026
815622c
[rust] Share one async model downloader across Ensu and the ML tests …
mnvr Jul 22, 2026
7c557fb
Use identity colors in family storage
ua741 Jul 22, 2026
4c56168
Use linked person names in Family
ua741 Jul 22, 2026
fd9afd8
[mobile][photos] Fix Family member identity display (#11609)
ua741 Jul 22, 2026
b45c33a
Update Photos changelog translations
ua741 Jul 22, 2026
6dc38a4
Remove changelog tests
ua741 Jul 22, 2026
6eaa8a5
Show family member names on storage limit page
ua741 Jul 22, 2026
0c9880f
Handle contacts resolved during family actions
ua741 Jul 22, 2026
c544ddc
[mobile][photos] Update in-app changelog (#11610)
ua741 Jul 22, 2026
9cc2314
[mobile][photos] Show family member names on storage limit page (#11611)
ua741 Jul 22, 2026
b6ea466
Link contacts to unassigned faces
ua741 Jul 22, 2026
aac8ee7
[mobile] Link contacts to unassigned faces (#11612)
ua741 Jul 22, 2026
86565f1
Merge official Ente main at aac8ee79eb713c16122f1f2664484b22cdda8c08
vanton1 Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/.github/ @mnvr @ua741
/server/ @ua741 @mnvr
/.github/ @mnvr @ua741 @mnvr-sudo
/server/ @ua741 @mnvr @mnvr-sudo
/mobile/packages/ente_components/ @ashilkn @AmanRajSinghMourya
74 changes: 4 additions & 70 deletions mobile/apps/auth/assets/custom-icons/icons/capcom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 22 additions & 33 deletions mobile/apps/auth/assets/custom-icons/icons/warner_bros.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add comments and reactions to memories.
66 changes: 63 additions & 3 deletions mobile/apps/photos/lib/db/social_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,48 @@ class SocialDB {
return rows.map(_rowToComment).toList();
}

Future<int> getCommentCountForFile(int fileID) async {
/// Restricts the lookup to [candidateCollectionIDs] so the composite
/// file/collection index can narrow the rows considered for the latest item.
Future<Comment?> getLatestCommentForFile(
int fileID, {
required List<int> candidateCollectionIDs,
}) async {
if (candidateCollectionIDs.isEmpty) {
return null;
}

final placeholders = List.filled(
candidateCollectionIDs.length,
'?',
).join(',');
final db = await database;
final rows = await db.query(
_commentsTable,
where:
'file_id = ? AND is_deleted = 0 '
'AND collection_id IN ($placeholders)',
whereArgs: [fileID, ...candidateCollectionIDs],
orderBy: 'created_at DESC',
limit: 1,
);
return rows.isEmpty ? null : _rowToComment(rows.first);
}

Future<int> getCommentCountForFileInCollections(
int fileID,
List<int> collectionIDs,
) async {
if (collectionIDs.isEmpty) {
return 0;
}

final placeholders = List.filled(collectionIDs.length, '?').join(',');
final db = await database;
final result = await db.rawQuery(
'SELECT COUNT(*) as count FROM $_commentsTable '
'WHERE file_id = ? AND is_deleted = 0',
[fileID],
'WHERE file_id = ? AND collection_id IN ($placeholders) '
'AND is_deleted = 0',
[fileID, ...collectionIDs],
);
return Sqflite.firstIntValue(result) ?? 0;
}
Expand Down Expand Up @@ -269,6 +305,30 @@ class SocialDB {
return rows.map(_rowToReaction).toList();
}

Future<bool> hasUserReactedToFileInCollections(
int fileID,
int userID,
List<int> collectionIDs,
) async {
if (collectionIDs.isEmpty) {
return false;
}

final placeholders = List.filled(collectionIDs.length, '?').join(',');
final db = await database;
final rows = await db.rawQuery(
'''
SELECT 1 FROM $_reactionsTable
WHERE file_id = ? AND user_id = ?
AND collection_id IN ($placeholders)
AND comment_id IS NULL AND is_deleted = 0
LIMIT 1
''',
[fileID, userID, ...collectionIDs],
);
return rows.isNotEmpty;
}

Future<List<Reaction>> getReactionsForFileInCollection(
int fileID,
int collectionID,
Expand Down
2 changes: 1 addition & 1 deletion mobile/apps/photos/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@
"theyAlsoGetXGb": "They also get {storageAmountInGB} GB",
"referralStorageForBoth": "{storageAmountInGB} GB for them + {storageAmountInGB} GB for you when they upgrade.",
"freeStorageOnReferralSuccess": "{storageAmountInGB} GB each time someone signs up for a paid plan and applies your code",
"shareTextReferralCode": "Ente Photos is a private and safe home for your photos\n* Download Ente Photos from https://ente.com/app\n* Create an account\n* Apply the referral code {referralCode} in Settings->Referral\n* Get {referralStorageInGB}GB free when you upgrade to a paid plan",
"shareTextReferralCode": "Ente Photos is a private and safe home for your photos\n* Download Ente Photos from https://ente.com/app\n* Create an account\n* Apply the referral code {referralCode} in Settings->Referral\n* Get extra {referralStorageInGB} GB free!",
"claimFreeStorage": "Claim free storage",
"inviteYourFriends": "Invite your friends",
"earnFreeStorage": "Earn free storage",
Expand Down
27 changes: 25 additions & 2 deletions mobile/apps/photos/lib/models/social/social_data_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,23 @@ class SocialDataProvider {
return _db.getCommentsForFile(fileID);
}

Future<int> getCommentCountForFile(int fileID) {
return _db.getCommentCountForFile(fileID);
/// [candidateCollectionIDs] narrows the indexed lookup to collections the
/// caller already knows are eligible.
Future<Comment?> getLatestCommentForFile(
int fileID, {
required List<int> candidateCollectionIDs,
}) {
return _db.getLatestCommentForFile(
fileID,
candidateCollectionIDs: candidateCollectionIDs,
);
}

Future<int> getCommentCountForFileInCollections(
int fileID,
List<int> collectionIDs,
) {
return _db.getCommentCountForFileInCollections(fileID, collectionIDs);
}

Future<int> getCommentCountForFileInCollection(int fileID, int collectionID) {
Expand All @@ -36,6 +51,14 @@ class SocialDataProvider {
return _db.getReactionsForFile(fileID);
}

Future<bool> hasUserReactedToFileInCollections(
int fileID,
int userID,
List<int> collectionIDs,
) {
return _db.hasUserReactedToFileInCollections(fileID, userID, collectionIDs);
}

Future<List<Reaction>> getReactionsForFileInCollection(
int fileID,
int collectionID,
Expand Down
88 changes: 58 additions & 30 deletions mobile/apps/photos/lib/services/collections_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -295,48 +295,76 @@ class CollectionsService {
return false;
}

/// Returns the count of shared collections containing this file.
/// Uses early exit optimization - stops counting at 2.
/// Returns the shared collections containing [uploadedFileID].
///
/// Returns:
/// - 0: File not in any shared collection
/// - 1: File in exactly one shared collection
/// - 2: File in multiple shared collections (early exit)
Future<int> getSharedCollectionCountForFile(int uploadedFileID) async {
/// A collection is considered shared if it has sharees, has a public link,
/// or is owned by someone else (incoming share).
Future<List<Collection>> getSharedCollectionsForFile(
int uploadedFileID, {
bool includeHidden = false,
}) async {
final Set<int> collectionIDs = await _filesDB.getAllCollectionIDsOfFile(
uploadedFileID,
);

if (collectionIDs.isEmpty) {
return 0;
}

final int? currentUserID = _config.getUserID();
if (currentUserID == null) {
return 0;
if (collectionIDs.isEmpty || currentUserID == null) {
return [];
}

int sharedCount = 0;
for (final int collectionID in collectionIDs) {
final Collection? collection = _collectionIDToCollections[collectionID];

if (collection == null || collection.isDeleted) {
continue;
final sharedCollections = <Collection>[];
for (final collectionID in collectionIDs) {
final collection = _collectionIDToCollections[collectionID];
if (_isEligibleSharedCollection(
collection,
currentUserID,
includeHidden: includeHidden,
)) {
sharedCollections.add(collection!);
}
}
return sharedCollections;
}

// Same logic as isFileInSharedCollection
if (collection.hasSharees ||
collection.hasLink ||
!collection.isOwner(currentUserID)) {
sharedCount++;
// Early exit: we only need to distinguish between 0, 1, and >1
if (sharedCount > 1) {
return 2;
}
/// Returns IDs of shared collections containing [uploadedFileID].
///
/// Use this to scope social content on the view path without constructing a
/// list of collection objects.
Future<List<int>> getSharedCollectionIDsForFile(
int uploadedFileID, {
bool includeHidden = false,
}) async {
final collectionIDs = await _filesDB.getAllCollectionIDsOfFile(
uploadedFileID,
);
final currentUserID = _config.getUserID();
if (collectionIDs.isEmpty || currentUserID == null) {
return [];
}

final sharedCollectionIDs = <int>[];
for (final collectionID in collectionIDs) {
if (_isEligibleSharedCollection(
_collectionIDToCollections[collectionID],
currentUserID,
includeHidden: includeHidden,
)) {
sharedCollectionIDs.add(collectionID);
}
}
return sharedCollectionIDs;
}

return sharedCount;
bool _isEligibleSharedCollection(
Collection? collection,
int currentUserID, {
required bool includeHidden,
}) {
return collection != null &&
!collection.isDeleted &&
(includeHidden || !collection.isHidden()) &&
(collection.hasSharees ||
collection.hasLink ||
!collection.isOwner(currentUserID));
}

Future<List<Collection>> getArchivedCollection() async {
Expand Down
Loading