Changes in the feed screen, keys are generated after the account is created
This commit is contained in:
parent
6921e30ecd
commit
a7ea864c47
BIN
assets/images/icons/drifter_vector.png
Normal file
BIN
assets/images/icons/drifter_vector.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
@ -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(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -18,7 +18,7 @@ class _MessageScreenState extends State<MessageScreen> {
|
||||
children: const [
|
||||
Center(
|
||||
child: Text(
|
||||
"List of posts",
|
||||
"Message",
|
||||
),
|
||||
)
|
||||
],
|
||||
|
18
lib/pages/notifications_screen/notifications_screen.dart
Normal file
18
lib/pages/notifications_screen/notifications_screen.dart
Normal 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'),
|
||||
);
|
||||
}
|
||||
}
|
18
lib/pages/search_screen/search_screen.dart
Normal file
18
lib/pages/search_screen/search_screen.dart
Normal 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'),
|
||||
);
|
||||
}
|
||||
}
|
41
lib/pages/settings_screen/settings_screen.dart
Normal file
41
lib/pages/settings_screen/settings_screen.dart
Normal 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'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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,
|
||||
),
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user