Merge branch 'main' into video_no_thum

This commit is contained in:
Neeraj Gupta 2024-02-21 13:32:35 +05:30 committed by GitHub
commit 23ff7e4b69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 147 additions and 113 deletions

View file

@ -48,6 +48,19 @@ class EmbeddingsDB {
return await _isar.embeddings.filter().updationTimeEqualTo(null).findAll();
}
Future<void> deleteEmbeddings(List<int> fileIDs) async {
await _isar.writeTxn(() async {
final embeddings = <Embedding>[];
for (final fileID in fileIDs) {
embeddings.addAll(
await _isar.embeddings.filter().fileIDEqualTo(fileID).findAll(),
);
}
await _isar.embeddings.deleteAll(embeddings.map((e) => e.id).toList());
Bus.instance.fire(EmbeddingUpdatedEvent());
});
}
Future<void> deleteAllForModel(Model model) async {
await _isar.writeTxn(() async {
final embeddings =

View file

@ -53,13 +53,22 @@ class EmbeddingStore {
final fileMap = await FilesDB.instance
.getFilesFromIDs(pendingItems.map((e) => e.fileID).toList());
_logger.info("Pushing ${pendingItems.length} embeddings");
final deletedEntries = <int>[];
for (final item in pendingItems) {
try {
await _pushEmbedding(fileMap[item.fileID]!, item);
final file = fileMap[item.fileID];
if (file != null) {
await _pushEmbedding(file, item);
} else {
deletedEntries.add(item.fileID);
}
} catch (e, s) {
_logger.severe(e, s);
}
}
if (deletedEntries.isNotEmpty) {
await EmbeddingsDB.instance.deleteEmbeddings(deletedEntries);
}
}
Future<void> storeEmbedding(EnteFile file, Embedding embedding) async {

View file

@ -243,15 +243,23 @@ class SemanticSearchService {
final ignoredCollections =
CollectionsService.instance.getHiddenCollectionIds();
final deletedEntries = <int>[];
for (final result in queryResults) {
final file = filesMap[result.id];
if (file != null && !ignoredCollections.contains(file.collectionID)) {
results.add(filesMap[result.id]!);
results.add(file);
}
if (file == null) {
deletedEntries.add(result.id);
}
}
_logger.info(results.length.toString() + " results");
if (deletedEntries.isNotEmpty) {
unawaited(EmbeddingsDB.instance.deleteEmbeddings(deletedEntries));
}
return results;
}

View file

@ -42,7 +42,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
_passwordController.text = _volatilePassword!;
Future.delayed(
Duration.zero,
() => verifyPassword(_volatilePassword!),
() => verifyPassword(_volatilePassword!),
);
}
_passwordFocusNode.addListener(() {
@ -100,69 +100,68 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
}
Future<void> verifyPassword(String password) async {
FocusScope.of(context).unfocus();
final dialog =
createProgressDialog(context, S.of(context).pleaseWait);
await dialog.show();
try {
final kek = await Configuration.instance.decryptSecretsAndGetKeyEncKey(
password,
Configuration.instance.getKeyAttributes()!,
);
_registerSRPForExistingUsers(kek).ignore();
} on KeyDerivationError catch (e, s) {
_logger.severe("Password verification failed", e, s);
await dialog.hide();
final dialogChoice = await showChoiceDialog(
context,
title: S.of(context).recreatePasswordTitle,
body: S.of(context).recreatePasswordBody,
firstButtonLabel: S.of(context).useRecoveryKey,
);
if (dialogChoice!.action == ButtonAction.first) {
// ignore: unawaited_futures
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RecoveryPage();
},
),
);
}
return;
} catch (e, s) {
_logger.severe("Password verification failed", e, s);
await dialog.hide();
final dialogChoice = await showChoiceDialog(
context,
title: S.of(context).incorrectPasswordTitle,
body: S.of(context).pleaseTryAgain,
firstButtonLabel: S.of(context).contactSupport,
secondButtonLabel: S.of(context).ok,
);
if (dialogChoice!.action == ButtonAction.first) {
await sendLogs(
context,
S.of(context).contactSupport,
"support@ente.io",
postShare: () {},
);
}
return;
}
FocusScope.of(context).unfocus();
final dialog = createProgressDialog(context, S.of(context).pleaseWait);
await dialog.show();
try {
final kek = await Configuration.instance.decryptSecretsAndGetKeyEncKey(
password,
Configuration.instance.getKeyAttributes()!,
);
_registerSRPForExistingUsers(kek).ignore();
} on KeyDerivationError catch (e, s) {
_logger.severe("Password verification failed", e, s);
await dialog.hide();
Configuration.instance.setVolatilePassword(null);
Bus.instance.fire(SubscriptionPurchasedEvent());
unawaited(
Navigator.of(context).pushAndRemoveUntil(
final dialogChoice = await showChoiceDialog(
context,
title: S.of(context).recreatePasswordTitle,
body: S.of(context).recreatePasswordBody,
firstButtonLabel: S.of(context).useRecoveryKey,
);
if (dialogChoice!.action == ButtonAction.first) {
// ignore: unawaited_futures
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const HomeWidget();
return const RecoveryPage();
},
),
(route) => false,
),
);
}
return;
} catch (e, s) {
_logger.severe("Password verification failed", e, s);
await dialog.hide();
final dialogChoice = await showChoiceDialog(
context,
title: S.of(context).incorrectPasswordTitle,
body: S.of(context).pleaseTryAgain,
firstButtonLabel: S.of(context).contactSupport,
secondButtonLabel: S.of(context).ok,
);
if (dialogChoice!.action == ButtonAction.first) {
await sendLogs(
context,
S.of(context).contactSupport,
"support@ente.io",
postShare: () {},
);
}
return;
}
await dialog.hide();
Configuration.instance.setVolatilePassword(null);
Bus.instance.fire(SubscriptionPurchasedEvent());
unawaited(
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) {
return const HomeWidget();
},
),
(route) => false,
),
);
}
Future<void> _registerSRPForExistingUsers(Uint8List key) async {
@ -266,8 +265,8 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
child: Wrap(
alignment: WrapAlignment.spaceBetween,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
@ -280,17 +279,13 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
),
);
},
child: Center(
child: Text(
S.of(context).forgotPassword,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
child: Text(
S.of(context).forgotPassword,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
GestureDetector(
@ -306,17 +301,13 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
Navigator.of(context)
.popUntil((route) => route.isFirst);
},
child: Center(
child: Text(
S.of(context).changeEmail,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
child: Text(
S.of(context).changeEmail,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
],

View file

@ -60,7 +60,6 @@ class DynamicFAB extends StatelessWidget {
} else {
return Container(
width: double.infinity,
height: 56,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: OutlinedButton(
onPressed:

View file

@ -1,5 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/services/feature_flag_service.dart';
import 'package:photos/services/update_service.dart';
import "package:photos/ui/payment/store_subscription_page.dart";
@ -9,18 +8,9 @@ StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
if (UpdateService.instance.isIndependentFlavor()) {
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
}
if (FeatureFlagService.instance.enableStripe() &&
_isUserCreatedPostStripeSupport()) {
if (FeatureFlagService.instance.enableStripe()) {
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
} else {
return StoreSubscriptionPage(isOnboarding: isOnBoarding);
}
}
// return true if the user was created after we added support for stripe payment
// on frame. We do this check to avoid showing Stripe payment option for earlier
// users who might have paid via playStore. This method should be removed once
// we have better handling for active play/app store subscription & stripe plans.
bool _isUserCreatedPostStripeSupport() {
return Configuration.instance.getUserID()! > 1580559962386460;
}

View file

@ -36,13 +36,9 @@ class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
S.of(context).selectYourPlan,
style: Theme.of(context).textTheme.headlineMedium,
),
],
Text(
S.of(context).selectYourPlan,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 10),
Text(

View file

@ -252,10 +252,14 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
void _setVideoController(String url) {
if (mounted) {
setState(() {
player.setPlaylistMode(PlaylistMode.single);
controller = VideoController(player);
player.open(Media(url), play: _isAppInFG);
setState(() async {
try {
await player.setPlaylistMode(PlaylistMode.single);
controller = VideoController(player);
await player.open(Media(url), play: _isAppInFG);
} catch (e, s) {
_logger.severe("failed to set video url", e, s);
}
});
}
}

View file

@ -129,7 +129,6 @@ class SearchWidgetState extends State<SearchWidget> {
child: Container(
color: colorScheme.backgroundBase,
child: Container(
height: 44,
color: colorScheme.fillFaint,
child: TextFormField(
controller: textController,

View file

@ -35,6 +35,7 @@ import "package:photos/services/user_service.dart";
import 'package:photos/utils/crypto_util.dart';
import 'package:photos/utils/file_download_util.dart';
import 'package:photos/utils/file_uploader_util.dart';
import "package:photos/utils/file_util.dart";
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tuple/tuple.dart';
import "package:uuid/uuid.dart";
@ -309,12 +310,36 @@ class FileUploader {
return file.path.contains(kUploadTempPrefix) &&
file.path.contains(".encrypted");
});
if (filesToDelete.isEmpty) {
return;
if (filesToDelete.isNotEmpty) {
_logger.info('cleaning up state files ${filesToDelete.length}');
for (final file in filesToDelete) {
await file.delete();
}
}
_logger.info('cleaning up state files ${filesToDelete.length}');
for (final file in filesToDelete) {
await file.delete();
if (Platform.isAndroid) {
final sharedMediaDir =
Configuration.instance.getSharedMediaDirectory() + "/";
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 Set<String> trackedSharedFilePaths = {};
for (String localID in existingLocalFileIDs) {
if (localID.contains(sharedMediaIdentifier)) {
trackedSharedFilePaths
.add(getSharedMediaPathFromLocalID(localID));
}
}
for (final file in sharedFiles) {
if (!trackedSharedFilePaths.contains(file.path)) {
_logger.info('Deleting stale shared media file ${file.path}');
await file.delete();
}
}
}
}
} catch (e, s) {
_logger.severe("Failed to remove stale files", e, s);