l10n: Extract strings [Part-1] (#955)

This commit is contained in:
Neeraj Gupta 2023-04-05 08:24:25 +05:30 committed by GitHub
commit f3e2c2d962
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 2112 additions and 256 deletions

View file

@ -20,18 +20,260 @@ typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en';
static String m0(user) =>
"${user} will not be able to add more photos to this album\n\nThey will still be able to remove existing photos added by them";
static String m1(supportEmail) =>
"Please drop an email to ${supportEmail} from your registered email address";
static String m2(passwordStrengthValue) =>
"Password strength: ${passwordStrengthValue}";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"accountWelcomeBack":
MessageLookupByLibrary.simpleMessage("Welcome back!"),
"ackPasswordLostWarningPart1": MessageLookupByLibrary.simpleMessage(
"I understand that if I lose my password, I may lose my data since my data is "),
"ackPasswordLostWarningPart2":
MessageLookupByLibrary.simpleMessage(" with ente"),
"activeSessions":
MessageLookupByLibrary.simpleMessage("Active sessions"),
"addANewEmail": MessageLookupByLibrary.simpleMessage("Add a new email"),
"addCollaborator":
MessageLookupByLibrary.simpleMessage("Add collaborator"),
"addMore": MessageLookupByLibrary.simpleMessage("Add more"),
"addViewer": MessageLookupByLibrary.simpleMessage("Add viewer"),
"addedAs": MessageLookupByLibrary.simpleMessage("Added as"),
"albumOwner": MessageLookupByLibrary.simpleMessage("Owner"),
"and": MessageLookupByLibrary.simpleMessage("and"),
"askDeleteReason": MessageLookupByLibrary.simpleMessage(
"What is the main reason you are deleting your account?"),
"byClickingLogInIAgreeToThe": MessageLookupByLibrary.simpleMessage(
"By clicking log in, I agree to the"),
"cancel": MessageLookupByLibrary.simpleMessage("Cancel"),
"cannotAddMorePhotosAfterBecomingViewer": m0,
"changeEmail": MessageLookupByLibrary.simpleMessage("Change email"),
"changePasswordTitle":
MessageLookupByLibrary.simpleMessage("Change password"),
"changePermissions":
MessageLookupByLibrary.simpleMessage("Change permissions?"),
"checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage(
"Please check your inbox (and spam) to complete verification"),
"codeCopiedToClipboard":
MessageLookupByLibrary.simpleMessage("Code copied to clipboard"),
"collaborator": MessageLookupByLibrary.simpleMessage("Collaborator"),
"collaboratorsCanAddPhotosAndVideosToTheSharedAlbum":
MessageLookupByLibrary.simpleMessage(
"Collaborators can add photos and videos to the shared album."),
"confirm": MessageLookupByLibrary.simpleMessage("Confirm"),
"confirmAccountDeletion":
MessageLookupByLibrary.simpleMessage("Confirm Account Deletion"),
"confirmDeletePrompt": MessageLookupByLibrary.simpleMessage(
"Yes, I want to permanently delete this account and all its data."),
"confirmPassword":
MessageLookupByLibrary.simpleMessage("Confirm password"),
"confirmRecoveryKey":
MessageLookupByLibrary.simpleMessage("Confirm recovery key"),
"confirmYourRecoveryKey":
MessageLookupByLibrary.simpleMessage("Confirm your recovery key"),
"contactSupport":
MessageLookupByLibrary.simpleMessage("Contact support"),
"continueLabel": MessageLookupByLibrary.simpleMessage("Continue"),
"copypasteThisCodentoYourAuthenticatorApp":
MessageLookupByLibrary.simpleMessage(
"Copy-paste this code\nto your authenticator app"),
"createAccount": MessageLookupByLibrary.simpleMessage("Create account"),
"createNewAccount":
MessageLookupByLibrary.simpleMessage("Create new account"),
"decrypting": MessageLookupByLibrary.simpleMessage("Decrypting..."),
"deleteAccount": MessageLookupByLibrary.simpleMessage("Delete account"),
"deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage(
"We are sorry to see you go. Please share your feedback to help us improve."),
"deleteAccountPermanentlyButton":
MessageLookupByLibrary.simpleMessage("Delete Account Permanently"),
"deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage(
"You are about to permanently delete your account and all its data.\nThis action is irreversible."),
"deleteReason1": MessageLookupByLibrary.simpleMessage(
"Its missing a key feature that I need"),
"deleteReason2": MessageLookupByLibrary.simpleMessage(
"The app or a certain feature does not \nbehave as I think it should"),
"deleteReason3": MessageLookupByLibrary.simpleMessage(
"I found another service that I like better"),
"deleteReason4":
MessageLookupByLibrary.simpleMessage("My reason isnt listed"),
"deleteRequestSLAText": MessageLookupByLibrary.simpleMessage(
"Your request will be processed within 72 hours."),
"doThisLater": MessageLookupByLibrary.simpleMessage("Do this later"),
"dropSupportEmail": m1,
"email": MessageLookupByLibrary.simpleMessage("Email"),
"encryption": MessageLookupByLibrary.simpleMessage("Encryption"),
"encryptionKeys":
MessageLookupByLibrary.simpleMessage("Encryption keys"),
"endToEndEncrypted":
MessageLookupByLibrary.simpleMessage("end-to-end encrypted"),
"enterCode": MessageLookupByLibrary.simpleMessage("Enter code"),
"enterEmail": MessageLookupByLibrary.simpleMessage("Enter email"),
"enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage(
"Enter a new password we can use to encrypt your data"),
"enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage(
"Enter a password we can use to encrypt your data"),
"enterThe6digitCodeFromnyourAuthenticatorApp":
MessageLookupByLibrary.simpleMessage(
"Enter the 6-digit code from\nyour authenticator app"),
"enterValidEmail": MessageLookupByLibrary.simpleMessage(
"Please enter a valid email address."),
"enterYourEmailAddress":
MessageLookupByLibrary.simpleMessage("Enter your email address"),
"enterYourPassword":
MessageLookupByLibrary.simpleMessage("Enter your password"),
"enterYourRecoveryKey":
MessageLookupByLibrary.simpleMessage("Enter your recovery key"),
"feedback": MessageLookupByLibrary.simpleMessage("Feedback"),
"forgotPassword":
MessageLookupByLibrary.simpleMessage("Forgot password"),
"fromYourRegisteredEmailAddress": MessageLookupByLibrary.simpleMessage(
"from your registered email address."),
"generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage(
"Generating encryption keys..."),
"howItWorks": MessageLookupByLibrary.simpleMessage("How it works"),
"incorrectPasswordTitle":
MessageLookupByLibrary.simpleMessage("Incorrect password"),
"incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage(
"The recovery key you entered is incorrect"),
"incorrectRecoveryKeyTitle":
MessageLookupByLibrary.simpleMessage("Incorrect recovery key"),
"insecureDevice":
MessageLookupByLibrary.simpleMessage("Insecure device"),
"invalidEmailAddress":
MessageLookupByLibrary.simpleMessage("Invalid email address"),
"verify": MessageLookupByLibrary.simpleMessage("Verify")
"invalidKey": MessageLookupByLibrary.simpleMessage("Invalid key"),
"invalidRecoveryKey": MessageLookupByLibrary.simpleMessage(
"The recovery key you entered is not valid. Please make sure it "),
"kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage(
"Kindly help us with this information"),
"logInLabel": MessageLookupByLibrary.simpleMessage("Log in"),
"lostDevice": MessageLookupByLibrary.simpleMessage("Lost device?"),
"manage": MessageLookupByLibrary.simpleMessage("Manage"),
"moderateStrength": MessageLookupByLibrary.simpleMessage("Moderate"),
"noPasswordWarningPart1": MessageLookupByLibrary.simpleMessage(
"We don\'t store this password, so if you forget,"),
"noPasswordWarningPart2":
MessageLookupByLibrary.simpleMessage("we cannot decrypt your data"),
"noRecoveryKey":
MessageLookupByLibrary.simpleMessage("No recovery key?"),
"noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage(
"Due to the nature of our end-to-end encryption protocol, your data cannot be decrypted without your password or recovery key"),
"ok": MessageLookupByLibrary.simpleMessage("Ok"),
"oops": MessageLookupByLibrary.simpleMessage("Oops"),
"orPickAnExistingOne":
MessageLookupByLibrary.simpleMessage("Or pick an existing one"),
"password": MessageLookupByLibrary.simpleMessage("Password"),
"passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage(
"Password changed successfully"),
"passwordStrength": m2,
"pleaseSendAnEmailTo":
MessageLookupByLibrary.simpleMessage("Please send an email to"),
"pleaseTryAgain":
MessageLookupByLibrary.simpleMessage("Please try again"),
"pleaseWait": MessageLookupByLibrary.simpleMessage("Please wait..."),
"privacyPolicy": MessageLookupByLibrary.simpleMessage("privacy policy"),
"privacyPolicyTitle":
MessageLookupByLibrary.simpleMessage("Privacy Policy"),
"recover": MessageLookupByLibrary.simpleMessage("Recover"),
"recoverAccount":
MessageLookupByLibrary.simpleMessage("Recover account"),
"recoverButton": MessageLookupByLibrary.simpleMessage("Recover"),
"recoveryKey": MessageLookupByLibrary.simpleMessage("Recovery key"),
"recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage(
"Recovery key copied to clipboard"),
"recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage(
"If you forget your password, the only way you can recover your data is with this key."),
"recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage(
"We don\'t store this key, please save this 24 word key in a safe place."),
"recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage(
"Great! Your recovery key is valid. Thank you for verifying.\n\nPlease remember to keep your recovery key safely backed up."),
"recoveryKeyVerified":
MessageLookupByLibrary.simpleMessage("Recovery key verified"),
"recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage(
"Your recovery key is the only way to recover your photos if you forget your password. You can find your recovery key in Settings > Account.\n\nPlease enter your recovery key here to verify that you have saved it correctly."),
"recoverySuccessful":
MessageLookupByLibrary.simpleMessage("Recovery successful!"),
"recreatePasswordBody": MessageLookupByLibrary.simpleMessage(
"The current device is not powerful enough to verify your "),
"recreatePasswordTitle":
MessageLookupByLibrary.simpleMessage("Recreate password"),
"remove": MessageLookupByLibrary.simpleMessage("Remove"),
"removeParticipant":
MessageLookupByLibrary.simpleMessage("Remove participant"),
"resendEmail": MessageLookupByLibrary.simpleMessage("Resend email"),
"resetPasswordTitle":
MessageLookupByLibrary.simpleMessage("Reset password"),
"saveKey": MessageLookupByLibrary.simpleMessage("Save key"),
"saveYourRecoveryKeyIfYouHaventAlready":
MessageLookupByLibrary.simpleMessage(
"Save your recovery key if you haven\'t already"),
"scanCode": MessageLookupByLibrary.simpleMessage("Scan code"),
"scanThisBarcodeWithnyourAuthenticatorApp":
MessageLookupByLibrary.simpleMessage(
"Scan this barcode with\nyour authenticator app"),
"selectReason": MessageLookupByLibrary.simpleMessage("Select reason"),
"sendEmail": MessageLookupByLibrary.simpleMessage("Send email"),
"setPasswordTitle":
MessageLookupByLibrary.simpleMessage("Set password"),
"setupComplete": MessageLookupByLibrary.simpleMessage("Setup complete"),
"somethingWentWrongPleaseTryAgain":
MessageLookupByLibrary.simpleMessage(
"Something went wrong, please try again"),
"sorry": MessageLookupByLibrary.simpleMessage("Sorry"),
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease":
MessageLookupByLibrary.simpleMessage(
"Sorry, we could not generate secure keys on this device.\n\nplease sign up from a different device."),
"strongStrength": MessageLookupByLibrary.simpleMessage("Strong"),
"tapToCopy": MessageLookupByLibrary.simpleMessage("tap to copy"),
"tapToEnterCode":
MessageLookupByLibrary.simpleMessage("Tap to enter code"),
"terminate": MessageLookupByLibrary.simpleMessage("Terminate"),
"terminateSession":
MessageLookupByLibrary.simpleMessage("Terminate session?"),
"termsAgreePart1":
MessageLookupByLibrary.simpleMessage("I agree to the "),
"termsOfService":
MessageLookupByLibrary.simpleMessage("terms of service"),
"termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("Terms"),
"thisCanBeUsedToRecoverYourAccountIfYou":
MessageLookupByLibrary.simpleMessage(
"This can be used to recover your account if you lose your second factor"),
"thisDevice": MessageLookupByLibrary.simpleMessage("This device"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"This will log you out of the following device:"),
"thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage(
"This will log you out of this device!"),
"tryAgain": MessageLookupByLibrary.simpleMessage("Try again"),
"twofactorAuthenticationPageTitle":
MessageLookupByLibrary.simpleMessage("Two-factor authentication"),
"twofactorSetup":
MessageLookupByLibrary.simpleMessage("Two-factor setup"),
"useRecoveryKey":
MessageLookupByLibrary.simpleMessage("Use recovery key"),
"verify": MessageLookupByLibrary.simpleMessage("Verify"),
"verifyEmail": MessageLookupByLibrary.simpleMessage("Verify email"),
"verifyPassword":
MessageLookupByLibrary.simpleMessage("Verify password"),
"verifyingRecoveryKey":
MessageLookupByLibrary.simpleMessage("Verifying recovery key..."),
"viewRecoveryKey":
MessageLookupByLibrary.simpleMessage("View recovery key"),
"viewer": MessageLookupByLibrary.simpleMessage("Viewer"),
"weakStrength": MessageLookupByLibrary.simpleMessage("Weak"),
"welcomeBack": MessageLookupByLibrary.simpleMessage("Welcome back!"),
"weveSentAMailTo":
MessageLookupByLibrary.simpleMessage("We\'ve sent a mail to"),
"yesConvertToViewer":
MessageLookupByLibrary.simpleMessage("Yes, convert to viewer"),
"you": MessageLookupByLibrary.simpleMessage("You"),
"yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage(
"Your account has been deleted")
};
}

File diff suppressed because it is too large Load diff

View file

@ -5,5 +5,197 @@
"cancel": "Cancel",
"verify": "Verify",
"invalidEmailAddress": "Invalid email address",
"enterValidEmail": "Please enter a valid email address."
"enterValidEmail": "Please enter a valid email address.",
"deleteAccount": "Delete account",
"askDeleteReason": "What is the main reason you are deleting your account?",
"deleteAccountFeedbackPrompt": "We are sorry to see you go. Please share your feedback to help us improve.",
"feedback": "Feedback",
"kindlyHelpUsWithThisInformation": "Kindly help us with this information",
"confirmDeletePrompt": "Yes, I want to permanently delete this account and all its data.",
"confirmAccountDeletion": "Confirm Account Deletion",
"deleteConfirmDialogBody": "You are about to permanently delete your account and all its data.\nThis action is irreversible.",
"deleteAccountPermanentlyButton": "Delete Account Permanently",
"yourAccountHasBeenDeleted": "Your account has been deleted",
"selectReason": "Select reason",
"deleteReason1": "Its missing a key feature that I need",
"deleteReason2": "The app or a certain feature does not \nbehave as I think it should",
"deleteReason3": "I found another service that I like better",
"deleteReason4": "My reason isnt listed",
"sendEmail": "Send email",
"deleteRequestSLAText": "Your request will be processed within 72 hours.",
"pleaseSendAnEmailTo": "Please send an email to",
"@pleaseSendAnEmailTo": {
"description": "This text is part of the sentence 'Please send an email to email@ente.io from your registered email address.'"
},
"fromYourRegisteredEmailAddress": "from your registered email address.",
"@fromYourRegisteredEmailAddress": {
"description": "This text is part of the sentence 'Please send an email to email@ente.io from your registered email address.'"
},
"ok": "Ok",
"createAccount": "Create account",
"createNewAccount": "Create new account",
"password": "Password",
"confirmPassword": "Confirm password",
"activeSessions": "Active sessions",
"oops": "Oops",
"somethingWentWrongPleaseTryAgain": "Something went wrong, please try again",
"thisWillLogYouOutOfThisDevice": "This will log you out of this device!",
"thisWillLogYouOutOfTheFollowingDevice": "This will log you out of the following device:",
"terminateSession": "Terminate session?",
"terminate": "Terminate",
"thisDevice": "This device",
"recoverButton": "Recover",
"recoverySuccessful": "Recovery successful!",
"decrypting": "Decrypting...",
"incorrectRecoveryKeyTitle": "Incorrect recovery key",
"incorrectRecoveryKeyBody": "The recovery key you entered is incorrect",
"forgotPassword": "Forgot password",
"enterYourRecoveryKey": "Enter your recovery key",
"noRecoveryKey": "No recovery key?",
"sorry": "Sorry",
"noRecoveryKeyNoDecryption": "Due to the nature of our end-to-end encryption protocol, your data cannot be decrypted without your password or recovery key",
"verifyEmail": "Verify email",
"checkInboxAndSpamFolder": "Please check your inbox (and spam) to complete verification",
"tapToEnterCode": "Tap to enter code",
"resendEmail": "Resend email",
"weveSentAMailTo": "We've sent a mail to",
"setPasswordTitle": "Set password",
"changePasswordTitle": "Change password",
"resetPasswordTitle": "Reset password",
"encryptionKeys": "Encryption keys",
"noPasswordWarningPart1": "We don't store this password, so if you forget,",
"@noPasswordWarningPart1": {
"description": "This text is part1 the sentence 'We don't store this password, so if you forget, we cannot decrypt your data.'"
},
"noPasswordWarningPart2": "we cannot decrypt your data",
"@noPasswordWarningPart2": {
"description": "This text is part2 the sentence 'We don't store this password, so if you forget, we cannot decrypt your data.'"
},
"enterPasswordToEncrypt": "Enter a password we can use to encrypt your data",
"enterNewPasswordToEncrypt": "Enter a new password we can use to encrypt your data",
"weakStrength": "Weak",
"strongStrength": "Strong",
"moderateStrength": "Moderate",
"passwordStrength": "Password strength: {passwordStrengthValue}",
"@passwordStrength": {
"description": "Text to indicate the password strength",
"placeholders": {
"passwordStrengthValue": {
"description": "The strength of the password as a string",
"type": "String",
"example": "Weak or Moderate or Strong"
}
},
"message": "Password Strength: {passwordStrengthText}"
},
"passwordChangedSuccessfully": "Password changed successfully",
"generatingEncryptionKeys": "Generating encryption keys...",
"pleaseWait": "Please wait...",
"continueLabel": "Continue",
"insecureDevice": "Insecure device",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Sorry, we could not generate secure keys on this device.\n\nplease sign up from a different device.",
"howItWorks": "How it works",
"encryption": "Encryption",
"ackPasswordLostWarningPart1": "I understand that if I lose my password, I may lose my data since my data is ",
"endToEndEncrypted": "end-to-end encrypted",
"ackPasswordLostWarningPart2": " with ente",
"@ackPasswordLostWarningPart2": {
"description": "This text is part2 the sentence 'I understand that if I lose my password, I may lose my data since my data is end-to-end encrypted with ente.'"
},
"privacyPolicyTitle": "Privacy Policy",
"termsOfServicesTitle": "Terms",
"termsAgreePart1": "I agree to the ",
"@termsAgreePart1": {
"description": "Note: there's a trailing space. This text is part the sentence 'I agree to the terms of service and privacy policy.'"
},
"privacyPolicy": "privacy policy",
"and": "and",
"@and": {
"description": "Separator used in sentences like 'I agree to the terms of service and privacy policy.'"
},
"termsOfService": "terms of service",
"logInLabel": "Log in",
"byClickingLogInIAgreeToThe": "By clicking log in, I agree to the",
"@byClickingLogInIAgreeToThe": {
"description": "This text is part the sentence 'By clicking log in, I agree to the terms of service and privacy policy'"
},
"changeEmail": "Change email",
"enterYourPassword": "Enter your password",
"welcomeBack": "Welcome back!",
"contactSupport": "Contact support",
"incorrectPasswordTitle": "Incorrect password",
"pleaseTryAgain": "Please try again",
"recreatePasswordTitle": "Recreate password",
"useRecoveryKey": "Use recovery key",
"recreatePasswordBody": "The current device is not powerful enough to verify your ",
"verifyPassword": "Verify password",
"recoveryKey": "Recovery key",
"recoveryKeyOnForgotPassword": "If you forget your password, the only way you can recover your data is with this key.",
"recoveryKeySaveDescription": "We don't store this key, please save this 24 word key in a safe place.",
"doThisLater": "Do this later",
"saveKey": "Save key",
"recoveryKeyCopiedToClipboard": "Recovery key copied to clipboard",
"recoverAccount": "Recover account",
"recover": "Recover",
"dropSupportEmail": "Please drop an email to {supportEmail} from your registered email address",
"@dropSupportEmail": {
"placeholders": {
"supportEmail": {
"description": "The support email address",
"type": "String",
"example": "support@ente.io"
}
}
},
"twofactorSetup": "Two-factor setup",
"enterCode": "Enter code",
"scanCode": "Scan code",
"codeCopiedToClipboard": "Code copied to clipboard",
"copypasteThisCodentoYourAuthenticatorApp": "Copy-paste this code\nto your authenticator app",
"tapToCopy": "tap to copy",
"scanThisBarcodeWithnyourAuthenticatorApp": "Scan this barcode with\nyour authenticator app",
"enterThe6digitCodeFromnyourAuthenticatorApp": "Enter the 6-digit code from\nyour authenticator app",
"confirm": "Confirm",
"setupComplete": "Setup complete",
"saveYourRecoveryKeyIfYouHaventAlready": "Save your recovery key if you haven't already",
"thisCanBeUsedToRecoverYourAccountIfYou": "This can be used to recover your account if you lose your second factor",
"twofactorAuthenticationPageTitle": "Two-factor authentication",
"lostDevice": "Lost device?",
"verifyingRecoveryKey": "Verifying recovery key...",
"recoveryKeyVerified": "Recovery key verified",
"recoveryKeySuccessBody": "Great! Your recovery key is valid. Thank you for verifying.\n\nPlease remember to keep your recovery key safely backed up.",
"invalidRecoveryKey": "The recovery key you entered is not valid. Please make sure it ",
"invalidKey": "Invalid key",
"tryAgain": "Try again",
"viewRecoveryKey": "View recovery key",
"confirmRecoveryKey": "Confirm recovery key",
"recoveryKeyVerifyReason": "Your recovery key is the only way to recover your photos if you forget your password. You can find your recovery key in Settings > Account.\n\nPlease enter your recovery key here to verify that you have saved it correctly.",
"confirmYourRecoveryKey": "Confirm your recovery key",
"addViewer": "Add viewer",
"addCollaborator": "Add collaborator",
"addANewEmail": "Add a new email",
"orPickAnExistingOne": "Or pick an existing one",
"collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Collaborators can add photos and videos to the shared album.",
"enterEmail": "Enter email",
"albumOwner": "Owner",
"@albumOwner": {
"description": "Role of the album owner"
},
"you": "You",
"collaborator": "Collaborator",
"addMore": "Add more",
"@addMore": {
"description": "Button text to add more collaborators/viewers"
},
"viewer": "Viewer",
"remove": "Remove",
"removeParticipant": "Remove participant",
"@removeParticipant": {
"description": "menuSectionTitle for removing a participant"
},
"manage": "Manage",
"addedAs": "Added as",
"changePermissions": "Change permissions?",
"yesConvertToViewer": "Yes, convert to viewer",
"cannotAddMorePhotosAfterBecomingViewer": "{user} will not be able to add more photos to this album\n\nThey will still be able to remove existing photos added by them"
}

View file

@ -4,6 +4,7 @@ import "package:dropdown_button2/dropdown_button2.dart";
import 'package:flutter/material.dart';
import "package:logging/logging.dart";
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/delete_account.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/theme/ente_theme.dart';
@ -26,23 +27,26 @@ class DeleteAccountPage extends StatefulWidget {
class _DeleteAccountPageState extends State<DeleteAccountPage> {
bool _hasConfirmedDeletion = false;
final _feedbackTextCtrl = TextEditingController();
final String _defaultSelection = 'Select reason';
late String _dropdownValue = _defaultSelection;
late String _defaultSelection = S.of(context).selectReason;
String? _dropdownValue;
late final List<String> _deletionReason = [
_defaultSelection,
'Its missing a key feature that I need',
'The app or a certain feature does not \nbehave as I think it should',
'I found another service that I like better',
'My reason isnt listed',
S.of(context).deleteReason1,
S.of(context).deleteReason2,
S.of(context).deleteReason3,
S.of(context).deleteReason4,
];
@override
Widget build(BuildContext context) {
_defaultSelection = S.of(context).selectReason;
_dropdownValue ??= _defaultSelection;
final colorScheme = getEnteColorScheme(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
title: const Text("Delete account"),
title: Text(S.of(context).deleteAccount),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
color: Theme.of(context).iconTheme.color,
@ -59,7 +63,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
"What is the main reason you are deleting your account?",
S.of(context).askDeleteReason,
style: getEnteTextTheme(context).body,
),
const SizedBox(height: 4),
@ -97,8 +101,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
),
const SizedBox(height: 24),
Text(
"We are sorry to see you go. Please share your feedback to "
"help us improve.",
S.of(context).deleteAccountFeedbackPrompt,
style: getEnteTextTheme(context).body,
),
const SizedBox(height: 4),
@ -116,7 +119,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
),
filled: true,
fillColor: Colors.transparent,
hintText: "Feedback",
hintText: S.of(context).feedback,
contentPadding: const EdgeInsets.all(12),
),
controller: _feedbackTextCtrl,
@ -135,7 +138,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
child: Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Text(
"Kindly help us with this information",
S.of(context).kindlyHelpUsWithThisInformation,
style: getEnteTextTheme(context)
.smallBold
.copyWith(color: colorScheme.warning700),
@ -162,8 +165,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
),
Expanded(
child: Text(
"Yes, I want to permanently delete this account and "
"all its data.",
S.of(context).confirmDeletePrompt,
style: getEnteTextTheme(context).bodyMuted,
textAlign: TextAlign.left,
),
@ -177,7 +179,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
children: [
ButtonWidget(
buttonType: ButtonType.critical,
labelText: "Confirm Account Deletion",
labelText: S.of(context).confirmAccountDeletion,
isDisabled: _shouldBlockDeletion(),
onTap: () async {
await _initiateDelete(context);
@ -187,7 +189,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
const SizedBox(height: 8),
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: "Cancel",
labelText: S.of(context).cancel,
onTap: () async {
Navigator.of(context).pop();
},
@ -220,10 +222,9 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
Future<void> _initiateDelete(BuildContext context) async {
final choice = await showChoiceDialog(
context,
title: "Confirm Account Deletion",
body: "You are about to permanently delete your account and all its data."
"\nThis action is irreversible.",
firstButtonLabel: "Delete Account Permanently",
title: S.of(context).confirmAccountDeletion,
body: S.of(context).deleteConfirmDialogBody,
firstButtonLabel: S.of(context).deleteAccountPermanentlyButton,
firstButtonType: ButtonType.critical,
firstButtonOnTap: () async {
final deleteChallengeResponse =
@ -260,11 +261,11 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
await UserService.instance.deleteAccount(
context,
challengeResponseStr,
reasonCategory: _dropdownValue,
reasonCategory: _dropdownValue!,
feedback: _feedbackTextCtrl.text.trim(),
);
Navigator.of(context).popUntil((route) => route.isFirst);
showShortToast(context, "Your account has been deleted");
showShortToast(context, S.of(context).yourAccountHasBeenDeleted);
} catch (e, s) {
Logger("DeleteAccount").severe("failed to delete", e, s);
showGenericErrorDialog(context: context);
@ -273,17 +274,17 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
Future<void> _requestEmailForDeletion(BuildContext context) async {
final AlertDialog alert = AlertDialog(
title: const Text(
"Delete account",
style: TextStyle(
title: Text(
S.of(context).deleteAccount,
style: const TextStyle(
color: Colors.red,
),
),
content: RichText(
text: TextSpan(
children: [
const TextSpan(
text: "Please send an email to ",
TextSpan(
text: S.of(context).pleaseSendAnEmailTo,
),
TextSpan(
text: "account-deletion@ente.io",
@ -291,9 +292,9 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
color: Colors.orange[300],
),
),
const TextSpan(
TextSpan(
text:
" from your registered email address.\n\nYour request will be processed within 72 hours.",
" ${S.of(context).fromYourRegisteredEmailAddress}\n\n${S.of(context).deleteRequestSLAText}",
),
],
style: TextStyle(
@ -305,9 +306,9 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
),
actions: [
TextButton(
child: const Text(
"Send email",
style: TextStyle(
child: Text(
S.of(context).sendEmail,
style: const TextStyle(
color: Colors.red,
),
),
@ -316,13 +317,13 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
await sendEmail(
context,
to: 'account-deletion@ente.io',
subject: '[Delete account]',
subject: '[${S.of(context).deleteAccount}]',
);
},
),
TextButton(
child: Text(
"Ok",
S.of(context).ok,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),

View file

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:password_strength/password_strength.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:photos/ui/common/web_page.dart';
@ -99,7 +100,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _isFormValid(),
buttonText: 'Create account',
buttonText: S.of(context).createAccount,
onPressedFunction: () {
_config.setVolatilePassword(_passwordController1.text);
UserService.instance.setEmail(_email!);
@ -114,13 +115,13 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
}
Widget _getBody() {
var passwordStrengthText = 'Weak';
var passwordStrengthText = S.of(context).weakStrength;
var passwordStrengthColor = Colors.redAccent;
if (_passwordStrength > kStrongPasswordStrengthThreshold) {
passwordStrengthText = 'Strong';
passwordStrengthText = S.of(context).strongStrength;
passwordStrengthColor = Colors.greenAccent;
} else if (_passwordStrength > kMildPasswordStrengthThreshold) {
passwordStrengthText = 'Moderate';
passwordStrengthText = S.of(context).moderateStrength;
passwordStrengthColor = Colors.orangeAccent;
}
return Column(
@ -133,7 +134,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Create new account',
S.of(context).createNewAccount,
style: Theme.of(context).textTheme.headline4,
),
),
@ -145,7 +146,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
decoration: InputDecoration(
fillColor: _emailIsValid ? _validFieldValueColor : null,
filled: true,
hintText: 'Email',
hintText: S.of(context).email,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
@ -193,7 +194,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
fillColor:
_passwordIsValid ? _validFieldValueColor : null,
filled: true,
hintText: "Password",
hintText: S.of(context).password,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
@ -262,7 +263,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
? _validFieldValueColor
: null,
filled: true,
hintText: "Confirm password",
hintText: S.of(context).confirmPassword,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
@ -314,7 +315,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: Text(
'Password strength: $passwordStrengthText',
S.of(context).passwordStrength(passwordStrengthText),
style: TextStyle(
color: passwordStrengthColor,
fontWeight: FontWeight.w500,
@ -371,11 +372,11 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
child: RichText(
text: TextSpan(
children: [
const TextSpan(
text: "I agree to the ",
TextSpan(
text: S.of(context).termsAgreePart1,
),
TextSpan(
text: "terms of service",
text: S.of(context).termsOfService,
style: const TextStyle(
decoration: TextDecoration.underline,
),
@ -384,8 +385,8 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"Terms",
return WebPage(
S.of(context).termsOfServicesTitle,
"https://ente.io/terms",
);
},
@ -393,9 +394,9 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
);
},
),
const TextSpan(text: " and "),
TextSpan(text: ' ${S.of(context).and} '),
TextSpan(
text: "privacy policy",
text: S.of(context).privacyPolicy,
style: const TextStyle(
decoration: TextDecoration.underline,
),
@ -404,8 +405,8 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"Privacy",
return WebPage(
S.of(context).privacyPolicyTitle,
"https://ente.io/privacy",
);
},
@ -450,12 +451,11 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
child: RichText(
text: TextSpan(
children: [
const TextSpan(
text:
"I understand that if I lose my password, I may lose my data since my data is ",
TextSpan(
text: S.of(context).ackPasswordLostWarningPart1,
),
TextSpan(
text: "end-to-end encrypted",
text: S.of(context).endToEndEncrypted,
style: const TextStyle(
decoration: TextDecoration.underline,
),
@ -464,8 +464,8 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"Encryption",
return WebPage(
S.of(context).encryption,
"https://ente.io/architecture",
);
},
@ -473,7 +473,9 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
);
},
),
const TextSpan(text: " with ente"),
TextSpan(
text: " ${S.of(context).ackPasswordLostWarningPart2}",
),
],
style: Theme.of(context)
.textTheme

View file

@ -2,6 +2,7 @@ import 'package:email_validator/email_validator.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/l10n/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
@ -54,7 +55,7 @@ class _LoginPageState extends State<LoginPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _emailIsValid,
buttonText: 'Log in',
buttonText: S.of(context).logInLabel,
onPressedFunction: () {
UserService.instance.setEmail(_email!);
UserService.instance
@ -148,11 +149,12 @@ class _LoginPageState extends State<LoginPage> {
.subtitle1!
.copyWith(fontSize: 12),
children: [
const TextSpan(
text: "By clicking log in, I agree to the ",
TextSpan(
text: S.of(context).byClickingLogInIAgreeToThe +
" ",
),
TextSpan(
text: "terms of service",
text: S.of(context).termsOfService,
style: const TextStyle(
decoration: TextDecoration.underline,
),
@ -161,8 +163,8 @@ class _LoginPageState extends State<LoginPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"terms",
return WebPage(
S.of(context).termsOfServicesTitle,
"https://ente.io/terms",
);
},
@ -170,9 +172,9 @@ class _LoginPageState extends State<LoginPage> {
);
},
),
const TextSpan(text: " and "),
TextSpan(text: " ${S.of(context).and} "),
TextSpan(
text: "privacy policy",
text: S.of(context).privacyPolicy,
style: const TextStyle(
decoration: TextDecoration.underline,
),
@ -181,8 +183,8 @@ class _LoginPageState extends State<LoginPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"privacy",
return WebPage(
S.of(context).privacyPolicyTitle,
"https://ente.io/privacy",
);
},

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';
@ -64,7 +65,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _verificationCodeController.text.isNotEmpty,
buttonText: 'Verify',
buttonText: S.of(context).verify,
onPressedFunction: () {
if (widget.isChangeEmail) {
UserService.instance.changeEmail(
@ -93,7 +94,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
Padding(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 15),
child: Text(
'Verify email',
S.of(context).verifyEmail,
style: Theme.of(context).textTheme.headline4,
),
),
@ -114,7 +115,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
.subtitle1!
.copyWith(fontSize: 14),
children: [
const TextSpan(text: "We've sent a mail to "),
TextSpan(text: S.of(context).weveSentAMailTo),
TextSpan(
text: widget.email,
style: TextStyle(
@ -128,7 +129,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
),
),
Text(
'Please check your inbox (and spam) to complete verification',
S.of(context).checkInboxAndSpamFolder,
style: Theme.of(context)
.textTheme
.subtitle1!
@ -150,7 +151,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
style: Theme.of(context).textTheme.subtitle1,
decoration: InputDecoration(
filled: true,
hintText: 'Tap to enter code',
hintText: S.of(context).tapToEnterCode,
contentPadding: const EdgeInsets.all(15),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
@ -183,7 +184,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
);
},
child: Text(
"Resend email",
S.of(context).resendEmail,
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,

View file

@ -6,6 +6,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/account_configured_event.dart';
import 'package:photos/events/subscription_purchased_event.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/account/recovery_key_page.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
@ -87,13 +88,13 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
}
String title = "Set password";
String title = S.of(context).setPasswordTitle;
if (widget.mode == PasswordEntryMode.update) {
title = "Change password";
title = S.of(context).changePasswordTitle;
} else if (widget.mode == PasswordEntryMode.reset) {
title = "Reset password";
title = S.of(context).resetPasswordTitle;
} else if (_volatilePassword != null) {
title = "Encryption keys";
title = S.of(context).encryptionKeys;
}
return Scaffold(
resizeToAvoidBottomInset: isKeypadOpen,
@ -130,13 +131,13 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Widget _getBody(String buttonTextAndHeading) {
final email = Configuration.instance.getEmail();
var passwordStrengthText = 'Weak';
var passwordStrengthText = S.of(context).weakStrength;
var passwordStrengthColor = Colors.redAccent;
if (_passwordStrength > kStrongPasswordStrengthThreshold) {
passwordStrengthText = 'Strong';
passwordStrengthText = S.of(context).strongStrength;
passwordStrengthColor = Colors.greenAccent;
} else if (_passwordStrength > kMildPasswordStrengthThreshold) {
passwordStrengthText = 'Moderate';
passwordStrengthText = S.of(context).moderateStrength;
passwordStrengthColor = Colors.orangeAccent;
}
if (_volatilePassword != null) {
@ -159,9 +160,9 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
"Enter a" +
(widget.mode != PasswordEntryMode.set ? " new " : " ") +
"password we can use to encrypt your data",
widget.mode == PasswordEntryMode.set
? S.of(context).enterPasswordToEncrypt
: S.of(context).enterNewPasswordToEncrypt,
textAlign: TextAlign.start,
style: Theme.of(context)
.textTheme
@ -179,12 +180,11 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
.subtitle1!
.copyWith(fontSize: 14),
children: [
const TextSpan(
text:
"We don't store this password, so if you forget, ",
TextSpan(
text: '${S.of(context).noPasswordWarningPart1} ',
),
TextSpan(
text: "we cannot decrypt your data",
text: S.of(context).noPasswordWarningPart2,
style:
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
@ -218,7 +218,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
fillColor:
_isPasswordValid ? _validFieldValueColor : null,
filled: true,
hintText: "Password",
hintText: S.of(context).password,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
@ -281,7 +281,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
decoration: InputDecoration(
fillColor: _passwordsMatch ? _validFieldValueColor : null,
filled: true,
hintText: "Confirm password",
hintText: S.of(context).confirmPassword,
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
@ -335,7 +335,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
child: Text(
'Password Strength: $passwordStrengthText',
S.of(context).passwordStrength(passwordStrengthText),
style: TextStyle(
color: passwordStrengthColor,
),
@ -349,8 +349,8 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"How it works",
return WebPage(
S.of(context).howItWorks,
"https://ente.io/architecture",
);
},
@ -361,7 +361,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
padding: const EdgeInsets.symmetric(horizontal: 20),
child: RichText(
text: TextSpan(
text: "How it works",
text: S.of(context).howItWorks,
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
@ -381,14 +381,14 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
void _updatePassword() async {
final dialog =
createProgressDialog(context, "Generating encryption keys...");
createProgressDialog(context, S.of(context).generatingEncryptionKeys);
await dialog.show();
try {
final keyAttributes = await Configuration.instance
.updatePassword(_passwordController1.text);
await UserService.instance.updateKeyAttributes(keyAttributes);
await dialog.hide();
showShortToast(context, "Password changed successfully");
showShortToast(context, S.of(context).passwordChangedSuccessfully);
Navigator.of(context).pop();
if (widget.mode == PasswordEntryMode.reset) {
Bus.instance.fire(SubscriptionPurchasedEvent());
@ -403,14 +403,14 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Future<void> _showRecoveryCodeDialog(String password) async {
final dialog =
createProgressDialog(context, "Generating encryption keys...");
createProgressDialog(context, S.of(context).generatingEncryptionKeys);
await dialog.show();
try {
final result = await Configuration.instance.generateKey(password);
Configuration.instance.setVolatilePassword(null);
await dialog.hide();
onDone() async {
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, S.of(context).pleaseWait);
await dialog.show();
try {
await UserService.instance.setAttributes(result);
@ -435,7 +435,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
context,
RecoveryKeyPage(
result.privateKeyAttributes.recoveryKey,
"Continue",
S.of(context).continueLabel,
showAppBar: false,
isDismissible: false,
onDone: onDone,
@ -448,8 +448,8 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
if (e is UnsupportedError) {
showErrorDialog(
context,
"Insecure device",
"Sorry, we could not generate secure keys on this device.\n\nplease sign up from a different device.",
S.of(context).insecureDevice,
S.of(context).sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease,
);
} else {
showGenericErrorDialog(context: context);

View file

@ -6,6 +6,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/subscription_purchased_event.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/ui/account/recovery_page.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:photos/ui/components/buttons/button_widget.dart';
@ -67,10 +68,11 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _passwordController.text.isNotEmpty,
buttonText: 'Verify password',
buttonText: S.of(context).verifyPassword,
onPressedFunction: () async {
FocusScope.of(context).unfocus();
final dialog = createProgressDialog(context, "Please wait...");
final dialog =
createProgressDialog(context, S.of(context).pleaseWait);
await dialog.show();
try {
await Configuration.instance.decryptAndSaveSecrets(
@ -82,12 +84,9 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
await dialog.hide();
final dialogChoice = await showChoiceDialog(
context,
title: "Recreate password",
body: "The current device is not powerful enough to verify your "
"password, so we need to regenerate it once in a way that "
"works with all devices. \n\nPlease login using your "
"recovery key and regenerate your password (you can use the same one again if you wish).",
firstButtonLabel: "Use recovery key",
title: S.of(context).recreatePasswordTitle,
body: S.of(context).recreatePasswordBody,
firstButtonLabel: S.of(context).useRecoveryKey,
);
if (dialogChoice!.action == ButtonAction.first) {
Navigator.of(context).push(
@ -104,15 +103,15 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
await dialog.hide();
final dialogChoice = await showChoiceDialog(
context,
title: "Incorrect password",
body: "Please try again",
firstButtonLabel: "Contact Support",
secondButtonLabel: "OK",
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,
"Contact support",
S.of(context).contactSupport,
"support@ente.io",
postShare: () {},
);
@ -149,7 +148,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
S.of(context).welcomeBack,
style: Theme.of(context).textTheme.headline4,
),
),
@ -172,7 +171,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
child: TextFormField(
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
hintText: "Enter your password",
hintText: S.of(context).enterYourPassword,
filled: true,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
@ -234,7 +233,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
},
child: Center(
child: Text(
"Forgot password",
S.of(context).forgotPassword,
style:
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
@ -246,8 +245,8 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
final dialog =
createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(
context, S.of(context).pleaseWait);
await dialog.show();
await Configuration.instance.logout();
await dialog.hide();
@ -256,7 +255,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
},
child: Center(
child: Text(
"Change email",
S.of(context).changeEmail,
style:
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,

View file

@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/ui/common/gradient_button.dart';
import 'package:photos/utils/toast_util.dart';
import 'package:share_plus/share_plus.dart';
@ -80,7 +81,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
: widget.showAppBar!
? AppBar(
elevation: 0,
title: Text(widget.title ?? "Recovery key"),
title: Text(widget.title ?? S.of(context).recoveryKey),
)
: null,
body: Padding(
@ -101,7 +102,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
widget.showAppBar!
? const SizedBox.shrink()
: Text(
widget.title ?? "Recovery key",
widget.title ?? S.of(context).recoveryKey,
style: Theme.of(context).textTheme.headline4,
),
Padding(
@ -109,7 +110,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
),
Text(
widget.text ??
"If you forget your password, the only way you can recover your data is with this key.",
S.of(context).recoveryKeyOnForgotPassword,
style: Theme.of(context).textTheme.subtitle1,
),
const Padding(padding: EdgeInsets.only(top: 24)),
@ -136,7 +137,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
);
showShortToast(
context,
"Recovery key copied to clipboard",
S.of(context).recoveryKeyCopiedToClipboard,
);
setState(() {
_hasTriedToSave = true;
@ -176,7 +177,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
widget.subText ??
"We don't store this key, please save this 24 word key in a safe place.",
S.of(context).recoveryKeySaveDescription,
style: Theme.of(context).textTheme.bodyText1,
),
),
@ -212,7 +213,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
onPressed: () async {
await _saveKeys();
},
child: const Text('Do this later'),
child: Text(S.of(context).doThisLater),
),
);
childrens.add(const SizedBox(height: 10));
@ -223,7 +224,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
onTap: () async {
await _shareRecoveryKey(recoveryKey);
},
text: 'Save key',
text: S.of(context).saveKey,
),
);
if (_hasTriedToSave) {

View file

@ -2,6 +2,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/ui/account/password_entry_page.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:photos/utils/dialog_util.dart';
@ -43,15 +44,16 @@ class _RecoveryPageState extends State<RecoveryPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _recoveryKey.text.isNotEmpty,
buttonText: 'Recover',
buttonText: S.of(context).recoverButton,
onPressedFunction: () async {
FocusScope.of(context).unfocus();
final dialog = createProgressDialog(context, "Decrypting...");
final dialog =
createProgressDialog(context, S.of(context).decrypting);
await dialog.show();
try {
await Configuration.instance.recover(_recoveryKey.text.trim());
await dialog.hide();
showShortToast(context, "Recovery successful!");
showShortToast(context, S.of(context).recoverySuccessful);
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (BuildContext context) {
@ -66,11 +68,15 @@ class _RecoveryPageState extends State<RecoveryPage> {
);
} catch (e) {
await dialog.hide();
String errMessage = "The recovery key you entered is incorrect";
String errMessage = S.of(context).incorrectRecoveryKeyBody;
if (e is AssertionError) {
errMessage = '$errMessage : ${e.message}';
}
showErrorDialog(context, "Incorrect recovery key", errMessage);
showErrorDialog(
context,
S.of(context).incorrectRecoveryKeyTitle,
errMessage,
);
}
},
),
@ -85,7 +91,7 @@ class _RecoveryPageState extends State<RecoveryPage> {
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Forgot password',
S.of(context).forgotPassword,
style: Theme.of(context).textTheme.headline4,
),
),
@ -94,7 +100,7 @@ class _RecoveryPageState extends State<RecoveryPage> {
child: TextFormField(
decoration: InputDecoration(
filled: true,
hintText: "Enter your recovery key",
hintText: S.of(context).enterYourRecoveryKey,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
@ -128,15 +134,15 @@ class _RecoveryPageState extends State<RecoveryPage> {
onTap: () {
showErrorDialog(
context,
"Sorry",
"Due to the nature of our end-to-end encryption protocol, your data cannot be decrypted without your password or recovery key",
S.of(context).sorry,
S.of(context).noRecoveryKeyNoDecryption,
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: Text(
"No recovery key?",
S.of(context).noRecoveryKey,
style:
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/sessions.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/common/loading_widget.dart';
@ -33,7 +34,7 @@ class _SessionsPageState extends State<SessionsPage> {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: const Text("Active sessions"),
title: Text(S.of(context).activeSessions),
),
body: _getBody(),
);
@ -111,7 +112,7 @@ class _SessionsPageState extends State<SessionsPage> {
}
Future<void> _terminateSession(Session session) async {
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, S.of(context).pleaseWait);
await dialog.show();
try {
await UserService.instance.terminateSession(session.token);
@ -122,8 +123,8 @@ class _SessionsPageState extends State<SessionsPage> {
_logger.severe('failed to terminate');
showErrorDialog(
context,
'Oops',
"Something went wrong, please try again",
S.of(context).oops,
S.of(context).somethingWentWrongPleaseTryAgain,
);
}
}
@ -148,15 +149,15 @@ class _SessionsPageState extends State<SessionsPage> {
session.token == Configuration.instance.getToken();
Widget text;
if (isLoggingOutFromThisDevice) {
text = const Text(
"This will log you out of this device!",
text = Text(
S.of(context).thisWillLogYouOutOfThisDevice,
);
} else {
text = SingleChildScrollView(
child: Column(
children: [
const Text(
"This will log you out of the following device:",
Text(
S.of(context).thisWillLogYouOutOfTheFollowingDevice,
),
const Padding(padding: EdgeInsets.all(8)),
Text(
@ -168,13 +169,13 @@ class _SessionsPageState extends State<SessionsPage> {
);
}
final AlertDialog alert = AlertDialog(
title: const Text("Terminate session?"),
title: Text(S.of(context).terminateSession),
content: text,
actions: [
TextButton(
child: const Text(
"Terminate",
style: TextStyle(
child: Text(
S.of(context).terminate,
style: const TextStyle(
color: Colors.red,
),
),
@ -189,7 +190,7 @@ class _SessionsPageState extends State<SessionsPage> {
),
TextButton(
child: Text(
"Cancel",
S.of(context).cancel,
style: TextStyle(
color: isLoggingOutFromThisDevice
? Theme.of(context).colorScheme.greenAlternative
@ -214,7 +215,7 @@ class _SessionsPageState extends State<SessionsPage> {
Widget _getUAWidget(Session session) {
if (session.token == Configuration.instance.getToken()) {
return Text(
"This device",
S.of(context).thisDevice,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.greenAlternative,

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/lifecycle_event_handler.dart';
import 'package:pinput/pin_put/pin_put.dart';
@ -51,8 +52,8 @@ class _TwoFactorAuthenticationPageState
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Two-factor authentication",
title: Text(
S.of(context).twofactorAuthenticationPageTitle,
),
),
body: _getBody(),
@ -65,9 +66,9 @@ class _TwoFactorAuthenticationPageState
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
const Text(
"Enter the 6-digit code from\nyour authenticator app",
style: TextStyle(
Text(
S.of(context).enterThe6digitCodeFromnyourAuthenticatorApp,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
@ -116,7 +117,7 @@ class _TwoFactorAuthenticationPageState
_verifyTwoFactorCode(_code);
}
: null,
child: const Text("Verify"),
child: Text(S.of(context).verify),
),
),
const Padding(padding: EdgeInsets.all(30)),
@ -127,10 +128,10 @@ class _TwoFactorAuthenticationPageState
},
child: Container(
padding: const EdgeInsets.all(10),
child: const Center(
child: Center(
child: Text(
"Lost device?",
style: TextStyle(
S.of(context).lostDevice,
style: const TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,
),

View file

@ -1,6 +1,7 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/utils/dialog_util.dart';
@ -27,9 +28,9 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Recover account",
style: TextStyle(
title: Text(
S.of(context).recoverAccount,
style: const TextStyle(
fontSize: 18,
),
),
@ -42,9 +43,9 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
Padding(
padding: const EdgeInsets.fromLTRB(60, 0, 60, 0),
child: TextFormField(
decoration: const InputDecoration(
hintText: "Enter your recovery key",
contentPadding: EdgeInsets.all(20),
decoration: InputDecoration(
hintText: S.of(context).enterYourRecoveryKey,
contentPadding: const EdgeInsets.all(20),
),
style: const TextStyle(
fontSize: 14,
@ -77,7 +78,7 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
);
}
: null,
child: const Text("Recover"),
child: Text(S.of(context).recover),
),
),
GestureDetector(
@ -85,15 +86,15 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
onTap: () {
showErrorDialog(
context,
"Contact support",
"Please drop an email to support@ente.io from your registered email address",
S.of(context).contactSupport,
S.of(context).dropSupportEmail("support@ente.io"),
);
},
child: Container(
padding: const EdgeInsets.all(40),
child: Center(
child: Text(
"No recovery key?",
S.of(context).noRecoveryKey,
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,

View file

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/account/recovery_key_page.dart';
import 'package:photos/ui/lifecycle_event_handler.dart';
@ -75,8 +76,8 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
return Scaffold(
appBar: AppBar(
elevation: 0,
title: const Text(
"Two-factor setup",
title: Text(
S.of(context).twofactorSetup,
),
),
body: _getBody(),
@ -97,12 +98,12 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
TabBar(
labelColor: Theme.of(context).colorScheme.greenAlternative,
unselectedLabelColor: Colors.grey,
tabs: const [
tabs: [
Tab(
text: "Enter code",
text: S.of(context).enterCode,
),
Tab(
text: "Scan code",
text: S.of(context).scanCode,
)
],
controller: _tabController,
@ -137,15 +138,15 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
return GestureDetector(
onTap: () async {
await Clipboard.setData(ClipboardData(text: widget.secretCode));
showShortToast(context, "Code copied to clipboard");
showShortToast(context, S.of(context).codeCopiedToClipboard);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(padding: EdgeInsets.all(12)),
const Text(
"Copy-paste this code\nto your authenticator app",
style: TextStyle(
Text(
S.of(context).copypasteThisCodentoYourAuthenticatorApp,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
@ -171,7 +172,7 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
),
const Padding(padding: EdgeInsets.all(6)),
Text(
"tap to copy",
S.of(context).tapToCopy,
style: TextStyle(color: textColor.withOpacity(0.5)),
)
],
@ -184,9 +185,9 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
child: Column(
children: [
const Padding(padding: EdgeInsets.all(12)),
const Text(
"Scan this barcode with\nyour authenticator app",
style: TextStyle(
Text(
S.of(context).scanThisBarcodeWithnyourAuthenticatorApp,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
@ -207,9 +208,9 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
return Column(
children: [
const Padding(padding: EdgeInsets.all(12)),
const Text(
"Enter the 6-digit code from\nyour authenticator app",
style: TextStyle(
Text(
S.of(context).enterThe6digitCodeFromnyourAuthenticatorApp,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
@ -253,7 +254,7 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
_enableTwoFactor(_code);
}
: null,
child: const Text("Confirm"),
child: Text(S.of(context).confirm),
),
const Padding(padding: EdgeInsets.only(bottom: 24)),
],
@ -275,13 +276,12 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
context,
RecoveryKeyPage(
recoveryKey,
"OK",
S.of(context).ok,
showAppBar: true,
onDone: () {},
title: "Setup complete",
text: "Save your recovery key if you haven't already",
subText:
"This can be used to recover your account if you lose your second factor",
title: S.of(context).setupComplete,
text: S.of(context).saveYourRecoveryKeyIfYouHaventAlready,
subText: S.of(context).thisCanBeUsedToRecoverYourAccountIfYou,
),
);
}

View file

@ -7,6 +7,7 @@ import 'package:logging/logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/events/notification_event.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/local_authentication_service.dart';
import 'package:photos/services/user_remote_flag_service.dart';
import 'package:photos/services/user_service.dart';
@ -29,7 +30,8 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
final Logger _logger = Logger((_VerifyRecoveryPageState).toString());
void _verifyRecoveryKey() async {
final dialog = createProgressDialog(context, "Verifying recovery key...");
final dialog =
createProgressDialog(context, S.of(context).verifyingRecoveryKey);
await dialog.show();
try {
final String inputKey = _recoveryKey.text.trim();
@ -58,10 +60,8 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
// todo: change this as per figma once the component is ready
await showErrorDialog(
context,
"Recovery key verified",
"Great! Your recovery key is valid. Thank you for verifying.\n"
"\nPlease"
" remember to keep your recovery key safely backed up.",
S.of(context).recoveryKeyVerified,
S.of(context).recoveryKeySuccessBody,
);
Navigator.of(context).pop();
} else {
@ -70,16 +70,13 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
} catch (e, s) {
_logger.severe("failed to verify recovery key", e, s);
await dialog.hide();
const String errMessage =
"The recovery key you entered is not valid. Please make sure it "
"contains 24 words, and check the spelling of each.\n\nIf you "
"entered an older recovery code, make sure it is 64 characters long, and check each of them.";
final String errMessage = S.of(context).invalidRecoveryKey;
final result = await showChoiceDialog(
context,
title: "Invalid key",
title: S.of(context).invalidKey,
body: errMessage,
firstButtonLabel: "Try again",
secondButtonLabel: "View recovery key",
firstButtonLabel: S.of(context).tryAgain,
secondButtonLabel: S.of(context).viewRecoveryKey,
secondButtonAction: ButtonAction.second,
);
if (result!.action == ButtonAction.second) {
@ -104,7 +101,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
context,
RecoveryKeyPage(
recoveryKey,
"OK",
S.of(context).ok,
showAppBar: true,
onDone: () {
Navigator.of(context).pop();
@ -149,14 +146,14 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
SizedBox(
width: double.infinity,
child: Text(
'Confirm recovery key',
S.of(context).confirmRecoveryKey,
style: enteTheme.textTheme.h3Bold,
textAlign: TextAlign.left,
),
),
const SizedBox(height: 18),
Text(
"Your recovery key is the only way to recover your photos if you forget your password. You can find your recovery key in Settings > Account.\n\nPlease enter your recovery key here to verify that you have saved it correctly.",
S.of(context).recoveryKeyVerifyReason,
style: enteTheme.textTheme.small
.copyWith(color: enteTheme.colorScheme.textMuted),
),
@ -164,7 +161,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
TextFormField(
decoration: InputDecoration(
filled: true,
hintText: "Enter your recovery key",
hintText: S.of(context).enterYourRecoveryKey,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
@ -197,7 +194,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
children: [
GradientButton(
onTap: _verifyRecoveryKey,
text: "Confirm",
text: S.of(context).confirm,
),
const SizedBox(height: 8),
],

View file

@ -6,6 +6,7 @@ import 'package:photos/core/event_bus.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/events/notification_event.dart';
import 'package:photos/events/sync_status_update_event.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/sync_service.dart';
import 'package:photos/services/user_remote_flag_service.dart';
import 'package:photos/theme/text_style.dart';
@ -100,14 +101,14 @@ class _StatusBarWidgetState extends State<StatusBarWidget> {
_showErrorBanner
? HeaderErrorWidget(error: _syncError)
: const SizedBox.shrink(),
UserRemoteFlagService.instance.shouldShowRecoveryVerification()
!UserRemoteFlagService.instance.shouldShowRecoveryVerification()
? Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12),
child: NotificationWidget(
startIcon: Icons.error_outline,
actionIcon: Icons.arrow_forward,
text: "Confirm your recovery key",
text: S.of(context).confirmYourRecoveryKey,
onTap: () async => {
await routeToPage(
context,

View file

@ -1,6 +1,7 @@
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/collection.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/theme/ente_theme.dart';
@ -60,7 +61,9 @@ class _AddParticipantPage extends State<AddParticipantPage> {
return Scaffold(
resizeToAvoidBottomInset: isKeypadOpen,
appBar: AppBar(
title: Text(widget.isAddingViewer ? "Add viewer" : "Add collaborator"),
title: Text(widget.isAddingViewer
? S.of(context).addViewer
: S.of(context).addCollaborator),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
@ -70,7 +73,7 @@ class _AddParticipantPage extends State<AddParticipantPage> {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
"Add a new email",
S.of(context).addANewEmail,
style: enteTextTheme.small
.copyWith(color: enteColorScheme.textMuted),
),
@ -88,21 +91,22 @@ class _AddParticipantPage extends State<AddParticipantPage> {
child: Column(
children: [
!isEmailListEmpty
? const MenuSectionTitle(
title: "Or pick an existing one",
? MenuSectionTitle(
title: S.of(context).orPickAnExistingOne,
)
: const SizedBox.shrink(),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
if (index >= suggestedUsers.length) {
return const Padding(
padding: EdgeInsets.symmetric(
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0,
),
child: MenuSectionDescriptionWidget(
content:
"Collaborators can add photos and videos to the shared album.",
content: S
.of(context)
.collaboratorsCanAddPhotosAndVideosToTheSharedAlbum,
),
);
}
@ -176,8 +180,8 @@ class _AddParticipantPage extends State<AddParticipantPage> {
buttonType: ButtonType.primary,
buttonSize: ButtonSize.large,
labelText: widget.isAddingViewer
? "Add viewer"
: "Add collaborator",
? S.of(context).addViewer
: S.of(context).addCollaborator,
isDisabled: (selectedEmail == '' && !_emailIsValid),
onTap: (selectedEmail == '' && !_emailIsValid)
? null
@ -204,8 +208,8 @@ class _AddParticipantPage extends State<AddParticipantPage> {
if ((selectedEmail == '' && !_emailIsValid)) {
await showErrorDialog(
context,
"Invalid email address",
"Please enter a valid email address.",
S.of(context).invalidEmailAddress,
S.of(context).enterValidEmail,
);
return;
}
@ -261,7 +265,7 @@ class _AddParticipantPage extends State<AddParticipantPage> {
),
fillColor: getEnteColorScheme(context).fillFaint,
filled: true,
hintText: 'Enter email',
hintText: S.of(context).enterEmail,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/extensions/list.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/collection.dart';
import 'package:photos/theme/ente_theme.dart';
import 'package:photos/ui/components/captioned_text_widget.dart';
@ -95,14 +96,14 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
children: [
Column(
children: [
const MenuSectionTitle(
title: "Owner",
MenuSectionTitle(
title: S.of(context).albumOwner,
iconData: Icons.admin_panel_settings_outlined,
),
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: isOwner
? "You"
? S.of(context).you
: widget.collection.owner?.email ?? '',
makeTextBold: isOwner,
),
@ -130,8 +131,8 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == 0 && (isOwner || collaborators.isNotEmpty)) {
return const MenuSectionTitle(
title: "Collaborator",
return MenuSectionTitle(
title: S.of(context).collaborator,
iconData: Icons.edit_outlined,
);
} else if (index > 0 && index <= collaborators.length) {
@ -146,7 +147,7 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: isSameAsLoggedInUser
? "You"
? S.of(context).you
: currentUser.email,
makeTextBold: isSameAsLoggedInUser,
),
@ -182,8 +183,8 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
return MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: collaborators.isNotEmpty
? "Add more"
: "Add collaborator",
? S.of(context).addMore
: S.of(context).addCollaborator,
makeTextBold: true,
),
leadingIcon: Icons.add_outlined,
@ -207,8 +208,8 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == 0 && (isOwner || viewers.isNotEmpty)) {
return const MenuSectionTitle(
title: "Viewer",
return MenuSectionTitle(
title: S.of(context).viewer,
iconData: Icons.photo_outlined,
);
} else if (index > 0 && index <= viewers.length) {
@ -222,7 +223,7 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: isSameAsLoggedInUser
? "You"
? S.of(context).you
: currentUser.email,
makeTextBold: isSameAsLoggedInUser,
),
@ -257,7 +258,9 @@ class _AlbumParticipantsPageState extends State<AlbumParticipantsPage> {
} else if (index == (1 + viewers.length) && isOwner) {
return MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: viewers.isNotEmpty ? "Add more" : "Add viewer",
title: viewers.isNotEmpty
? S.of(context).addMore
: S.of(context).addViewer,
makeTextBold: true,
),
leadingIcon: Icons.add_outlined,

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/collection.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/theme/colors.dart';
@ -52,8 +53,8 @@ class _ManageIndividualParticipantState
const SizedBox(
height: 12,
),
const TitleBarTitleWidget(
title: "Manage",
TitleBarTitleWidget(
title: S.of(context).manage,
),
Text(
widget.user.email.toString().trim(),
@ -65,10 +66,10 @@ class _ManageIndividualParticipantState
),
),
const SizedBox(height: 12),
const MenuSectionTitle(title: "Added as"),
MenuSectionTitle(title: S.of(context).addedAs),
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Collaborator",
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).collaborator,
),
leadingIcon: Icons.edit_outlined,
menuItemColor: getEnteColorScheme(context).fillFaint,
@ -97,8 +98,8 @@ class _ManageIndividualParticipantState
bgColor: getEnteColorScheme(context).fillFaint,
),
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Viewer",
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).viewer,
),
leadingIcon: Icons.photo_outlined,
leadingIconColor: getEnteColorScheme(context).strokeBase,
@ -110,10 +111,12 @@ class _ManageIndividualParticipantState
: () async {
final actionResult = await showChoiceActionSheet(
context,
title: "Change permissions?",
firstButtonLabel: "Yes, convert to viewer",
body:
'${widget.user.email} will not be able to add more photos to this album\n\nThey will still be able to remove existing photos added by them',
title: S.of(context).changePermissions,
firstButtonLabel: S.of(context).yesConvertToViewer,
body: S
.of(context)
.cannotAddMorePhotosAfterBecomingViewer(
widget.user.email),
isCritical: true,
);
if (actionResult?.action != null) {
@ -141,15 +144,16 @@ class _ManageIndividualParticipantState
},
isTopBorderRadiusRemoved: true,
),
const MenuSectionDescriptionWidget(
content:
"Collaborators can add photos and videos to the shared album.",
MenuSectionDescriptionWidget(
content: S
.of(context)
.collaboratorsCanAddPhotosAndVideosToTheSharedAlbum,
),
const SizedBox(height: 24),
const MenuSectionTitle(title: "Remove participant"),
MenuSectionTitle(title: S.of(context).removeParticipant),
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Remove",
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).remove,
textColor: warning500,
makeTextBold: true,
),