| 1 | import 'package:cake_wallet/generated/i18n.dart'; |
| 2 | import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; |
| 3 | import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; |
| 4 | import 'package:cake_wallet/src/widgets/primary_button.dart'; |
| 5 | import 'package:cake_wallet/themes/core/theme_extension.dart'; |
| 6 | import 'package:flutter/material.dart'; |
| 7 | |
| 8 | class AddPassphraseBottomSheet extends StatefulWidget { |
| 9 | AddPassphraseBottomSheet({ |
| 10 | required String titleText, |
| 11 | required this.onRestoreButtonPressed, |
| 12 | }); |
| 13 | |
| 14 | final void Function(String) onRestoreButtonPressed; |
| 15 | |
| 16 | @override |
| 17 | State<AddPassphraseBottomSheet> createState() => _AddPassphraseBottomSheetState(); |
| 18 | } |
| 19 | |
| 20 | class _AddPassphraseBottomSheetState extends State<AddPassphraseBottomSheet> { |
| 21 | late final TextEditingController passphraseController; |
| 22 | late final TextEditingController confirmPassphraseController; |
| 23 | final _passphraseFormKey = GlobalKey<FormState>(); |
| 24 | |
| 25 | @override |
| 26 | void initState() { |
| 27 | super.initState(); |
| 28 | passphraseController = TextEditingController(); |
| 29 | confirmPassphraseController = TextEditingController(); |
| 30 | } |
| 31 | |
| 32 | @override |
| 33 | void dispose() { |
| 34 | passphraseController.dispose(); |
| 35 | confirmPassphraseController.dispose(); |
| 36 | super.dispose(); |
| 37 | } |
| 38 | |
| 39 | final passphraseImageLight = 'assets/images/passphrase_light.png'; |
| 40 | final passphraseImageDark = 'assets/images/passphrase_dark.png'; |
| 41 | |
| 42 | bool obscurePassphrase = true; |
| 43 | @override |
| 44 | Widget build(BuildContext context) { |
| 45 | final passphraseImage = |
| 46 | context.currentTheme.isDark ? passphraseImageDark : passphraseImageLight; |
| 47 | |
| 48 | return Container( |
| 49 | decoration: BoxDecoration( |
| 50 | borderRadius: const BorderRadius.vertical(top: Radius.circular(30.0)), |
| 51 | color: Theme.of(context).colorScheme.surface, |
| 52 | ), |
| 53 | child: SingleChildScrollView( |
| 54 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), |
| 55 | child: Column( |
| 56 | children: [ |
| 57 | Row( |
| 58 | children: [ |
| 59 | const Spacer(flex: 4), |
| 60 | Expanded( |
| 61 | flex: 2, |
| 62 | child: Container( |
| 63 | height: 6, |
| 64 | decoration: BoxDecoration( |
| 65 | borderRadius: BorderRadius.circular(4), |
| 66 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), |
| 67 | ), |
| 68 | ), |
| 69 | ), |
| 70 | const Spacer(flex: 4), |
| 71 | ], |
| 72 | ), |
| 73 | SizedBox(height: 16), |
| 74 | Text( |
| 75 | S.of(context).add_passphrase, |
| 76 | textAlign: TextAlign.center, |
| 77 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( |
| 78 | fontSize: 18, |
| 79 | fontWeight: FontWeight.w600, |
| 80 | color: Theme.of(context).colorScheme.onSurface, |
| 81 | decoration: TextDecoration.none, |
| 82 | ), |
| 83 | ), |
| 84 | SizedBox(height: 20), |
| 85 | CakeImageWidget(imageUrl: passphraseImage, height: 85), |
| 86 | SizedBox(height: 20), |
| 87 | Padding( |
| 88 | padding: const EdgeInsets.symmetric(horizontal: 16), |
| 89 | child: Text.rich( |
| 90 | TextSpan( |
| 91 | children: [ |
| 92 | TextSpan( |
| 93 | text: '${S.of(context).warning.toUpperCase()}: ', |
| 94 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( |
| 95 | fontSize: 16, |
| 96 | fontWeight: FontWeight.w700, |
| 97 | color: Theme.of(context).colorScheme.errorContainer, |
| 98 | decoration: TextDecoration.none, |
| 99 | ), |
| 100 | ), |
| 101 | TextSpan( |
| 102 | text: S.of(context).add_passphrase_warning_text, |
| 103 | ), |
| 104 | ], |
| 105 | ), |
| 106 | textAlign: TextAlign.center, |
| 107 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( |
| 108 | fontSize: 16, |
| 109 | fontWeight: FontWeight.w500, |
| 110 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), |
| 111 | decoration: TextDecoration.none, |
| 112 | ), |
| 113 | ), |
| 114 | ), |
| 115 | SizedBox(height: 24), |
| 116 | Form( |
| 117 | key: _passphraseFormKey, |
| 118 | child: Column( |
| 119 | children: [ |
| 120 | BaseTextFormField( |
| 121 | key: ValueKey('add_passphrase_bottom_sheet_widget_passphrase_textfield_key'), |
| 122 | controller: passphraseController, |
| 123 | obscureText: obscurePassphrase, |
| 124 | contentPadding: EdgeInsets.symmetric(horizontal: 12), |
| 125 | hintText: S.of(context).required_passphrase, |
| 126 | suffixIcon: GestureDetector( |
| 127 | onTap: () { |
| 128 | setState(() { |
| 129 | obscurePassphrase = !obscurePassphrase; |
| 130 | }); |
| 131 | }, |
| 132 | child: Icon( |
| 133 | obscurePassphrase ? Icons.visibility_off : Icons.visibility, |
| 134 | size: 24, |
| 135 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), |
| 136 | ), |
| 137 | ), |
| 138 | ), |
| 139 | SizedBox(height: 8), |
| 140 | BaseTextFormField( |
| 141 | key: ValueKey( |
| 142 | 'add_passphrase_bottom_sheet_widget_confirm_passphrase_textfield_key', |
| 143 | ), |
| 144 | controller: confirmPassphraseController, |
| 145 | obscureText: obscurePassphrase, |
| 146 | contentPadding: EdgeInsets.symmetric(horizontal: 12), |
| 147 | hintText: S.of(context).confirm_passphrase, |
| 148 | suffixIcon: GestureDetector( |
| 149 | onTap: () { |
| 150 | setState(() { |
| 151 | obscurePassphrase = !obscurePassphrase; |
| 152 | }); |
| 153 | }, |
| 154 | child: Icon( |
| 155 | obscurePassphrase ? Icons.visibility_off : Icons.visibility, |
| 156 | size: 24, |
| 157 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), |
| 158 | ), |
| 159 | ), |
| 160 | validator: (text) { |
| 161 | if (text == passphraseController.text) { |
| 162 | return null; |
| 163 | } |
| 164 | |
| 165 | return S.of(context).passphrases_doesnt_match; |
| 166 | }, |
| 167 | ), |
| 168 | ], |
| 169 | ), |
| 170 | ), |
| 171 | SizedBox(height: 16), |
| 172 | Padding( |
| 173 | padding: const EdgeInsets.symmetric(horizontal: 16), |
| 174 | child: Row( |
| 175 | mainAxisSize: MainAxisSize.max, |
| 176 | children: [ |
| 177 | Flexible( |
| 178 | child: Container( |
| 179 | padding: const EdgeInsets.only(right: 8.0, top: 8.0), |
| 180 | child: PrimaryButton( |
| 181 | key: ValueKey('add_passphrase_bottom_sheet_widget_cancel_button_key'), |
| 182 | onPressed: () { |
| 183 | Navigator.pop(context); |
| 184 | }, |
| 185 | text: S.of(context).cancel, |
| 186 | color: Theme.of(context).colorScheme.surfaceContainer, |
| 187 | textColor: Theme.of(context).colorScheme.onSurface, |
| 188 | ), |
| 189 | ), |
| 190 | ), |
| 191 | Flexible( |
| 192 | child: Container( |
| 193 | padding: const EdgeInsets.only(left: 8.0, top: 8.0), |
| 194 | child: PrimaryButton( |
| 195 | key: ValueKey('add_passphrase_bottom_sheet_widget_restore_button_key'), |
| 196 | onPressed: () { |
| 197 | if (_passphraseFormKey.currentState != null && |
| 198 | !_passphraseFormKey.currentState!.validate()) { |
| 199 | return; |
| 200 | } |
| 201 | |
| 202 | Navigator.pop(context); |
| 203 | widget.onRestoreButtonPressed(passphraseController.text); |
| 204 | }, |
| 205 | text: S.of(context).restore, |
| 206 | color: Theme.of(context).colorScheme.primary, |
| 207 | textColor: Theme.of(context).colorScheme.onPrimary, |
| 208 | ), |
| 209 | ), |
| 210 | ), |
| 211 | ], |
| 212 | ), |
| 213 | ), |
| 214 | SizedBox(height: 24), |
| 215 | ], |
| 216 | ), |
| 217 | ), |
| 218 | ); |
| 219 | } |
| 220 | } |