forked from alexvasl/drifter_app
Changes to the LoginScreen, setting up the key entry.
This commit is contained in:
parent
76609f6cf1
commit
d25e5074f6
@ -1,6 +1,7 @@
|
||||
import 'package:dart_nostr/dart_nostr.dart';
|
||||
import 'package:drifter/models/keys.dart';
|
||||
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.dart';
|
||||
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
||||
|
||||
import 'package:drifter/pages/profile_screen/widgets/keys_option_modal_bottom_sheet.dart';
|
||||
import 'package:drifter/pages/profile_screen/widgets/message_snack_bar.dart';
|
||||
@ -11,30 +12,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:nostr_tools/nostr_tools.dart';
|
||||
|
||||
class LoginScreen extends StatelessWidget {
|
||||
class LoginScreen extends StatefulWidget {
|
||||
const LoginScreen({super.key});
|
||||
|
||||
final _secureStorage = const FlutterSecureStorage();
|
||||
@override
|
||||
State<LoginScreen> createState() => LoginScreenState();
|
||||
}
|
||||
|
||||
Future<bool> 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
|
||||
|
||||
// Returns a boolean value indicating whether the keys were successfully added to the repository or not.
|
||||
return Keys.keysExist;
|
||||
}
|
||||
class LoginScreenState extends State<LoginScreen> {
|
||||
final keyGenerator = KeyApi();
|
||||
final nip19 = Nip19();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -70,8 +57,9 @@ class LoginScreen extends StatelessWidget {
|
||||
bool isValidHexKey =
|
||||
Nostr.instance.keysService.isValidPrivateKey(value);
|
||||
bool isValidNSec = value.trim().startsWith('nsec') &&
|
||||
Nostr.instance.keysService.isValidPrivateKey(
|
||||
NostrClientUtils.hexEncode(value)['data']);
|
||||
Nostr.instance.keysService.isValidPrivateKey(Nostr
|
||||
.instance.keysService
|
||||
.decodeNsecKeyToPrivateKey(value));
|
||||
if (!(isValidHexKey || isValidNSec)) {
|
||||
return 'Your private key is not valid.';
|
||||
}
|
||||
@ -92,59 +80,68 @@ class LoginScreen extends StatelessWidget {
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(AppColors.background)),
|
||||
child: const Text(
|
||||
'Login',
|
||||
),
|
||||
onPressed: () {
|
||||
if (formKey.currentState!.validate()) {
|
||||
// Он получает значение закрытого ключа из _keyController текстового поля и присваивает его переменной privateKeyHex.
|
||||
String privateKeyHex = keyController.text.trim();
|
||||
String publicKeyHex;
|
||||
String nsecKey;
|
||||
String npubKey;
|
||||
|
||||
// Он проверяет, начинается ли строка privateKeyHex со строки « nsec », что указывает на то, что она может быть в формате NIP-19. Если это так, он декодирует метод privateKeyHex using _nip19.decode(privateKeyHex) для получения поля « данные », которое представляет фактический закрытый ключ в шестнадцатеричном формате.
|
||||
// if (privateKeyHex.startsWith('nsec')) {
|
||||
// nsecKey = privateKeyHex;
|
||||
// final decoded = Nostr.instance.keysService
|
||||
// .decodeNsecKeyToPrivateKey(privateKeyHex);
|
||||
// privateKeyHex = decoded;
|
||||
// publicKeyHex = Nostr.instance.keysService
|
||||
// .derivePublicKey(privateKey: 'privateKeyHex');
|
||||
// npubKey = Nostr.instance.keysService
|
||||
// .encodePublicKeyToNpub(publicKeyHex);
|
||||
// } else {
|
||||
// publicKeyHex = Nostr.instance.keysService
|
||||
// .derivePublicKey(privateKey: 'privateKeyHex');
|
||||
// nsecKey = Nostr.instance.keysService
|
||||
// .encodePrivateKeyToNsec(privateKeyHex);
|
||||
// npubKey = Nostr.instance.keysService
|
||||
// .encodePublicKeyToNpub(publicKeyHex);
|
||||
// }
|
||||
|
||||
if (privateKeyHex.startsWith('nsec')) {
|
||||
nsecKey = privateKeyHex;
|
||||
final decoded = Nostr.instance.keysService
|
||||
.decodeNsecKeyToPrivateKey(privateKeyHex);
|
||||
privateKeyHex = decoded;
|
||||
publicKeyHex = Nostr.instance.keysService
|
||||
.derivePublicKey(privateKey: 'privateKeyHex');
|
||||
npubKey = Nostr.instance.keysService
|
||||
.encodePublicKeyToNpub(publicKeyHex);
|
||||
}
|
||||
// Если privateKeyHex не начинается с « nsec », это означает, что это обычный шестнадцатеричный закрытый ключ.
|
||||
else {
|
||||
publicKeyHex = Nostr.instance.keysService
|
||||
.derivePublicKey(privateKey: 'privateKeyHex');
|
||||
nsecKey = Nostr.instance.keysService
|
||||
.encodePrivateKeyToNsec(privateKeyHex);
|
||||
npubKey = Nostr.instance.keysService
|
||||
.encodePublicKeyToNpub(publicKeyHex);
|
||||
final decoded = nip19.decode(privateKeyHex);
|
||||
privateKeyHex = decoded['data'];
|
||||
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
||||
nsecKey = nip19.nsecEncode(privateKeyHex);
|
||||
npubKey = nip19.npubEncode(publicKeyHex);
|
||||
} else {
|
||||
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
||||
nsecKey = nip19.nsecEncode(privateKeyHex);
|
||||
npubKey = nip19.npubEncode(publicKeyHex);
|
||||
}
|
||||
|
||||
// Затем он вызывает _addKeysToStorage метод для добавления закрытого ключа и открытого ключа в хранилище. Он прикрепляет then() к этому методу обратный вызов для обработки случая, когда ключи успешно добавлены в хранилище.
|
||||
addKeyToStorage(privateKeyHex, publicKeyHex, nsecKey, npubKey)
|
||||
ProfileScreenState()
|
||||
.addKeyToStorage(
|
||||
privateKeyHex, publicKeyHex, nsecKey, npubKey)
|
||||
.then((keysAdded) {
|
||||
if (keysAdded) {
|
||||
keyController.clear();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
MessageSnackBar(label: 'Congratulations! Keys Stored!'),
|
||||
);
|
||||
setState() {
|
||||
Keys.privateKey = privateKeyHex;
|
||||
Keys.publicKey = publicKeyHex;
|
||||
Keys.nsecKey = nsecKey;
|
||||
Keys.npubKey = npubKey;
|
||||
Keys.keysExist = true;
|
||||
}
|
||||
// setState() {
|
||||
// Keys.privateKey = privateKeyHex;
|
||||
// Keys.publicKey = publicKeyHex;
|
||||
// Keys.nsecKey = nsecKey;
|
||||
// Keys.npubKey = npubKey;
|
||||
// Keys.keysExist = true;
|
||||
// }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
formKey.currentState?.setState(() {});
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
'Login',
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
@ -17,7 +17,8 @@ class ProfileScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class ProfileScreenState extends State<ProfileScreen> {
|
||||
final _secureStorage = const FlutterSecureStorage();
|
||||
final secureStorage = const FlutterSecureStorage();
|
||||
bool _toHex = false;
|
||||
|
||||
TextEditingController privateKeyInput = TextEditingController();
|
||||
TextEditingController publicKeyInput = TextEditingController();
|
||||
@ -37,6 +38,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
|
||||
final nsec =
|
||||
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
||||
|
||||
// final nsecDecoded =
|
||||
// Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
||||
// assert(nsecDecoded['type'] == 'nsec');
|
||||
@ -47,6 +49,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
||||
|
||||
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
||||
|
||||
// final npubDecoded =
|
||||
// Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
||||
// assert(npubDecoded['type'] == 'npub');
|
||||
@ -57,11 +60,11 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
|
||||
Future<void> _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 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');
|
||||
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 &&
|
||||
@ -88,10 +91,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
) async {
|
||||
// Waiting for both write operations to complete
|
||||
Future.wait([
|
||||
_secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
||||
_secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
||||
_secureStorage.write(key: 'nsec', value: nsecKey),
|
||||
_secureStorage.write(key: 'npub', value: npubKey),
|
||||
secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
||||
secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
||||
secureStorage.write(key: 'nsec', value: nsecKey),
|
||||
secureStorage.write(key: 'npub', value: npubKey),
|
||||
]);
|
||||
|
||||
// Updating status variables and starting widget rebuilding
|
||||
@ -110,10 +113,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
Future<void> _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'),
|
||||
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
|
||||
@ -128,42 +131,49 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
privateKeyInput.text = Keys.nsecKey;
|
||||
publicKeyInput.text = Keys.npubKey;
|
||||
privateKeyInput.text = _toHex ? Keys.nsecKey : Keys.privateKey;
|
||||
publicKeyInput.text = _toHex ? Keys.npubKey : Keys.publicKey;
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
const SizedBox(
|
||||
height: 60,
|
||||
),
|
||||
UserInfo(),
|
||||
SizedBox(
|
||||
const UserInfo(),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
FormKeys(),
|
||||
SizedBox(height: 20),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Keys.keysExist
|
||||
? ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(AppColors.background)),
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
keysExistDialog(
|
||||
Nostr.instance.keysService
|
||||
.encodePublicKeyToNpub(Keys.publicKey),
|
||||
Nostr.instance.keysService
|
||||
.encodePrivateKeyToNsec(Keys.privateKey),
|
||||
);
|
||||
setState(() {
|
||||
_toHex = !_toHex;
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
'Keys',
|
||||
),
|
||||
)
|
||||
icon: const Icon(Icons.refresh))
|
||||
// ElevatedButton(
|
||||
// style: ButtonStyle(
|
||||
// backgroundColor:
|
||||
// MaterialStateProperty.all(AppColors.background)),
|
||||
// onPressed: () {
|
||||
// keysExistDialog(
|
||||
// Nostr.instance.keysService
|
||||
// .encodePublicKeyToNpub(Keys.publicKey),
|
||||
// Nostr.instance.keysService
|
||||
// .encodePrivateKeyToNsec(Keys.privateKey),
|
||||
// );
|
||||
// },
|
||||
// child: const Text(
|
||||
// 'Keys',
|
||||
// ),
|
||||
// )
|
||||
: ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
@ -171,7 +181,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
onPressed: () {
|
||||
modalBottomSheet();
|
||||
},
|
||||
child: Text(
|
||||
child: const Text(
|
||||
'Generate Keys',
|
||||
),
|
||||
),
|
||||
|
@ -1,87 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:drifter/theme/app_colors.dart';
|
||||
|
||||
import 'ok_button_widget.dart';
|
||||
|
||||
class DeleteKeysDialog extends StatelessWidget {
|
||||
const DeleteKeysDialog({
|
||||
super.key,
|
||||
required this.onNoPressed,
|
||||
required this.onYesPressed,
|
||||
});
|
||||
|
||||
final void Function()? onNoPressed;
|
||||
final void Function()? onYesPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Delete Keys!',
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Do you want to delete your keys?',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: onNoPressed,
|
||||
child: Text(
|
||||
'On',
|
||||
style: TextStyle(color: AppColors.mainDarkBlue),
|
||||
),
|
||||
),
|
||||
OkButton(
|
||||
onPressed: onYesPressed,
|
||||
label: 'YES',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'ok_button_widget.dart';
|
||||
|
||||
class GeneratedKeys extends StatefulWidget {
|
||||
const GeneratedKeys({
|
||||
super.key,
|
||||
required this.npubEncoded,
|
||||
required this.nsecEncoded,
|
||||
required this.hexPriv,
|
||||
required this.hexPub,
|
||||
});
|
||||
|
||||
final String npubEncoded;
|
||||
final String nsecEncoded;
|
||||
final String hexPriv;
|
||||
final String hexPub;
|
||||
|
||||
@override
|
||||
State<GeneratedKeys> createState() => _GeneratedKeysState();
|
||||
}
|
||||
|
||||
class _GeneratedKeysState extends State<GeneratedKeys> {
|
||||
bool _toHex = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.indigo,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Keys',
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Public Key',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SelectableText(
|
||||
_toHex ? widget.hexPub : widget.npubEncoded,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey[800],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Private Key',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SelectableText(
|
||||
_toHex ? widget.hexPriv : widget.nsecEncoded,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment
|
||||
.spaceBetween, // Changed to space between to create space for icon buttons
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_toHex = !_toHex;
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.autorenew_outlined),
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
OkButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'OK',
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:drifter/theme/app_colors.dart';
|
||||
|
||||
import 'ok_button_widget.dart';
|
||||
|
||||
class KeysExistDialog extends StatefulWidget {
|
||||
const KeysExistDialog({
|
||||
super.key,
|
||||
required this.npubEncoded,
|
||||
required this.nsecEncoded,
|
||||
required this.hexPriv,
|
||||
required this.hexPub,
|
||||
});
|
||||
|
||||
final String npubEncoded;
|
||||
final String nsecEncoded;
|
||||
final String hexPriv;
|
||||
final String hexPub;
|
||||
|
||||
@override
|
||||
State<KeysExistDialog> createState() => _KeysExistDialogState();
|
||||
}
|
||||
|
||||
class _KeysExistDialogState extends State<KeysExistDialog> {
|
||||
bool _toHex = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: AppColors.mainDarkBlue,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Keys',
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Public Key',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SelectableText(
|
||||
_toHex ? widget.hexPub : widget.npubEncoded,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey[800],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Private Key',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SelectableText(
|
||||
_toHex ? widget.hexPriv : widget.nsecEncoded,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey[800],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment
|
||||
.spaceBetween, // Changed to space between to create space for icon buttons
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_toHex = !_toHex;
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.autorenew_outlined),
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
OkButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'OK',
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:drifter/theme/app_colors.dart';
|
||||
|
||||
class KeysOptionModalBottomSheet extends StatelessWidget {
|
||||
const KeysOptionModalBottomSheet({
|
||||
super.key,
|
||||
required this.generateNewKeyPressed,
|
||||
});
|
||||
|
||||
final void Function()? generateNewKeyPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(color: AppColors.mainDarkBlue),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(Colors.white)),
|
||||
onPressed: generateNewKeyPressed,
|
||||
child: Text(
|
||||
'Generate New Key',
|
||||
style: TextStyle(color: AppColors.mainDarkBlue),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MessageSnackBar extends SnackBar {
|
||||
MessageSnackBar({Key? key, required this.label, this.isWarning = false})
|
||||
: super(
|
||||
key: key,
|
||||
content: _GenericErrorSnackBarMessage(
|
||||
label: label,
|
||||
isWarning: isWarning,
|
||||
),
|
||||
backgroundColor: isWarning! ? Colors.red : Colors.white,
|
||||
elevation: 6.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
behavior: SnackBarBehavior.fixed,
|
||||
);
|
||||
|
||||
final String label;
|
||||
final bool? isWarning;
|
||||
}
|
||||
|
||||
class _GenericErrorSnackBarMessage extends StatelessWidget {
|
||||
const _GenericErrorSnackBarMessage({
|
||||
Key? key,
|
||||
required this.label,
|
||||
this.isWarning,
|
||||
}) : super(key: key);
|
||||
|
||||
final String label;
|
||||
final bool? isWarning;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: isWarning! ? Colors.white : Colors.black,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:drifter/theme/app_colors.dart';
|
||||
|
||||
class OkButton extends StatelessWidget {
|
||||
const OkButton({
|
||||
super.key,
|
||||
required this.onPressed,
|
||||
required this.label,
|
||||
});
|
||||
|
||||
final void Function()? onPressed;
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.mainDarkBlue,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
import 'package:drifter/theme/app_colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UserInfo extends StatelessWidget {
|
||||
const UserInfo({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
AvatarWidget(),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
UserNameWidget(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AvatarWidget extends StatelessWidget {
|
||||
const AvatarWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.black),
|
||||
borderRadius: BorderRadius.all(Radius.circular(75))),
|
||||
width: 150,
|
||||
height: 150,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserNameWidget extends StatefulWidget {
|
||||
const UserNameWidget({super.key});
|
||||
|
||||
@override
|
||||
State<UserNameWidget> createState() => _UserNameWidgetState();
|
||||
}
|
||||
|
||||
class _UserNameWidgetState extends State<UserNameWidget> {
|
||||
late final TextEditingController messageController;
|
||||
late final FocusNode messageFocusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
messageController = TextEditingController();
|
||||
messageFocusNode = FocusNode();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
messageController.dispose();
|
||||
messageFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(
|
||||
0.0,
|
||||
),
|
||||
),
|
||||
child: TextField(
|
||||
controller: messageController,
|
||||
focusNode: messageFocusNode,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Username',
|
||||
hintStyle: const TextStyle(fontSize: 14),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.send,
|
||||
color: AppColors.mainDarkBlue,
|
||||
size: 30,
|
||||
),
|
||||
onPressed: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user