forked from alexvasl/drifter_app
main #2
@ -1,6 +1,7 @@
|
|||||||
import 'package:dart_nostr/dart_nostr.dart';
|
import 'package:dart_nostr/dart_nostr.dart';
|
||||||
import 'package:drifter/models/keys.dart';
|
import 'package:drifter/models/keys.dart';
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.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/keys_option_modal_bottom_sheet.dart';
|
||||||
import 'package:drifter/pages/profile_screen/widgets/message_snack_bar.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:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
import 'package:nostr_tools/nostr_tools.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatelessWidget {
|
class LoginScreen extends StatefulWidget {
|
||||||
const LoginScreen({super.key});
|
const LoginScreen({super.key});
|
||||||
|
|
||||||
final _secureStorage = const FlutterSecureStorage();
|
@override
|
||||||
|
State<LoginScreen> createState() => LoginScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> addKeyToStorage(
|
class LoginScreenState extends State<LoginScreen> {
|
||||||
String privateKeyHex,
|
final keyGenerator = KeyApi();
|
||||||
String publicKeyHex,
|
final nip19 = Nip19();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -70,8 +57,9 @@ class LoginScreen extends StatelessWidget {
|
|||||||
bool isValidHexKey =
|
bool isValidHexKey =
|
||||||
Nostr.instance.keysService.isValidPrivateKey(value);
|
Nostr.instance.keysService.isValidPrivateKey(value);
|
||||||
bool isValidNSec = value.trim().startsWith('nsec') &&
|
bool isValidNSec = value.trim().startsWith('nsec') &&
|
||||||
Nostr.instance.keysService.isValidPrivateKey(
|
Nostr.instance.keysService.isValidPrivateKey(Nostr
|
||||||
NostrClientUtils.hexEncode(value)['data']);
|
.instance.keysService
|
||||||
|
.decodeNsecKeyToPrivateKey(value));
|
||||||
if (!(isValidHexKey || isValidNSec)) {
|
if (!(isValidHexKey || isValidNSec)) {
|
||||||
return 'Your private key is not valid.';
|
return 'Your private key is not valid.';
|
||||||
}
|
}
|
||||||
@ -92,59 +80,68 @@ class LoginScreen extends StatelessWidget {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
MaterialStateProperty.all(AppColors.background)),
|
MaterialStateProperty.all(AppColors.background)),
|
||||||
|
child: const Text(
|
||||||
|
'Login',
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
// Он получает значение закрытого ключа из _keyController текстового поля и присваивает его переменной privateKeyHex.
|
|
||||||
String privateKeyHex = keyController.text.trim();
|
String privateKeyHex = keyController.text.trim();
|
||||||
String publicKeyHex;
|
String publicKeyHex;
|
||||||
String nsecKey;
|
String nsecKey;
|
||||||
String npubKey;
|
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')) {
|
if (privateKeyHex.startsWith('nsec')) {
|
||||||
nsecKey = privateKeyHex;
|
final decoded = nip19.decode(privateKeyHex);
|
||||||
final decoded = Nostr.instance.keysService
|
privateKeyHex = decoded['data'];
|
||||||
.decodeNsecKeyToPrivateKey(privateKeyHex);
|
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
||||||
privateKeyHex = decoded;
|
nsecKey = nip19.nsecEncode(privateKeyHex);
|
||||||
publicKeyHex = Nostr.instance.keysService
|
npubKey = nip19.npubEncode(publicKeyHex);
|
||||||
.derivePublicKey(privateKey: 'privateKeyHex');
|
} else {
|
||||||
npubKey = Nostr.instance.keysService
|
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
||||||
.encodePublicKeyToNpub(publicKeyHex);
|
nsecKey = nip19.nsecEncode(privateKeyHex);
|
||||||
}
|
npubKey = nip19.npubEncode(publicKeyHex);
|
||||||
// Если privateKeyHex не начинается с « nsec », это означает, что это обычный шестнадцатеричный закрытый ключ.
|
|
||||||
else {
|
|
||||||
publicKeyHex = Nostr.instance.keysService
|
|
||||||
.derivePublicKey(privateKey: 'privateKeyHex');
|
|
||||||
nsecKey = Nostr.instance.keysService
|
|
||||||
.encodePrivateKeyToNsec(privateKeyHex);
|
|
||||||
npubKey = Nostr.instance.keysService
|
|
||||||
.encodePublicKeyToNpub(publicKeyHex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Затем он вызывает _addKeysToStorage метод для добавления закрытого ключа и открытого ключа в хранилище. Он прикрепляет then() к этому методу обратный вызов для обработки случая, когда ключи успешно добавлены в хранилище.
|
ProfileScreenState()
|
||||||
addKeyToStorage(privateKeyHex, publicKeyHex, nsecKey, npubKey)
|
.addKeyToStorage(
|
||||||
|
privateKeyHex, publicKeyHex, nsecKey, npubKey)
|
||||||
.then((keysAdded) {
|
.then((keysAdded) {
|
||||||
if (keysAdded) {
|
if (keysAdded) {
|
||||||
keyController.clear();
|
keyController.clear();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
MessageSnackBar(label: 'Congratulations! Keys Stored!'),
|
MessageSnackBar(label: 'Congratulations! Keys Stored!'),
|
||||||
);
|
);
|
||||||
setState() {
|
// setState() {
|
||||||
Keys.privateKey = privateKeyHex;
|
// Keys.privateKey = privateKeyHex;
|
||||||
Keys.publicKey = publicKeyHex;
|
// Keys.publicKey = publicKeyHex;
|
||||||
Keys.nsecKey = nsecKey;
|
// Keys.nsecKey = nsecKey;
|
||||||
Keys.npubKey = npubKey;
|
// Keys.npubKey = npubKey;
|
||||||
Keys.keysExist = true;
|
// Keys.keysExist = true;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
formKey.currentState?.setState(() {});
|
formKey.currentState?.setState(() {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
|
||||||
'Login',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -17,7 +17,8 @@ class ProfileScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProfileScreenState extends State<ProfileScreen> {
|
class ProfileScreenState extends State<ProfileScreen> {
|
||||||
final _secureStorage = const FlutterSecureStorage();
|
final secureStorage = const FlutterSecureStorage();
|
||||||
|
bool _toHex = false;
|
||||||
|
|
||||||
TextEditingController privateKeyInput = TextEditingController();
|
TextEditingController privateKeyInput = TextEditingController();
|
||||||
TextEditingController publicKeyInput = TextEditingController();
|
TextEditingController publicKeyInput = TextEditingController();
|
||||||
@ -37,6 +38,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
final nsec =
|
final nsec =
|
||||||
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
||||||
|
|
||||||
// final nsecDecoded =
|
// final nsecDecoded =
|
||||||
// Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
// Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
||||||
// assert(nsecDecoded['type'] == 'nsec');
|
// assert(nsecDecoded['type'] == 'nsec');
|
||||||
@ -47,6 +49,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
||||||
|
|
||||||
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
||||||
|
|
||||||
// final npubDecoded =
|
// final npubDecoded =
|
||||||
// Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
// Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
||||||
// assert(npubDecoded['type'] == 'npub');
|
// assert(npubDecoded['type'] == 'npub');
|
||||||
@ -57,11 +60,11 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
Future<void> _getKeysFromStorage() async {
|
Future<void> _getKeysFromStorage() async {
|
||||||
// Reading values associated with the " privateKey " and " publicKey " keys from a secure repository
|
// Reading values associated with the " privateKey " and " publicKey " keys from a secure repository
|
||||||
final storedPrivateKey = await _secureStorage.read(key: 'privateKey');
|
final storedPrivateKey = await secureStorage.read(key: 'privateKey');
|
||||||
final storedPublicKey = await _secureStorage.read(key: 'publicKey');
|
final storedPublicKey = await secureStorage.read(key: 'publicKey');
|
||||||
|
|
||||||
final storedNsecKey = await _secureStorage.read(key: 'nsec');
|
final storedNsecKey = await secureStorage.read(key: 'nsec');
|
||||||
final storedNpubKey = await _secureStorage.read(key: 'npub');
|
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
|
// Indicates that both private and public keys are stored in a secure repository, after which, the state variables are updated
|
||||||
if (storedPrivateKey != null &&
|
if (storedPrivateKey != null &&
|
||||||
@ -88,10 +91,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
) async {
|
) async {
|
||||||
// Waiting for both write operations to complete
|
// Waiting for both write operations to complete
|
||||||
Future.wait([
|
Future.wait([
|
||||||
_secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
||||||
_secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
||||||
_secureStorage.write(key: 'nsec', value: nsecKey),
|
secureStorage.write(key: 'nsec', value: nsecKey),
|
||||||
_secureStorage.write(key: 'npub', value: npubKey),
|
secureStorage.write(key: 'npub', value: npubKey),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Updating status variables and starting widget rebuilding
|
// Updating status variables and starting widget rebuilding
|
||||||
@ -110,10 +113,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
Future<void> _deleteKeysStorage() async {
|
Future<void> _deleteKeysStorage() async {
|
||||||
// Calling secure storage to remove keys from storage
|
// Calling secure storage to remove keys from storage
|
||||||
Future.wait([
|
Future.wait([
|
||||||
_secureStorage.delete(key: 'privateKey'),
|
secureStorage.delete(key: 'privateKey'),
|
||||||
_secureStorage.delete(key: 'publicKey'),
|
secureStorage.delete(key: 'publicKey'),
|
||||||
_secureStorage.delete(key: 'nsec'),
|
secureStorage.delete(key: 'nsec'),
|
||||||
_secureStorage.delete(key: 'npub'),
|
secureStorage.delete(key: 'npub'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Updating status variables, resetting values after deleting keys from the repository
|
// Updating status variables, resetting values after deleting keys from the repository
|
||||||
@ -128,42 +131,49 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
privateKeyInput.text = Keys.nsecKey;
|
privateKeyInput.text = _toHex ? Keys.nsecKey : Keys.privateKey;
|
||||||
publicKeyInput.text = Keys.npubKey;
|
publicKeyInput.text = _toHex ? Keys.npubKey : Keys.publicKey;
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 60,
|
height: 60,
|
||||||
),
|
),
|
||||||
UserInfo(),
|
const UserInfo(),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
),
|
),
|
||||||
FormKeys(),
|
FormKeys(),
|
||||||
SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
Keys.keysExist
|
Keys.keysExist
|
||||||
? ElevatedButton(
|
? IconButton(
|
||||||
style: ButtonStyle(
|
|
||||||
backgroundColor:
|
|
||||||
MaterialStateProperty.all(AppColors.background)),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
keysExistDialog(
|
setState(() {
|
||||||
Nostr.instance.keysService
|
_toHex = !_toHex;
|
||||||
.encodePublicKeyToNpub(Keys.publicKey),
|
});
|
||||||
Nostr.instance.keysService
|
|
||||||
.encodePrivateKeyToNsec(Keys.privateKey),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
child: Text(
|
icon: const Icon(Icons.refresh))
|
||||||
'Keys',
|
// 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(
|
: ElevatedButton(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
@ -171,7 +181,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
modalBottomSheet();
|
modalBottomSheet();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: const Text(
|
||||||
'Generate Keys',
|
'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