1- import 'package:bip32_keys/bip32_keys.dart' ;
2- import 'package:bip39_mnemonic/bip39_mnemonic.dart' ;
3- import 'package:convert/convert.dart' ;
41import 'package:flutter/material.dart' ;
52import 'package:flutter/services.dart' ;
3+ import 'package:flutter_bloc/flutter_bloc.dart' ;
4+ import 'package:subterfuge/features/show_secret/cubit.dart' ;
5+ import 'package:subterfuge/features/show_secret/state.dart' ;
66
7- enum ScriptType {
8- legacy (title: 'Legacy (BIP44)' ),
9- nestedSegwit (title: 'Nested Segwit (BIP49)' ),
10- segwit (title: 'Segwit (BIP84)' );
7+ class ShowSecretPage extends StatelessWidget {
8+ final Uint8List secret;
9+ const ShowSecretPage ({super .key, required this .secret});
1110
12- final String title;
13- const ScriptType ({required this .title});
11+ @override
12+ Widget build (BuildContext context) {
13+ return BlocProvider (
14+ create: (context) => ShowSecretCubit (secret: secret),
15+ child: const _ShowSecretView (),
16+ );
17+ }
1418}
1519
16- class ShowSecretPage extends StatefulWidget {
17- final Uint8List secret;
18- const ShowSecretPage ({super .key, required this .secret});
20+ class _ShowSecretView extends StatefulWidget {
21+ const _ShowSecretView ();
1922
2023 @override
21- State <ShowSecretPage > createState () => _ShowSecretPageState ();
24+ State <_ShowSecretView > createState () => _ShowSecretViewState ();
2225}
2326
24- class _ShowSecretPageState extends State <ShowSecretPage > {
25- bool isMnemonic = false ;
26- ScriptType _selectedScriptType = ScriptType .segwit;
27+ class _ShowSecretViewState extends State <_ShowSecretView > {
2728 final TextEditingController _accountController = TextEditingController (
2829 text: '0' ,
2930 );
@@ -36,112 +37,104 @@ class _ShowSecretPageState extends State<ShowSecretPage> {
3637
3738 @override
3839 Widget build (BuildContext context) {
39- String ? extendedPublicKey;
40- if (isMnemonic) {
41- try {
42- final mnemonic = Mnemonic (widget.secret, Language .english);
43- final seed = Uint8List .fromList (mnemonic.seed);
44- final masterNode = Bip32MasterNode .fromSeed (seed);
45- final int account = int .tryParse (_accountController.text) ?? 0 ;
46- final safeAccount = account < 0 ? 0 : account;
47-
48- final Bip32Accounts wallet;
49- switch (_selectedScriptType) {
50- case ScriptType .legacy:
51- wallet = masterNode.toBip44Legacy (account: safeAccount);
52- break ;
53- case ScriptType .nestedSegwit:
54- wallet = masterNode.toBip49NestedSegwit (account: safeAccount);
55- break ;
56- case ScriptType .segwit:
57- wallet = masterNode.toBip84SegwitWallet (account: safeAccount);
58- break ;
59- }
60- extendedPublicKey = wallet.extendedPublicKey;
61- } catch (_) {
62- // Handle derivation errors if any
63- }
64- }
40+ return BlocBuilder <ShowSecretCubit , ShowSecretState >(
41+ builder: (context, state) {
42+ final cubit = context.read <ShowSecretCubit >();
6543
66- return Scaffold (
67- appBar: AppBar (title: const Text ('Secret' )),
68- body: Center (
69- child: SingleChildScrollView (
70- padding: const EdgeInsets .all (24.0 ),
71- child: Column (
72- mainAxisSize: MainAxisSize .min,
73- crossAxisAlignment: CrossAxisAlignment .center,
74- children: [
75- Icon (
76- Icons .lock_open_rounded,
77- size: 64 ,
78- color: Theme .of (context).colorScheme.primary,
79- ),
80- const SizedBox (height: 24 ),
81- _SecretCard (
82- title: 'Your Secret' ,
83- icon: Icons .key_rounded,
84- content: hex.encode (widget.secret),
85- ),
86- const SizedBox (height: 16 ),
87- SwitchListTile (
88- title: const Text ('The secret is a Mnemonic' ),
89- value: isMnemonic,
90- onChanged: (value) => setState (() => isMnemonic = value),
91- ),
92- if (isMnemonic) ...[
93- const SizedBox (height: 16 ),
94- DropdownButtonFormField <ScriptType >(
95- initialValue: _selectedScriptType,
96- decoration: const InputDecoration (
97- labelText: 'Script Type' ,
98- border: OutlineInputBorder (),
44+ return Scaffold (
45+ appBar: AppBar (title: const Text ('Secret' )),
46+ body: Center (
47+ child: SingleChildScrollView (
48+ padding: const EdgeInsets .all (24.0 ),
49+ child: Column (
50+ mainAxisSize: MainAxisSize .min,
51+ crossAxisAlignment: CrossAxisAlignment .center,
52+ children: [
53+ Icon (
54+ Icons .lock_open_rounded,
55+ size: 64 ,
56+ color: Theme .of (context).colorScheme.primary,
9957 ),
100- items: ScriptType .values.map ((type) {
101- return DropdownMenuItem (
102- value: type,
103- child: Text (type.title),
104- );
105- }).toList (),
106- onChanged: (value) {
107- if (value != null ) {
108- setState (() => _selectedScriptType = value);
109- }
110- },
111- ),
112- const SizedBox (height: 16 ),
113- TextFormField (
114- controller: _accountController,
115- decoration: const InputDecoration (
116- labelText: 'Account' ,
117- border: OutlineInputBorder (),
118- helperText: 'Account index (default: 0)' ,
58+ const SizedBox (height: 24 ),
59+ _SecretCard (
60+ title: state.isEntropy ? 'Mnemonic' : 'Seed' ,
61+ icon: state.isEntropy
62+ ? Icons .article_rounded
63+ : Icons .key_rounded,
64+ content: state.displaySecret,
65+ ),
66+ const SizedBox (height: 8 ),
67+ Text (
68+ state.secretType.title,
69+ style: Theme .of (context).textTheme.bodySmall? .copyWith (
70+ color: Theme .of (context).colorScheme.secondary,
71+ ),
72+ ),
73+ const SizedBox (height: 24 ),
74+ DropdownButtonFormField <ScriptType >(
75+ initialValue: state.scriptType,
76+ decoration: const InputDecoration (
77+ labelText: 'Script Type' ,
78+ border: OutlineInputBorder (),
79+ ),
80+ items: ScriptType .values.map ((type) {
81+ return DropdownMenuItem (
82+ value: type,
83+ child: Text (type.title),
84+ );
85+ }).toList (),
86+ onChanged: (value) {
87+ if (value != null ) {
88+ cubit.setScriptType (value);
89+ }
90+ },
11991 ),
120- keyboardType: TextInputType .number,
121- inputFormatters: [FilteringTextInputFormatter .digitsOnly],
122- onChanged: (_) => setState (() {}),
123- ),
124- if (extendedPublicKey != null ) ...[
12592 const SizedBox (height: 16 ),
126- _SecretCard (
127- title: 'Extended Public Key' ,
128- icon: Icons .public_rounded,
129- content: extendedPublicKey,
93+ TextFormField (
94+ controller: _accountController,
95+ decoration: const InputDecoration (
96+ labelText: 'Account' ,
97+ border: OutlineInputBorder (),
98+ helperText: 'Account index (default: 0)' ,
99+ ),
100+ keyboardType: TextInputType .number,
101+ inputFormatters: [FilteringTextInputFormatter .digitsOnly],
102+ onChanged: (value) {
103+ final account = int .tryParse (value) ?? 0 ;
104+ cubit.setAccount (account);
105+ },
106+ ),
107+ if (state.extendedPublicKey != null ) ...[
108+ const SizedBox (height: 16 ),
109+ _SecretCard (
110+ title: 'Extended Public Key' ,
111+ icon: Icons .public_rounded,
112+ content: state.extendedPublicKey! ,
113+ ),
114+ ],
115+ if (state.error != null ) ...[
116+ const SizedBox (height: 16 ),
117+ Text (
118+ state.error! ,
119+ style: TextStyle (
120+ color: Theme .of (context).colorScheme.error,
121+ ),
122+ ),
123+ ],
124+ const SizedBox (height: 24 ),
125+ FilledButton .icon (
126+ onPressed: () {
127+ Navigator .of (context).popUntil ((route) => route.isFirst);
128+ },
129+ icon: const Icon (Icons .check_circle_rounded),
130+ label: const Text ('Done' ),
130131 ),
131132 ],
132- ],
133- const SizedBox (height: 24 ),
134- FilledButton .icon (
135- onPressed: () {
136- Navigator .of (context).popUntil ((route) => route.isFirst);
137- },
138- icon: const Icon (Icons .check_circle_rounded),
139- label: const Text ('Done' ),
140133 ),
141- ] ,
134+ ) ,
142135 ),
143- ),
144- ) ,
136+ );
137+ } ,
145138 );
146139 }
147140}
0 commit comments