main #2

Closed
ryleedavis wants to merge 8 commits from alexvasl/drifter_app:main into main
11 changed files with 298 additions and 33 deletions
Showing only changes of commit a7ea864c47 - Show all commits

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/home_screen/home_screen_widget.dart';
import 'package:drifter/pages/login_screen/login_screen.dart'; import 'package:drifter/pages/login_screen/login_screen.dart';
import 'package:drifter/pages/main_screen/main_screen_widget.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/splash_screen/splash_screen.dart';
import 'package:drifter/pages/terms_of_service/terms_of_service.dart'; import 'package:drifter/pages/terms_of_service/terms_of_service.dart';
import 'package:drifter/pages/welcome_screen/welcome_screen.dart'; import 'package:drifter/pages/welcome_screen/welcome_screen.dart';
@ -40,6 +41,7 @@ class MyApp extends StatelessWidget {
'/terms': (context) => const TermsOfServiceScreen(), '/terms': (context) => const TermsOfServiceScreen(),
'/createAccount': (context) => const CreateAccountScreen(), '/createAccount': (context) => const CreateAccountScreen(),
'/MainScreen': (context) => const MainScreenWidget(), '/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/models/models.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/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/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';
@ -24,6 +25,84 @@ class CreateAccountScreen extends StatefulWidget {
} }
class CreateAccountScreenState extends State<CreateAccountScreen> { 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -123,6 +202,15 @@ class CreateAccountScreenState extends State<CreateAccountScreen> {
height: 56, height: 56,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
final currentContext = context;
generateNewKeys().then(
(keysGenerated) {
if (keysGenerated) {
ScaffoldMessenger.of(currentContext).showSnackBar(
MessageSnackBar(label: 'Keys Generated!'));
}
},
);
Navigator.pushNamedAndRemoveUntil( Navigator.pushNamedAndRemoveUntil(
context, '/MainScreen', (_) => false); context, '/MainScreen', (_) => false);
}, },

View File

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

View File

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

View File

@ -18,7 +18,7 @@ class _MessageScreenState extends State<MessageScreen> {
children: const [ children: const [
Center( Center(
child: Text( 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, height: 300,
), ),
Image.asset( Image.asset(
'assets/images/logo/drifter_vector.png', 'assets/images/icons/drifter_vector.png',
height: 111, height: 111,
width: 93, width: 93,
), ),

View File

@ -64,7 +64,8 @@ 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/images/logo/ - assets/images//icons/
- assets/images//logo/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg