diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 413773ab5..47597b395 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1,4 +1,3 @@ - { "account": "Account", "recoveryKey": "Recovery key", @@ -14,10 +13,10 @@ "importAccountPageTitle": "Enter account details", "secretCanNotBeEmpty": "Secret can not be empty", "bothIssuerAndAccountCanNotBeEmpty": "Both issuer and account can not be empty", - "incorrectDetails" :"Incorrect details", + "incorrectDetails": "Incorrect details", "pleaseVerifyDetails": "Please verify the details and try again", "codeIssuerHint": "Issuer", - "codeSecretKeyHint" : "Secret Key", + "codeSecretKeyHint": "Secret Key", "codeAccountHint": "Account (you@domain.com)", "accountKeyType": "Type of key", "sessionExpired": "Session expired", @@ -25,7 +24,7 @@ "description": "Title of the dialog when the users current session is invalid/expired" }, "pleaseLoginAgain": "Please login again", - "loggingOut" : "Logging out...", + "loggingOut": "Logging out...", "timeBasedKeyType": "Time based (TOTP)", "counterBasedKeyType": "Counter based (HOTP)", "saveAction": "Save", @@ -67,15 +66,15 @@ "incorrectPasswordTitle": "Incorrect password", "welcomeBack": "Welcome back!", "madeWithLoveAtPrefix": "made with ❤️ at ", - "supportDevs" : "Subscribe to ente to support this project.", - "supportDiscount" : "Use coupon code \"AUTH\" to get 10% off first year", + "supportDevs": "Subscribe to ente to support this project.", + "supportDiscount": "Use coupon code \"AUTH\" to get 10% off first year", "changeEmail": "Change email", "changePassword": "Change password", - "data" : "Data", + "data": "Data", "importCodes": "Import codes", "importTypePlainText": "Plain text", "importTypeEnteEncrypted": "ente Encrypted export", - "passwordForDecryptingExport" : "Password to decrypt export", + "passwordForDecryptingExport": "Password to decrypt export", "passwordEmptyError": "Password can not be empty", "importFromApp": "Import codes from {appName}", "importGoogleAuthGuide": "Export your accounts from Google Authenticator to a QR code using the \"Transfer Accounts\" option. Then using another device, scan the QR code.", @@ -102,11 +101,22 @@ "copied": "Copied", "pleaseTryAgain": "Please try again", "existingUser": "Existing User", - "newUser" : "New to ente", + "newUser": "New to ente", "delete": "Delete", "enterYourPasswordHint": "Enter your password", "forgotPassword": "Forgot password", "oops": "Oops", + "faq": "FAQ", + "faq_q_1": "How secure is ente Auth?", + "faq_a_1": "All codes you backup via ente is stored end-to-end encrypted. This means only you can access your codes. Our apps are open source and our cryptography has been externally audited.", + "faq_q_2": "Can I access my codes on desktop?", + "faq_a_2": "You can access your codes on the web @ auth.ente.io.", + "faq_q_3": "How can I delete codes?", + "faq_a_3": "You can delete a code by swiping left on that item.", + "faq_q_4": "How can I support this project?", + "faq_a_4": "You can support the development of this project by subscribing to our Photos app @ ente.io.", + "faq_q_5": "How can I enable FaceID lock in ente Auth", + "faq_a_5": "You can enable FaceID lock under Settings → Security → Lockscreen.", "somethingWentWrongMessage": "Something went wrong, please try again", "leaveFamily": "Leave family", "leaveFamilyMessage": "Are you sure that you want to leave the family plan?", @@ -122,7 +132,7 @@ "recoverAccount": "Recover account", "enterRecoveryKeyHint": "Enter your recovery key", "recover": "Recover", - "contactSupportViaEmailMessage":"Please drop an email to {email} from your registered email address", + "contactSupportViaEmailMessage": "Please drop an email to {email} from your registered email address", "@contactSupportViaEmailMessage": { "placeholders": { "email": { @@ -187,7 +197,7 @@ "message": "Password Strength: {passwordStrengthText}" }, "password": "Password", - "signUpTerms" : "I agree to the terms of service and privacy policy", + "signUpTerms": "I agree to the terms of service and privacy policy", "privacyPolicyTitle": "Privacy Policy", "termsOfServicesTitle": "Terms", "encryption": "Encryption", @@ -240,14 +250,14 @@ "youAreOnTheLatestVersion": "You are on the latest version", "warning": "Warning", "exportWarningDesc": "The exported file contains sensitive information. Please store this safely.", - "iUnderStand" : "I understand", + "iUnderStand": "I understand", "@iUnderStand": { "description": "Text for the button to confirm the user understands the warning" }, "authToExportCodes": "Please authenticate to export your codes", "importSuccessTitle": "Yay!", "importSuccessDesc": "You have imported {count} codes!", - "@importSuccessDesc" : { + "@importSuccessDesc": { "placeholders": { "count": { "description": "The number of codes imported", @@ -256,9 +266,9 @@ } } }, - "sorry" : "Sorry", + "sorry": "Sorry", "importFailureDesc": "Could not parse the selected file.\nPlease write to support@ente.io if you need help!", - "pendingSyncs" : "Warning", + "pendingSyncs": "Warning", "pendingSyncsWarningBody": "Some of your codes have not been backed up.\n\nPlease ensure that you have a backup for these codes before you logout.", "checkInboxAndSpamFolder": "Please check your inbox (and spam) to complete verification", "tapToEnterCode": "Tap to enter code", diff --git a/lib/ui/settings/faq.dart b/lib/ui/settings/faq.dart new file mode 100644 index 000000000..7d7538622 --- /dev/null +++ b/lib/ui/settings/faq.dart @@ -0,0 +1,125 @@ +import 'dart:convert'; + +import 'package:ente_auth/core/network.dart'; +import 'package:ente_auth/ente_theme_data.dart'; +import 'package:ente_auth/l10n/l10n.dart'; +import 'package:ente_auth/ui/common/loading_widget.dart'; +import 'package:expansion_tile_card/expansion_tile_card.dart'; +import 'package:flutter/material.dart'; + +class FAQQuestionsWidget extends StatelessWidget { + const FAQQuestionsWidget({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return FutureBuilder>( + future: Future.value(_getFAQs(context)), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + final faqs = []; + faqs.add( + Padding( + padding: const EdgeInsets.all(24), + child: Text( + context.l10n.faq, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + for (final faq in snapshot.data) { + faqs.add(FaqWidget(faq: faq)); + } + faqs.add( + const Padding( + padding: EdgeInsets.all(16), + ), + ); + return SingleChildScrollView( + child: Column( + children: faqs, + ), + ); + } else { + return const EnteLoadingWidget(); + } + }, + ); + } + + List _getFAQs(BuildContext context) { + final l01n = context.l10n; + List faqs = []; + faqs.add(FaqItem(q: l01n.faq_q_1, a: l01n.faq_a_1)); + faqs.add(FaqItem(q: l01n.faq_q_2, a: l01n.faq_a_2)); + faqs.add(FaqItem(q: l01n.faq_q_3, a: l01n.faq_a_3)); + faqs.add(FaqItem(q: l01n.faq_q_4, a: l01n.faq_a_4)); + faqs.add(FaqItem(q: l01n.faq_q_5, a: l01n.faq_a_5)); + return faqs; + } +} + +class FaqWidget extends StatelessWidget { + const FaqWidget({ + Key? key, + required this.faq, + }) : super(key: key); + + final FaqItem? faq; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(2), + child: ExpansionTileCard( + elevation: 0, + title: Text(faq!.q), + expandedTextColor: Theme.of(context).colorScheme.alternativeColor, + baseColor: Theme.of(context).cardColor, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 12, + ), + child: Text( + faq!.a, + style: const TextStyle( + height: 1.5, + ), + ), + ), + ) + ], + ), + ); + } +} + +class FaqItem { + final String q; + final String a; + + FaqItem({ + required this.q, + required this.a, + }); + + factory FaqItem.fromMap(Map map) { + return FaqItem( + q: map['q'] ?? 'q', + a: map['a'] ?? 'a', + ); + } + + factory FaqItem.fromJson(String source) => + FaqItem.fromMap(json.decode(source)); + +} diff --git a/lib/ui/settings/support_section_widget.dart b/lib/ui/settings/support_section_widget.dart index 8695e0664..b06b28b05 100644 --- a/lib/ui/settings/support_section_widget.dart +++ b/lib/ui/settings/support_section_widget.dart @@ -7,6 +7,7 @@ import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart'; import 'package:ente_auth/ui/components/menu_item_widget.dart'; import 'package:ente_auth/ui/components/toggle_switch_widget.dart'; import 'package:ente_auth/ui/settings/common_settings.dart'; +import 'package:ente_auth/ui/settings/faq.dart'; import 'package:ente_auth/utils/email_util.dart'; import 'package:flutter/material.dart'; @@ -33,6 +34,27 @@ class _SupportSectionWidgetState extends State { return Column( children: [ sectionOptionSpacing, + + MenuItemWidget( + captionedTextWidget: CaptionedTextWidget( + title: l10n.faq, + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + showModalBottomSheet( + backgroundColor: Theme.of(context).colorScheme.background, + barrierColor: Colors.black87, + context: context, + builder: (context) { + return const FAQQuestionsWidget(); + }, + ); + }, + ), + sectionOptionSpacing, + MenuItemWidget( captionedTextWidget: CaptionedTextWidget( title: l10n.email,