Compare commits

..

No commits in common. "834af8472a66d7ea8aad2f62217767e7e956f17c" and "578a461075af717d7eebf431c16aee2cdc164002" have entirely different histories.

13 changed files with 630 additions and 137 deletions

View File

@ -2,9 +2,9 @@ import 'package:dart_nostr/dart_nostr.dart';
import 'package:drifter/models/keys.dart';
import 'package:drifter/pages/profile_screen/widgets/delete_keys_dialog.dart';
import 'package:drifter/pages/profile_screen/widgets/key_exist_dialog.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/user_info_widget.dart';
import 'package:drifter/pages/widgets/flust_bar_type.dart';
import 'package:drifter/pages/widgets/show_flush_bar.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -126,20 +126,6 @@ class ProfileScreenState extends State<ProfileScreen> {
});
}
void keysExistDialog(String npubEncode, String nsecEncode) async {
await showDialog(
context: context,
builder: ((context) {
return KeysExistDialog(
npubEncoded: npubEncode,
nsecEncoded: nsecEncode,
hexPriv: Keys.privateKey,
hexPub: Keys.publicKey,
);
}),
);
}
@override
Widget build(BuildContext context) {
privateKeyInput.text = Keys.nsecKey;
@ -147,14 +133,11 @@ class ProfileScreenState extends State<ProfileScreen> {
return ListView(
children: [
const SizedBox(
SizedBox(
height: 60,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: UserInfo(),
),
const SizedBox(
UserInfo(),
SizedBox(
height: 40,
),
FormKeys(),
@ -178,32 +161,18 @@ class ProfileScreenState extends State<ProfileScreen> {
);
},
child: Text(
"Keys",
'Keys',
),
)
: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(AppColors.background)),
backgroundColor: MaterialStateProperty.all(
AppColors.mainDarkBlue)),
onPressed: () {
final currentContext = context;
generateNewKeys().then(
(keysGenerated) async {
if (keysGenerated) {
await Future<void>.delayed(
const Duration(milliseconds: 300));
showFloatingFlushBar(
type: FlushBarType.success,
message: "Keys generated!",
context: context,
);
}
},
);
modalBottomSheet();
},
child: Text(
"Generate Keys",
'Generate Keys',
),
),
Keys.keysExist
@ -211,27 +180,7 @@ class ProfileScreenState extends State<ProfileScreen> {
children: [
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => DeleteKeysDialog(
onNoPressed: () {
Navigator.pop(context);
},
onYesPressed: () {
final currentContext = context;
_deleteKeysStorage().then((_) {
if (!Keys.keysExist) {
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Keys deleted!",
context: context,
);
}
});
Navigator.pop(context);
},
),
);
deleteKeysDialog();
},
icon: const Icon(Icons.delete)),
],
@ -285,4 +234,66 @@ class ProfileScreenState extends State<ProfileScreen> {
),
);
}
void modalBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return KeysOptionModalBottomSheet(
generateNewKeyPressed: () {
final currentContext = context;
generateNewKeys().then(
(keysGenerated) {
if (keysGenerated) {
ScaffoldMessenger.of(currentContext).showSnackBar(
MessageSnackBar(label: 'Keys Generated!'));
}
},
);
Navigator.pop(context);
},
);
});
}
void keysExistDialog(String npubEncode, String nsecEncode) async {
await showDialog(
context: context,
builder: ((context) {
return KeysExistDialog(
npubEncoded: npubEncode,
nsecEncoded: nsecEncode,
hexPriv: Keys.privateKey,
hexPub: Keys.publicKey,
);
}),
);
}
void deleteKeysDialog() async {
await showDialog(
context: context,
builder: ((context) {
return DeleteKeysDialog(
onNoPressed: () {
Navigator.pop(context);
},
onYesPressed: () {
final currentContext = context;
_deleteKeysStorage().then((_) {
if (!Keys.keysExist) {
ScaffoldMessenger.of(currentContext).showSnackBar(
MessageSnackBar(
label: 'Keys successfully deleted!',
isWarning: true,
),
);
}
});
Navigator.pop(context);
},
);
}),
);
}
}

View File

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
import 'ok_button_widget.dart';
class DeleteKeysDialog extends StatelessWidget {
const DeleteKeysDialog({
super.key,
required this.onNoPressed,
required this.onYesPressed,
});
final void Function()? onNoPressed;
final void Function()? onYesPressed;
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.redAccent,
),
child: const Center(
child: Text(
'Delete Keys!',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Do you want to delete your keys?',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: onNoPressed,
child: Text(
'On',
style: TextStyle(color: AppColors.mainDarkBlue),
),
),
OkButton(
onPressed: onYesPressed,
label: 'YES',
),
],
),
],
),
)
],
),
),
);
}
}

View File

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'ok_button_widget.dart';
class GeneratedKeys extends StatefulWidget {
const GeneratedKeys({
super.key,
required this.npubEncoded,
required this.nsecEncoded,
required this.hexPriv,
required this.hexPub,
});
final String npubEncoded;
final String nsecEncoded;
final String hexPriv;
final String hexPub;
@override
State<GeneratedKeys> createState() => _GeneratedKeysState();
}
class _GeneratedKeysState extends State<GeneratedKeys> {
bool _toHex = false;
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.indigo,
),
child: const Center(
child: Text(
'Keys',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Public Key',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 12),
SelectableText(
_toHex ? widget.hexPub : widget.npubEncoded,
style: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
),
const SizedBox(height: 24),
Text(
'Private Key',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 12),
SelectableText(
_toHex ? widget.hexPriv : widget.nsecEncoded,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.redAccent,
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment
.spaceBetween, // Changed to space between to create space for icon buttons
children: [
IconButton(
onPressed: () {
setState(() {
_toHex = !_toHex;
});
},
icon: const Icon(Icons.autorenew_outlined),
color: Colors.grey[700],
),
OkButton(
onPressed: () {
Navigator.pop(context);
},
label: 'OK',
),
],
)
],
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
import 'ok_button_widget.dart';
class KeysExistDialog extends StatefulWidget {
const KeysExistDialog({
super.key,
required this.npubEncoded,
required this.nsecEncoded,
required this.hexPriv,
required this.hexPub,
});
final String npubEncoded;
final String nsecEncoded;
final String hexPriv;
final String hexPub;
@override
State<KeysExistDialog> createState() => _KeysExistDialogState();
}
class _KeysExistDialogState extends State<KeysExistDialog> {
bool _toHex = false;
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColors.mainDarkBlue,
),
child: const Center(
child: Text(
'Keys',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Public Key',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 12),
SelectableText(
_toHex ? widget.hexPub : widget.npubEncoded,
style: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
),
const SizedBox(height: 24),
Text(
'Private Key',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 12),
SelectableText(
_toHex ? widget.hexPriv : widget.nsecEncoded,
style: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment
.spaceBetween, // Changed to space between to create space for icon buttons
children: [
IconButton(
onPressed: () {
setState(() {
_toHex = !_toHex;
});
},
icon: const Icon(Icons.autorenew_outlined),
color: Colors.grey[700],
),
OkButton(
onPressed: () {
Navigator.pop(context);
},
label: 'OK',
),
],
)
],
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
class KeysOptionModalBottomSheet extends StatelessWidget {
const KeysOptionModalBottomSheet({
super.key,
required this.generateNewKeyPressed,
});
final void Function()? generateNewKeyPressed;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: AppColors.mainDarkBlue),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: generateNewKeyPressed,
child: Text(
'Generate New Key',
style: TextStyle(color: AppColors.mainDarkBlue),
),
),
const SizedBox(height: 10),
],
),
);
}
}

View File

@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
class MessageSnackBar extends SnackBar {
MessageSnackBar({Key? key, required this.label, this.isWarning = false})
: super(
key: key,
content: _GenericErrorSnackBarMessage(
label: label,
isWarning: isWarning,
),
backgroundColor: isWarning! ? Colors.red : Colors.white,
elevation: 6.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
behavior: SnackBarBehavior.fixed,
);
final String label;
final bool? isWarning;
}
class _GenericErrorSnackBarMessage extends StatelessWidget {
const _GenericErrorSnackBarMessage({
Key? key,
required this.label,
this.isWarning,
}) : super(key: key);
final String label;
final bool? isWarning;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
child: Text(
label,
style: TextStyle(
color: isWarning! ? Colors.white : Colors.black,
fontSize: 16.0,
),
),
);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
class OkButton extends StatelessWidget {
const OkButton({
super.key,
required this.onPressed,
required this.label,
});
final void Function()? onPressed;
final String label;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.mainDarkBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text(
label,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
);
}
}

View File

@ -0,0 +1,97 @@
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
class UserInfo extends StatelessWidget {
const UserInfo({super.key});
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
AvatarWidget(),
SizedBox(
height: 10,
),
UserNameWidget(),
],
),
);
}
}
class AvatarWidget extends StatelessWidget {
const AvatarWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.all(Radius.circular(75))),
width: 150,
height: 150,
);
}
}
class UserNameWidget extends StatefulWidget {
const UserNameWidget({super.key});
@override
State<UserNameWidget> createState() => _UserNameWidgetState();
}
class _UserNameWidgetState extends State<UserNameWidget> {
late final TextEditingController messageController;
late final FocusNode messageFocusNode;
@override
void initState() {
messageController = TextEditingController();
messageFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
messageController.dispose();
messageFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(
0.0,
),
),
child: TextField(
controller: messageController,
focusNode: messageFocusNode,
style: const TextStyle(
fontSize: 14,
),
decoration: InputDecoration(
hintText: 'Username',
hintStyle: const TextStyle(fontSize: 14),
suffixIcon: IconButton(
icon: const Icon(
Icons.send,
color: AppColors.mainDarkBlue,
size: 30,
),
onPressed: () {},
),
),
),
),
);
}
}

View File

@ -1,10 +1,11 @@
import 'package:drifter/pages/animated_widgets/rotate_icon.dart';
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
import 'package:drifter/pages/widgets/animated_widgets/rotate_icon.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:drifter/utilities/assets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import '../../utilities/assets.dart';
class Splash extends StatefulWidget {
const Splash({super.key});

View File

@ -1 +0,0 @@
enum FlushBarType { success, info, warning }

View File

@ -1,64 +0,0 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:another_flushbar/flushbar_route.dart' as flushRoute;
import 'package:drifter/pages/widgets/flust_bar_type.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
Future<dynamic> showFloatingFlushBar({
required FlushBarType type,
required String message,
String? iconAsset,
required BuildContext context,
Duration? duration = const Duration(milliseconds: 1500),
FlushbarPosition flushbarPosition = FlushbarPosition.TOP,
VoidCallback? onTap,
}) {
Color bg;
Color fg;
switch (type) {
case FlushBarType.success:
fg = AppColors.snackBarTextSuccess;
bg = AppColors.snackBarBackSuccess;
break;
case FlushBarType.info:
fg = AppColors.snackBarTextInfo;
bg = AppColors.snackBarBackInfo;
break;
case FlushBarType.warning:
fg = AppColors.snackBarTextError;
bg = AppColors.snackBarBackError;
break;
}
final bar = Flushbar<dynamic>(
onTap: (_) {
onTap?.call();
},
icon: iconAsset != null
? SvgPicture.asset(
iconAsset,
height: 16,
width: 16,
// color: fg,
)
: null,
message: message,
messageColor: fg,
flushbarPosition: flushbarPosition,
backgroundColor: bg,
duration: duration,
flushbarStyle: FlushbarStyle.FLOATING,
borderRadius: BorderRadius.circular(
8.0,
),
margin: const EdgeInsets.all(20),
maxWidth: MediaQuery.of(context).size.width - 50,
);
final _route = flushRoute.showFlushbar<dynamic>(
context: context,
flushbar: bar,
);
return Navigator.of(context, rootNavigator: true).push(_route);
}

View File

@ -5,14 +5,6 @@ abstract class AppColors {
static const mainAccent = const Color(0xFFFFCC11);
static const mainBackground = const Color(0xFFF2EFFF);
// snack bar
static const snackBarBackSuccess = const Color(0xFFB9E9D4);
static const snackBarBackError = const Color(0xFFFFDAD4);
static const snackBarBackInfo = const Color(0xFFDAE2FF);
static const snackBarTextSuccess = const Color(0xFF006C4D);
static const snackBarTextError = const Color(0xFF930006);
static const snackBarTextInfo = const Color(0xFF002A78);
static const mainDarkBlue = Color.fromRGBO(3, 37, 65, 1);
static const mainLightBlue = Color.fromRGBO(48, 86, 117, 1);
}