account_section_widget.dart 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // @dart=2.9
  2. import 'dart:async';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_sodium/flutter_sodium.dart';
  5. import 'package:photos/ente_theme_data.dart';
  6. import 'package:photos/services/local_authentication_service.dart';
  7. import 'package:photos/services/user_service.dart';
  8. import 'package:photos/theme/ente_theme.dart';
  9. import 'package:photos/ui/account/change_email_dialog.dart';
  10. import 'package:photos/ui/account/delete_account_page.dart';
  11. import 'package:photos/ui/account/password_entry_page.dart';
  12. import 'package:photos/ui/account/recovery_key_page.dart';
  13. import 'package:photos/ui/components/captioned_text_widget.dart';
  14. import 'package:photos/ui/components/dialog_widget.dart';
  15. import 'package:photos/ui/components/expandable_menu_item_widget.dart';
  16. import 'package:photos/ui/components/menu_item_widget.dart';
  17. import 'package:photos/ui/settings/common_settings.dart';
  18. import 'package:photos/utils/navigation_util.dart';
  19. class AccountSectionWidget extends StatelessWidget {
  20. const AccountSectionWidget({Key key}) : super(key: key);
  21. @override
  22. Widget build(BuildContext context) {
  23. return ExpandableMenuItemWidget(
  24. title: "Account",
  25. selectionOptionsWidget: _getSectionOptions(context),
  26. leadingIcon: Icons.account_circle_outlined,
  27. );
  28. }
  29. Column _getSectionOptions(BuildContext context) {
  30. return Column(
  31. children: [
  32. sectionOptionSpacing,
  33. MenuItemWidget(
  34. captionedTextWidget: const CaptionedTextWidget(
  35. title: "Recovery key",
  36. ),
  37. pressedColor: getEnteColorScheme(context).fillFaint,
  38. trailingIcon: Icons.chevron_right_outlined,
  39. trailingIconIsMuted: true,
  40. onTap: () async {
  41. final hasAuthenticated = await LocalAuthenticationService.instance
  42. .requestLocalAuthentication(
  43. context,
  44. "Please authenticate to view your recovery key",
  45. );
  46. if (hasAuthenticated) {
  47. String recoveryKey;
  48. try {
  49. recoveryKey = await _getOrCreateRecoveryKey(context);
  50. } catch (e) {
  51. await showGenericErrorDialog(context: context);
  52. return;
  53. }
  54. unawaited(
  55. routeToPage(
  56. context,
  57. RecoveryKeyPage(
  58. recoveryKey,
  59. "OK",
  60. showAppBar: true,
  61. onDone: () {},
  62. ),
  63. ),
  64. );
  65. }
  66. },
  67. ),
  68. sectionOptionSpacing,
  69. MenuItemWidget(
  70. captionedTextWidget: const CaptionedTextWidget(
  71. title: "Change email",
  72. ),
  73. pressedColor: getEnteColorScheme(context).fillFaint,
  74. trailingIcon: Icons.chevron_right_outlined,
  75. trailingIconIsMuted: true,
  76. onTap: () async {
  77. final hasAuthenticated = await LocalAuthenticationService.instance
  78. .requestLocalAuthentication(
  79. context,
  80. "Please authenticate to change your email",
  81. );
  82. if (hasAuthenticated) {
  83. showDialog(
  84. context: context,
  85. builder: (BuildContext context) {
  86. return const ChangeEmailDialog();
  87. },
  88. barrierColor: Colors.black.withOpacity(0.85),
  89. barrierDismissible: false,
  90. );
  91. }
  92. },
  93. ),
  94. sectionOptionSpacing,
  95. MenuItemWidget(
  96. captionedTextWidget: const CaptionedTextWidget(
  97. title: "Change password",
  98. ),
  99. pressedColor: getEnteColorScheme(context).fillFaint,
  100. trailingIcon: Icons.chevron_right_outlined,
  101. trailingIconIsMuted: true,
  102. onTap: () async {
  103. final hasAuthenticated = await LocalAuthenticationService.instance
  104. .requestLocalAuthentication(
  105. context,
  106. "Please authenticate to change your password",
  107. );
  108. if (hasAuthenticated) {
  109. Navigator.of(context).push(
  110. MaterialPageRoute(
  111. builder: (BuildContext context) {
  112. return const PasswordEntryPage(
  113. mode: PasswordEntryMode.update,
  114. );
  115. },
  116. ),
  117. );
  118. }
  119. },
  120. ),
  121. sectionOptionSpacing,
  122. MenuItemWidget(
  123. captionedTextWidget: const CaptionedTextWidget(
  124. title: "Logout",
  125. ),
  126. pressedColor: getEnteColorScheme(context).fillFaint,
  127. trailingIcon: Icons.chevron_right_outlined,
  128. trailingIconIsMuted: true,
  129. onTap: () {
  130. _onLogoutTapped(context);
  131. },
  132. ),
  133. sectionOptionSpacing,
  134. MenuItemWidget(
  135. captionedTextWidget: const CaptionedTextWidget(
  136. title: "Delete account",
  137. ),
  138. pressedColor: getEnteColorScheme(context).fillFaint,
  139. trailingIcon: Icons.chevron_right_outlined,
  140. trailingIconIsMuted: true,
  141. onTap: () {
  142. routeToPage(context, const DeleteAccountPage());
  143. },
  144. ),
  145. sectionOptionSpacing,
  146. ],
  147. );
  148. }
  149. Future<String> _getOrCreateRecoveryKey(BuildContext context) async {
  150. return Sodium.bin2hex(
  151. await UserService.instance.getOrCreateRecoveryKey(context),
  152. );
  153. }
  154. Future<void> _onLogoutTapped(BuildContext context) async {
  155. final AlertDialog alert = AlertDialog(
  156. title: const Text(
  157. "Logout",
  158. style: TextStyle(
  159. color: Colors.red,
  160. ),
  161. ),
  162. content: const Text("Are you sure you want to logout?"),
  163. actions: [
  164. TextButton(
  165. child: const Text(
  166. "Yes, logout",
  167. style: TextStyle(
  168. color: Colors.red,
  169. ),
  170. ),
  171. onPressed: () async {
  172. Navigator.of(context, rootNavigator: true).pop('dialog');
  173. await UserService.instance.logout(context);
  174. },
  175. ),
  176. TextButton(
  177. child: Text(
  178. "No",
  179. style: TextStyle(
  180. color: Theme.of(context).colorScheme.greenAlternative,
  181. ),
  182. ),
  183. onPressed: () {
  184. Navigator.of(context, rootNavigator: true).pop('dialog');
  185. },
  186. ),
  187. ],
  188. );
  189. await showDialog(
  190. context: context,
  191. builder: (BuildContext context) {
  192. return alert;
  193. },
  194. );
  195. }
  196. }