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';
class Keys {
@ -11,3 +12,6 @@ class Keys {
class Relay {
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),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColors.mainDarkBlue,
color: AppColors.background,
),
child: const Center(
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/login_screen/login_screen.dart';
import 'package:drifter/pages/message_screen/message_screen_widget.dart';
import 'package:drifter/pages/profile_screen/profile_screen.dart';
import 'package:drifter/theme/app_colors.dart';
@ -58,6 +59,7 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
HomeScreen(),
MessageScreen(),
ProfileScreen(),
LoginScreen(),
],
),
bottomNavigationBar: BottomNavigationBar(
@ -75,6 +77,10 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
icon: Icon(Icons.person),
label: 'Profile',
),
BottomNavigationBarItem(
icon: Icon(Icons.login),
label: 'Login',
),
],
onTap: onSelectedtap,
),

View File

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

View File

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

View File

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

View File

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