Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
dac68c0b86 | |||
136e7efc3d | |||
6012526b33 | |||
ab899e7501 | |||
5bda858a02 | |||
c43e182a52 | |||
d7769061c5 | |||
05dc4bdd94 | |||
264313abfa | |||
834af8472a | |||
651a4e2421 | |||
578a461075 | |||
41e0117c65 | |||
01652be658 | |||
f6a466872f | |||
795afcb0f4 | |||
a5a6133a40 |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 202 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 3.9 KiB |
@ -1,10 +0,0 @@
|
|||||||
<svg width="132" height="132" viewBox="0 0 132 132" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<mask id="mask0_248_2340" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="132" height="132">
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.169312 0.167984H131.57V131.504H0.169312V0.167984Z" fill="white"/>
|
|
||||||
</mask>
|
|
||||||
<g mask="url(#mask0_248_2340)">
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M37.3651 10.0417C20.7686 10.0417 10.0443 21.4111 10.0443 39.0017V92.6691C10.0443 110.266 20.7686 121.629 37.3651 121.629H94.311C110.947 121.629 121.698 110.266 121.698 92.6691V39.0017C121.698 21.4111 110.947 10.0417 94.311 10.0417H37.3651ZM94.311 131.504H37.3651C15.1135 131.504 0.169312 115.895 0.169312 92.6691V39.0017C0.169312 15.7757 15.1135 0.166667 37.3651 0.166667H94.311C116.596 0.166667 131.573 15.7757 131.573 39.0017V92.6691C131.573 115.895 116.596 131.504 94.311 131.504V131.504Z" fill="#4A40EC"/>
|
|
||||||
</g>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7692 100.104C20.5447 100.104 19.3268 99.6566 18.3722 98.7481C16.3906 96.8785 16.3116 93.7448 18.1879 91.7764L28.2472 81.1575C33.5731 75.5024 42.5594 75.2259 48.2408 80.5584L54.5476 86.9574C56.3054 88.7349 59.1625 88.7678 60.9269 87.0298C61.5918 86.2464 75.9303 68.8335 75.9303 68.8335C78.6558 65.5286 82.5005 63.4878 86.773 63.0665C91.0522 62.6912 95.2063 63.9355 98.5177 66.6544C98.8008 66.8848 99.0575 67.1086 113.515 81.954C115.417 83.9027 115.384 87.0298 113.429 88.9324C111.48 90.8481 108.347 90.7889 106.444 88.8402C106.444 88.8402 92.9548 74.9955 91.9936 74.0606C90.9732 73.2246 89.334 72.7374 87.721 72.8954C86.0818 73.06 84.6071 73.8434 83.5604 75.114C68.2607 93.6724 68.0764 93.8501 67.8262 94.0937C62.1777 99.6369 53.0598 99.5447 47.51 93.883C47.51 93.883 41.3875 87.6684 41.2822 87.5433C39.7615 86.1345 37.0491 86.2266 35.423 87.9449L25.3505 98.5638C24.3762 99.5908 23.0727 100.104 21.7692 100.104V100.104Z" fill="#4A40EC"/>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.3375 40.5153C39.6969 40.5153 36.7344 43.4778 36.7344 47.1249C36.7344 50.7721 39.6969 53.7412 43.3441 53.7412C46.9913 53.7412 49.9604 50.7721 49.9604 47.1249C49.9604 43.4843 46.9913 40.5218 43.3375 40.5153M43.3441 63.6162C34.2525 63.6162 26.8594 56.2165 26.8594 47.1249C26.8594 38.0333 34.2525 30.6403 43.3441 30.6403C52.4423 30.6468 59.8354 38.0465 59.8354 47.1249C59.8354 56.2165 52.4357 63.6162 43.3441 63.6162" fill="#4A40EC"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 462 B |
3
assets/images/svg/clipboard.svg
Normal 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
@ -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 |
@ -1,20 +1,7 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:drifter/pages/create_account_screen/create_account_screen.dart';
|
|
||||||
import 'package:drifter/pages/home_screen/home_screen_widget.dart';
|
|
||||||
import 'package:drifter/pages/login_screen/login_screen.dart';
|
|
||||||
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/edit_profile_screen.dart';
|
|
||||||
import 'package:drifter/pages/qr_code_screen/qr_code_screen.dart';
|
|
||||||
import 'package:drifter/pages/settings_screen/settings_screen.dart';
|
|
||||||
import 'package:drifter/pages/splash_screen/splash_screen.dart';
|
import 'package:drifter/pages/splash_screen/splash_screen.dart';
|
||||||
import 'package:drifter/pages/terms_of_service/terms_of_service.dart';
|
|
||||||
import 'package:drifter/pages/welcome_screen/welcome_screen.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
import 'package:drifter/theme/app_colors.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||||
import 'pages/profile_screen/view_profile_photo_screen/view_profile_photo_screen.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -25,31 +12,19 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return KeyboardDismisser(
|
||||||
title: 'Flutter Demo',
|
child: MaterialApp(
|
||||||
theme: ThemeData(
|
title: 'Flutter Demo',
|
||||||
appBarTheme: const AppBarTheme(backgroundColor: AppColors.background),
|
theme: ThemeData(
|
||||||
textButtonTheme: TextButtonThemeData(
|
appBarTheme: const AppBarTheme(backgroundColor: AppColors.background),
|
||||||
style: TextButton.styleFrom(foregroundColor: AppColors.background)),
|
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
||||||
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
backgroundColor: AppColors.background,
|
||||||
backgroundColor: AppColors.background,
|
selectedItemColor: AppColors.mainAccent,
|
||||||
selectedItemColor: AppColors.mainAccent,
|
unselectedItemColor: Colors.grey,
|
||||||
unselectedItemColor: Colors.grey,
|
),
|
||||||
),
|
),
|
||||||
|
home: const Splash(),
|
||||||
),
|
),
|
||||||
routes: {
|
|
||||||
'/': (context) => const Splash()
|
|
||||||
// Splash()
|
|
||||||
,
|
|
||||||
'/login': (context) => const LoginScreen(),
|
|
||||||
'/terms': (context) => const TermsOfServiceScreen(),
|
|
||||||
'/createAccount': (context) => const CreateAccountScreen(),
|
|
||||||
'/MainScreen': (context) => const MainScreenWidget(),
|
|
||||||
'/Settings': (context) => const SettingsScreen(),
|
|
||||||
'/QrCodeScreen': (context) => const QrCodeScreen(),
|
|
||||||
'/EditProfileScreen': (context) => const EditProfileScreen(),
|
|
||||||
'/ViewProfilePhotoScreen': (context) => const ViewProfilePhotoScreen(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
import 'package:nostr_tools/nostr_tools.dart';
|
||||||
|
|
||||||
class Keys {
|
class Keys {
|
||||||
@ -12,6 +11,3 @@ class Keys {
|
|||||||
class Relay {
|
class Relay {
|
||||||
static final relay = RelayApi(relayUrl: 'wss://relay.damus.io');
|
static final relay = RelayApi(relayUrl: 'wss://relay.damus.io');
|
||||||
}
|
}
|
||||||
|
|
||||||
final keyController = TextEditingController();
|
|
||||||
final formKey = GlobalKey<FormFieldState>();
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
|
||||||
|
|
||||||
class Keys {
|
|
||||||
static String privateKey = '';
|
|
||||||
static String publicKey = '';
|
|
||||||
static String nsecKey = '';
|
|
||||||
static String npubKey = '';
|
|
||||||
static bool keysExist = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Relay {
|
|
||||||
static final relay = RelayApi(relayUrl: 'wss://relay.damus.io');
|
|
||||||
}
|
|
||||||
|
|
||||||
final keyController = TextEditingController();
|
|
||||||
final formKey = GlobalKey<FormFieldState>();
|
|
||||||
final userNameController = TextEditingController();
|
|
||||||
final nameController = TextEditingController();
|
|
||||||
final descriptionController = TextEditingController();
|
|
||||||
|
|
||||||
class UserData {
|
|
||||||
static bool isLogin = true;
|
|
||||||
}
|
|
@ -1,252 +0,0 @@
|
|||||||
import 'package:dart_nostr/dart_nostr.dart';
|
|
||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
|
||||||
|
|
||||||
import 'package:drifter/pages/profile_screen/widgets/keys_option_modal_bottom_sheet.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/widgets/message_snack_bar.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/widgets/ok_button_widget.dart';
|
|
||||||
import 'package:drifter/widgets/btn_continue.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:drifter/utilities/assets.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
|
||||||
import 'package:sliding_switch/sliding_switch.dart';
|
|
||||||
import 'package:toggle_switch/toggle_switch.dart';
|
|
||||||
|
|
||||||
class CreateAccountScreen extends StatefulWidget {
|
|
||||||
const CreateAccountScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CreateAccountScreen> createState() => CreateAccountScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CreateAccountScreenState extends State<CreateAccountScreen> {
|
|
||||||
final secureStorage = const FlutterSecureStorage();
|
|
||||||
|
|
||||||
Future<bool> generateNewKeys() async {
|
|
||||||
final newPrivateKey = await Nostr.instance.keysService.generatePrivateKey();
|
|
||||||
// final newPrivateKey = keyGenerator.generatePrivateKey();
|
|
||||||
|
|
||||||
final nsec =
|
|
||||||
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
|
||||||
|
|
||||||
// final nsecDecoded =
|
|
||||||
// Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
|
||||||
// assert(nsecDecoded['type'] == 'nsec');
|
|
||||||
// assert(nsecDecoded['data'] == newPrivateKey);
|
|
||||||
|
|
||||||
final newPublicKey = await Nostr.instance.keysService
|
|
||||||
.derivePublicKey(privateKey: newPrivateKey);
|
|
||||||
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
|
||||||
|
|
||||||
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
|
||||||
|
|
||||||
// final npubDecoded =
|
|
||||||
// Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
|
||||||
// assert(npubDecoded['type'] == 'npub');
|
|
||||||
// assert(npubDecoded['data'] == newPublicKey);
|
|
||||||
|
|
||||||
return await addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _getKeysFromStorage() async {
|
|
||||||
// Reading values associated with the " privateKey " and " publicKey " keys from a secure repository
|
|
||||||
final storedPrivateKey = await secureStorage.read(key: 'privateKey');
|
|
||||||
final storedPublicKey = await secureStorage.read(key: 'publicKey');
|
|
||||||
|
|
||||||
final storedNsecKey = await secureStorage.read(key: 'nsec');
|
|
||||||
final storedNpubKey = await secureStorage.read(key: 'npub');
|
|
||||||
|
|
||||||
// Indicates that both private and public keys are stored in a secure repository, after which, the state variables are updated
|
|
||||||
if (storedPrivateKey != null &&
|
|
||||||
storedPublicKey != null &&
|
|
||||||
storedNsecKey != null &&
|
|
||||||
storedNpubKey != null) {
|
|
||||||
setState(() {
|
|
||||||
Keys.privateKey = storedPrivateKey;
|
|
||||||
Keys.publicKey = storedPublicKey;
|
|
||||||
Keys.nsecKey = storedNsecKey;
|
|
||||||
Keys.npubKey = storedNpubKey;
|
|
||||||
Keys.keysExist = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> addKeyToStorage(
|
|
||||||
String privateKeyHex,
|
|
||||||
String publicKeyHex,
|
|
||||||
String nsecKey,
|
|
||||||
String npubKey,
|
|
||||||
) async {
|
|
||||||
// Waiting for both write operations to complete
|
|
||||||
Future.wait([
|
|
||||||
secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
|
||||||
secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
|
||||||
secureStorage.write(key: 'nsec', value: nsecKey),
|
|
||||||
secureStorage.write(key: 'npub', value: npubKey),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Updating status variables and starting widget rebuilding
|
|
||||||
setState(() {
|
|
||||||
Keys.privateKey = privateKeyHex;
|
|
||||||
Keys.publicKey = publicKeyHex;
|
|
||||||
Keys.nsecKey = nsecKey;
|
|
||||||
Keys.npubKey = npubKey;
|
|
||||||
Keys.keysExist = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Returns a boolean value indicating whether the keys were successfully added to the repository or not.
|
|
||||||
return Keys.keysExist;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconBack,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Skip'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Create an account',
|
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 13),
|
|
||||||
const Text(
|
|
||||||
'You can change this information later in your Profile.',
|
|
||||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Username',
|
|
||||||
labelStyle: TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
prefixIcon: const Icon(Icons.alternate_email),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: userNameController,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Name (optional)',
|
|
||||||
labelStyle: TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: nameController,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
SizedBox(
|
|
||||||
height: 112,
|
|
||||||
child: TextField(
|
|
||||||
minLines: 3,
|
|
||||||
maxLines: 5,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Description (optional)',
|
|
||||||
alignLabelWithHint: true,
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: descriptionController,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(child: SizedBox()),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
final currentContext = context;
|
|
||||||
generateNewKeys().then(
|
|
||||||
(keysGenerated) {
|
|
||||||
if (keysGenerated) {
|
|
||||||
ScaffoldMessenger.of(currentContext).showSnackBar(
|
|
||||||
MessageSnackBar(label: 'Keys Generated!'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Navigator.pushNamedAndRemoveUntil(
|
|
||||||
context, '/MainScreen', (_) => false);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultText)),
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Note {
|
|
||||||
static final note = Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
style: TextStyle(
|
|
||||||
height: 1.6,
|
|
||||||
fontSize: 10,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
children: <TextSpan>[
|
|
||||||
TextSpan(
|
|
||||||
style: TextStyle(color: AppColors.noteText),
|
|
||||||
text:
|
|
||||||
"Your private key starts with “nsec” or “hex” and gives your full access to your account. That means, if you log in using your private key, you will be able to make posts and send and receive private messages.\n\n"
|
|
||||||
"Your public key starts with “npub” and gives your view-only access to account. If you log in using your public key, you won’t be able to make posts or access private messages, but you will be able to view your feed. Go to “View only” tab to log in via your public key.")
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
@ -3,14 +3,13 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:drifter/domain_models/domain_models.dart';
|
import 'package:drifter/domain_models/domain_models.dart';
|
||||||
import 'package:drifter/models/models.dart';
|
import 'package:drifter/models/keys.dart';
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
import 'package:drifter/theme/app_colors.dart';
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_ok_button_widget.dart';
|
import 'package:drifter/pages/home_screen/widgets/message_ok_button_widget.dart';
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.dart';
|
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.dart';
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_text_form_field_widget.dart';
|
import 'package:drifter/pages/home_screen/widgets/message_text_form_field_widget.dart';
|
||||||
import 'package:drifter/pages/profile_screen/widgets/message_snack_bar.dart';
|
import 'package:drifter/pages/profile_screen/widgets/message_snack_bar.dart';
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
import 'package:nostr_tools/nostr_tools.dart';
|
||||||
import 'package:toggle_switch/toggle_switch.dart';
|
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
const HomeScreen({super.key});
|
const HomeScreen({super.key});
|
||||||
@ -21,7 +20,6 @@ class HomeScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _HomeScreenState extends State<HomeScreen> {
|
class _HomeScreenState extends State<HomeScreen> {
|
||||||
bool _isConnected = false;
|
bool _isConnected = false;
|
||||||
List<bool> isSelected = [true, false];
|
|
||||||
|
|
||||||
final List<Event> _events = [];
|
final List<Event> _events = [];
|
||||||
final Map<String, Metadata> _metaDatas = {};
|
final Map<String, Metadata> _metaDatas = {};
|
||||||
@ -92,128 +90,47 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _resubscribeStream();
|
await _resubscribeStream();
|
||||||
},
|
},
|
||||||
child: Column(
|
child: StreamBuilder(
|
||||||
children: [
|
stream: _controller.stream,
|
||||||
// ToggleButtons(
|
builder: (context, snapshot) {
|
||||||
// isSelected: isSelected,
|
// Inside the builder callback, the snapshot object contains the most recent event from the thread.
|
||||||
// renderBorder: false,
|
// If snapshot.hasData is true, there is data to display. In this case, ListView.builder is returned, which displays a list of NoostCard widgets.
|
||||||
// fillColor: Color(0xFFFFFFFF),
|
if (snapshot.hasData) {
|
||||||
// selectedColor: Color(0xFF4F46F1),
|
return ListView.builder(
|
||||||
// disabledColor: Color(0xFF837CA3),
|
// The itemCount property of ListView.builder is set to _events.length, , which is the number of events in the _events list.
|
||||||
// children: <Widget>[
|
itemCount: _events.length,
|
||||||
// Container(
|
itemBuilder: (context, index) {
|
||||||
// margin: const EdgeInsets.all(4),
|
final event = _events[index];
|
||||||
// child: const Text('Following')),
|
final metadata = _metaDatas[event.pubkey];
|
||||||
// Container(
|
// For each event, a Noost object is created that encapsulates the details of the event, including id, avatarUrl, name,username, time, content и pubkey.
|
||||||
// margin: const EdgeInsets.all(4),
|
// _metaDatas, you can map the event public key to the author's metadata.
|
||||||
// child: const Text('Global')),
|
final domain = Domain(
|
||||||
// ],
|
noteId: event.id,
|
||||||
// onPressed: (int newIndex) {
|
avatarUrl: metadata?.picture ??
|
||||||
// setState(() {
|
'https://robohash.org/${event.pubkey}',
|
||||||
// for (int index = 0; index < isSelected.length; index++) {
|
name: metadata?.name ?? 'Anon',
|
||||||
// if (index == newIndex) {
|
username: metadata?.displayName ??
|
||||||
// isSelected[index] = true;
|
(metadata?.display_name ?? 'Anon'),
|
||||||
// } else {
|
time: TimeAgo.format(event.created_at),
|
||||||
// isSelected[index] = false;
|
content: event.content,
|
||||||
// }
|
pubkey: event.pubkey,
|
||||||
// }
|
);
|
||||||
// });
|
return DomainCard(domain: domain);
|
||||||
// }),
|
|
||||||
ToggleSwitch(
|
|
||||||
minWidth: double.infinity,
|
|
||||||
minHeight: 40,
|
|
||||||
totalSwitches: 2,
|
|
||||||
labels: ['Following', 'Global'],
|
|
||||||
activeBgColor: [AppColors.toggleSwitchActiveBg],
|
|
||||||
activeFgColor: AppColors.toggleSwitchTextActive,
|
|
||||||
inactiveBgColor: AppColors.toggleSwitchBg,
|
|
||||||
inactiveFgColor: AppColors.toggleSwitchTextInactive,
|
|
||||||
activeBorders: [
|
|
||||||
Border.all(
|
|
||||||
color: AppColors.toggleSwitchBg,
|
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
radiusStyle: true,
|
|
||||||
cornerRadius: 100,
|
|
||||||
customTextStyles: [
|
|
||||||
TextStyle(fontSize: 14, fontWeight: FontWeight.w600)
|
|
||||||
],
|
|
||||||
onToggle: (indexToggle) {
|
|
||||||
print(indexToggle);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 12,
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
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();
|
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
),
|
} 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();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// ToggleButtons(
|
|
||||||
// isSelected: isSelected,
|
|
||||||
// children: <Widget>[
|
|
||||||
// SizedBox(width: 300, child: Text('Following')),
|
|
||||||
// SizedBox(child: Text('Global')),
|
|
||||||
// ],
|
|
||||||
// onPressed: (int newIndex) {
|
|
||||||
// setState(() {
|
|
||||||
// for (int index = 0;
|
|
||||||
// index < isSelected.length;
|
|
||||||
// index++) {
|
|
||||||
// if (index == newIndex) {
|
|
||||||
// isSelected[index] = true;
|
|
||||||
// } else {
|
|
||||||
// isSelected[index] = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }),
|
|
||||||
|
|
||||||
floatingActionButton: Keys.keysExist
|
floatingActionButton: Keys.keysExist
|
||||||
? CreatePost(
|
? CreatePost(
|
||||||
// The publishNote function is called when the user launches the "Noost!" button in the dialog box.
|
// The publishNote function is called when the user launches the "Noost!" button in the dialog box.
|
||||||
@ -275,16 +192,16 @@ class TimeAgo {
|
|||||||
String timeAgo = '';
|
String timeAgo = '';
|
||||||
|
|
||||||
if (difference.inDays > 0) {
|
if (difference.inDays > 0) {
|
||||||
timeAgo = '${difference.inDays}d';
|
timeAgo =
|
||||||
// '${difference.inDays} ${difference.inDays == 1 ? 'day' : 'days'} ago';
|
'${difference.inDays} ${difference.inDays == 1 ? 'day' : 'days'} ago';
|
||||||
} else if (difference.inHours > 0) {
|
} else if (difference.inHours > 0) {
|
||||||
timeAgo = '${difference.inHours}h';
|
timeAgo =
|
||||||
// '${difference.inHours} ${difference.inHours == 1 ? 'hour' : 'hours'} ago';
|
'${difference.inHours} ${difference.inHours == 1 ? 'hour' : 'hours'} ago';
|
||||||
} else if (difference.inMinutes > 0) {
|
} else if (difference.inMinutes > 0) {
|
||||||
timeAgo = '${difference.inMinutes}m';
|
timeAgo =
|
||||||
// '${difference.inMinutes} ${difference.inMinutes == 1 ? 'minute' : 'minutes'} ago';
|
'${difference.inMinutes} ${difference.inMinutes == 1 ? 'minute' : 'minutes'} ago';
|
||||||
} else {
|
} else {
|
||||||
timeAgo = '${difference.inMinutes}m';
|
timeAgo = 'just now';
|
||||||
}
|
}
|
||||||
|
|
||||||
return timeAgo;
|
return timeAgo;
|
||||||
@ -318,81 +235,44 @@ class DomainCard extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String>? imageLinks = extractImage(domain.content);
|
final List<String>? imageLinks = extractImage(domain.content);
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColors.postBg,
|
color: AppColors.mainLightBlue,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 2,
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: const Offset(0, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Row(
|
|
||||||
// children: [
|
|
||||||
// CircleAvatar(
|
|
||||||
// radius: 25,
|
|
||||||
// backgroundImage: FadeInImage(
|
|
||||||
// placeholder: const NetworkImage(
|
|
||||||
// 'https://i.ibb.co/mJkxDkb/satoshi.png'),
|
|
||||||
// image: NetworkImage(domain.avatarUrl),
|
|
||||||
// ).image,
|
|
||||||
// ),
|
|
||||||
// Container(
|
|
||||||
// width: 300,
|
|
||||||
// child: Row(
|
|
||||||
// children: [
|
|
||||||
// Text(domain.name),
|
|
||||||
// SizedBox(
|
|
||||||
// width: 4,
|
|
||||||
// ),
|
|
||||||
// Text('@${domain.username.toLowerCase()}',
|
|
||||||
// style: TextStyle(color: AppColors.postUserName)),
|
|
||||||
// Expanded(child: SizedBox()),
|
|
||||||
// Text('${domain.time}',
|
|
||||||
// style: TextStyle(color: AppColors.postUserName)),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: EdgeInsets.only(top: 16, right: 16, left: 16),
|
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
radius: 25,
|
|
||||||
backgroundImage: FadeInImage(
|
backgroundImage: FadeInImage(
|
||||||
placeholder:
|
placeholder:
|
||||||
const NetworkImage('https://i.ibb.co/mJkxDkb/satoshi.png'),
|
const NetworkImage('https://i.ibb.co/mJkxDkb/satoshi.png'),
|
||||||
image: NetworkImage(domain.avatarUrl),
|
image: NetworkImage(domain.avatarUrl),
|
||||||
).image,
|
).image,
|
||||||
),
|
),
|
||||||
title: Row(
|
title:
|
||||||
children: [
|
Text(domain.name, style: const TextStyle(color: Colors.white)),
|
||||||
Text(domain.name),
|
subtitle: Text('@${domain.username.toLowerCase()} • ${domain.time}',
|
||||||
SizedBox(
|
style: TextStyle(color: Colors.grey.shade400)),
|
||||||
width: 4,
|
trailing: const Icon(Icons.more_vert, color: Colors.grey),
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
child: Text('@${domain.username.toLowerCase()}',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(color: AppColors.postUserName)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text('${domain.time}',
|
|
||||||
style: TextStyle(color: AppColors.postUserName)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
trailing:
|
|
||||||
const Icon(Icons.more_horiz, color: AppColors.postMoreIcon),
|
|
||||||
),
|
),
|
||||||
|
Divider(height: 1, color: Colors.grey.shade400),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
const EdgeInsets.only(top: 12, right: 16, bottom: 14, left: 78),
|
|
||||||
child: Text(domain.content,
|
child: Text(domain.content,
|
||||||
style: const TextStyle(color: AppColors.postBodyText)),
|
style: const TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
if (imageLinks != null && imageLinks.isNotEmpty)
|
if (imageLinks != null && imageLinks.isNotEmpty)
|
||||||
Padding(
|
Center(
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 12, right: 16, bottom: 14, left: 78),
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
const Placeholder(
|
const Placeholder(
|
||||||
@ -400,15 +280,12 @@ class DomainCard extends StatelessWidget {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: ClipRRect(
|
child: FadeInImage(
|
||||||
borderRadius: BorderRadius.circular(8),
|
placeholder: const NetworkImage(
|
||||||
child: FadeInImage(
|
'https://i.ibb.co/D9jqXgR/58038897-167f0280-7ae6-11e9-94eb-88e880a25f0f.gif',
|
||||||
placeholder: const NetworkImage(
|
|
||||||
'https://media.tenor.com/On7kvXhzml4AAAAj/loading-gif.gif',
|
|
||||||
),
|
|
||||||
image: NetworkImage(imageLinks.first),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
),
|
||||||
|
image: NetworkImage(imageLinks.first),
|
||||||
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -495,7 +372,7 @@ class _CreatePostState extends State<CreatePost> {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: AppColors.background,
|
color: AppColors.mainDarkBlue,
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -1,252 +0,0 @@
|
|||||||
import 'package:dart_nostr/dart_nostr.dart';
|
|
||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/pages/home_screen/widgets/message_text_button_widget.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
|
||||||
|
|
||||||
import 'package:drifter/pages/profile_screen/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/ok_button_widget.dart';
|
|
||||||
import 'package:drifter/widgets/btn_continue.dart';
|
|
||||||
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:drifter/utilities/assets.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:nostr_tools/nostr_tools.dart';
|
|
||||||
import 'package:sliding_switch/sliding_switch.dart';
|
|
||||||
import 'package:toggle_switch/toggle_switch.dart';
|
|
||||||
|
|
||||||
class LoginScreen extends StatefulWidget {
|
|
||||||
const LoginScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LoginScreen> createState() => LoginScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoginScreenState extends State<LoginScreen> {
|
|
||||||
final keyGenerator = KeyApi();
|
|
||||||
final nip19 = Nip19();
|
|
||||||
final indexToggle = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconBack,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Skip'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
height: 56,
|
|
||||||
),
|
|
||||||
ToggleSwitch(
|
|
||||||
minWidth: double.infinity,
|
|
||||||
minHeight: 56,
|
|
||||||
totalSwitches: 2,
|
|
||||||
labels: ['Login', 'View only'],
|
|
||||||
activeBgColor: [AppColors.toggleSwitchActiveBg],
|
|
||||||
activeFgColor: AppColors.toggleSwitchTextActive,
|
|
||||||
inactiveBgColor: AppColors.toggleSwitchBg,
|
|
||||||
inactiveFgColor: AppColors.toggleSwitchTextInactive,
|
|
||||||
activeBorders: [
|
|
||||||
Border.all(
|
|
||||||
color: AppColors.toggleSwitchBg,
|
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
radiusStyle: true,
|
|
||||||
cornerRadius: 8,
|
|
||||||
customTextStyles: [
|
|
||||||
TextStyle(fontSize: 14, fontWeight: FontWeight.w600)
|
|
||||||
],
|
|
||||||
onToggle: (indexToggle) {
|
|
||||||
print(indexToggle);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 56,
|
|
||||||
),
|
|
||||||
const Text(
|
|
||||||
'Login',
|
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 13),
|
|
||||||
const Text(
|
|
||||||
'Paste your password (AKA Private Key)',
|
|
||||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
TextFormField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'nsec... / hex...',
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
suffixIcon: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.paste),
|
|
||||||
color: AppColors.textFieldActiveIconTrail,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.qr_code_scanner),
|
|
||||||
color: AppColors.textFieldActiveIconTrail,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: keyController,
|
|
||||||
key: formKey,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Please enter your private key';
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
bool isValidHexKey =
|
|
||||||
Nostr.instance.keysService.isValidPrivateKey(value);
|
|
||||||
bool isValidNSec = value.trim().startsWith('nsec') &&
|
|
||||||
Nostr.instance.keysService.isValidPrivateKey(Nostr
|
|
||||||
.instance.keysService
|
|
||||||
.decodeNsecKeyToPrivateKey(value));
|
|
||||||
if (!(isValidHexKey || isValidNSec)) {
|
|
||||||
return 'Your private key is not valid.';
|
|
||||||
}
|
|
||||||
} on ChecksumVerificationException catch (e) {
|
|
||||||
return e.message;
|
|
||||||
} catch (e) {
|
|
||||||
return 'Error: $e';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Container(
|
|
||||||
padding: EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
height: 168,
|
|
||||||
child: Note.note,
|
|
||||||
),
|
|
||||||
Expanded(child: SizedBox()),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (formKey.currentState!.validate()) {
|
|
||||||
String privateKeyHex = keyController.text.trim();
|
|
||||||
String publicKeyHex;
|
|
||||||
String nsecKey;
|
|
||||||
String npubKey;
|
|
||||||
|
|
||||||
// if (privateKeyHex.startsWith('nsec')) {
|
|
||||||
// nsecKey = privateKeyHex;
|
|
||||||
// final decoded = Nostr.instance.keysService
|
|
||||||
// .decodeNsecKeyToPrivateKey(privateKeyHex);
|
|
||||||
// privateKeyHex = decoded;
|
|
||||||
// publicKeyHex = Nostr.instance.keysService
|
|
||||||
// .derivePublicKey(privateKey: 'privateKeyHex');
|
|
||||||
// npubKey = Nostr.instance.keysService
|
|
||||||
// .encodePublicKeyToNpub(publicKeyHex);
|
|
||||||
// } else {
|
|
||||||
// publicKeyHex = Nostr.instance.keysService
|
|
||||||
// .derivePublicKey(privateKey: 'privateKeyHex');
|
|
||||||
// nsecKey = Nostr.instance.keysService
|
|
||||||
// .encodePrivateKeyToNsec(privateKeyHex);
|
|
||||||
// npubKey = Nostr.instance.keysService
|
|
||||||
// .encodePublicKeyToNpub(publicKeyHex);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (privateKeyHex.startsWith('nsec')) {
|
|
||||||
final decoded = nip19.decode(privateKeyHex);
|
|
||||||
privateKeyHex = decoded['data'];
|
|
||||||
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
|
||||||
nsecKey = nip19.nsecEncode(privateKeyHex);
|
|
||||||
npubKey = nip19.npubEncode(publicKeyHex);
|
|
||||||
} else {
|
|
||||||
publicKeyHex = keyGenerator.getPublicKey(privateKeyHex);
|
|
||||||
nsecKey = nip19.nsecEncode(privateKeyHex);
|
|
||||||
npubKey = nip19.npubEncode(publicKeyHex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ProfileScreenState().addKeyToStorage(
|
|
||||||
privateKeyHex, publicKeyHex, nsecKey, npubKey);
|
|
||||||
|
|
||||||
keyController.clear();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
MessageSnackBar(
|
|
||||||
label: 'Congratulations! Keys Stored!'),
|
|
||||||
);
|
|
||||||
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
} catch (e) {}
|
|
||||||
} else {
|
|
||||||
formKey.currentState?.setState(() {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultText)),
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Note {
|
|
||||||
static final note = Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
style: TextStyle(
|
|
||||||
height: 1.6,
|
|
||||||
fontSize: 10,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
children: <TextSpan>[
|
|
||||||
TextSpan(
|
|
||||||
style: TextStyle(color: AppColors.noteText),
|
|
||||||
text:
|
|
||||||
"Your private key starts with “nsec” or “hex” and gives your full access to your account. That means, if you log in using your private key, you will be able to make posts and send and receive private messages.\n\n"
|
|
||||||
"Your public key starts with “npub” and gives your view-only access to account. If you log in using your public key, you won’t be able to make posts or access private messages, but you will be able to view your feed. Go to “View only” tab to log in via your public key.")
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,12 +1,8 @@
|
|||||||
// import 'package:drifter/pages/home_screen/home_screen_widget.dart';
|
// import 'package:drifter/pages/home_screen/home_screen_widget.dart';
|
||||||
import 'package:drifter/pages/home_screen/home_screen_widget.dart';
|
import 'package:drifter/pages/home_screen/home_screen_widget.dart';
|
||||||
import 'package:drifter/pages/login_screen/login_screen.dart';
|
|
||||||
import 'package:drifter/pages/message_screen/message_screen_widget.dart';
|
import 'package:drifter/pages/message_screen/message_screen_widget.dart';
|
||||||
import 'package:drifter/pages/notifications_screen/notifications_screen.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
import 'package:drifter/pages/profile_screen/profile_screen.dart';
|
||||||
import 'package:drifter/pages/search_screen/search_screen.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
import 'package:drifter/theme/app_colors.dart';
|
||||||
import 'package:drifter/main.dart';
|
|
||||||
import 'package:drifter/utilities/assets.dart';
|
import 'package:drifter/utilities/assets.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
@ -19,123 +15,67 @@ class MainScreenWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MainScreenWidgetState extends State<MainScreenWidget> {
|
class _MainScreenWidgetState extends State<MainScreenWidget> {
|
||||||
int _selectedTap = 2;
|
int _selectedTap = 0;
|
||||||
late String _title;
|
|
||||||
|
|
||||||
void onSelectedtap(int index) {
|
void onSelectedtap(int index) {
|
||||||
if (_selectedTap == index) return;
|
if (_selectedTap == index) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTap = index;
|
_selectedTap = index;
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
_title = 'Message';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
_title = 'Search';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
_title = 'Feed';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
_title = 'Notifications';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
_title = 'Profile';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
initState() {
|
|
||||||
_title = 'Feed';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColors.mainBackground,
|
backgroundColor: AppColors.mainBackground,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
title: Row(
|
||||||
icon: Icon(Icons.settings),
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
color: AppColors.topNavIconPtimary,
|
children: [
|
||||||
onPressed: () {
|
// use png instead
|
||||||
Navigator.pushNamed(context, '/Settings');
|
SvgPicture.asset(
|
||||||
},
|
Assets.svg.drifterIcon,
|
||||||
),
|
height: 30,
|
||||||
actions: <Widget>[
|
width: 30,
|
||||||
IconButton(
|
alignment: Alignment.centerLeft,
|
||||||
icon: Icon(Icons.rss_feed),
|
),
|
||||||
color: AppColors.topNavIconPtimary,
|
const SizedBox(
|
||||||
onPressed: () {},
|
width: 125,
|
||||||
),
|
),
|
||||||
],
|
const Text(
|
||||||
title: Text(
|
"Drifter",
|
||||||
_title,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: AppColors.mainAccent,
|
||||||
color: AppColors.topNavText,
|
),
|
||||||
),
|
// textAlign: TextAlign.center,
|
||||||
// textAlign: TextAlign.center,
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
elevation: 0,
|
|
||||||
),
|
),
|
||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: _selectedTap,
|
index: _selectedTap,
|
||||||
children: const [
|
children: const [
|
||||||
MessageScreen(),
|
|
||||||
SearchScreen(),
|
|
||||||
HomeScreen(),
|
HomeScreen(),
|
||||||
NotificationsScreen(),
|
MessageScreen(),
|
||||||
ProfileScreen(),
|
ProfileScreen(),
|
||||||
// LoginScreen(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
backgroundColor: AppColors.bottomNavBackground,
|
|
||||||
selectedItemColor: AppColors.bottomNavIconActive,
|
|
||||||
unselectedItemColor: AppColors.bottomNavIconDefault,
|
|
||||||
selectedFontSize: 0,
|
|
||||||
currentIndex: _selectedTap,
|
currentIndex: _selectedTap,
|
||||||
type: BottomNavigationBarType.fixed,
|
|
||||||
items: const [
|
items: const [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.mail_outline),
|
icon: Icon(Icons.home),
|
||||||
label: '',
|
label: 'Home',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.search),
|
icon: Icon(Icons.message),
|
||||||
label: '',
|
label: 'Message',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon:
|
icon: Icon(Icons.person),
|
||||||
ImageIcon(AssetImage('assets/images/icons/drifter_vector.png')),
|
label: 'Profile',
|
||||||
label: '',
|
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
|
||||||
icon: Icon(Icons.notifications_outlined),
|
|
||||||
label: '',
|
|
||||||
),
|
|
||||||
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
icon: Icon(Icons.person_2_outlined),
|
|
||||||
label: '',
|
|
||||||
),
|
|
||||||
// BottomNavigationBarItem(
|
|
||||||
// icon: Icon(Icons.login),
|
|
||||||
// label: 'Login',
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
onTap: onSelectedtap,
|
onTap: onSelectedtap,
|
||||||
),
|
),
|
||||||
|
@ -18,7 +18,7 @@ class _MessageScreenState extends State<MessageScreen> {
|
|||||||
children: const [
|
children: const [
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Message",
|
"List of posts",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
|
|
||||||
class NotificationsScreen extends StatefulWidget {
|
|
||||||
const NotificationsScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<NotificationsScreen> createState() => _NotificationsScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _NotificationsScreenState extends State<NotificationsScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Center(
|
|
||||||
child: Text('Notifications Page'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,333 +0,0 @@
|
|||||||
import 'package:dart_nostr/dart_nostr.dart';
|
|
||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/widgets/delete_keys_dialog.dart';
|
|
||||||
import 'package:drifter/main.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/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
|
|
||||||
class EditProfileScreen extends StatefulWidget {
|
|
||||||
const EditProfileScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<EditProfileScreen> createState() => EditProfileScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class EditProfileScreenState extends State<EditProfileScreen> {
|
|
||||||
final secureStorage = const FlutterSecureStorage();
|
|
||||||
bool _toHex = false;
|
|
||||||
|
|
||||||
TextEditingController privateKeyInput = TextEditingController();
|
|
||||||
TextEditingController publicKeyInput = TextEditingController();
|
|
||||||
|
|
||||||
// final keyGenerator = KeyApi();
|
|
||||||
// final nip19 = Nip19();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
appBar: AppBar(
|
|
||||||
actions: [
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
||||||
height: 40,
|
|
||||||
width: 82,
|
|
||||||
child: ElevatedButton(
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
MaterialStateProperty.all(AppColors.buttonPrimaryDefaultBg),
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Save'),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconPtimary,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
('Edit profile'),
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.topNavText,
|
|
||||||
),
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
elevation: 0,
|
|
||||||
),
|
|
||||||
body: ListView(
|
|
||||||
children: [
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 70,
|
|
||||||
child: FittedBox(
|
|
||||||
child: Image.asset('assets/images/banner.png'),
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(top: 30, left: 16, right: 58),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(200),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pushNamed(
|
|
||||||
context, '/ViewProfilePhotoScreen');
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 80,
|
|
||||||
height: 80,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
width: 2, color: Color(0xFFF2EFFF))),
|
|
||||||
child: Image.asset('assets/images/avatar.png')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'User info',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.label, fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Username',
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
prefixIcon: const Icon(Icons.alternate_email),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: userNameController,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Name',
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: nameController,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
SizedBox(
|
|
||||||
height: 112,
|
|
||||||
child: TextField(
|
|
||||||
minLines: 3,
|
|
||||||
maxLines: 5,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Description',
|
|
||||||
alignLabelWithHint: true,
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: descriptionController,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.textFieldDefaultBg,
|
|
||||||
labelText: 'Website URL',
|
|
||||||
labelStyle:
|
|
||||||
TextStyle(color: AppColors.textFieldDefaultText),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0,
|
|
||||||
style: BorderStyle.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
iconColor: AppColors.textFieldDefaultIconTrail),
|
|
||||||
controller: nameController,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// return ListView(
|
|
||||||
// children: [
|
|
||||||
// const SizedBox(
|
|
||||||
// height: 60,
|
|
||||||
// ),
|
|
||||||
// const UserInfo(),
|
|
||||||
// const SizedBox(
|
|
||||||
// height: 40,
|
|
||||||
// ),
|
|
||||||
// FormKeys(),
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.all(16.0),
|
|
||||||
// child: Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
// children: [
|
|
||||||
// Keys.keysExist
|
|
||||||
// ? IconButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// setState(() {
|
|
||||||
// _toHex = !_toHex;
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// icon: const Icon(Icons.refresh))
|
|
||||||
// // ElevatedButton(
|
|
||||||
// // style: ButtonStyle(
|
|
||||||
// // backgroundColor:
|
|
||||||
// // MaterialStateProperty.all(AppColors.background)),
|
|
||||||
// // onPressed: () {
|
|
||||||
// // keysExistDialog(
|
|
||||||
// // Nostr.instance.keysService
|
|
||||||
// // .encodePublicKeyToNpub(Keys.publicKey),
|
|
||||||
// // Nostr.instance.keysService
|
|
||||||
// // .encodePrivateKeyToNsec(Keys.privateKey),
|
|
||||||
// // );
|
|
||||||
// // },
|
|
||||||
// // child: const Text(
|
|
||||||
// // 'Keys',
|
|
||||||
// // ),
|
|
||||||
// // )
|
|
||||||
// : Row(
|
|
||||||
// children: [
|
|
||||||
// ElevatedButton(
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// backgroundColor: MaterialStateProperty.all(
|
|
||||||
// AppColors.background)),
|
|
||||||
// onPressed: () {
|
|
||||||
// modalBottomSheet();
|
|
||||||
// },
|
|
||||||
// child: const Text(
|
|
||||||
// 'Generate Keys',
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// SizedBox(width: 100),
|
|
||||||
// ElevatedButton(
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// backgroundColor: MaterialStateProperty.all(
|
|
||||||
// AppColors.background)),
|
|
||||||
// onPressed: () {
|
|
||||||
// Navigator.pushNamed(context, '/login').then((_) {
|
|
||||||
// initState();
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// child: const Text(
|
|
||||||
// 'Login',
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// 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(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,13 @@
|
|||||||
import 'package:dart_nostr/dart_nostr.dart';
|
import 'package:dart_nostr/dart_nostr.dart';
|
||||||
import 'package:drifter/models/models.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/delete_keys_dialog.dart';
|
||||||
import 'package:drifter/main.dart';
|
|
||||||
import 'package:drifter/pages/profile_screen/widgets/key_exist_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/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:drifter/theme/app_colors.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:toggle_switch/toggle_switch.dart';
|
|
||||||
|
|
||||||
class ProfileScreen extends StatefulWidget {
|
class ProfileScreen extends StatefulWidget {
|
||||||
const ProfileScreen({super.key});
|
const ProfileScreen({super.key});
|
||||||
@ -19,8 +17,7 @@ class ProfileScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProfileScreenState extends State<ProfileScreen> {
|
class ProfileScreenState extends State<ProfileScreen> {
|
||||||
final secureStorage = const FlutterSecureStorage();
|
final _secureStorage = const FlutterSecureStorage();
|
||||||
bool _toHex = false;
|
|
||||||
|
|
||||||
TextEditingController privateKeyInput = TextEditingController();
|
TextEditingController privateKeyInput = TextEditingController();
|
||||||
TextEditingController publicKeyInput = TextEditingController();
|
TextEditingController publicKeyInput = TextEditingController();
|
||||||
@ -40,9 +37,8 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
final nsec =
|
final nsec =
|
||||||
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
Nostr.instance.keysService.encodePrivateKeyToNsec(newPrivateKey);
|
||||||
|
final nsecDecoded =
|
||||||
// final nsecDecoded =
|
Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
||||||
// Nostr.instance.keysService.decodeNsecKeyToPrivateKey(nsec);
|
|
||||||
// assert(nsecDecoded['type'] == 'nsec');
|
// assert(nsecDecoded['type'] == 'nsec');
|
||||||
// assert(nsecDecoded['data'] == newPrivateKey);
|
// assert(nsecDecoded['data'] == newPrivateKey);
|
||||||
|
|
||||||
@ -51,22 +47,21 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
// final newPublicKey = keyGenerator.getPublicKey(newPrivateKey);
|
||||||
|
|
||||||
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
final npub = Nostr.instance.keysService.encodePublicKeyToNpub(newPublicKey);
|
||||||
|
final npubDecoded =
|
||||||
// final npubDecoded =
|
Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
||||||
// Nostr.instance.keysService.decodeNpubKeyToPublicKey(npub);
|
|
||||||
// assert(npubDecoded['type'] == 'npub');
|
// assert(npubDecoded['type'] == 'npub');
|
||||||
// assert(npubDecoded['data'] == newPublicKey);
|
// assert(npubDecoded['data'] == newPublicKey);
|
||||||
|
|
||||||
return await addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub);
|
return await _addKeyToStorage(newPrivateKey, newPublicKey, nsec, npub);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getKeysFromStorage() async {
|
Future<void> _getKeysFromStorage() async {
|
||||||
// Reading values associated with the " privateKey " and " publicKey " keys from a secure repository
|
// Reading values associated with the " privateKey " and " publicKey " keys from a secure repository
|
||||||
final storedPrivateKey = await secureStorage.read(key: 'privateKey');
|
final storedPrivateKey = await _secureStorage.read(key: 'privateKey');
|
||||||
final storedPublicKey = await secureStorage.read(key: 'publicKey');
|
final storedPublicKey = await _secureStorage.read(key: 'publicKey');
|
||||||
|
|
||||||
final storedNsecKey = await secureStorage.read(key: 'nsec');
|
final storedNsecKey = await _secureStorage.read(key: 'nsec');
|
||||||
final storedNpubKey = await secureStorage.read(key: 'npub');
|
final storedNpubKey = await _secureStorage.read(key: 'npub');
|
||||||
|
|
||||||
// Indicates that both private and public keys are stored in a secure repository, after which, the state variables are updated
|
// Indicates that both private and public keys are stored in a secure repository, after which, the state variables are updated
|
||||||
if (storedPrivateKey != null &&
|
if (storedPrivateKey != null &&
|
||||||
@ -85,7 +80,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
// Adding a new key
|
// Adding a new key
|
||||||
// Writing a private and public key to a secure vault
|
// Writing a private and public key to a secure vault
|
||||||
Future<bool> addKeyToStorage(
|
Future<bool> _addKeyToStorage(
|
||||||
String privateKeyHex,
|
String privateKeyHex,
|
||||||
String publicKeyHex,
|
String publicKeyHex,
|
||||||
String nsecKey,
|
String nsecKey,
|
||||||
@ -93,10 +88,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
) async {
|
) async {
|
||||||
// Waiting for both write operations to complete
|
// Waiting for both write operations to complete
|
||||||
Future.wait([
|
Future.wait([
|
||||||
secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
_secureStorage.write(key: 'privateKey', value: privateKeyHex),
|
||||||
secureStorage.write(key: 'publicKey', value: publicKeyHex),
|
_secureStorage.write(key: 'publicKey', value: privateKeyHex),
|
||||||
secureStorage.write(key: 'nsec', value: nsecKey),
|
_secureStorage.write(key: 'nsec', value: nsecKey),
|
||||||
secureStorage.write(key: 'npub', value: npubKey),
|
_secureStorage.write(key: 'npub', value: npubKey),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Updating status variables and starting widget rebuilding
|
// Updating status variables and starting widget rebuilding
|
||||||
@ -115,10 +110,10 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
Future<void> _deleteKeysStorage() async {
|
Future<void> _deleteKeysStorage() async {
|
||||||
// Calling secure storage to remove keys from storage
|
// Calling secure storage to remove keys from storage
|
||||||
Future.wait([
|
Future.wait([
|
||||||
secureStorage.delete(key: 'privateKey'),
|
_secureStorage.delete(key: 'privateKey'),
|
||||||
secureStorage.delete(key: 'publicKey'),
|
_secureStorage.delete(key: 'publicKey'),
|
||||||
secureStorage.delete(key: 'nsec'),
|
_secureStorage.delete(key: 'nsec'),
|
||||||
secureStorage.delete(key: 'npub'),
|
_secureStorage.delete(key: 'npub'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Updating status variables, resetting values after deleting keys from the repository
|
// Updating status variables, resetting values after deleting keys from the repository
|
||||||
@ -131,546 +126,7 @@ class ProfileScreenState extends State<ProfileScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void _keysExistDialog(String npubEncode, String nsecEncode) async {
|
||||||
Widget build(BuildContext context) {
|
|
||||||
publicKeyInput.text = Keys.npubKey;
|
|
||||||
|
|
||||||
return ListView(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
color: AppColors.profileWrapperBg,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 70,
|
|
||||||
child: FittedBox(
|
|
||||||
child: Image.asset('assets/images/banner.png'),
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(top: 30, left: 16, right: 58),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(200),
|
|
||||||
child: Container(
|
|
||||||
width: 80,
|
|
||||||
height: 80,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
width: 2, color: Color(0xFFF2EFFF))),
|
|
||||||
child: Image.asset('assets/images/avatar.png')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.only(top: 74, right: 16),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
backgroundColor:
|
|
||||||
AppColors.buttonSecondaryDefaultBg,
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(
|
|
||||||
context, '/EditProfileScreen');
|
|
||||||
},
|
|
||||||
elevation: 0,
|
|
||||||
child: Icon(
|
|
||||||
Icons.edit,
|
|
||||||
size: 18,
|
|
||||||
color: AppColors.buttonSecondaryIcon,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
backgroundColor:
|
|
||||||
AppColors.buttonSecondaryDefaultBg,
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(
|
|
||||||
context, '/QrCodeScreen');
|
|
||||||
},
|
|
||||||
elevation: 0,
|
|
||||||
child: Icon(
|
|
||||||
Icons.qr_code,
|
|
||||||
size: 18,
|
|
||||||
color: AppColors.buttonSecondaryIcon,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
backgroundColor:
|
|
||||||
AppColors.buttonSecondaryDefaultBg,
|
|
||||||
onPressed: () {},
|
|
||||||
elevation: 0,
|
|
||||||
child: Icon(
|
|
||||||
Icons.mail_outlined,
|
|
||||||
size: 18,
|
|
||||||
color: AppColors.buttonSecondaryIcon,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 100,
|
|
||||||
height: 32,
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text(
|
|
||||||
'Follow',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors
|
|
||||||
.buttonPrimaryDefaultText),
|
|
||||||
),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor:
|
|
||||||
AppColors.buttonPrimaryDefaultBg,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(100)))),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Cameron Williamson',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileFullName,
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
Text('@cameron',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileUserName,
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'This is the description of my profile. I am a nostrich and I love cats. Follow me for fun pictures and bad jokes. I also want to be a politician.',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSummary,
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
height: 12,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: TextField(
|
|
||||||
style: TextStyle(color: AppColors.profileKeyText),
|
|
||||||
readOnly: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
suffixIcon: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.copy),
|
|
||||||
color: AppColors.buttonSecondaryIcon,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.qr_code),
|
|
||||||
color: AppColors.buttonSecondaryIcon,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
filled: true,
|
|
||||||
fillColor: AppColors.profileKeyField,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: 0, style: BorderStyle.none),
|
|
||||||
)),
|
|
||||||
minLines: 2,
|
|
||||||
maxLines: 2,
|
|
||||||
controller: publicKeyInput,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 13),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'nip-05-name',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'www.cameronforpresident.com',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.score,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'@cameron_official',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'cameron.williamson.com/@cameron_official',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.flash_on,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'whoknowswhatgoeshere',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
child: TextButton.icon(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
tapTargetSize:
|
|
||||||
MaterialTapTargetSize.shrinkWrap,
|
|
||||||
),
|
|
||||||
// <-- TextButton
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.flash_on,
|
|
||||||
size: 15.0,
|
|
||||||
color: AppColors.profileSocialIcons,
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'cameron@satoshiwallet.com',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.profileSocialLinks,
|
|
||||||
fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: ProfileStats(),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8, bottom: 4, right: 4, left: 4),
|
|
||||||
child: ToggleSwitch(
|
|
||||||
customWidths: [133, 133, 133],
|
|
||||||
// minWidth: double.infinity,
|
|
||||||
minHeight: 48,
|
|
||||||
totalSwitches: 3,
|
|
||||||
labels: ['Posts', 'Posts & Replies', 'Bookmarks'],
|
|
||||||
activeBgColor: [AppColors.toggleSwitchActiveBg],
|
|
||||||
activeFgColor: AppColors.toggleSwitchTextActive,
|
|
||||||
inactiveBgColor: AppColors.toggleSwitchBg,
|
|
||||||
inactiveFgColor: AppColors.toggleSwitchTextInactive,
|
|
||||||
activeBorders: [
|
|
||||||
Border.all(
|
|
||||||
color: AppColors.toggleSwitchBg,
|
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
radiusStyle: true,
|
|
||||||
cornerRadius: 8,
|
|
||||||
customTextStyles: [
|
|
||||||
TextStyle(fontSize: 12, fontWeight: FontWeight.w600)
|
|
||||||
],
|
|
||||||
onToggle: (indexToggle) {
|
|
||||||
print(indexToggle);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
// return ListView(
|
|
||||||
// children: [
|
|
||||||
// const SizedBox(
|
|
||||||
// height: 60,
|
|
||||||
// ),
|
|
||||||
// const UserInfo(),
|
|
||||||
// const SizedBox(
|
|
||||||
// height: 40,
|
|
||||||
// ),
|
|
||||||
// FormKeys(),
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.all(16.0),
|
|
||||||
// child: Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
// children: [
|
|
||||||
// Keys.keysExist
|
|
||||||
// ? IconButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// setState(() {
|
|
||||||
// _toHex = !_toHex;
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// icon: const Icon(Icons.refresh))
|
|
||||||
// // ElevatedButton(
|
|
||||||
// // style: ButtonStyle(
|
|
||||||
// // backgroundColor:
|
|
||||||
// // MaterialStateProperty.all(AppColors.background)),
|
|
||||||
// // onPressed: () {
|
|
||||||
// // keysExistDialog(
|
|
||||||
// // Nostr.instance.keysService
|
|
||||||
// // .encodePublicKeyToNpub(Keys.publicKey),
|
|
||||||
// // Nostr.instance.keysService
|
|
||||||
// // .encodePrivateKeyToNsec(Keys.privateKey),
|
|
||||||
// // );
|
|
||||||
// // },
|
|
||||||
// // child: const Text(
|
|
||||||
// // 'Keys',
|
|
||||||
// // ),
|
|
||||||
// // )
|
|
||||||
// : Row(
|
|
||||||
// children: [
|
|
||||||
// ElevatedButton(
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// backgroundColor: MaterialStateProperty.all(
|
|
||||||
// AppColors.background)),
|
|
||||||
// onPressed: () {
|
|
||||||
// modalBottomSheet();
|
|
||||||
// },
|
|
||||||
// child: const Text(
|
|
||||||
// 'Generate Keys',
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// SizedBox(width: 100),
|
|
||||||
// ElevatedButton(
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// backgroundColor: MaterialStateProperty.all(
|
|
||||||
// AppColors.background)),
|
|
||||||
// onPressed: () {
|
|
||||||
// Navigator.pushNamed(context, '/login').then((_) {
|
|
||||||
// initState();
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// child: const Text(
|
|
||||||
// 'Login',
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// 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 {
|
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: ((context) {
|
builder: ((context) {
|
||||||
@ -684,62 +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,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProfileStats extends StatelessWidget {
|
|
||||||
const ProfileStats({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final following = '3,789';
|
|
||||||
final followers = '2,554';
|
|
||||||
final zaps = '1,878';
|
|
||||||
final relays = '6';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
privateKeyInput.text = Keys.nsecKey;
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
publicKeyInput.text = Keys.npubKey;
|
||||||
children: [
|
|
||||||
SizedBox(
|
return Padding(
|
||||||
child: Text('${following} Following'),
|
padding: const EdgeInsets.all(15.0),
|
||||||
),
|
child: Column(
|
||||||
SizedBox(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
child: Text('${followers} Followers'),
|
children: [
|
||||||
),
|
const SizedBox(
|
||||||
SizedBox(
|
height: 60,
|
||||||
child: Text('${zaps} Zaps'),
|
),
|
||||||
),
|
UserInfo(),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
child: Text('${relays} Relays'),
|
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],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: 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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
|
|
||||||
class ViewProfilePhotoScreen extends StatefulWidget {
|
|
||||||
const ViewProfilePhotoScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ViewProfilePhotoScreen> createState() => _ViewProfilePhotoScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ViewProfilePhotoScreenState extends State<ViewProfilePhotoScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconPtimary,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
('View profile photo'),
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.topNavText,
|
|
||||||
),
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
centerTitle: true,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
elevation: 0,
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(child: SizedBox()),
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
child: FittedBox(
|
|
||||||
child: Image.asset('assets/images/avatar_full.png'),
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(child: SizedBox()),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100)),
|
|
||||||
backgroundColor: AppColors.buttonSecondaryDefaultBg),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text(
|
|
||||||
'Edit profile photo',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.buttonSecondaryText,
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
|
|
||||||
import 'ok_button_widget.dart';
|
import 'ok_button_widget.dart';
|
||||||
|
|
||||||
@ -16,70 +15,60 @@ class DeleteKeysDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Dialog(
|
return Dialog(
|
||||||
shape: RoundedRectangleBorder(
|
// shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
// borderRadius: BorderRadius.circular(12),
|
||||||
),
|
// ),
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 600),
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: 700,
|
||||||
|
maxHeight: 190,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Padding(
|
||||||
mainAxisSize: MainAxisSize.min,
|
padding: const EdgeInsets.all(16.0),
|
||||||
children: [
|
child: Column(
|
||||||
Container(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
children: [
|
||||||
decoration: BoxDecoration(
|
const Text(
|
||||||
borderRadius: BorderRadius.circular(12),
|
"Delete Keys",
|
||||||
color: Colors.redAccent,
|
style: TextStyle(
|
||||||
),
|
fontSize: 28,
|
||||||
child: const Center(
|
fontWeight: FontWeight.bold,
|
||||||
child: Text(
|
color: Colors.black87,
|
||||||
'Delete Keys!',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 28,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 16),
|
||||||
const SizedBox(height: 24),
|
Text(
|
||||||
Padding(
|
"Are you sure you want to delete your keys?",
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
// textAlign: TextAlign.c,
|
||||||
child: Column(
|
style: TextStyle(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
OkButton(
|
||||||
'Do you want to delete your keys?',
|
onPressed: onNoPressed,
|
||||||
style: TextStyle(
|
label: "No",
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.grey[700],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(
|
||||||
Row(
|
width: 8,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
),
|
||||||
children: [
|
OkButton(
|
||||||
TextButton(
|
onPressed: onYesPressed,
|
||||||
onPressed: onNoPressed,
|
label: "Yes",
|
||||||
child: Text(
|
|
||||||
'On',
|
|
||||||
style: TextStyle(color: AppColors.mainDarkBlue),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
OkButton(
|
|
||||||
onPressed: onYesPressed,
|
|
||||||
label: 'YES',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
)
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
45
lib/pages/profile_screen/widgets/drifter_dialogue.dart
Normal 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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
|
|
||||||
import 'ok_button_widget.dart';
|
import 'ok_button_widget.dart';
|
||||||
|
|
||||||
@ -31,35 +30,34 @@ class _KeysExistDialogState extends State<KeysExistDialog> {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 600),
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: 700,
|
||||||
|
maxHeight: 340,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Padding(
|
||||||
mainAxisSize: MainAxisSize.min,
|
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0),
|
||||||
children: [
|
child: Column(
|
||||||
Container(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
children: [
|
||||||
decoration: BoxDecoration(
|
Row(
|
||||||
borderRadius: BorderRadius.circular(12),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
color: AppColors.background,
|
children: [
|
||||||
),
|
Text(
|
||||||
child: const Center(
|
"Keys",
|
||||||
child: Text(
|
style: TextStyle(
|
||||||
'Keys',
|
fontSize: 28,
|
||||||
style: TextStyle(
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 28,
|
color: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
color: Colors.white,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 24),
|
||||||
const SizedBox(height: 24),
|
Column(
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@ -96,31 +94,53 @@ class _KeysExistDialogState extends State<KeysExistDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Row(
|
Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
.spaceBetween, // Changed to space between to create space for icon buttons
|
child: Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
IconButton(
|
children: [
|
||||||
onPressed: () {
|
MaterialButton(
|
||||||
setState(() {
|
elevation: 3.0,
|
||||||
_toHex = !_toHex;
|
onPressed: () {
|
||||||
});
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.autorenew_outlined),
|
color: Colors.grey[400],
|
||||||
color: Colors.grey[700],
|
shape: RoundedRectangleBorder(
|
||||||
),
|
borderRadius: BorderRadius.circular(
|
||||||
OkButton(
|
8.0,
|
||||||
onPressed: () {
|
),
|
||||||
Navigator.pop(context);
|
),
|
||||||
},
|
child: Text(
|
||||||
label: 'OK',
|
"Cancel",
|
||||||
),
|
style: TextStyle(
|
||||||
],
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_toHex
|
||||||
|
? OkButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_toHex = !_toHex;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
label: "Encoded",
|
||||||
|
)
|
||||||
|
: OkButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_toHex = !_toHex;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
label: "Hex",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
import 'package:drifter/theme/app_colors.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class OkButton extends StatelessWidget {
|
class OkButton extends StatelessWidget {
|
||||||
const OkButton({
|
const OkButton({
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class UserInfo extends StatelessWidget {
|
class UserInfo extends StatelessWidget {
|
||||||
@ -8,7 +7,7 @@ class UserInfo extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: const [
|
||||||
AvatarWidget(),
|
AvatarWidget(),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
@ -25,13 +24,19 @@ class AvatarWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
// todo: create a slide up to choose avatar
|
||||||
decoration: BoxDecoration(
|
return CircleAvatar(
|
||||||
border: Border.all(color: Colors.black),
|
backgroundImage: NetworkImage('https://via.placeholder.com/150'),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(75))),
|
// backgroundColor: AppColors.mainAccent,
|
||||||
width: 150,
|
radius: 40,
|
||||||
height: 150,
|
|
||||||
);
|
);
|
||||||
|
// 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(
|
child: TextField(
|
||||||
controller: messageController,
|
controller: messageController,
|
||||||
focusNode: messageFocusNode,
|
focusNode: messageFocusNode,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Username',
|
hintText: 'Username',
|
||||||
hintStyle: const TextStyle(fontSize: 14),
|
hintStyle: const TextStyle(fontSize: 14),
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.send,
|
|
||||||
color: AppColors.mainDarkBlue,
|
|
||||||
size: 30,
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,166 +0,0 @@
|
|||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/pages/terms_of_service/btn_continue_terms_of_service.dart';
|
|
||||||
import 'package:drifter/pages/terms_of_service/terms_of_service_text.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
|
||||||
|
|
||||||
class QrCodeScreen extends StatefulWidget {
|
|
||||||
const QrCodeScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<QrCodeScreen> createState() => _QrCodeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _QrCodeScreenState extends State<QrCodeScreen> {
|
|
||||||
String _publicKey = Keys.npubKey;
|
|
||||||
bool isCopied = false;
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconBack,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(top: 10, right: 16, left: 16, bottom: 16),
|
|
||||||
child: Center(
|
|
||||||
child: Column(children: [
|
|
||||||
Text(
|
|
||||||
'Follow me on Nostr',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Color(0xFF302F38),
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 24, bottom: 83, right: 48, left: 48),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(32),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
height: 406,
|
|
||||||
width: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 32.0, bottom: 10),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(200),
|
|
||||||
child: Container(
|
|
||||||
width: 80,
|
|
||||||
height: 80,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
width: 2, color: Color(0xFFF2EFFF))),
|
|
||||||
child: Image.asset('assets/images/avatar.png')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Cameron Williamson',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Color(0xFF302F38),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
'@cameron',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12, color: AppColors.profileUserName),
|
|
||||||
),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Container(
|
|
||||||
width: 230,
|
|
||||||
child: Text(_publicKey,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: AppColors.profileSocialLinks))),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Container(
|
|
||||||
width: 143,
|
|
||||||
height: 143,
|
|
||||||
child: QrImageView(
|
|
||||||
eyeStyle: QrEyeStyle(
|
|
||||||
color: AppColors.qrCodeBody,
|
|
||||||
eyeShape: QrEyeShape.square),
|
|
||||||
dataModuleStyle:
|
|
||||||
QrDataModuleStyle(color: AppColors.qrCodeBody),
|
|
||||||
embeddedImage: AssetImage(
|
|
||||||
'assets/images/logo/drifter_logo_white.png'),
|
|
||||||
data: _publicKey,
|
|
||||||
version: QrVersions.auto,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
Expanded(child: SizedBox()),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100)),
|
|
||||||
backgroundColor: AppColors.buttonSecondaryDefaultBg),
|
|
||||||
onPressed: () {
|
|
||||||
Clipboard.setData(ClipboardData(text: _publicKey))
|
|
||||||
.then((value) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
||||||
content: Text('Copied to clipboard'),
|
|
||||||
));
|
|
||||||
isCopied = true;
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: isCopied
|
|
||||||
? Text(
|
|
||||||
'Copied',
|
|
||||||
style: TextStyle(color: AppColors.buttonSecondaryText),
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
'Copy user ID',
|
|
||||||
style: TextStyle(color: AppColors.buttonSecondaryText),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100)),
|
|
||||||
backgroundColor: AppColors.buttonPrimaryDefaultBg),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text(
|
|
||||||
'Share QR code',
|
|
||||||
style: TextStyle(color: AppColors.buttonPrimaryDefaultText),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
|
|
||||||
class SearchScreen extends StatefulWidget {
|
|
||||||
const SearchScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SearchScreen> createState() => _SearchScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SearchScreenState extends State<SearchScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Center(
|
|
||||||
child: Text('Search Page'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
|
|
||||||
class SettingsScreen extends StatefulWidget {
|
|
||||||
const SettingsScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SettingsScreen> createState() => _SettingsScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SettingsScreenState extends State<SettingsScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconPtimary,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
('Settings'),
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.topNavText,
|
|
||||||
),
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
centerTitle: true,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
elevation: 0,
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Text('Settings'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,9 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
|
import 'package:drifter/pages/main_screen/main_screen_widget.dart';
|
||||||
import 'package:drifter/pages/welcome_screen/welcome_screen.dart';
|
import 'package:drifter/pages/widgets/animated_widgets/rotate_icon.dart';
|
||||||
import 'package:drifter/theme/app_colors.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/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
class Splash extends StatefulWidget {
|
class Splash extends StatefulWidget {
|
||||||
const Splash({super.key});
|
const Splash({super.key});
|
||||||
@ -14,44 +13,76 @@ class Splash extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SplashState extends State<Splash> {
|
class _SplashState extends State<Splash> {
|
||||||
|
late final RotateIconController _rotateIconController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
_rotateIconController = RotateIconController();
|
||||||
|
|
||||||
Future.delayed(const Duration(seconds: 3), () {
|
Future.delayed(const Duration(seconds: 3), () {
|
||||||
Navigator.pushReplacement(context,
|
Navigator.pushReplacement(context,
|
||||||
MaterialPageRoute(builder: (context) => const WelcomeScreen()));
|
MaterialPageRoute(builder: (context) => const MainScreenWidget()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
dispose() {
|
||||||
|
_rotateIconController.repeat = null;
|
||||||
|
_rotateIconController.reset = null;
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
_rotateIconController.reset?.call();
|
||||||
|
_rotateIconController.repeat?.call();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColors.background,
|
backgroundColor: AppColors.background,
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 300,
|
height: 200,
|
||||||
),
|
),
|
||||||
Image.asset(
|
SvgPicture.asset(
|
||||||
'assets/images/icons/drifter_vector.png',
|
Assets.svg.drifterIcon,
|
||||||
height: 111,
|
height: 150,
|
||||||
width: 93,
|
width: 150,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 250,
|
height: 10,
|
||||||
),
|
),
|
||||||
if (Platform.isAndroid)
|
const Text(
|
||||||
const CircularProgressIndicator(
|
"Drifter",
|
||||||
color: AppColors.mainAccent,
|
style: TextStyle(
|
||||||
)
|
color: AppColors.mainAccent,
|
||||||
else
|
fontSize: 50,
|
||||||
const CupertinoActivityIndicator(
|
fontWeight: FontWeight.bold,
|
||||||
radius: 20,
|
),
|
||||||
)
|
),
|
||||||
],
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DisabledElevatedButton extends StatelessWidget {
|
|
||||||
const DisabledElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: null,
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDisabledBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDisabledText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActiveElevatedButton extends StatelessWidget {
|
|
||||||
const ActiveElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
UserData.isLogin
|
|
||||||
? Navigator.pushNamed(context, '/login')
|
|
||||||
: Navigator.pushNamed(context, '/createAccount');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDefaultBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DisabledElevatedButton extends StatelessWidget {
|
|
||||||
const DisabledElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: null,
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDisabledBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDisabledText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActiveElevatedButton extends StatelessWidget {
|
|
||||||
const ActiveElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(context, '/login');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDefaultBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
import 'package:drifter/pages/terms_of_service/btn_continue_terms_of_service.dart';
|
|
||||||
import 'package:drifter/pages/terms_of_service/terms_of_service_text.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
|
|
||||||
class TermsOfServiceScreen extends StatefulWidget {
|
|
||||||
const TermsOfServiceScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<TermsOfServiceScreen> createState() => _TermsOfServiceScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TermsOfServiceScreenState extends State<TermsOfServiceScreen> {
|
|
||||||
bool isChecked = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: AppColors.topNavIconBack,
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 10, right: 16, left: 16),
|
|
||||||
child: Center(
|
|
||||||
child: Column(children: [
|
|
||||||
Text(
|
|
||||||
'Terms of service',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Color(0xFF302F38),
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 20, bottom: 14),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
height: 568,
|
|
||||||
child: ListView(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
children: [TermsOfServiceText.termsOfService],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Checkbox(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(4)),
|
|
||||||
checkColor: Colors.white,
|
|
||||||
activeColor: AppColors.checkboxCheckedBg,
|
|
||||||
value: isChecked,
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
isChecked = value!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Text(
|
|
||||||
'I agree to the Terms of Service and Privacy Policy',
|
|
||||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
child: isChecked
|
|
||||||
? const ActiveElevatedButton()
|
|
||||||
: const DisabledElevatedButton(),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
abstract class TermsOfServiceText {
|
|
||||||
static final termsOfService = Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
children: <TextSpan>[
|
|
||||||
TextSpan(
|
|
||||||
text: 'We do not collect your data\n\n',
|
|
||||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"Effective as of Jan 20, 2023 for the distributed applications in the Play Store and the F-Droid Catalogue\n\n"
|
|
||||||
"The Amethyst app for Android does not collect or process any personal information from its users. The app is used to connect to third-party Nostr servers (also called Relays) that may or may not collect personal information and are not covered by this privacy policy. Each third-party relay server comes equipped with its own privacy policy and terms of use that can be viewed through the app or through that server's website. The developers of this open source project or maintainers of the distribution channels (app stores) do not have access to the data located in the user's phone. Accounts are fully maintained by the user. We do not have control over them.\n\n"
|
|
||||||
"Data from connected accounts is only stored locally on the device when it is required for functionality and performance of Amethyst. This data is strictly confidental and cannot be accessed by other apps (on non-rooted devices). Phone data can be deleted by clearing Amethyst's local storage or uninstalling the app.\n\n"
|
|
||||||
"You cannot use the Amethyst app for Android to submit Objectionable Content to relays. Objectionable Content includes, but is not limited to: (i) sexually explicit materials; (ii) obscene, defamatory, libelous, slanderous, violent and/or unlawful content or profanity; (iii) content that infringes upon the rights of any third party, including copyright, trademark, privacy, publicity or other personal or proprietary right, or that is deceptive or fraudulent; (iv) content that promotes the use or sale of illegal or regulated substances, tobacco products, ammunition and/or firearms; and (v) illegal content related to gambling.\n\n"
|
|
||||||
"We reserve the right to modify this Privacy Policy at any time. Any modifications to this Privacy Policy will be effective upon our posting the new terms and/or upon implementation of the new changes on the Service (or as otherwise indicated at the time of posting). In all cases, your continued use of the app after the posting of any modified Privacy Policy indicates your acceptance of the terms of the modified Privacy Policy.\n\n"
|
|
||||||
"If you have any questions about Amethyst or this privacy policy, you can send a message to amethyst@vitorpamplona.com")
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
import 'package:drifter/models/models.dart';
|
|
||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class WelcomeScreen extends StatelessWidget {
|
|
||||||
const WelcomeScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.mainBackground,
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Image(image: AssetImage('assets/images/logo/welcome.png')),
|
|
||||||
SizedBox(
|
|
||||||
height: 270,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
|
||||||
child: SizedBox(
|
|
||||||
height: 56,
|
|
||||||
width: double.infinity,
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
UserData.isLogin = true;
|
|
||||||
Navigator.pushNamed(context, '/terms');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Login',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultBg),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: SizedBox(
|
|
||||||
height: 56,
|
|
||||||
width: double.infinity,
|
|
||||||
child: OutlinedButton(
|
|
||||||
onPressed: () {
|
|
||||||
UserData.isLogin = false;
|
|
||||||
Navigator.pushNamed(context, '/terms');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Create an account',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
side: const MaterialStatePropertyAll(BorderSide(
|
|
||||||
width: 2,
|
|
||||||
color: AppColors.buttonOutlinedDefaultBorder)),
|
|
||||||
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.mainBackground,
|
|
||||||
),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonOutlinedDefaultText),
|
|
||||||
overlayColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonOutlinedPressedBg)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
76
lib/pages/widgets/animated_widgets/rotate_icon.dart
Normal 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
32
lib/pages/widgets/app_bar_icon_button.dart
Normal 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],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
33
lib/pages/widgets/custom_text_button.dart
Normal 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
1
lib/pages/widgets/flust_bar_type.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
enum FlushBarType { success, info, warning }
|
64
lib/pages/widgets/show_flush_bar.dart
Normal 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);
|
||||||
|
}
|
@ -1,96 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
abstract class AppColors {
|
abstract class AppColors {
|
||||||
static const background = Color(0xFF4f46f1);
|
static const background = const Color(0xFF4f46f1);
|
||||||
static const mainAccent = Color(0xFFFFCC11);
|
static const mainAccent = const Color(0xFFFFCC11);
|
||||||
static const mainBackground = Color(0xFFF2EFFF);
|
static const mainBackground = const Color(0xFFF2EFFF);
|
||||||
|
|
||||||
static const label = Color(0xFF7F71C8);
|
// snack bar
|
||||||
|
static const snackBarBackSuccess = const Color(0xFFB9E9D4);
|
||||||
// Button
|
static const snackBarBackError = const Color(0xFFFFDAD4);
|
||||||
static const buttonPrimaryDefaultBg = Color(0xFF4F46F1);
|
static const snackBarBackInfo = const Color(0xFFDAE2FF);
|
||||||
static const buttonPrimaryDefaultText = Color(0xFFFFFFFF);
|
static const snackBarTextSuccess = const Color(0xFF006C4D);
|
||||||
static const buttonPrimaryDisabledBg = Color(0x1A18171B);
|
static const snackBarTextError = const Color(0xFF930006);
|
||||||
static const buttonPrimaryDisabledText = Color(0xFFA7A7A8);
|
static const snackBarTextInfo = const Color(0xFF002A78);
|
||||||
static const buttonOutlinedDefaultBorder = Color(0xFF4F46F1);
|
|
||||||
static const buttonOutlinedDefaultText = Color(0xFF4F46F1);
|
|
||||||
static const buttonOutlinedPressedBg = Color(0xFFE3E0F9);
|
|
||||||
static const buttonSecondaryDefaultBg = Color(0xFFDCDAFC);
|
|
||||||
static const buttonSecondaryIcon = Color(0xFF2D25BC);
|
|
||||||
static const buttonSecondaryText = Color(0xFF2D25BC);
|
|
||||||
|
|
||||||
// TopNav
|
|
||||||
|
|
||||||
static const topNavIconPtimary = Color(0xFF787680);
|
|
||||||
static const topNavText = Color(0xFF000000);
|
|
||||||
static const topNavIconBack = Color(0xFF4A40EC);
|
|
||||||
static const topNavIconBg = Color(0xFFE3E0F9);
|
|
||||||
|
|
||||||
// BottomNav
|
|
||||||
|
|
||||||
static const bottomNavIconDefault = Color(0xFF787680);
|
|
||||||
static const bottomNavIconActive = Color(0xFF4A40EC);
|
|
||||||
static const bottomNavBackground = Color(0xFFFFFFFF);
|
|
||||||
static const bottomNavShadow = Color(0xFFF2EFFF);
|
|
||||||
|
|
||||||
// Checkbox
|
|
||||||
static const checkboxCheckedIcon = Color(0xFFFFFFFF);
|
|
||||||
static const checkboxCheckedBg = Color(0xFF4A40EC);
|
|
||||||
static const checkboxEmptyBorder = Color(0xFF302F38);
|
|
||||||
static const checkboxTextLabel = Color(0xFF302F38);
|
|
||||||
static const checkboxDisabledBg = Color(0xFFB7B3F7);
|
|
||||||
static const checkboxDisabledIcon = Color(0xFFFFFFFF);
|
|
||||||
|
|
||||||
// ToggleSwitch
|
|
||||||
|
|
||||||
static const toggleSwitchBg = Color(0xFFE2DFFF);
|
|
||||||
static const toggleSwitchTextInactive = Color(0xFF837CA3);
|
|
||||||
static const toggleSwitchActiveBg = Color(0xFFFCF8FF);
|
|
||||||
static const toggleSwitchTextActive = Color(0xFF4F46F1);
|
|
||||||
|
|
||||||
// TextField
|
|
||||||
|
|
||||||
static const textFieldDefaultBg = Color(0xFFFCF8FF);
|
|
||||||
static const textFieldDefaultIconLead = Color(0xFFC9BFFF);
|
|
||||||
static const textFieldDefaultIconTrail = Color(0xFF5D55F2);
|
|
||||||
static const textFieldDefaultText = Color(0xFF837CA3);
|
|
||||||
|
|
||||||
static const textFieldActiveBg = Color(0xFFFFFCFF);
|
|
||||||
static const textFieldActiveIconLead = Color(0xFF5D55F2);
|
|
||||||
static const textFieldActiveIconTrail = Color(0xFF5D55F2);
|
|
||||||
static const textFieldActiveText = Color(0xFF252229);
|
|
||||||
static const textFieldActiveLabel = Color(0xFF5D55F2);
|
|
||||||
|
|
||||||
static const noteText = Color(0xFF787680);
|
|
||||||
|
|
||||||
static const mainDarkBlue = Color.fromRGBO(3, 37, 65, 1);
|
static const mainDarkBlue = Color.fromRGBO(3, 37, 65, 1);
|
||||||
static const mainLightBlue = Color.fromRGBO(48, 86, 117, 1);
|
static const mainLightBlue = Color.fromRGBO(48, 86, 117, 1);
|
||||||
|
|
||||||
// Post
|
|
||||||
|
|
||||||
static const postFullName = Color(0xFF302F38);
|
|
||||||
static const postUserName = Color(0xFFC8C5D0);
|
|
||||||
static const postBg = Color(0xFFF9F8FF);
|
|
||||||
static const postTime = Color(0xFFC8C5D0);
|
|
||||||
static const postMoreIcon = Color(0xFF323232);
|
|
||||||
static const postBodyText = Color(0xFF000000);
|
|
||||||
static const postBodyLink = Color(0xFF3A00E5);
|
|
||||||
static const postActionNumber = Color(0xFFC8C5D0);
|
|
||||||
static const postActionIconDefault = Color(0xFFC8C5D0);
|
|
||||||
static const postActionIconPressed = Color(0xFFFE82B1);
|
|
||||||
static const postBookmark = Color(0xFF8482FF);
|
|
||||||
|
|
||||||
// Profile
|
|
||||||
|
|
||||||
static const profileWrapperBg = Color(0xFFF9F8FF);
|
|
||||||
static const profileFullName = Color(0xFF302F38);
|
|
||||||
static const profileUserName = Color(0xFF787680);
|
|
||||||
static const profileSummary = Color(0xFF302F38);
|
|
||||||
static const profileKeyField = Color(0xFFF2EFFF);
|
|
||||||
static const profileKeyText = Color(0xFF6E61A0);
|
|
||||||
static const profileSocialLinks = Color(0xFF4F46F1);
|
|
||||||
static const profileSocialIcons = Color(0xFF837CA3);
|
|
||||||
|
|
||||||
// QR code
|
|
||||||
static const qrCodeBody = Color(0xFF25207A);
|
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ abstract class Assets {
|
|||||||
class _PNG {
|
class _PNG {
|
||||||
const _PNG();
|
const _PNG();
|
||||||
|
|
||||||
// String get drifterIcon => "assets/images/logo/drifter_vector.png";
|
String get drifterPNG => "assets/images/logo/drifter_vector.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SVG {
|
class _SVG {
|
||||||
const _SVG();
|
const _SVG();
|
||||||
|
|
||||||
String get drifterIcon => "assets/images/logo/drifter_logo_circle.svg";
|
String get drifterIcon => "assets/images/logo/drifter_logo_circle.svg";
|
||||||
String get welcomeImage => "assets/images/logo/welcome.svg";
|
String get x => "assets/images/svg/x.svg";
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import 'package:drifter/theme/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DisabledElevatedButton extends StatelessWidget {
|
|
||||||
const DisabledElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: null,
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDisabledBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDisabledText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActiveElevatedButton extends StatelessWidget {
|
|
||||||
const ActiveElevatedButton({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(context, '/login');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Continue',
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
style: ButtonStyle(
|
|
||||||
shape: MaterialStatePropertyAll(
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100))),
|
|
||||||
backgroundColor:
|
|
||||||
const MaterialStatePropertyAll(AppColors.buttonPrimaryDefaultBg),
|
|
||||||
foregroundColor: const MaterialStatePropertyAll(
|
|
||||||
AppColors.buttonPrimaryDefaultText)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
34
pubspec.lock
@ -352,35 +352,11 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.3"
|
version: "3.7.3"
|
||||||
qr:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: qr
|
|
||||||
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1"
|
|
||||||
qr_flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: qr_flutter
|
|
||||||
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.1.0"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
sliding_switch:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: sliding_switch
|
|
||||||
sha256: "049a9582c9bc30913ce4e34eb26063b468acf5fe47a053636bbf950e5b180dc0"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -429,14 +405,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.16"
|
version: "0.4.16"
|
||||||
toggle_switch:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: toggle_switch
|
|
||||||
sha256: "9e6af1f0c5a97d9de41109dc7b9e1b3bbe73417f89b10e0e44dc834fb493d4cb"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -495,4 +463,4 @@ packages:
|
|||||||
version: "6.2.2"
|
version: "6.2.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.6 <3.0.0"
|
dart: ">=2.19.6 <3.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0-0"
|
||||||
|
@ -34,13 +34,12 @@ dependencies:
|
|||||||
nostr_tools: ^1.0.7
|
nostr_tools: ^1.0.7
|
||||||
flutter_secure_storage: ^8.0.0
|
flutter_secure_storage: ^8.0.0
|
||||||
flutter_svg: ^2.0.5
|
flutter_svg: ^2.0.5
|
||||||
toggle_switch: ^2.1.0
|
keyboard_dismisser: ^3.0.0
|
||||||
sliding_switch: ^1.1.0
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
another_flushbar: ^1.12.29
|
another_flushbar: ^1.12.29
|
||||||
qr_flutter: ^4.1.0
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -65,10 +64,8 @@ flutter:
|
|||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
|
||||||
- assets/images/icons/
|
|
||||||
- assets/images/logo/
|
- assets/images/logo/
|
||||||
|
- assets/images/svg/
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|