Compare commits

...

17 Commits
main ... main

Author SHA1 Message Date
dac68c0b86 added clipboard svg to prep copy button 2023-05-19 09:49:59 -06:00
136e7efc3d WIP: moved functions around, working on pub/priv key display 2023-05-19 09:49:35 -06:00
6012526b33 Custom text button widget 2023-05-19 09:48:21 -06:00
ab899e7501 WIP: working on avatar and username 2023-05-19 09:47:50 -06:00
5bda858a02 changed button color 2023-05-19 09:47:16 -06:00
c43e182a52 updated dialogs 2023-05-19 09:46:45 -06:00
d7769061c5 added keyboard dismisser 2023-05-16 08:52:29 -06:00
05dc4bdd94 added x.svg for close dialogue button 2023-05-15 18:34:14 -06:00
264313abfa added x.svg for close dialogue button 2023-05-15 18:33:32 -06:00
834af8472a added flush bar for keys gen/delete 2023-05-15 14:32:54 -06:00
651a4e2421 added flush bar + moved widgets 2023-05-15 14:31:35 -06:00
578a461075 added rotating icon to splash loading 2023-05-15 09:55:49 -06:00
41e0117c65 added app name and icon to splash, prep for rotate icon 2023-05-12 16:23:40 -06:00
01652be658 updated assets path 2023-05-12 16:22:37 -06:00
f6a466872f added drifter image and app name to splash 2023-05-12 13:29:44 -06:00
795afcb0f4 adjusted path to show images 2023-05-12 13:29:12 -06:00
a5a6133a40 Merge pull request 'main' (#1) from alexvasl/drifter_app:main into main
Reviewed-on: ryleedavis/drifter_app#1
2023-05-12 17:46:08 +00:00
26 changed files with 637 additions and 871 deletions

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.3652 3.12516H13.4359C12.9626 1.79313 11.7021 0.833496 10.209 0.833496C8.71582 0.833496 7.4554 1.79313 6.98275 3.12516H5.05273C4.10384 3.12516 3.33398 3.8943 3.33398 4.84391V17.4481C3.33398 18.397 4.10384 19.1668 5.05273 19.1668H15.3652C16.3141 19.1668 17.084 18.3977 17.084 17.4481V4.84391C17.084 3.8943 16.3141 3.12516 15.3652 3.12516ZM10.209 3.12516C10.8417 3.12516 11.3548 3.63828 11.3548 4.271C11.3548 4.90371 10.8417 5.41683 10.209 5.41683C9.57627 5.41683 9.06315 4.90478 9.06315 4.271C9.06315 3.63828 9.5752 3.12516 10.209 3.12516ZM6.87565 8.75016C6.87565 8.52004 7.0622 8.3335 7.29232 8.3335H13.1257C13.3558 8.3335 13.5423 8.52004 13.5423 8.75016V9.16683C13.5423 9.39695 13.3558 9.5835 13.1257 9.5835H7.29232C7.0622 9.5835 6.87565 9.39695 6.87565 9.16683V8.75016ZM6.87565 12.0835C6.87565 11.8534 7.0622 11.6668 7.29232 11.6668H13.1257C13.3558 11.6668 13.5423 11.8534 13.5423 12.0835V12.5002C13.5423 12.7303 13.3558 12.9168 13.1257 12.9168H7.29232C7.0622 12.9168 6.87565 12.7303 6.87565 12.5002V12.0835ZM6.87565 15.4168C6.87565 15.1867 7.0622 15.0002 7.29232 15.0002H13.1257C13.3558 15.0002 13.5423 15.1867 13.5423 15.4168V15.8335C13.5423 16.0636 13.3558 16.2502 13.1257 16.2502H7.29232C7.0622 16.2502 6.87565 16.0636 6.87565 15.8335V15.4168Z" fill="#A9ACAC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

4
assets/images/svg/x.svg Normal file
View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 5L5 15" stroke="#8A95B2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 5L15 15" stroke="#8A95B2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 311 B

View File

@ -1,10 +1,7 @@
import 'dart:io';
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
import 'package:drifter/pages/splash_screen/splash_screen.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
void main() {
runApp(const MyApp());
@ -15,17 +12,19 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
appBarTheme: const AppBarTheme(backgroundColor: AppColors.background),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: AppColors.background,
selectedItemColor: AppColors.mainAccent,
unselectedItemColor: Colors.grey,
return KeyboardDismisser(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
appBarTheme: const AppBarTheme(backgroundColor: AppColors.background),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: AppColors.background,
selectedItemColor: AppColors.mainAccent,
unselectedItemColor: Colors.grey,
),
),
home: const Splash(),
),
home: const Splash(),
);
}
}

View File

@ -32,6 +32,7 @@ class _MainScreenWidgetState extends State<MainScreenWidget> {
title: Row(
// mainAxisAlignment: MainAxisAlignment.center,
children: [
// use png instead
SvgPicture.asset(
Assets.svg.drifterIcon,
height: 30,

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,137 +126,7 @@ class ProfileScreenState extends State<ProfileScreen> {
});
}
@override
Widget build(BuildContext context) {
privateKeyInput.text = Keys.nsecKey;
publicKeyInput.text = Keys.npubKey;
return ListView(
children: [
SizedBox(
height: 60,
),
UserInfo(),
SizedBox(
height: 40,
),
FormKeys(),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Keys.keysExist
? ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
AppColors.mainDarkBlue)),
onPressed: () {
keysExistDialog(
Nostr.instance.keysService
.encodePublicKeyToNpub(Keys.publicKey),
Nostr.instance.keysService
.encodePrivateKeyToNsec(Keys.privateKey),
);
},
child: Text(
'Keys',
),
)
: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
AppColors.mainDarkBlue)),
onPressed: () {
modalBottomSheet();
},
child: Text(
'Generate Keys',
),
),
Keys.keysExist
? Row(
children: [
IconButton(
onPressed: () {
deleteKeysDialog();
},
icon: const Icon(Icons.delete)),
],
)
: Container(),
],
),
)
],
);
}
Form FormKeys() {
return Form(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
controller: privateKeyInput,
// _toHex ? widget.hexPriv : widget.nsecEncoded,
decoration: const InputDecoration(
labelText: 'Private Key',
border: OutlineInputBorder(),
),
maxLength: 64,
),
const SizedBox(
height: 20,
),
TextFormField(
controller: publicKeyInput,
// _toHex ? widget.hexPub : widget.npubEncoded,
decoration: const InputDecoration(
labelText: 'Public Key',
border: OutlineInputBorder(),
),
),
const SizedBox(
height: 40,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Relay',
border: OutlineInputBorder(),
),
),
],
),
),
);
}
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 {
void _keysExistDialog(String npubEncode, String nsecEncode) async {
await showDialog(
context: context,
builder: ((context) {
@ -270,30 +140,172 @@ class ProfileScreenState extends State<ProfileScreen> {
);
}
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,
@override
Widget build(BuildContext context) {
privateKeyInput.text = Keys.nsecKey;
publicKeyInput.text = Keys.npubKey;
return Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
height: 60,
),
UserInfo(),
const SizedBox(
height: 40,
),
Row(
children: [
Text(
"Public Key",
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
],
),
const SizedBox(height: 12),
publicKeyInput.text.isNotEmpty
? SelectableText(
publicKeyInput.text,
style: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
);
}
});
Navigator.pop(context);
},
);
}),
)
: Text(
"Public Key empty",
textAlign: TextAlign.left,
),
const SizedBox(
height: 12,
),
Row(
children: [
Text(
"Private Key",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
],
),
const SizedBox(height: 12),
privateKeyInput.text.isNotEmpty
? SelectableText(
privateKeyInput.text,
style: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
)
: Text(
"Private Key empty",
textAlign: TextAlign.left,
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Keys.keysExist
? Row(
children: [
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.grey[500]),
),
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);
},
),
);
},
child: Text(
"Delete",
),
),
],
)
: Container(),
Keys.keysExist
? ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(AppColors.background),
),
onPressed: () {
_keysExistDialog(
Nostr.instance.keysService
.encodePublicKeyToNpub(Keys.publicKey),
Nostr.instance.keysService
.encodePrivateKeyToNsec(Keys.privateKey),
);
},
child: Text(
"Keys",
),
)
: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(AppColors.background),
),
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,
);
}
},
);
},
child: const Text(
"Generate Keys",
),
),
],
),
],
),
);
}
}

View File

@ -1,87 +0,0 @@
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

@ -1,128 +0,0 @@
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

@ -1,128 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,46 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,97 +0,0 @@
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,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
import 'ok_button_widget.dart';
@ -16,70 +15,60 @@ class DeleteKeysDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12),
// ),
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
constraints: BoxConstraints(
maxWidth: 700,
maxHeight: 190,
),
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,
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Delete Keys",
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
const SizedBox(height: 16),
Text(
"Are you sure you want to delete your keys?",
// textAlign: TextAlign.c,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'Do you want to delete your keys?',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
OkButton(
onPressed: onNoPressed,
label: "No",
),
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',
),
],
const SizedBox(
width: 8,
),
OkButton(
onPressed: onYesPressed,
label: "Yes",
),
],
),
)
],
)
],
),
),
),
);

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
class DrifterDialog extends StatelessWidget {
const DrifterDialog({
Key? key,
this.child,
this.maxWidth = 150,
this.maxHeight = 150,
}) : super(key: key);
final Widget? child;
final double maxWidth;
final double maxHeight;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: maxWidth,
maxHeight: maxHeight,
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(
20,
),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(
20,
),
),
child: child,
),
),
),
],
);
}
}

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
import 'ok_button_widget.dart';
@ -31,35 +30,34 @@ class _KeysExistDialogState extends State<KeysExistDialog> {
borderRadius: BorderRadius.circular(12),
),
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
constraints: BoxConstraints(
maxWidth: 700,
maxHeight: 340,
),
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,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Keys",
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
],
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
const SizedBox(height: 24),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
@ -96,31 +94,53 @@ class _KeysExistDialogState extends State<KeysExistDialog> {
),
),
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',
),
],
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
elevation: 3.0,
onPressed: () {
Navigator.of(context).pop();
},
color: Colors.grey[400],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8.0,
),
),
child: Text(
"Cancel",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
_toHex
? OkButton(
onPressed: () {
setState(() {
_toHex = !_toHex;
});
},
label: "Encoded",
)
: OkButton(
onPressed: () {
setState(() {
_toHex = !_toHex;
});
},
label: "Hex",
),
],
),
)
],
),
),
],
],
),
),
),
);

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
class OkButton extends StatelessWidget {
const OkButton({
@ -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

@ -1,4 +1,3 @@
import 'package:drifter/theme/app_colors.dart';
import 'package:flutter/material.dart';
class UserInfo extends StatelessWidget {
@ -8,7 +7,7 @@ class UserInfo extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
children: const [
AvatarWidget(),
SizedBox(
height: 10,
@ -25,13 +24,19 @@ class AvatarWidget extends StatelessWidget {
@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,
// todo: create a slide up to choose avatar
return CircleAvatar(
backgroundImage: NetworkImage('https://via.placeholder.com/150'),
// backgroundColor: AppColors.mainAccent,
radius: 40,
);
// return Container(
// decoration: BoxDecoration(
// border: Border.all(color: Colors.black),
// borderRadius: BorderRadius.all(Radius.circular(75))),
// width: 150,
// height: 150,
// );
}
}
@ -75,20 +80,13 @@ class _UserNameWidgetState extends State<UserNameWidget> {
child: TextField(
controller: messageController,
focusNode: messageFocusNode,
textAlign: TextAlign.center,
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,9 +1,9 @@
import 'dart:io';
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:flutter/cupertino.dart';
import 'package:drifter/utilities/assets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class Splash extends StatefulWidget {
const Splash({super.key});
@ -13,44 +13,76 @@ class Splash extends StatefulWidget {
}
class _SplashState extends State<Splash> {
late final RotateIconController _rotateIconController;
@override
void initState() {
super.initState();
_rotateIconController = RotateIconController();
Future.delayed(const Duration(seconds: 3), () {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => const MainScreenWidget()));
});
super.initState();
}
@override
dispose() {
_rotateIconController.repeat = null;
_rotateIconController.reset = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
_rotateIconController.reset?.call();
_rotateIconController.repeat?.call();
return Scaffold(
backgroundColor: AppColors.background,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 300,
),
Image.asset(
'assets/images/logo/drifter_vector.png',
height: 111,
width: 93,
),
const SizedBox(
height: 250,
),
if (Platform.isAndroid)
const CircularProgressIndicator(
color: AppColors.mainAccent,
)
else
const CupertinoActivityIndicator(
radius: 20,
)
],
)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 200,
),
SvgPicture.asset(
Assets.svg.drifterIcon,
height: 150,
width: 150,
),
const SizedBox(
height: 10,
),
const Text(
"Drifter",
style: TextStyle(
color: AppColors.mainAccent,
fontSize: 50,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 230,
),
//replace with rotating drifter icon
RotateIcon(
icon: SvgPicture.asset(
Assets.svg.drifterIcon,
height: 45,
width: 45,
),
curve: Curves.easeInOutSine,
animationDurationMultiplier: 1.2,
rotationPercent: 1.0,
controller: _rotateIconController,
),
],
),
),
);
}
}

View File

@ -0,0 +1,76 @@
import 'package:flutter/widgets.dart';
class RotateIconController {
// VoidCallback? forward;
VoidCallback? repeat;
VoidCallback? reset;
}
class RotateIcon extends StatefulWidget {
const RotateIcon({
Key? key,
required this.icon,
required this.curve,
this.controller,
this.animationDurationMultiplier = 1.0,
this.rotationPercent = 0.5,
}) : super(key: key);
final Widget icon;
final Curve curve;
final RotateIconController? controller;
final double animationDurationMultiplier;
final double rotationPercent;
@override
State<RotateIcon> createState() => _RotateIconState();
}
class _RotateIconState extends State<RotateIcon>
with SingleTickerProviderStateMixin {
late final AnimationController animationController;
late final Animation<double> animation;
late final Duration duration;
@override
void initState() {
duration = Duration(
milliseconds: (500 * widget.animationDurationMultiplier).toInt(),
);
animationController = AnimationController(
vsync: this,
duration: duration,
);
animation = Tween<double>(
begin: 0.0,
end: widget.rotationPercent,
).animate(
CurvedAnimation(
curve: widget.curve,
parent: animationController,
),
);
// widget.controller?.forward = animationController.forward;
widget.controller?.repeat = animationController.repeat;
widget.controller?.reset = animationController.reset;
super.initState();
}
@override
void dispose() {
animationController.dispose();
// widget.controller?.forward = null;
widget.controller?.repeat = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: animation,
child: widget.icon,
);
}
}

View File

@ -0,0 +1,32 @@
/// work for close dialogue button
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// Container(
// height: 30,
// width: 30,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(1000),
// color: Colors.grey[350],
// // boxShadow: shadows,
// ),
// child: MaterialButton(
// onPressed: () {
// Navigator.of(context).pop();
// },
// splashColor: Colors.grey[400],
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(1000),
// ),
// padding: EdgeInsets.all(2.0),
// child: SvgPicture.asset(
// Assets.svg.x,
// // height: ,
// // width: 35,
// color: Colors.grey[700],
// ),
// ),
// ),
// ],
// ),

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
enum ButtonHeight {
xxs,
xs,
s,
m,
l,
xl,
xxl,
}
class CustomTextButtonBase extends StatelessWidget {
const CustomTextButtonBase({
Key? key,
this.width,
this.height,
this.textButton,
}) : super(key: key);
final double? width;
final double? height;
final TextButton? textButton;
@override
Widget build(BuildContext context) {
return SizedBox(
height: height,
width: width,
child: textButton,
);
}
}

View File

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

View File

@ -0,0 +1,64 @@
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,6 +5,14 @@ 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);
}

View File

@ -6,11 +6,12 @@ abstract class Assets {
class _PNG {
const _PNG();
// String get drifterIcon => "assets/images/logo/drifter_vector.png";
String get drifterPNG => "assets/images/logo/drifter_vector.png";
}
class _SVG {
const _SVG();
String get drifterIcon => "assets/images/logo/drifter_logo_circle.svg";
String get x => "assets/images/svg/x.svg";
}

View File

@ -34,6 +34,7 @@ dependencies:
nostr_tools: ^1.0.7
flutter_secure_storage: ^8.0.0
flutter_svg: ^2.0.5
keyboard_dismisser: ^3.0.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
@ -63,7 +64,8 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/
- assets/images/logo/
- assets/images/svg/
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see