diff --git a/lib/lib/constants/constants.dart b/lib/lib/constants/constants.dart deleted file mode 100644 index 574d308..0000000 --- a/lib/lib/constants/constants.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:flutter/material.dart'; - -String avatarUrl = "https://sweary.com/avatar-generator/"; -String imageSize = "size=200x200"; diff --git a/lib/lib/domain_models/domain_models.dart b/lib/lib/domain_models/domain_models.dart deleted file mode 100644 index 1f78fda..0000000 --- a/lib/lib/domain_models/domain_models.dart +++ /dev/null @@ -1,21 +0,0 @@ -class Domain { - final String noteId; - final String avatarUrl; - final String name; - final String username; - final String time; - final String content; - final String pubkey; - final String? imageUrl; - - Domain({ - required this.noteId, - required this.avatarUrl, - required this.name, - required this.username, - required this.time, - required this.content, - required this.pubkey, - this.imageUrl, - }); -} diff --git a/lib/lib/main.dart b/lib/lib/main.dart deleted file mode 100644 index fd22fb8..0000000 --- a/lib/lib/main.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/theme/app_colors.dart'; - -import 'package:drifter/widgets/main_screen/main_screen_widget.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - appBarTheme: const AppBarTheme(backgroundColor: AppColors.mainDarkBlue), - primarySwatch: Colors.blue, - bottomNavigationBarTheme: const BottomNavigationBarThemeData( - backgroundColor: AppColors.mainDarkBlue, - selectedItemColor: Colors.white, - unselectedItemColor: Colors.grey, - ), - ), - home: const MainScreenWidget(), - ); - } -} diff --git a/lib/lib/models/keys.dart b/lib/lib/models/keys.dart deleted file mode 100644 index 16ca934..0000000 --- a/lib/lib/models/keys.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:nostr_tools/nostr_tools.dart'; - -class Keys { - static String privateKey = ''; - static String publicKey = ''; - static bool keysExist = false; -} - -class Relay { - static final relay = RelayApi(relayUrl: 'wss://relay.damus.io'); -} diff --git a/lib/lib/theme/app_colors.dart b/lib/lib/theme/app_colors.dart deleted file mode 100644 index 1ba08a9..0000000 --- a/lib/lib/theme/app_colors.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter/material.dart'; - -abstract class AppColors { - static const mainDarkBlue = Color.fromRGBO(3, 37, 65, 1); - static const mainLightBlue = Color.fromRGBO(48, 86, 117, 1); -} diff --git a/lib/lib/widgets/home_screen/home_screen_widget.dart b/lib/lib/widgets/home_screen/home_screen_widget.dart deleted file mode 100644 index 9e24614..0000000 --- a/lib/lib/widgets/home_screen/home_screen_widget.dart +++ /dev/null @@ -1,442 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:drifter/domain_models/domain_models.dart'; -import 'package:drifter/models/keys.dart'; -import 'package:drifter/theme/app_colors.dart'; -import 'package:drifter/widgets/home_screen/home_screen_widgets/message_ok_button_widget.dart'; -import 'package:drifter/widgets/home_screen/home_screen_widgets/message_text_button_widget.dart'; -import 'package:drifter/widgets/home_screen/home_screen_widgets/message_text_form_field_widget.dart'; -import 'package:drifter/widgets/profile_screen/profile_screen_widgets/message_snack_bar.dart'; -import 'package:nostr_tools/nostr_tools.dart'; - -import '../profile_screen/profile_screen.dart'; - -class HomeScreen extends StatefulWidget { - const HomeScreen({super.key}); - - @override - State createState() => _HomeScreenState(); -} - -class _HomeScreenState extends State { - bool _isConnected = false; - - final List _events = []; - final Map _metaDatas = {}; - late Stream _stream; - final _controller = StreamController(); - - bool _isNotePublishing = false; - - @override - void initState() { - _initStream(); - super.initState(); - } - - Future> _connectToRelay() async { - final stream = await Relay.relay.connect(); - - Relay.relay.on((event) { - if (event == RelayEvent.connect) { - setState(() => _isConnected = true); - } else if (event == RelayEvent.error) { - setState(() => _isConnected = false); - } - }); - - Relay.relay.sub([ - Filter( - kinds: [1], - limit: 100, - t: ['nostr'], - ) - ]); - - return stream - .where((message) => message.type == 'EVENT') - .map((message) => message.message); - } - - void _initStream() async { - _stream = await _connectToRelay(); - _stream.listen((message) { - final event = message; - if (event.kind == 1) { - setState(() => _events.add(event)); - Relay.relay.sub([ - Filter(kinds: [0], authors: [event.pubkey]) - ]); - } else if (event.kind == 0) { - final metadata = Metadata.fromJson(jsonDecode(event.content)); - setState(() => _metaDatas[event.pubkey] = metadata); - } - _controller.add(event); - }); - } - -// The _resubscribeStream() method clears the _events and _metaData scollection after a 1 second delay - Future _resubscribeStream() async { - await Future.delayed(const Duration(seconds: 1), () { - setState(() { - _events.clear(); - _metaDatas.clear(); - }); - // _initStream() method, responsible for initializing and subscribing to the stream, to reconnect and re-subscribe to the filter. - _initStream(); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: RefreshIndicator( - onRefresh: () async { - await _resubscribeStream(); - }, - child: StreamBuilder( - stream: _controller.stream, - builder: (context, snapshot) { - // Inside the builder callback, the snapshot object contains the most recent event from the thread. - // If snapshot.hasData is true, there is data to display. In this case, ListView.builder is returned, which displays a list of NoostCard widgets. - if (snapshot.hasData) { - return ListView.builder( - // The itemCount property of ListView.builder is set to _events.length, , which is the number of events in the _events list. - itemCount: _events.length, - itemBuilder: (context, index) { - final event = _events[index]; - final metadata = _metaDatas[event.pubkey]; - // For each event, a Noost object is created that encapsulates the details of the event, including id, avatarUrl, name,username, time, content и pubkey. - // _metaDatas, you can map the event public key to the author's metadata. - final domain = Domain( - noteId: event.id, - avatarUrl: metadata?.picture ?? - 'https://robohash.org/${event.pubkey}', - name: metadata?.name ?? 'Anon', - username: metadata?.displayName ?? - (metadata?.display_name ?? 'Anon'), - time: TimeAgo.format(event.created_at), - content: event.content, - pubkey: event.pubkey, - ); - return DomainCard(domain: domain); - }, - ); - } else if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: Text('Loading....')); - } else if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } - return const CenteredCircularProgressIndicator(); - }, - ), - ), - floatingActionButton: Keys.keysExist - ? CreatePost( - // The publishNote function is called when the user launches the "Noost!" button in the dialog box. - publishNote: (note) { - setState(() => _isNotePublishing = true); - - // EventApi Creates an instance of the class defined in the nostr_tools package. - final eventApi = EventApi(); - // The finishEvent method of the EventApi class is called with the Event object and the _privateKey variable. - // finishEvent will set the event id with the event hash and sign the event with the given _privateKey. - final event = eventApi.finishEvent( - // This creates a new instance of the Event class with certain properties, such as: - Event( - kind: 1, - tags: [ - ['t', 'nostr'] - ], - content: note!, - created_at: DateTime.now().millisecondsSinceEpoch ~/ 1000, - ), - Keys.publicKey, - ); - if (eventApi.verifySignature(event)) { - try { - // If the signature is verified, the _relay method is called for the object to publish the event. - Relay.relay.publish(event); - // After the _resubscribeStream event is published, a method is called that will probably update the stream or subscription to reflect the recently published event. - _resubscribeStream(); - // Show SnackBar to display a message that the note has been successfully published. - ScaffoldMessenger.of(context).showSnackBar( - MessageSnackBar( - label: 'Congratulations! Noost Published!'), - ); - } catch (_) { - // If an error occurs during the publishing process (e.g., an exception is caught), SnackBar displays a warning instead. - ScaffoldMessenger.of(context).showSnackBar(MessageSnackBar( - label: 'Oops! Something went wrong!', - isWarning: true, - )); - } - } - setState(() => _isNotePublishing = false); - Navigator.pop(context); - }, - isNotePublishing: _isNotePublishing, - ) - : - // If _keysExist is false, then an empty widget is displayed, which means that the FAB will not be visible. Container() - Container(), - ); - } -} - -class TimeAgo { - static String format(int timestamp) { - DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); - Duration difference = DateTime.now().difference(dateTime); - - String timeAgo = ''; - - if (difference.inDays > 0) { - timeAgo = - '${difference.inDays} ${difference.inDays == 1 ? 'day' : 'days'} ago'; - } else if (difference.inHours > 0) { - timeAgo = - '${difference.inHours} ${difference.inHours == 1 ? 'hour' : 'hours'} ago'; - } else if (difference.inMinutes > 0) { - timeAgo = - '${difference.inMinutes} ${difference.inMinutes == 1 ? 'minute' : 'minutes'} ago'; - } else { - timeAgo = 'just now'; - } - - return timeAgo; - } -} - -class DomainCard extends StatelessWidget { - const DomainCard({ - super.key, - required this.domain, - }); - - final Domain domain; - - List? extractImage(String text) { - final RegExp exp = RegExp( - r"(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|jpeg)", - caseSensitive: false, - multiLine: true, - ); - - final Iterable matches = exp.allMatches(text); - - final List imageLinks = - matches.map((match) => match.group(0)!).toList(); - - return imageLinks.isNotEmpty ? imageLinks : null; - } - - @override - Widget build(BuildContext context) { - final List? imageLinks = extractImage(domain.content); - return Container( - margin: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: AppColors.mainLightBlue, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: const Offset(0, 3), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListTile( - leading: CircleAvatar( - 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), - ), - Divider(height: 1, color: Colors.grey.shade400), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Text(domain.content, - style: const TextStyle(color: Colors.white)), - ), - if (imageLinks != null && imageLinks.isNotEmpty) - Center( - child: Stack( - children: [ - const Placeholder( - fallbackHeight: 200, - color: Colors.transparent, - ), - Center( - child: FadeInImage( - placeholder: const NetworkImage( - 'https://i.ibb.co/D9jqXgR/58038897-167f0280-7ae6-11e9-94eb-88e880a25f0f.gif', - ), - image: NetworkImage(imageLinks.first), - fit: BoxFit.cover, - ), - ), - ], - ), - ), - ], - ), - ); - } -} - -class CenteredCircularProgressIndicator extends StatelessWidget { - const CenteredCircularProgressIndicator({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return const Center( - child: CircularProgressIndicator(), - ); - } -} - -class CreatePost extends StatefulWidget { - const CreatePost({ - Key? key, - required this.publishNote, - required this.isNotePublishing, - }) : super(key: key); - - final Function(String?) publishNote; - final bool isNotePublishing; - - @override - State createState() => _CreatePostState(); -} - -class _CreatePostState extends State { - final _noteController = TextEditingController(); - final GlobalKey _formKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return FloatingActionButton( - backgroundColor: Colors.deepPurpleAccent, - tooltip: 'Create a new post', - elevation: 2, - highlightElevation: 4, - foregroundColor: Colors.white, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: const BoxDecoration( - shape: BoxShape.circle, color: AppColors.mainDarkBlue), - ), - const Icon( - Icons.add, - color: Colors.white, - ), - ], - ), - onPressed: () async { - _noteController.clear(); - await showDialog( - barrierDismissible: false, - context: context, - builder: ((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( - 'Create a Noost', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ), - const SizedBox(height: 24), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: MessageTextFormField( - maxLines: 5, - hintText: 'Type your Noost here...', - controller: _noteController, - formKey: _formKey, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return 'Please enter your note.'; - } - return null; - }, - ), - ), - const SizedBox(height: 24), - widget.isNotePublishing - ? const CenteredCircularProgressIndicator() - : Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - MessageTextButton( - onPressed: () { - Navigator.pop(context); - }, - label: 'Cancel', - ), - const SizedBox(width: 16), - MessageOkButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - widget.publishNote( - _noteController.text.trim()); - } else { - _formKey.currentState?.setState(() {}); - } - }, - label: 'Noost!', - ), - const SizedBox(width: 24), - ], - ) - ], - ), - ), - ); - }), - ); - }, - ); - } -} diff --git a/lib/lib/widgets/home_screen/home_screen_widgets/message_ok_button_widget.dart b/lib/lib/widgets/home_screen/home_screen_widgets/message_ok_button_widget.dart deleted file mode 100644 index 5585bcd..0000000 --- a/lib/lib/widgets/home_screen/home_screen_widgets/message_ok_button_widget.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/theme/app_colors.dart'; - -class MessageOkButton extends StatelessWidget { - const MessageOkButton({ - 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, - ), - ), - ); - } -} diff --git a/lib/lib/widgets/home_screen/home_screen_widgets/message_text_button_widget.dart b/lib/lib/widgets/home_screen/home_screen_widgets/message_text_button_widget.dart deleted file mode 100644 index 252ac8d..0000000 --- a/lib/lib/widgets/home_screen/home_screen_widgets/message_text_button_widget.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/theme/app_colors.dart'; - -class MessageTextButton extends StatelessWidget { - const MessageTextButton({ - super.key, - required this.onPressed, - required this.label, - this.color, - }); - - final void Function()? onPressed; - final String label; - final Color? color; - - @override - Widget build(BuildContext context) { - return TextButton( - onPressed: onPressed, - child: Text( - label, - style: TextStyle( - color: AppColors.mainDarkBlue, - ), - ), - ); - } -} diff --git a/lib/lib/widgets/home_screen/home_screen_widgets/message_text_form_field_widget.dart b/lib/lib/widgets/home_screen/home_screen_widgets/message_text_form_field_widget.dart deleted file mode 100644 index 8b51e48..0000000 --- a/lib/lib/widgets/home_screen/home_screen_widgets/message_text_form_field_widget.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/theme/app_colors.dart'; - -class MessageTextFormField extends StatelessWidget { - const MessageTextFormField({ - super.key, - required this.hintText, - required this.controller, - required this.formKey, - required this.validator, - this.maxLines, - }); - - final String hintText; - final TextEditingController controller; - final Key formKey; - final String? Function(String?)? validator; - final int? maxLines; - - @override - Widget build(BuildContext context) { - return TextFormField( - controller: controller, - key: formKey, - validator: validator, - maxLines: maxLines, - style: const TextStyle(color: Colors.black), - decoration: InputDecoration( - hintText: hintText, - hintStyle: const TextStyle(color: Colors.black54), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: Colors.black54), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: Colors.black54), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: AppColors.mainDarkBlue), - ), - ), - ); - } -} diff --git a/lib/lib/widgets/main_screen/main_screen_widget.dart b/lib/lib/widgets/main_screen/main_screen_widget.dart deleted file mode 100644 index a6c02ec..0000000 --- a/lib/lib/widgets/main_screen/main_screen_widget.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/widgets/home_screen/home_screen_widget.dart'; -import 'package:drifter/widgets/message_screen/message_screen_widget.dart'; -import 'package:drifter/widgets/profile_screen/profile_screen.dart'; - -class MainScreenWidget extends StatefulWidget { - const MainScreenWidget({super.key}); - - @override - State createState() => _MainScreenWidgetState(); -} - -class _MainScreenWidgetState extends State { - int _selectedTap = 0; - - void onSelectedtap(int index) { - if (_selectedTap == index) return; - setState(() { - _selectedTap = index; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Drifter'), - centerTitle: true, - ), - body: IndexedStack( - index: _selectedTap, - children: [ - HomeScreen(), - // MessageScreen(), - ProfileScreen(), - ], - ), - bottomNavigationBar: BottomNavigationBar( - currentIndex: _selectedTap, - items: [ - BottomNavigationBarItem( - icon: Icon(Icons.home), - label: 'Home', - ), - // BottomNavigationBarItem( - // icon: Icon(Icons.message), - // label: 'Message', - // ), - BottomNavigationBarItem( - icon: Icon(Icons.person), - label: 'Profile', - ), - ], - onTap: onSelectedtap, - ), - ); - } -} diff --git a/lib/lib/widgets/message_screen/message_screen_widget.dart b/lib/lib/widgets/message_screen/message_screen_widget.dart deleted file mode 100644 index 507672d..0000000 --- a/lib/lib/widgets/message_screen/message_screen_widget.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:drifter/theme/app_colors.dart'; - -class MessageScreen extends StatefulWidget { - const MessageScreen({super.key}); - - @override - State createState() => _MessageScreenState(); -} - -class _MessageScreenState extends State { - @override - Widget build(BuildContext context) { - return Stack( - children: [ - ListView( - padding: EdgeInsets.all(16), - children: [ - Center( - child: Text('List of posts'), - ) - ], - ), - MessageInput(), - ], - ); - } -} - -class MessageInput extends StatefulWidget { - const MessageInput({ - super.key, - }); - - @override - State createState() => _MessageInputState(); -} - -class _MessageInputState extends State { - final messageController = TextEditingController(); - - void submitData() { - final newMessage = messageController; - } - - @override - Widget build(BuildContext context) { - return Align( - alignment: Alignment.bottomCenter, - child: Container( - padding: const EdgeInsets.only(bottom: 16, left: 8, right: 8, top: 8), - child: Row( - children: [ - GestureDetector( - onTap: () {}, - child: const Icon( - Icons.add_a_photo, - color: AppColors.mainDarkBlue, - size: 30, - ), - ), - const SizedBox( - width: 8, - ), - Expanded( - child: TextField( - style: const TextStyle(fontSize: 20), - decoration: InputDecoration( - border: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - hintText: 'What\'s new?', - hintStyle: const TextStyle(fontSize: 20), - suffixIcon: IconButton( - icon: const Icon( - Icons.send, - color: AppColors.mainDarkBlue, - size: 30, - ), - onPressed: () { - submitData(); - }, - ), - ), - ), - ), - ], - ), - ), - ); - } -} - -class NewMessage extends StatefulWidget { - const NewMessage({super.key}); - - @override - State createState() => _NewMessageState(); -} - -class _NewMessageState extends State { - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen.dart b/lib/lib/widgets/profile_screen/profile_screen.dart deleted file mode 100644 index d89629d..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen.dart +++ /dev/null @@ -1,271 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:drifter/models/keys.dart'; -import 'package:drifter/theme/app_colors.dart'; -import 'package:nostr_tools/nostr_tools.dart'; - -import 'profile_screen_widgets/delete_keys_dialog.dart'; -import 'profile_screen_widgets/key_exist_dialog.dart'; -import 'profile_screen_widgets/keys_option_modal_bottom_sheet.dart'; -import 'profile_screen_widgets/message_snack_bar.dart'; -import 'profile_screen_widgets/user_info_widget.dart'; - -class ProfileScreen extends StatefulWidget { - const ProfileScreen({super.key}); - - @override - State createState() => ProfileScreenState(); -} - -class ProfileScreenState extends State { - final _secureStorage = const FlutterSecureStorage(); - - TextEditingController privateKeyInput = TextEditingController(); - TextEditingController publicKeyInput = TextEditingController(); - TextEditingController relayInput = TextEditingController(); - - final keyGenerator = KeyApi(); - final nip19 = Nip19(); - - void initState() { - _getKeysFromStorage(); - super.initState(); - } - - Future generateNewKeys() async { - final newPrivateKey = keyGenerator.generatePrivateKey(); - final nsec = nip19.nsecEncode(newPrivateKey); - final nsecDecoded = nip19.decode(nsec); - assert(nsecDecoded['type'] == 'nsec'); - assert(nsecDecoded['data'] == newPrivateKey); - - final newPublicKey = keyGenerator.getPublicKey(newPrivateKey); - final npub = nip19.npubEncode(newPublicKey); - final npubDecoded = nip19.decode(npub); - assert(npubDecoded['type'] == 'npub'); - assert(npubDecoded['data'] == newPublicKey); - return await _addKeyToStorage(nsec, npub); - } - - Future _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'); - // 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) { - setState(() { - Keys.privateKey = storedPrivateKey; - Keys.publicKey = storedPublicKey; - Keys.keysExist = true; - }); - } - } - - // Adding a new key -// Writing a private and public key to a secure vault - Future _addKeyToStorage( - String privateKeyHex, - String publicKeyHex, - ) async { -// Waiting for both write operations to complete - Future.wait([ - _secureStorage.write(key: 'privateKey', value: privateKeyHex), - _secureStorage.write(key: 'publicKey', value: privateKeyHex), - ]); - - // Updating status variables and starting widget rebuilding - setState(() { - Keys.privateKey = privateKeyHex; - Keys.publicKey = publicKeyHex; - Keys.keysExist = true; - }); - -// Returns a boolean value indicating whether the keys were successfully added to the repository or not. - return Keys.keysExist; - } - - Future _deleteKeysStorage() async { - // Calling secure storage to remove keys from storage - Future.wait([ - _secureStorage.delete(key: 'privateKey'), - _secureStorage.delete(key: 'publicKey'), - ]); - - // Updating status variables, resetting values after deleting keys from the repository - setState(() { - Keys.privateKey = ''; - Keys.publicKey = ''; - Keys.keysExist = false; - }); - } - - @override - Widget build(BuildContext context) { - privateKeyInput.text = Keys.privateKey; - publicKeyInput.text = Keys.publicKey; - relayInput.text = Relay.relay.relayUrl; - - 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( - nip19.npubEncode(Keys.publicKey), - nip19.nsecEncode(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(), - ), - ), - 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( - controller: relayInput, - 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 { - 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); - }, - ); - }), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/delete_keys_dialog.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/delete_keys_dialog.dart deleted file mode 100644 index 8e4874f..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/delete_keys_dialog.dart +++ /dev/null @@ -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', - ), - ], - ), - ], - ), - ) - ], - ), - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/generated_keys.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/generated_keys.dart deleted file mode 100644 index 4049374..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/generated_keys.dart +++ /dev/null @@ -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 createState() => _GeneratedKeysState(); -} - -class _GeneratedKeysState extends State { - 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', - ), - ], - ) - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/key_exist_dialog.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/key_exist_dialog.dart deleted file mode 100644 index d74e34f..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/key_exist_dialog.dart +++ /dev/null @@ -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 createState() => _KeysExistDialogState(); -} - -class _KeysExistDialogState extends State { - 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', - ), - ], - ) - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/keys_option_modal_bottom_sheet.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/keys_option_modal_bottom_sheet.dart deleted file mode 100644 index 25ad2e5..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/keys_option_modal_bottom_sheet.dart +++ /dev/null @@ -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), - ], - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/message_snack_bar.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/message_snack_bar.dart deleted file mode 100644 index d5c4fd1..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/message_snack_bar.dart +++ /dev/null @@ -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, - ), - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/ok_button_widget.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/ok_button_widget.dart deleted file mode 100644 index 6dbaad7..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/ok_button_widget.dart +++ /dev/null @@ -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, - ), - ), - ); - } -} diff --git a/lib/lib/widgets/profile_screen/profile_screen_widgets/user_info_widget.dart b/lib/lib/widgets/profile_screen/profile_screen_widgets/user_info_widget.dart deleted file mode 100644 index 8e28069..0000000 --- a/lib/lib/widgets/profile_screen/profile_screen_widgets/user_info_widget.dart +++ /dev/null @@ -1,50 +0,0 @@ -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 StatelessWidget { - const UserNameWidget({super.key}); - - @override - Widget build(BuildContext context) { - return Align( - alignment: Alignment.center, - child: Text( - 'Username', - style: TextStyle(fontSize: 25), - ), - ); - } -}