import 'package:dart_nostr/dart_nostr.dart'; import 'package:drifter/models/keys.dart'; import 'package:drifter/pages/profile_screen/widgets/delete_keys_dialog.dart'; import 'package:drifter/pages/profile_screen/widgets/key_exist_dialog.dart'; import 'package:drifter/pages/profile_screen/widgets/user_info_widget.dart'; import 'package:drifter/pages/widgets/flust_bar_type.dart'; import 'package:drifter/pages/widgets/show_flush_bar.dart'; import 'package:drifter/theme/app_colors.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); @override State createState() => ProfileScreenState(); } class ProfileScreenState extends State { final _secureStorage = const FlutterSecureStorage(); TextEditingController privateKeyInput = TextEditingController(); TextEditingController publicKeyInput = TextEditingController(); // final keyGenerator = KeyApi(); // final nip19 = Nip19(); @override void initState() { _getKeysFromStorage(); super.initState(); } Future generateNewKeys() async { final newPrivateKey = await Nostr.instance.keysService.generatePrivateKey(); // final newPrivateKey = keyGenerator.generatePrivateKey(); final nsec = Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey); final nsecDecoded = Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec); // assert(nsecDecoded['type'] == 'nsec'); // assert(nsecDecoded['data'] == newPrivateKey); final newPublicKey = await Nostr.instance.keysService .derivePublicKey(privateKey: newPrivateKey); // final newPublicKey = keyGenerator.getPublicKey(newPrivateKey); final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey); final npubDecoded = Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub); // assert(npubDecoded['type'] == 'npub'); // assert(npubDecoded['data'] == newPublicKey); return await _addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub); } Future _getKeysFromStorage() async { // Reading values associated with the " privateKey " and " publicKey " keys from a secure repository final storedPrivateKey = await _secureStorage.read(key: 'privateKey'); final storedPublicKey = await _secureStorage.read(key: 'publicKey'); final storedNsecKey = await _secureStorage.read(key: 'nsec'); final storedNpubKey = await _secureStorage.read(key: 'npub'); // Indicates that both private and public keys are stored in a secure repository, after which, the state variables are updated if (storedPrivateKey != null && storedPublicKey != null && storedNsecKey != null && storedNpubKey != null) { setState(() { Keys.privateKey = storedPrivateKey; Keys.publicKey = storedPublicKey; Keys.nsecKey = storedNsecKey; Keys.npubKey = storedNpubKey; Keys.keysExist = true; }); } } // Adding a new key // Writing a private and public key to a secure vault Future _addKeyToStorage( String privateKeyHex, String publicKeyHex, String nsecKey, String npubKey, ) async { // Waiting for both write operations to complete Future.wait([ _secureStorage.write(key: 'privateKey', value: privateKeyHex), _secureStorage.write(key: 'publicKey', value: privateKeyHex), _secureStorage.write(key: 'nsec', value: nsecKey), _secureStorage.write(key: 'npub', value: npubKey), ]); // Updating status variables and starting widget rebuilding setState(() { Keys.privateKey = privateKeyHex; Keys.publicKey = publicKeyHex; Keys.nsecKey = nsecKey; Keys.npubKey = npubKey; Keys.keysExist = true; }); // Returns a boolean value indicating whether the keys were successfully added to the repository or not. return Keys.keysExist; } Future _deleteKeysStorage() async { // Calling secure storage to remove keys from storage Future.wait([ _secureStorage.delete(key: 'privateKey'), _secureStorage.delete(key: 'publicKey'), _secureStorage.delete(key: 'nsec'), _secureStorage.delete(key: 'npub'), ]); // Updating status variables, resetting values after deleting keys from the repository setState(() { Keys.privateKey = ''; Keys.publicKey = ''; Keys.nsecKey = ''; Keys.npubKey = ''; Keys.keysExist = false; }); } void _keysExistDialog(String npubEncode, String nsecEncode) async { await showDialog( context: context, builder: ((context) { return KeysExistDialog( npubEncoded: npubEncode, nsecEncoded: nsecEncode, hexPriv: Keys.privateKey, hexPub: Keys.publicKey, ); }), ); } @override Widget build(BuildContext context) { privateKeyInput.text = Keys.nsecKey; publicKeyInput.text = Keys.npubKey; return Padding( padding: const EdgeInsets.all(15.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox( height: 60, ), UserInfo(), const SizedBox( height: 40, ), Row( children: [ Text( "Public Key", textAlign: TextAlign.start, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.grey[700], ), ), ], ), const SizedBox(height: 12), publicKeyInput.text.isNotEmpty ? SelectableText( publicKeyInput.text, style: TextStyle( fontSize: 16, color: Colors.grey[800], ), ) : Text( "Public Key empty", textAlign: TextAlign.left, ), const SizedBox( height: 12, ), Row( children: [ Text( "Private Key", textAlign: TextAlign.left, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.grey[700], ), ), ], ), const SizedBox(height: 12), privateKeyInput.text.isNotEmpty ? SelectableText( privateKeyInput.text, style: TextStyle( fontSize: 16, color: Colors.grey[800], ), ) : Text( "Private Key empty", textAlign: TextAlign.left, ), const SizedBox( height: 20, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Keys.keysExist ? Row( children: [ ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.grey[500]), ), onPressed: () { showDialog( context: context, builder: (context) => DeleteKeysDialog( onNoPressed: () { Navigator.pop(context); }, onYesPressed: () { final currentContext = context; _deleteKeysStorage().then( (_) { if (!Keys.keysExist) { showFloatingFlushBar( type: FlushBarType.warning, message: "Keys deleted!", context: context, ); } }, ); Navigator.pop(context); }, ), ); }, child: Text( "Delete", ), ), ], ) : Container(), Keys.keysExist ? ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(AppColors.background), ), onPressed: () { _keysExistDialog( Nostr.instance.keysService .encodePublicKeyToNpub(Keys.publicKey), Nostr.instance.keysService .encodePrivateKeyToNsec(Keys.privateKey), ); }, child: Text( "Keys", ), ) : ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(AppColors.background), ), onPressed: () { final currentContext = context; generateNewKeys().then( (keysGenerated) async { if (keysGenerated) { await Future.delayed( const Duration(milliseconds: 300)); showFloatingFlushBar( type: FlushBarType.success, message: "Keys generated!", context: context, ); } }, ); }, child: const Text( "Generate Keys", ), ), ], ), ], ), ); } }