Added Login Screen

This commit is contained in:
Alex Vasilev 2023-05-18 02:16:20 +03:00
parent 000a7bd433
commit 76609f6cf1
8 changed files with 178 additions and 15 deletions

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:nostr_tools/nostr_tools.dart'; import 'package:nostr_tools/nostr_tools.dart';
class Keys { class Keys {
@ -11,3 +12,6 @@ class Keys {
class Relay { class Relay {
static final relay = RelayApi(relayUrl: 'wss://relay.damus.io'); static final relay = RelayApi(relayUrl: 'wss://relay.damus.io');
} }
final keyController = TextEditingController();
final formKey = GlobalKey<FormFieldState>();

View File

@ -372,7 +372,7 @@ class _CreatePostState extends State<CreatePost> {
padding: const EdgeInsets.symmetric(vertical: 24), padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
color: AppColors.mainDarkBlue, color: AppColors.background,
), ),
child: const Center( child: const Center(
child: Text( child: Text(

View File

@ -0,0 +1,153 @@
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/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/ok_button_widget.dart';
import 'package:drifter/theme/app_colors.dart';
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 {
const LoginScreen({super.key});
final _secureStorage = const FlutterSecureStorage();
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;
}
@override
Widget build(BuildContext context) {
return ListView(
children: [
SizedBox(
height: 200,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text(
'Enter your private key',
style: TextStyle(
fontSize: 20,
),
),
const SizedBox(height: 30),
TextFormField(
decoration: const InputDecoration(
labelText: 'Enter nsec or hex',
border: OutlineInputBorder(),
),
maxLength: 64,
controller: keyController,
key: formKey,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your private key';
}
try {
bool isValidHexKey =
Nostr.instance.keysService.isValidPrivateKey(value);
bool isValidNSec = value.trim().startsWith('nsec') &&
Nostr.instance.keysService.isValidPrivateKey(
NostrClientUtils.hexEncode(value)['data']);
if (!(isValidHexKey || isValidNSec)) {
return 'Your private key is not valid.';
}
} on ChecksumVerificationException catch (e) {
return e.message;
} catch (e) {
return 'Error: $e';
}
return null;
}),
],
),
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(AppColors.background)),
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);
}
// Если privateKeyHex не начинается с « nsec », это означает, что это обычный шестнадцатеричный закрытый ключ.
else {
publicKeyHex = Nostr.instance.keysService
.derivePublicKey(privateKey: 'privateKeyHex');
nsecKey = Nostr.instance.keysService
.encodePrivateKeyToNsec(privateKeyHex);
npubKey = Nostr.instance.keysService
.encodePublicKeyToNpub(publicKeyHex);
}
// Затем он вызывает _addKeysToStorage метод для добавления закрытого ключа и открытого ключа в хранилище. Он прикрепляет then() к этому методу обратный вызов для обработки случая, когда ключи успешно добавлены в хранилище.
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;
}
}
});
} else {
formKey.currentState?.setState(() {});
}
},
child: Text(
'Login',
),
),
)
],
);
}
}

View File

@ -1,5 +1,6 @@
// import 'package:drifter/pages/home_screen/home_screen_widget.dart'; // import 'package:drifter/pages/home_screen/home_screen_widget.dart';
import 'package:drifter/pages/home_screen/home_screen_widget.dart'; import 'package:drifter/pages/home_screen/home_screen_widget.dart';
import 'package:drifter/pages/login_screen/login_screen.dart';
import 'package:drifter/pages/message_screen/message_screen_widget.dart'; import 'package:drifter/pages/message_screen/message_screen_widget.dart';
import 'package:drifter/pages/profile_screen/profile_screen.dart'; import 'package:drifter/pages/profile_screen/profile_screen.dart';
import 'package:drifter/theme/app_colors.dart'; import 'package:drifter/theme/app_colors.dart';
@ -58,6 +59,7 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
HomeScreen(), HomeScreen(),
MessageScreen(), MessageScreen(),
ProfileScreen(), ProfileScreen(),
LoginScreen(),
], ],
), ),
bottomNavigationBar: BottomNavigationBar( bottomNavigationBar: BottomNavigationBar(
@ -75,6 +77,10 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
icon: Icon(Icons.person), icon: Icon(Icons.person),
label: 'Profile', label: 'Profile',
), ),
BottomNavigationBarItem(
icon: Icon(Icons.login),
label: 'Login',
),
], ],
onTap: onSelectedtap, onTap: onSelectedtap,
), ),

View File

@ -37,8 +37,8 @@ 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');
// assert(nsecDecoded['data'] == newPrivateKey); // assert(nsecDecoded['data'] == newPrivateKey);
@ -47,12 +47,12 @@ 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');
// assert(npubDecoded['data'] == newPublicKey); // assert(npubDecoded['data'] == newPublicKey);
return await _addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub); return await addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub);
} }
Future<void> _getKeysFromStorage() async { Future<void> _getKeysFromStorage() async {
@ -80,7 +80,7 @@ class ProfileScreenState extends State<ProfileScreen> {
// Adding a new key // Adding a new key
// Writing a private and public key to a secure vault // Writing a private and public key to a secure vault
Future<bool> _addKeyToStorage( Future<bool> addKeyToStorage(
String privateKeyHex, String privateKeyHex,
String publicKeyHex, String publicKeyHex,
String nsecKey, String nsecKey,
@ -89,7 +89,7 @@ class ProfileScreenState extends State<ProfileScreen> {
// 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: privateKeyHex), _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),
]); ]);
@ -150,8 +150,8 @@ class ProfileScreenState extends State<ProfileScreen> {
Keys.keysExist Keys.keysExist
? ElevatedButton( ? ElevatedButton(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.all( backgroundColor:
AppColors.mainDarkBlue)), MaterialStateProperty.all(AppColors.background)),
onPressed: () { onPressed: () {
keysExistDialog( keysExistDialog(
Nostr.instance.keysService Nostr.instance.keysService
@ -166,8 +166,8 @@ class ProfileScreenState extends State<ProfileScreen> {
) )
: ElevatedButton( : ElevatedButton(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.all( backgroundColor:
AppColors.mainDarkBlue)), MaterialStateProperty.all(AppColors.background)),
onPressed: () { onPressed: () {
modalBottomSheet(); modalBottomSheet();
}, },

View File

@ -43,7 +43,7 @@ class _KeysExistDialogState extends State<KeysExistDialog> {
padding: const EdgeInsets.symmetric(vertical: 24), padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
color: AppColors.mainDarkBlue, color: AppColors.background,
), ),
child: const Center( child: const Center(
child: Text( child: Text(

View File

@ -16,7 +16,7 @@ class OkButton extends StatelessWidget {
return ElevatedButton( return ElevatedButton(
onPressed: onPressed, onPressed: onPressed,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppColors.mainDarkBlue, backgroundColor: AppColors.background,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),

View File

@ -63,7 +63,7 @@ flutter:
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: assets:
- assets/ - assets/images/logo/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see