Changes in the feed screen, keys are generated after the account is created

This commit is contained in:
Alex Vasilev 2023-05-31 00:56:26 +03:00
parent 6921e30ecd
commit a7ea864c47
11 changed files with 298 additions and 33 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -4,6 +4,7 @@ import 'package:drifter/pages/create_account_screen/create_account_screen.dart';
import 'package:drifter/pages/home_screen/home_screen_widget.dart';
import 'package:drifter/pages/login_screen/login_screen.dart';
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
import 'package:drifter/pages/settings_screen/settings_screen.dart';
import 'package:drifter/pages/splash_screen/splash_screen.dart';
import 'package:drifter/pages/terms_of_service/terms_of_service.dart';
import 'package:drifter/pages/welcome_screen/welcome_screen.dart';
@ -40,6 +41,7 @@ class MyApp extends StatelessWidget {
'/terms': (context) => const TermsOfServiceScreen(),
'/createAccount': (context) => const CreateAccountScreen(),
'/MainScreen': (context) => const MainScreenWidget(),
'/Settings': (context) => const SettingsScreen(),
},
);
}

View File

@ -2,6 +2,7 @@ import 'package:dart_nostr/dart_nostr.dart';
import 'package:drifter/models/models.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/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';
@ -24,6 +25,84 @@ class CreateAccountScreen extends StatefulWidget {
}
class CreateAccountScreenState extends State<CreateAccountScreen> {
final secureStorage = const FlutterSecureStorage();
Future<bool> 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<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 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;
});
}
}
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: publicKeyHex),
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;
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -123,6 +202,15 @@ class CreateAccountScreenState extends State<CreateAccountScreen> {
height: 56,
child: ElevatedButton(
onPressed: () {
final currentContext = context;
generateNewKeys().then(
(keysGenerated) {
if (keysGenerated) {
ScaffoldMessenger.of(currentContext).showSnackBar(
MessageSnackBar(label: 'Keys Generated!'));
}
},
);
Navigator.pushNamedAndRemoveUntil(
context, '/MainScreen', (_) => false);
},

View File

@ -90,6 +90,7 @@ class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.mainBackground,
body: RefreshIndicator(
onRefresh: () async {
await _resubscribeStream();
@ -192,16 +193,16 @@ class TimeAgo {
String timeAgo = '';
if (difference.inDays > 0) {
timeAgo =
'${difference.inDays} ${difference.inDays == 1 ? 'day' : 'days'} ago';
timeAgo = '${difference.inDays}d';
// '${difference.inDays} ${difference.inDays == 1 ? 'day' : 'days'} ago';
} else if (difference.inHours > 0) {
timeAgo =
'${difference.inHours} ${difference.inHours == 1 ? 'hour' : 'hours'} ago';
timeAgo = '${difference.inHours}h';
// '${difference.inHours} ${difference.inHours == 1 ? 'hour' : 'hours'} ago';
} else if (difference.inMinutes > 0) {
timeAgo =
'${difference.inMinutes} ${difference.inMinutes == 1 ? 'minute' : 'minutes'} ago';
timeAgo = '${difference.inMinutes}m';
// '${difference.inMinutes} ${difference.inMinutes == 1 ? 'minute' : 'minutes'} ago';
} else {
timeAgo = 'just now';
timeAgo = '${difference.inMinutes}m';
}
return timeAgo;
@ -237,34 +238,79 @@ class DomainCard extends StatelessWidget {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.grey,
color: AppColors.postBg,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// children: [
// CircleAvatar(
// radius: 25,
// backgroundImage: FadeInImage(
// placeholder: const NetworkImage(
// 'https://i.ibb.co/mJkxDkb/satoshi.png'),
// image: NetworkImage(domain.avatarUrl),
// ).image,
// ),
// Container(
// width: 300,
// child: Row(
// children: [
// Text(domain.name),
// SizedBox(
// width: 4,
// ),
// Text('@${domain.username.toLowerCase()}',
// style: TextStyle(color: AppColors.postUserName)),
// Expanded(child: SizedBox()),
// Text('${domain.time}',
// style: TextStyle(color: AppColors.postUserName)),
// ],
// ),
// )
// ],
// ),
ListTile(
contentPadding: EdgeInsets.only(top: 16, right: 16, left: 16),
leading: CircleAvatar(
radius: 25,
backgroundImage: FadeInImage(
placeholder:
const NetworkImage('https://i.ibb.co/mJkxDkb/satoshi.png'),
image: NetworkImage(domain.avatarUrl),
).image,
),
title:
Text(domain.name, style: const TextStyle(color: Colors.white)),
subtitle: Text('@${domain.username.toLowerCase()}${domain.time}',
style: TextStyle(color: Colors.grey.shade400)),
trailing: const Icon(Icons.more_vert, color: Colors.grey),
title: Row(
children: [
Text(domain.name),
SizedBox(
width: 4,
),
Expanded(
child: Container(
child: Text('@${domain.username.toLowerCase()}',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: AppColors.postUserName)),
),
),
Text('${domain.time}',
style: TextStyle(color: AppColors.postUserName)),
],
),
trailing:
const Icon(Icons.more_horiz, color: AppColors.postMoreIcon),
),
Divider(height: 1, color: Colors.grey.shade400),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding:
const EdgeInsets.only(top: 12, right: 16, bottom: 14, left: 78),
child: Text(domain.content,
style: const TextStyle(color: Colors.white)),
style: const TextStyle(color: AppColors.postBodyText)),
),
if (imageLinks != null && imageLinks.isNotEmpty)
Center(
Padding(
padding: const EdgeInsets.only(
top: 12, right: 16, bottom: 14, left: 78),
child: Stack(
children: [
const Placeholder(
@ -274,7 +320,7 @@ class DomainCard extends StatelessWidget {
Center(
child: FadeInImage(
placeholder: const NetworkImage(
'https://i.ibb.co/D9jqXgR/58038897-167f0280-7ae6-11e9-94eb-88e880a25f0f.gif',
'https://media.tenor.com/On7kvXhzml4AAAAj/loading-gif.gif',
),
image: NetworkImage(imageLinks.first),
fit: BoxFit.cover,

View File

@ -2,7 +2,9 @@
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/notifications_screen/notifications_screen.dart';
import 'package:drifter/pages/profile_screen/profile_screen.dart';
import 'package:drifter/pages/search_screen/search_screen.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:drifter/main.dart';
import 'package:drifter/utilities/assets.dart';
@ -17,15 +19,48 @@ class MainScreenWidget extends StatefulWidget {
}
class _MainScreenWidgetState extends State<MainScreenWidget> {
int _selectedTap = 0;
int _selectedTap = 2;
late String _title;
void onSelectedtap(int index) {
if (_selectedTap == index) return;
setState(() {
_selectedTap = index;
switch (index) {
case 0:
{
_title = 'Message';
}
break;
case 1:
{
_title = 'Search';
}
break;
case 2:
{
_title = 'Feed';
}
break;
case 3:
{
_title = 'Notifications';
}
break;
case 4:
{
_title = 'Profile';
}
break;
}
});
}
@override
initState() {
_title = 'Feed';
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -34,7 +69,9 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
leading: IconButton(
icon: Icon(Icons.settings),
color: AppColors.topNavIconPtimary,
onPressed: () {},
onPressed: () {
Navigator.pushNamed(context, '/Settings');
},
),
actions: <Widget>[
IconButton(
@ -43,8 +80,8 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
onPressed: () {},
),
],
title: const Text(
"Drifter",
title: Text(
_title,
style: TextStyle(
color: AppColors.topNavText,
),
@ -57,8 +94,10 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
body: IndexedStack(
index: _selectedTap,
children: const [
HomeScreen(),
MessageScreen(),
SearchScreen(),
HomeScreen(),
NotificationsScreen(),
ProfileScreen(),
// LoginScreen(),
],
@ -67,19 +106,31 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
backgroundColor: AppColors.bottomNavBackground,
selectedItemColor: AppColors.bottomNavIconActive,
unselectedItemColor: AppColors.bottomNavIconDefault,
selectedFontSize: 0,
currentIndex: _selectedTap,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
icon: Icon(Icons.mail_outline),
label: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: 'Message',
icon: Icon(Icons.search),
label: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
icon:
ImageIcon(AssetImage('assets/images/icons/drifter_vector.png')),
label: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications_outlined),
label: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_2_outlined),
label: '',
),
// BottomNavigationBarItem(
// icon: Icon(Icons.login),

View File

@ -18,7 +18,7 @@ class _MessageScreenState extends State<MessageScreen> {
children: const [
Center(
child: Text(
"List of posts",
"Message",
),
)
],

View File

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/placeholder.dart';
class NotificationsScreen extends StatefulWidget {
const NotificationsScreen({super.key});
@override
State<NotificationsScreen> createState() => _NotificationsScreenState();
}
class _NotificationsScreenState extends State<NotificationsScreen> {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Notifications Page'),
);
}
}

View File

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/placeholder.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({super.key});
@override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Search Page'),
);
}
}

View File

@ -0,0 +1,41 @@
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/placeholder.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.mainBackground,
appBar: AppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: AppColors.topNavIconPtimary,
),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
('Settings'),
style: TextStyle(
color: AppColors.topNavText,
),
// textAlign: TextAlign.center,
),
centerTitle: true,
backgroundColor: AppColors.mainBackground,
elevation: 0,
),
body: Center(
child: Text('Settings'),
),
);
}
}

View File

@ -35,7 +35,7 @@ class _SplashState extends State<Splash> {
height: 300,
),
Image.asset(
'assets/images/logo/drifter_vector.png',
'assets/images/icons/drifter_vector.png',
height: 111,
width: 93,
),

View File

@ -64,7 +64,8 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/logo/
- assets/images//icons/
- assets/images//logo/
# - images/a_dot_ham.jpeg