Merge pull request #225 from cypherstack/desktop

Desktop
This commit is contained in:
julian-CStack 2022-11-15 21:03:41 -06:00 committed by GitHub
commit 4fb35be79f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 2624 additions and 1897 deletions

View file

@ -0,0 +1,11 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" rx="24" fill="#E0E3E3"/>
<g clip-path="url(#clip0_5813_29086)">
<path d="M13.5 30.5625C13.5 29.8365 14.0878 29.25 14.8125 29.25H17.0544C17.5605 28.0893 18.7172 27.2812 20.0625 27.2812C21.4078 27.2812 22.5275 28.0893 23.0689 29.25H33.1875C33.9135 29.25 34.5 29.8365 34.5 30.5625C34.5 31.2885 33.9135 31.875 33.1875 31.875H23.0689C22.5275 33.0357 21.4078 33.8438 20.0625 33.8438C18.7172 33.8438 17.5605 33.0357 17.0544 31.875H14.8125C14.0878 31.875 13.5 31.2885 13.5 30.5625ZM21.375 30.5625C21.375 29.8365 20.7885 29.25 20.0625 29.25C19.3365 29.25 18.75 29.8365 18.75 30.5625C18.75 31.2885 19.3365 31.875 20.0625 31.875C20.7885 31.875 21.375 31.2885 21.375 30.5625ZM27.9375 20.7188C29.2828 20.7188 30.4025 21.5268 30.9439 22.6875H33.1875C33.9135 22.6875 34.5 23.274 34.5 24C34.5 24.726 33.9135 25.3125 33.1875 25.3125H30.9439C30.4025 26.4732 29.2828 27.2812 27.9375 27.2812C26.5922 27.2812 25.4355 26.4732 24.9311 25.3125H14.8125C14.0878 25.3125 13.5 24.726 13.5 24C13.5 23.274 14.0878 22.6875 14.8125 22.6875H24.9311C25.4355 21.5268 26.5922 20.7188 27.9375 20.7188ZM29.25 24C29.25 23.274 28.6635 22.6875 27.9375 22.6875C27.2115 22.6875 26.625 23.274 26.625 24C26.625 24.726 27.2115 25.3125 27.9375 25.3125C28.6635 25.3125 29.25 24.726 29.25 24ZM33.1875 16.125C33.9135 16.125 34.5 16.7128 34.5 17.4375C34.5 18.1635 33.9135 18.75 33.1875 18.75H24.3814C23.84 19.9107 22.7203 20.7188 21.375 20.7188C20.0297 20.7188 18.873 19.9107 18.3686 18.75H14.8125C14.0878 18.75 13.5 18.1635 13.5 17.4375C13.5 16.7128 14.0878 16.125 14.8125 16.125H18.3686C18.873 14.9663 20.0297 14.1562 21.375 14.1562C22.7203 14.1562 23.84 14.9663 24.3814 16.125H33.1875ZM20.0625 17.4375C20.0625 18.1635 20.649 18.75 21.375 18.75C22.101 18.75 22.6875 18.1635 22.6875 17.4375C22.6875 16.7128 22.101 16.125 21.375 16.125C20.649 16.125 20.0625 16.7128 20.0625 17.4375Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_5813_29086">
<rect width="21" height="21" fill="white" transform="translate(13.5 13.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -76,7 +76,7 @@ void main() async {
if (Util.isDesktop) { if (Util.isDesktop) {
setWindowTitle('Stack Wallet'); setWindowTitle('Stack Wallet');
setWindowMinSize(const Size(1200, 900)); setWindowMinSize(const Size(1200, 1100));
setWindowMaxSize(Size.infinite); setWindowMaxSize(Size.infinite);
} }

View file

@ -13,7 +13,9 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/address_book_card.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/loading_indicator.dart';
@ -21,8 +23,6 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/utilities/util.dart';
class AddressBookView extends ConsumerStatefulWidget { class AddressBookView extends ConsumerStatefulWidget {
const AddressBookView({Key? key, this.coin}) : super(key: key); const AddressBookView({Key? key, this.coin}) : super(key: key);
@ -103,8 +103,13 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
final addressBookEntriesFuture = ref.watch( final addressBookEntriesFuture = ref.watch(
addressBookServiceProvider.select((value) => value.addressBookEntries)); addressBookServiceProvider.select((value) => value.addressBookEntries));
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background, backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar( appBar: AppBar(
leading: AppBarBackButton( leading: AppBarBackButton(
onPressed: () { onPressed: () {
@ -128,7 +133,8 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
key: const Key("addressBookFilterViewButton"), key: const Key("addressBookFilterViewButton"),
size: 36, size: 36,
shadows: const [], shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background, color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.filter, Assets.svg.filter,
color: Theme.of(context) color: Theme.of(context)
@ -157,7 +163,8 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
key: const Key("addressBookAddNewContactViewButton"), key: const Key("addressBookAddNewContactViewButton"),
size: 36, size: 36,
shadows: const [], shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background, color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.plus, Assets.svg.plus,
color: Theme.of(context) color: Theme.of(context)
@ -192,6 +199,20 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
child: IntrinsicHeight( child: IntrinsicHeight(
child: Padding( child: Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: child,
),
),
),
),
);
},
),
);
},
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height - 271,
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -199,7 +220,8 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: !isDesktop
? TextField(
autocorrect: Util.isDesktop ? false : true, autocorrect: Util.isDesktop ? false : true,
enableSuggestions: Util.isDesktop ? false : true, enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController, controller: _searchController,
@ -246,11 +268,10 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
) )
: null, : null,
), ),
)
: null,
), ),
), if (!isDesktop) const SizedBox(height: 16),
const SizedBox(
height: 16,
),
Text( Text(
"Favorites", "Favorites",
style: STextStyles.smallMed12(context), style: STextStyles.smallMed12(context),
@ -261,8 +282,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
FutureBuilder( FutureBuilder(
future: addressBookEntriesFuture, future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) { builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState == if (snapshot.connectionState == ConnectionState.done &&
ConnectionState.done &&
snapshot.hasData) { snapshot.hasData) {
_cacheFav = snapshot.data!; _cacheFav = snapshot.data!;
} }
@ -272,29 +292,25 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
} else { } else {
if (_cacheFav!.isNotEmpty) { if (_cacheFav!.isNotEmpty) {
return RoundedWhiteContainer( return RoundedWhiteContainer(
padding: const EdgeInsets.all(0), padding: EdgeInsets.all(!isDesktop ? 0 : 15),
child: Column( child: Column(
children: [ children: [
..._cacheFav! ..._cacheFav!
.where((element) => element.addresses .where((element) => element.addresses
.where((e) => ref.watch( .where((e) => ref.watch(
addressBookFilterProvider addressBookFilterProvider.select(
.select((value) => value (value) =>
.coins value.coins.contains(e.coin))))
.contains(e.coin))))
.isNotEmpty) .isNotEmpty)
.where((e) => .where((e) =>
e.isFavorite && e.isFavorite &&
ref ref
.read( .read(addressBookServiceProvider)
addressBookServiceProvider)
.matches(_searchTerm, e)) .matches(_searchTerm, e))
.where( .where((element) => element.isFavorite)
(element) => element.isFavorite)
.map( .map(
(e) => AddressBookCard( (e) => AddressBookCard(
key: Key( key: Key("favContactCard_${e.id}_key"),
"favContactCard_${e.id}_key"),
contactId: e.id, contactId: e.id,
), ),
), ),
@ -327,8 +343,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
FutureBuilder( FutureBuilder(
future: addressBookEntriesFuture, future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) { builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState == if (snapshot.connectionState == ConnectionState.done &&
ConnectionState.done &&
snapshot.hasData) { snapshot.hasData) {
_cache = snapshot.data!; _cache = snapshot.data!;
} }
@ -337,32 +352,37 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
return const LoadingIndicator(); return const LoadingIndicator();
} else { } else {
if (_cache!.isNotEmpty) { if (_cache!.isNotEmpty) {
return RoundedWhiteContainer( return Column(
padding: const EdgeInsets.all(0), children: [
RoundedWhiteContainer(
padding: EdgeInsets.all(!isDesktop ? 0 : 15),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
children: [ children: [
..._cache! ..._cache!
.where((element) => element.addresses .where((element) => element.addresses
.where((e) => ref.watch( .where((e) => ref.watch(
addressBookFilterProvider addressBookFilterProvider.select(
.select((value) => value (value) => value.coins
.coins
.contains(e.coin)))) .contains(e.coin))))
.isNotEmpty) .isNotEmpty)
.where((e) => ref .where((e) => ref
.read(addressBookServiceProvider) .read(addressBookServiceProvider)
.matches(_searchTerm, e)) .matches(_searchTerm, e))
.where( .where((element) => !element.isFavorite)
(element) => !element.isFavorite)
.map( .map(
(e) => AddressBookCard( (e) => AddressBookCard(
key: Key( key: Key(
"contactCard_${e.id}_key"), "desktopContactCard_${e.id}_key"),
contactId: e.id, contactId: e.id,
), ),
), ),
], ],
), ),
),
),
],
); );
} else { } else {
return RoundedWhiteContainer( return RoundedWhiteContainer(
@ -380,12 +400,6 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
], ],
), ),
), ),
),
),
),
);
},
),
); );
} }
} }

View file

@ -224,7 +224,11 @@ class _AddAddressBookEntryViewState
const DesktopDialogCloseButton(), const DesktopDialogCloseButton(),
], ],
), ),
Expanded(child: child), Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: child,
)),
], ],
); );
}, },
@ -248,9 +252,12 @@ class _AddAddressBookEntryViewState
child: IntrinsicHeight( child: IntrinsicHeight(
child: Column( child: Column(
children: [ children: [
const SizedBox( if (!isDesktop) const SizedBox(height: 4),
height: 4, isDesktop
), ? Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () {
if (_selectedEmoji != null) { if (_selectedEmoji != null) {
@ -263,14 +270,18 @@ class _AddAddressBookEntryViewState
///TODO if desktop make dialog ///TODO if desktop make dialog
!isDesktop !isDesktop
? showModalBottomSheet<dynamic>( ? showModalBottomSheet<dynamic>(
backgroundColor: Colors.transparent, backgroundColor:
Colors.transparent,
context: context, context: context,
shape: const RoundedRectangleBorder( shape:
borderRadius: BorderRadius.vertical( const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(
top: Radius.circular(20), top: Radius.circular(20),
), ),
), ),
builder: (_) => const EmojiSelectSheet(), builder: (_) =>
const EmojiSelectSheet(),
).then((value) { ).then((value) {
if (value is Emoji) { if (value is Emoji) {
setState(() { setState(() {
@ -290,40 +301,279 @@ class _AddAddressBookEntryViewState
children: [ children: [
Padding( Padding(
padding: padding:
const EdgeInsets.all(32), const EdgeInsets
.all(32),
child: Text( child: Text(
"Select emoji", "Select emoji",
style: style: STextStyles
STextStyles.desktopH3( .desktopH3(
context), context),
textAlign: TextAlign.center, textAlign:
TextAlign
.center,
), ),
), ),
], ],
), ),
Expanded( Expanded(
child: LayoutBuilder( child: LayoutBuilder(
builder: builder: (context,
(context, constraints) { constraints) {
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: scrollDirection:
Axis.vertical, Axis.vertical,
child: ConstrainedBox( child:
ConstrainedBox(
constraints: constraints:
BoxConstraints( BoxConstraints(
minHeight: constraints minHeight:
constraints
.maxHeight, .maxHeight,
minWidth: constraints minWidth:
constraints
.maxWidth, .maxWidth,
), ),
child: IntrinsicHeight( child:
IntrinsicHeight(
child: Column( child: Column(
children: const [ children: const [
Padding( Padding(
padding: EdgeInsets padding:
.symmetric( EdgeInsets.symmetric(horizontal: 32),
horizontal: // child:
32), // EmojiSelectSheet(),
),
],
),
),
),
);
},
),
),
],
),
);
}).then((value) {
if (value is Emoji) {
setState(() {
_selectedEmoji = value;
});
}
});
},
child: SizedBox(
height: 56,
width: 56,
child: Stack(
children: [
Container(
height: 56,
width: 56,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(24),
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveBG,
),
child: Center(
child: _selectedEmoji == null
? SvgPicture.asset(
Assets.svg.user,
height: 30,
width: 30,
)
: Text(
_selectedEmoji!.char,
style: STextStyles
.pageTitleH1(context),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
height: 14,
width: 14,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(14),
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
child: Center(
child: _selectedEmoji == null
? SvgPicture.asset(
Assets.svg.plus,
color: Theme.of(context)
.extension<
StackColors>()!
.textWhite,
width: 12,
height: 12,
)
: SvgPicture.asset(
Assets.svg.thickX,
color: Theme.of(context)
.extension<
StackColors>()!
.textWhite,
width: 8,
height: 8,
),
),
),
)
],
),
),
),
const SizedBox(width: 8),
SizedBox(
width: isDesktop ? 450 : null,
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect:
Util.isDesktop ? false : true,
enableSuggestions:
Util.isDesktop ? false : true,
controller: nameController,
focusNode: nameFocusNode,
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Enter contact name",
nameFocusNode,
context,
).copyWith(
labelStyle:
STextStyles.fieldLabel(context),
suffixIcon: ref
.read(
contactNameIsNotEmptyStateProvider
.state)
.state
? Padding(
padding:
const EdgeInsets.only(
right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
nameController
.text = "";
});
},
),
],
),
),
)
: null,
),
onChanged: (newValue) {
ref
.read(
contactNameIsNotEmptyStateProvider
.state)
.state = newValue.isNotEmpty;
},
),
),
),
],
)
: Column(
children: [
GestureDetector(
onTap: () {
if (_selectedEmoji != null) {
setState(() {
_selectedEmoji = null;
});
return;
}
///TODO if desktop make dialog
!isDesktop
? showModalBottomSheet<dynamic>(
backgroundColor:
Colors.transparent,
context: context,
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) =>
const EmojiSelectSheet(),
).then((value) {
if (value is Emoji) {
setState(() {
_selectedEmoji = value;
});
}
})
: showDialog<dynamic>(
context: context,
builder: (context) {
return DesktopDialog(
maxHeight: 700,
maxWidth: 700,
child: Column(
children: [
Row(
children: [
Padding(
padding:
const EdgeInsets
.all(32),
child: Text(
"Select emoji",
style: STextStyles
.desktopH3(
context),
textAlign:
TextAlign
.center,
),
),
],
),
Expanded(
child: LayoutBuilder(
builder: (context,
constraints) {
return SingleChildScrollView(
scrollDirection:
Axis.vertical,
child:
ConstrainedBox(
constraints:
BoxConstraints(
minHeight:
constraints
.maxHeight,
minWidth:
constraints
.maxWidth,
),
child:
IntrinsicHeight(
child: Column(
children: const [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 32),
// child: // child:
// EmojiSelectSheet(), // EmojiSelectSheet(),
), ),
@ -355,7 +605,8 @@ class _AddAddressBookEntryViewState
height: 48, height: 48,
width: 48, width: 48,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24), borderRadius:
BorderRadius.circular(24),
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textFieldActiveBG, .textFieldActiveBG,
@ -369,8 +620,8 @@ class _AddAddressBookEntryViewState
) )
: Text( : Text(
_selectedEmoji!.char, _selectedEmoji!.char,
style: STextStyles.pageTitleH1( style: STextStyles
context), .pageTitleH1(context),
), ),
), ),
), ),
@ -380,7 +631,8 @@ class _AddAddressBookEntryViewState
height: 14, height: 14,
width: 14, width: 14,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14), borderRadius:
BorderRadius.circular(14),
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark), .accentColorDark),
@ -389,7 +641,8 @@ class _AddAddressBookEntryViewState
? SvgPicture.asset( ? SvgPicture.asset(
Assets.svg.plus, Assets.svg.plus,
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<
StackColors>()!
.textWhite, .textWhite,
width: 12, width: 12,
height: 12, height: 12,
@ -397,7 +650,8 @@ class _AddAddressBookEntryViewState
: SvgPicture.asset( : SvgPicture.asset(
Assets.svg.thickX, Assets.svg.thickX,
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<
StackColors>()!
.textWhite, .textWhite,
width: 8, width: 8,
height: 8, height: 8,
@ -409,16 +663,16 @@ class _AddAddressBookEntryViewState
), ),
), ),
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: TextField(
autocorrect: Util.isDesktop ? false : true, autocorrect:
enableSuggestions: Util.isDesktop ? false : true, Util.isDesktop ? false : true,
enableSuggestions:
Util.isDesktop ? false : true,
controller: nameController, controller: nameController,
focusNode: nameFocusNode, focusNode: nameFocusNode,
style: STextStyles.field(context), style: STextStyles.field(context),
@ -428,11 +682,13 @@ class _AddAddressBookEntryViewState
context, context,
).copyWith( ).copyWith(
suffixIcon: ref suffixIcon: ref
.read(contactNameIsNotEmptyStateProvider .read(
contactNameIsNotEmptyStateProvider
.state) .state)
.state .state
? Padding( ? Padding(
padding: const EdgeInsets.only(right: 0), padding: const EdgeInsets.only(
right: 0),
child: UnconstrainedBox( child: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [
@ -440,7 +696,8 @@ class _AddAddressBookEntryViewState
child: const XIcon(), child: const XIcon(),
onTap: () async { onTap: () async {
setState(() { setState(() {
nameController.text = ""; nameController
.text = "";
}); });
}, },
), ),
@ -453,11 +710,15 @@ class _AddAddressBookEntryViewState
onChanged: (newValue) { onChanged: (newValue) {
ref ref
.read( .read(
contactNameIsNotEmptyStateProvider.state) contactNameIsNotEmptyStateProvider
.state)
.state = newValue.isNotEmpty; .state = newValue.isNotEmpty;
}, },
), ),
), ),
],
),
if (!isDesktop) const SizedBox(height: 8),
if (forms.length <= 1) if (forms.length <= 1)
const SizedBox( const SizedBox(
height: 8, height: 8,

View file

@ -14,14 +14,13 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/utilities/util.dart';
class NewContactAddressEntryForm extends ConsumerStatefulWidget { class NewContactAddressEntryForm extends ConsumerStatefulWidget {
const NewContactAddressEntryForm({ const NewContactAddressEntryForm({
Key? key, Key? key,
@ -70,6 +69,7 @@ class _NewContactAddressEntryFormState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
return Column( return Column(
children: [ children: [
TextField( TextField(
@ -168,6 +168,7 @@ class _NewContactAddressEntryFormState
addressLabelFocusNode, addressLabelFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
suffixIcon: addressLabelController.text.isNotEmpty suffixIcon: addressLabelController.text.isNotEmpty
? Padding( ? Padding(
padding: const EdgeInsets.only(right: 0), padding: const EdgeInsets.only(right: 0),
@ -212,6 +213,7 @@ class _NewContactAddressEntryFormState
addressFocusNode, addressFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [

View file

@ -1,9 +1,11 @@
import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui; import 'dart:ui' as ui;
// import 'package:document_file_save_plus/document_file_save_plus.dart'; // import 'package:document_file_save_plus/document_file_save_plus.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
@ -71,19 +73,53 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
await image.toByteData(format: ui.ImageByteFormat.png); await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List(); Uint8List pngBytes = byteData!.buffer.asUint8List();
// if (shouldSaveInsteadOfShare) { if (shouldSaveInsteadOfShare) {
if (Util.isDesktop) {
final dir = Directory("${Platform.environment['HOME']}");
if (!dir.existsSync()) {
throw Exception(
"Home dir not found while trying to open filepicker on QR image save");
}
final path = await FilePicker.platform.saveFile(
fileName: "qrcode.png",
initialDirectory: dir.path,
);
if (path != null) {
final file = File(path);
if (file.existsSync()) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "$path already exists!",
context: context,
),
);
} else {
await file.writeAsBytes(pngBytes);
unawaited(
showFloatingFlushBar(
type: FlushBarType.success,
message: "$path saved!",
context: context,
),
);
}
}
} else {
// await DocumentFileSavePlus.saveFile( // await DocumentFileSavePlus.saveFile(
// pngBytes, // pngBytes,
// "receive_qr_code_${DateTime.now().toLocal().toIso8601String()}.png", // "receive_qr_code_${DateTime.now().toLocal().toIso8601String()}.png",
// "image/png"); // "image/png");
// } else { }
} else {
final tempDir = await getTemporaryDirectory(); final tempDir = await getTemporaryDirectory();
final file = await File("${tempDir.path}/qrcode.png").create(); final file = await File("${tempDir.path}/qrcode.png").create();
await file.writeAsBytes(pngBytes); await file.writeAsBytes(pngBytes);
await Share.shareFiles(["${tempDir.path}/qrcode.png"], await Share.shareFiles(["${tempDir.path}/qrcode.png"],
text: "Receive URI QR Code"); text: "Receive URI QR Code");
// } }
} catch (e) { } catch (e) {
debugPrint(e.toString()); debugPrint(e.toString());
} }
@ -511,6 +547,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
borderColor: Theme.of(context) borderColor: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.background, .background,
width: isDesktop ? 370 : null,
child: Column( child: Column(
children: [ children: [
Text( Text(
@ -542,7 +579,11 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
height: 12, height: 12,
), ),
Row( Row(
mainAxisAlignment: isDesktop
? MainAxisAlignment.center
: MainAxisAlignment.start,
children: [ children: [
if (!isDesktop)
SecondaryButton( SecondaryButton(
width: 170, width: 170,
desktopMed: true, desktopMed: true,
@ -559,6 +600,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
.buttonTextSecondary, .buttonTextSecondary,
), ),
), ),
if (!isDesktop)
const SizedBox( const SizedBox(
width: 16, width: 16,
), ),
@ -567,6 +609,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
desktopMed: true, desktopMed: true,
onPressed: () async { onPressed: () async {
// TODO: add save functionality instead of share // TODO: add save functionality instead of share
// save works on linux at the moment
await _capturePng(true); await _capturePng(true);
}, },
label: "Save", label: "Save",

View file

@ -14,11 +14,10 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import '../../../widgets/rounded_white_container.dart';
class BaseCurrencySettingsView extends ConsumerStatefulWidget { class BaseCurrencySettingsView extends ConsumerStatefulWidget {
const BaseCurrencySettingsView({Key? key}) : super(key: key); const BaseCurrencySettingsView({Key? key}) : super(key: key);
@ -37,6 +36,11 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
final _searchFocusNode = FocusNode(); final _searchFocusNode = FocusNode();
void onTap(int index) { void onTap(int index) {
if (Util.isDesktop) {
setState(() {
current = currenciesWithoutSelected[index];
});
} else {
if (currenciesWithoutSelected[index] == current || current.isEmpty) { if (currenciesWithoutSelected[index] == current || current.isEmpty) {
// ignore if already selected currency // ignore if already selected currency
return; return;
@ -46,6 +50,7 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
currenciesWithoutSelected.insert(0, current); currenciesWithoutSelected.insert(0, current);
ref.read(prefsChangeNotifierProvider).currency = current; ref.read(prefsChangeNotifierProvider).currency = current;
} }
}
BorderRadius? _borderRadius(int index) { BorderRadius? _borderRadius(int index) {
if (index == 0 && currenciesWithoutSelected.length == 1) { if (index == 0 && currenciesWithoutSelected.length == 1) {
@ -82,6 +87,15 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
@override @override
void initState() { void initState() {
_searchController = TextEditingController(); _searchController = TextEditingController();
if (Util.isDesktop) {
currenciesWithoutSelected =
ref.read(baseCurrenciesProvider).map.keys.toList();
current = ref.read(prefsChangeNotifierProvider).currency;
if (current.isNotEmpty) {
currenciesWithoutSelected.remove(current);
currenciesWithoutSelected.insert(0, current);
}
}
super.initState(); super.initState();
} }
@ -94,6 +108,9 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
if (!isDesktop) {
current = ref current = ref
.watch(prefsChangeNotifierProvider.select((value) => value.currency)); .watch(prefsChangeNotifierProvider.select((value) => value.currency));
@ -101,12 +118,14 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
.watch(baseCurrenciesProvider.select((value) => value.map)) .watch(baseCurrenciesProvider.select((value) => value.map))
.keys .keys
.toList(); .toList();
if (current.isNotEmpty) { if (current.isNotEmpty) {
currenciesWithoutSelected.remove(current); currenciesWithoutSelected.remove(current);
currenciesWithoutSelected.insert(0, current); currenciesWithoutSelected.insert(0, current);
} }
}
currenciesWithoutSelected = _filtered(); currenciesWithoutSelected = _filtered();
final isDesktop = Util.isDesktop;
return ConditionalParent( return ConditionalParent(
condition: !isDesktop, condition: !isDesktop,
@ -181,7 +200,20 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
child: PrimaryButton( child: PrimaryButton(
label: "Save changes", label: "Save changes",
desktopMed: true, desktopMed: true,
onPressed: Navigator.of(context).pop, onPressed: () {
ref.read(prefsChangeNotifierProvider).currency =
current;
if (ref
.read(prefsChangeNotifierProvider)
.externalCalls) {
ref
.read(priceAnd24hChangeNotifierProvider)
.updatePrice();
}
Navigator.of(context).pop();
},
), ),
), ),
], ],

View file

@ -18,6 +18,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/progress_bar.dart'; import 'package:stackwallet/widgets/progress_bar.dart';
@ -523,7 +524,7 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
if (mounted) { if (mounted) {
// pop encryption progress dialog // pop encryption progress dialog
Navigator.of(context).pop(); if (!isDesktop) Navigator.of(context).pop();
if (result) { if (result) {
await showDialog<dynamic>( await showDialog<dynamic>(
@ -607,14 +608,52 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
return; return;
} }
unawaited(showDialog<dynamic>( unawaited(
showDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (_) => const StackDialog( builder: (_) {
title: "Encrypting backup", if (Util.isDesktop) {
message: "This shouldn't take long", return DesktopDialog(
maxHeight: double.infinity,
maxWidth: 450,
child: Padding(
padding: const EdgeInsets.all(
32,
), ),
)); child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Encrypting initial backup",
style:
STextStyles.desktopH3(
context),
),
const SizedBox(
height: 40,
),
Text(
"This shouldn't take long",
style: STextStyles
.desktopTextExtraExtraSmall(
context),
),
],
),
),
);
} else {
return const StackDialog(
title: "Encrypting initial backup",
message: "This shouldn't take long",
);
}
},
),
);
// make sure the dialog is able to be displayed for at least 1 second // make sure the dialog is able to be displayed for at least 1 second
await Future<void>.delayed( await Future<void>.delayed(
const Duration(seconds: 1)); const Duration(seconds: 1));
@ -637,7 +676,7 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
if (mounted) { if (mounted) {
// pop encryption progress dialog // pop encryption progress dialog
Navigator.of(context).pop(); if (!isDesktop) Navigator.of(context).pop();
if (result) { if (result) {
await showDialog<dynamic>( await showDialog<dynamic>(
@ -648,9 +687,67 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
title: "Backup saved to:", title: "Backup saved to:",
message: fileToSave, message: fileToSave,
) )
: const StackOkDialog( : !isDesktop
? const StackOkDialog(
title: title:
"Backup creation succeeded"), "Backup creation succeeded")
: DesktopDialog(
maxHeight: double.infinity,
maxWidth: 500,
child: Padding(
padding:
const EdgeInsets.only(
left: 32,
right: 32,
bottom: 32,
),
child: Column(
mainAxisSize:
MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
const SizedBox(
height: 26),
Text(
"Stack backup saved to: \n",
style: STextStyles
.desktopH3(
context),
),
Text(
fileToSave,
style: STextStyles
.desktopTextExtraExtraSmall(
context),
),
const SizedBox(
height: 40,
),
Row(
children: [
// const Spacer(),
Expanded(
child:
PrimaryButton(
label: "Ok",
desktopMed:
true,
onPressed:
() {
// Navigator.of(
// context)
// .pop();
},
),
),
],
)
],
),
),
),
); );
passwordController.text = ""; passwordController.text = "";
passwordRepeatController.text = ""; passwordRepeatController.text = "";

View file

@ -424,6 +424,7 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
passwordFocusNode, passwordFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [
@ -555,6 +556,7 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
passwordRepeatFocusNode, passwordRepeatFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [
@ -631,7 +633,11 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
return DropdownMenuItem( return DropdownMenuItem(
value: e, value: e,
child: Text(message), child: Text(
message,
style:
STextStyles.desktopTextExtraExtraSmall(context),
),
); );
}, },
), ),

View file

@ -17,14 +17,13 @@ class SupportView extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
static const String routeName = "/support"; static const String routeName = "/support";
final double iconSize = 28;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
final isDesktop = Util.isDesktop;
return ConditionalParent( return ConditionalParent(
condition: !isDesktop, condition: !isDesktop,
builder: (child) { builder: (child) {
@ -64,321 +63,168 @@ class SupportView extends StatelessWidget {
: const SizedBox( : const SizedBox(
height: 12, height: 12,
), ),
RoundedWhiteContainer( AboutItem(
padding: const EdgeInsets.all(0), linkUrl: "https://t.me/stackwallet",
child: RawMaterialButton( label: "Telegram",
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, buttonText: "@stackwallet",
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconAsset: Assets.socials.telegram,
shape: RoundedRectangleBorder( isDesktop: isDesktop,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (!isDesktop) {
launchUrl(
Uri.parse("https://t.me/stackwallet"),
mode: LaunchMode.externalApplication,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
Assets.socials.telegram,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
const SizedBox(
width: 12,
),
Text(
"Telegram",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
BlueTextButton(
text: isDesktop ? "@stackwallet" : "",
onTap: () {
launchUrl(
Uri.parse("https://t.me/stackwallet"),
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
), ),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
RoundedWhiteContainer( AboutItem(
padding: const EdgeInsets.all(0), linkUrl: "https://discord.gg/RZMG3yUm",
child: RawMaterialButton( label: "Discord",
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, buttonText: "Stack Wallet",
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconAsset: Assets.socials.discord,
shape: RoundedRectangleBorder( isDesktop: isDesktop,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (!isDesktop) {
launchUrl(
Uri.parse("https://discord.gg/RZMG3yUm"),
mode: LaunchMode.externalApplication,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
Assets.socials.discord,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
const SizedBox(
width: 12,
),
Text(
"Discord",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
BlueTextButton(
text: isDesktop ? "Stack Wallet" : "",
onTap: () {
launchUrl(
Uri.parse(
"https://discord.gg/RZMG3yUm"), //expired link?
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
), ),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
RoundedWhiteContainer( AboutItem(
padding: const EdgeInsets.all(0), linkUrl: "https://www.reddit.com/r/stackwallet/",
child: RawMaterialButton( label: "Reddit",
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, buttonText: "r/stackwallet",
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconAsset: Assets.socials.reddit,
shape: RoundedRectangleBorder( isDesktop: isDesktop,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (!isDesktop) {
launchUrl(
Uri.parse("https://www.reddit.com/r/stackwallet/"),
mode: LaunchMode.externalApplication,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
Assets.socials.reddit,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
const SizedBox(
width: 12,
),
Text(
"Reddit",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
BlueTextButton(
text: isDesktop ? "r/stackwallet" : "",
onTap: () {
launchUrl(
Uri.parse("https://www.reddit.com/r/stackwallet/"),
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
), ),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
RoundedWhiteContainer( AboutItem(
padding: const EdgeInsets.all(0), linkUrl: "https://twitter.com/stack_wallet",
child: RawMaterialButton( label: "Twitter",
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, buttonText: "@stack_wallet",
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconAsset: Assets.socials.twitter,
shape: RoundedRectangleBorder( isDesktop: isDesktop,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (!isDesktop) {
launchUrl(
Uri.parse("https://twitter.com/stack_wallet"),
mode: LaunchMode.externalApplication,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
Assets.socials.twitter,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
const SizedBox(
width: 12,
),
Text(
"Twitter",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
BlueTextButton(
text: isDesktop ? "@stack_wallet" : "",
onTap: () {
launchUrl(
Uri.parse("https://twitter.com/stack_wallet"),
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
), ),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
RoundedWhiteContainer( AboutItem(
padding: const EdgeInsets.all(0), linkUrl: "mailto:support@stackwallet.com",
child: RawMaterialButton( label: "Email",
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, buttonText: "support@stackwallet.com",
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconAsset: Assets.svg.envelope,
shape: RoundedRectangleBorder( isDesktop: isDesktop,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (!isDesktop) {
launchUrl(
Uri.parse("mailto:support@stackwallet.com"),
mode: LaunchMode.externalApplication,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
Assets.svg.envelope,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
const SizedBox(
width: 12,
),
Text(
"Email",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
BlueTextButton(
text: isDesktop ? "support@stackwallet.com" : "",
onTap: () {
launchUrl(
Uri.parse("mailto:support@stackwallet.com"),
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
), ),
], ],
), ),
); );
} }
} }
class AboutItem extends StatelessWidget {
const AboutItem({
Key? key,
required this.linkUrl,
required this.label,
required this.buttonText,
required this.iconAsset,
required this.isDesktop,
}) : super(key: key);
final String linkUrl;
final String label;
final String buttonText;
final String iconAsset;
final bool isDesktop;
@override
Widget build(BuildContext context) {
final double iconSize = isDesktop ? 20 : 28;
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
launchUrl(
Uri.parse(linkUrl),
mode: LaunchMode.externalApplication,
);
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: child,
),
),
child: Padding(
padding: isDesktop
? const EdgeInsets.symmetric(
horizontal: 20,
vertical: 15,
)
: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ConditionalParent(
condition: isDesktop,
builder: (child) => Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10000),
color: Theme.of(context)
.extension<StackColors>()!
.buttonBackSecondary,
),
child: Center(
child: child,
),
),
child: SvgPicture.asset(
iconAsset,
width: iconSize,
height: iconSize,
color: Theme.of(context)
.extension<StackColors>()!
.bottomNavIconIcon,
),
),
const SizedBox(
width: 12,
),
Text(
label,
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
],
),
if (isDesktop)
BlueTextButton(
text: buttonText,
onTap: () {
launchUrl(
Uri.parse(linkUrl),
mode: LaunchMode.externalApplication,
);
},
),
],
),
),
),
);
}
}

View file

@ -203,6 +203,8 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
height: 32, height: 32,
width: 32, width: 32,
child: Center( child: Center(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: SvgPicture.asset( child: SvgPicture.asset(
hidePassword hidePassword
? Assets.svg.eye ? Assets.svg.eye
@ -216,6 +218,7 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
), ),
), ),
), ),
),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
@ -354,6 +357,8 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
height: 32, height: 32,
width: 32, width: 32,
child: Center( child: Center(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: SvgPicture.asset( child: SvgPicture.asset(
fieldsMatch && passwordStrength == 1 fieldsMatch && passwordStrength == 1
? Assets.svg.checkCircle ? Assets.svg.checkCircle
@ -374,6 +379,7 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
), ),
), ),
), ),
),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),

View file

@ -17,6 +17,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
class DesktopLoginView extends ConsumerStatefulWidget { class DesktopLoginView extends ConsumerStatefulWidget {
@ -45,6 +46,15 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
Future<void> login() async { Future<void> login() async {
try { try {
unawaited(
showDialog(
context: context,
builder: (context) => const LoadingIndicator(
width: 200,
),
),
);
await ref await ref
.read(storageCryptoHandlerProvider) .read(storageCryptoHandlerProvider)
.initFromExisting(passwordController.text); .initFromExisting(passwordController.text);
@ -55,6 +65,9 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
// if no errors passphrase is correct // if no errors passphrase is correct
if (mounted) { if (mounted) {
// pop loading indicator
Navigator.of(context).pop();
unawaited( unawaited(
Navigator.of(context).pushNamedAndRemoveUntil( Navigator.of(context).pushNamedAndRemoveUntil(
DesktopHomeView.routeName, DesktopHomeView.routeName,
@ -63,6 +76,9 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
); );
} }
} catch (e) { } catch (e) {
// pop loading indicator
Navigator.of(context).pop();
await showFloatingFlushBar( await showFloatingFlushBar(
type: FlushBarType.warning, type: FlushBarType.warning,
message: e.toString(), message: e.toString(),
@ -159,6 +175,8 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
hidePassword = !hidePassword; hidePassword = !hidePassword;
}); });
}, },
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: SvgPicture.asset( child: SvgPicture.asset(
hidePassword hidePassword
? Assets.svg.eye ? Assets.svg.eye
@ -170,6 +188,7 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
height: 24, height: 24,
), ),
), ),
),
const SizedBox( const SizedBox(
width: 12, width: 12,
), ),

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/pages/address_book_views/address_book_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
@ -9,11 +10,11 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
@ -36,7 +37,7 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
late bool hasContacts = false; late bool hasContacts = false;
String filter = ""; String _searchTerm = "";
Future<void> selectCryptocurrency() async { Future<void> selectCryptocurrency() async {
await showDialog<dynamic>( await showDialog<dynamic>(
@ -123,25 +124,25 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: TextField(
autocorrect: false, autocorrect: Util.isDesktop ? false : true,
enableSuggestions: false, enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
onChanged: (newString) { onChanged: (value) {
setState(() => filter = newString); setState(() {
_searchTerm = value;
});
}, },
style: STextStyles.field(context), style: STextStyles.field(context),
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Search...", "Search",
_searchFocusNode, _searchFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: STextStyles.fieldLabel(context)
.copyWith(fontSize: 16),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 16, vertical: 20,
), ),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.search, Assets.svg.search,
@ -160,7 +161,6 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
onTap: () async { onTap: () async {
setState(() { setState(() {
_searchController.text = ""; _searchController.text = "";
filter = "";
}); });
}, },
), ),
@ -239,18 +239,11 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
), ),
), ),
), ),
Padding( const Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 26), padding: EdgeInsets.symmetric(horizontal: 24, vertical: 26),
child: SizedBox( child: SizedBox(
width: 489, width: 489,
child: RoundedWhiteContainer( child: AddressBookView(),
child: Center(
child: Text(
"Your contacts will appear here",
style: STextStyles.itemSubtitle(context),
),
),
),
), ),
), ),
], ],

View file

@ -292,13 +292,13 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
eventBus: eventBus, eventBus: eventBus,
), ),
const SizedBox( const SizedBox(
width: 32, width: 2,
), ),
WalletKeysButton( WalletKeysButton(
walletId: walletId, walletId: walletId,
), ),
const SizedBox( const SizedBox(
width: 32, width: 12,
), ),
], ],
), ),

View file

@ -0,0 +1,369 @@
import 'package:decimal/decimal.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/models.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/animated_text.dart';
class DesktopFeeDropDown extends ConsumerStatefulWidget {
const DesktopFeeDropDown({
Key? key,
required this.walletId,
}) : super(key: key);
final String walletId;
@override
ConsumerState<DesktopFeeDropDown> createState() => _DesktopFeeDropDownState();
}
class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
late final String walletId;
FeeObject? feeObject;
FeeRateType feeRateType = FeeRateType.average;
final stringsToLoopThrough = [
"Calculating",
"Calculating.",
"Calculating..",
"Calculating...",
];
Future<Decimal> feeFor({
required int amount,
required FeeRateType feeRateType,
required int feeRate,
required Coin coin,
}) async {
switch (feeRateType) {
case FeeRateType.fast:
if (ref.read(feeSheetSessionCacheProvider).fast[amount] == null) {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.read(publicPrivateBalanceStateProvider.state).state !=
"Private") {
ref.read(feeSheetSessionCacheProvider).fast[amount] =
Format.satoshisToAmount(await (manager.wallet as FiroWallet)
.estimateFeeForPublic(amount, feeRate));
} else {
ref.read(feeSheetSessionCacheProvider).fast[amount] =
Format.satoshisToAmount(
await manager.estimateFeeFor(amount, feeRate));
}
}
return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
case FeeRateType.average:
if (ref.read(feeSheetSessionCacheProvider).average[amount] == null) {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.read(publicPrivateBalanceStateProvider.state).state !=
"Private") {
ref.read(feeSheetSessionCacheProvider).average[amount] =
Format.satoshisToAmount(await (manager.wallet as FiroWallet)
.estimateFeeForPublic(amount, feeRate));
} else {
ref.read(feeSheetSessionCacheProvider).average[amount] =
Format.satoshisToAmount(
await manager.estimateFeeFor(amount, feeRate));
}
}
return ref.read(feeSheetSessionCacheProvider).average[amount]!;
case FeeRateType.slow:
if (ref.read(feeSheetSessionCacheProvider).slow[amount] == null) {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.read(publicPrivateBalanceStateProvider.state).state !=
"Private") {
ref.read(feeSheetSessionCacheProvider).slow[amount] =
Format.satoshisToAmount(await (manager.wallet as FiroWallet)
.estimateFeeForPublic(amount, feeRate));
} else {
ref.read(feeSheetSessionCacheProvider).slow[amount] =
Format.satoshisToAmount(
await manager.estimateFeeFor(amount, feeRate));
}
}
return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
}
}
String estimatedTimeToBeIncludedInNextBlock(
int targetBlockTime, int estimatedNumberOfBlocks) {
int time = targetBlockTime * estimatedNumberOfBlocks;
int hours = (time / 3600).floor();
if (hours > 1) {
return "~$hours hours";
} else if (hours == 1) {
return "~$hours hour";
}
// less than an hour
final string = (time / 60).toStringAsFixed(1);
if (string == "1.0") {
return "~1 minute";
} else {
if (string.endsWith(".0")) {
return "~${(time / 60).floor()} minutes";
}
return "~$string minutes";
}
}
@override
void initState() {
walletId = widget.walletId;
super.initState();
}
String? labelSlow;
String? labelAverage;
String? labelFast;
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)));
return FutureBuilder(
future: manager.fees,
builder: (context, AsyncSnapshot<FeeObject> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
feeObject = snapshot.data!;
}
return DropdownButtonHideUnderline(
child: DropdownButton2(
offset: const Offset(0, -10),
isExpanded: true,
dropdownElevation: 0,
value: ref.watch(feeRateTypeStateProvider.state).state,
// selectedItemBuilder: (s) {
// return [
// ...FeeRateType.values.map(
// (e) => DropdownMenuItem(
// value: e,
// child: FeeDropDownChild(
// feeObject: feeObject,
// feeRateType: e,
// walletId: walletId,
// amount: amount,
// feeFor: feeFor,
// isSelected: true,
// ),
// ),
// ),
// ];
// },
items: [
...FeeRateType.values.map(
(e) => DropdownMenuItem(
value: e,
child: FeeDropDownChild(
feeObject: feeObject,
feeRateType: e,
walletId: walletId,
feeFor: feeFor,
isSelected: false,
),
),
),
],
onChanged: (newRateType) {
if (newRateType is FeeRateType) {
ref.read(feeRateTypeStateProvider.state).state = newRateType;
}
},
icon: SvgPicture.asset(
Assets.svg.chevronDown,
width: 12,
height: 6,
color: Theme.of(context).extension<StackColors>()!.textDark3,
),
buttonPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
buttonDecoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
dropdownDecoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
),
);
});
}
}
final sendAmountProvider =
StateProvider.autoDispose<Decimal>((_) => Decimal.zero);
class FeeDropDownChild extends ConsumerWidget {
const FeeDropDownChild({
Key? key,
required this.feeObject,
required this.feeRateType,
required this.walletId,
required this.feeFor,
required this.isSelected,
}) : super(key: key);
final FeeObject? feeObject;
final FeeRateType feeRateType;
final String walletId;
final Future<Decimal> Function({
required int amount,
required FeeRateType feeRateType,
required int feeRate,
required Coin coin,
}) feeFor;
final bool isSelected;
static const stringsToLoopThrough = [
"Calculating",
"Calculating.",
"Calculating..",
"Calculating...",
];
String estimatedTimeToBeIncludedInNextBlock(
int targetBlockTime, int estimatedNumberOfBlocks) {
int time = targetBlockTime * estimatedNumberOfBlocks;
int hours = (time / 3600).floor();
if (hours > 1) {
return "~$hours hours";
} else if (hours == 1) {
return "~$hours hour";
}
// less than an hour
final string = (time / 60).toStringAsFixed(1);
if (string == "1.0") {
return "~1 minute";
} else {
if (string.endsWith(".0")) {
return "~${(time / 60).floor()} minutes";
}
return "~$string minutes";
}
}
@override
Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: $runtimeType : $feeRateType");
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)));
if (feeObject == null) {
return AnimatedText(
stringsToLoopThrough: stringsToLoopThrough,
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.textFieldActiveText,
),
);
} else {
return FutureBuilder(
future: feeFor(
coin: manager.coin,
feeRateType: FeeRateType.fast,
feeRate: feeRateType == FeeRateType.fast
? feeObject!.fast
: feeRateType == FeeRateType.slow
? feeObject!.slow
: feeObject!.medium,
amount: Format.decimalAmountToSatoshis(
ref.watch(sendAmountProvider.state).state,
),
),
builder: (_, AsyncSnapshot<Decimal> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${feeRateType.prettyName} (~${snapshot.data!} ${manager.coin.ticker})",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
),
textAlign: TextAlign.left,
),
if (feeObject != null)
Text(
estimatedTimeToBeIncludedInNextBlock(
Constants.targetBlockTimeInSeconds(manager.coin),
feeRateType == FeeRateType.fast
? feeObject!.numberOfBlocksFast
: feeRateType == FeeRateType.slow
? feeObject!.numberOfBlocksSlow
: feeObject!.numberOfBlocksAverage,
),
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
),
],
);
} else {
return AnimatedText(
stringsToLoopThrough: stringsToLoopThrough,
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
),
);
}
},
);
}
}
}

View file

@ -13,6 +13,7 @@ import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dia
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart'; import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
import 'package:stackwallet/providers/ui/preview_tx_button_state_provider.dart'; import 'package:stackwallet/providers/ui/preview_tx_button_state_provider.dart';
@ -94,11 +95,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
late VoidCallback onCryptoAmountChanged; late VoidCallback onCryptoAmountChanged;
Future<void> previewSend() async { Future<void> previewSend() async {
// wait for keyboard to disappear
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 100),
);
final manager = final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId); ref.read(walletsChangeNotifierProvider).getManager(walletId);
@ -794,35 +790,25 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
_addressToggleFlag = true; _addressToggleFlag = true;
} }
// _cryptoFocus.addListener(() { _cryptoFocus.addListener(() {
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) { if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
// if (_amountToSend == null) { if (_amountToSend == null) {
// setState(() { ref.refresh(sendAmountProvider);
// _calculateFeesFuture = calculateFees(0); } else {
// }); ref.read(sendAmountProvider.state).state = _amountToSend!;
// } else { }
// setState(() { }
// _calculateFeesFuture = });
// calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
// }); _baseFocus.addListener(() {
// } if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
// } if (_amountToSend == null) {
// }); ref.refresh(sendAmountProvider);
// } else {
// _baseFocus.addListener(() { ref.read(sendAmountProvider.state).state = _amountToSend!;
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) { }
// if (_amountToSend == null) { }
// setState(() { });
// _calculateFeesFuture = calculateFees(0);
// });
// } else {
// setState(() {
// _calculateFeesFuture =
// calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
// });
// }
// }
// });
super.initState(); super.initState();
} }
@ -1371,6 +1357,24 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
), ),
), ),
), ),
const SizedBox(
height: 20,
),
Text(
"Transaction fee (estimated)",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
textAlign: TextAlign.left,
),
const SizedBox(
height: 10,
),
DesktopFeeDropDown(
walletId: walletId,
),
const SizedBox( const SizedBox(
height: 36, height: 36,
), ),

View file

@ -98,25 +98,26 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
Widget _buildNetworkIcon(WalletSyncStatus status, BuildContext context) { Widget _buildNetworkIcon(WalletSyncStatus status, BuildContext context) {
const size = 24.0; const size = 24.0;
final color = _getColor(status, context);
switch (status) { switch (status) {
case WalletSyncStatus.unableToSync: case WalletSyncStatus.unableToSync:
return SvgPicture.asset( return SvgPicture.asset(
Assets.svg.radioProblem, Assets.svg.radioProblem,
color: Theme.of(context).extension<StackColors>()!.accentColorRed, color: color,
width: size, width: size,
height: size, height: size,
); );
case WalletSyncStatus.synced: case WalletSyncStatus.synced:
return SvgPicture.asset( return SvgPicture.asset(
Assets.svg.radio, Assets.svg.radio,
color: Theme.of(context).extension<StackColors>()!.accentColorGreen, color: color,
width: size, width: size,
height: size, height: size,
); );
case WalletSyncStatus.syncing: case WalletSyncStatus.syncing:
return SvgPicture.asset( return SvgPicture.asset(
Assets.svg.radioSyncing, Assets.svg.radioSyncing,
color: Theme.of(context).extension<StackColors>()!.accentColorYellow, color: color,
width: size, width: size,
height: size, height: size,
); );
@ -125,35 +126,46 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
Widget _buildText(WalletSyncStatus status, BuildContext context) { Widget _buildText(WalletSyncStatus status, BuildContext context) {
String label; String label;
Color color;
switch (status) { switch (status) {
case WalletSyncStatus.unableToSync: case WalletSyncStatus.unableToSync:
label = "Unable to sync"; label = "Unable to sync";
color = Theme.of(context).extension<StackColors>()!.accentColorRed;
break; break;
case WalletSyncStatus.synced: case WalletSyncStatus.synced:
label = "Synchronised"; label = "Synchronized";
color = Theme.of(context).extension<StackColors>()!.accentColorGreen;
break; break;
case WalletSyncStatus.syncing: case WalletSyncStatus.syncing:
label = "Synchronising"; label = "Synchronizing";
color = Theme.of(context).extension<StackColors>()!.accentColorYellow;
break; break;
} }
return Text( return Text(
label, label,
style: STextStyles.desktopMenuItemSelected(context).copyWith( style: STextStyles.desktopMenuItemSelected(context).copyWith(
color: color, color: _getColor(status, context),
), ),
); );
} }
Color _getColor(WalletSyncStatus status, BuildContext context) {
switch (status) {
case WalletSyncStatus.unableToSync:
return Theme.of(context).extension<StackColors>()!.accentColorRed;
case WalletSyncStatus.synced:
return Theme.of(context).extension<StackColors>()!.accentColorGreen;
case WalletSyncStatus.syncing:
return Theme.of(context).extension<StackColors>()!.accentColorYellow;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return RawMaterialButton(
onTap: () { hoverColor: _getColor(_currentSyncStatus, context).withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(1000),
),
onPressed: () {
if (Util.isDesktop) { if (Util.isDesktop) {
// showDialog<void>( // showDialog<void>(
// context: context, // context: context,
@ -265,8 +277,11 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
); );
} }
}, },
child: Container( child: Padding(
color: Colors.transparent, padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 32,
),
child: Row( child: Row(
children: [ children: [
_buildNetworkIcon(_currentSyncStatus, context), _buildNetworkIcon(_currentSyncStatus, context),

View file

@ -39,6 +39,8 @@ class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
return Row( return Row(
children: [ children: [
Expanded( Expanded(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: () => _onChanged(0), onTap: () => _onChanged(0),
child: Container( child: Container(
@ -50,7 +52,8 @@ class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
), ),
Text( Text(
"Send", "Send",
style: STextStyles.desktopTextExtraSmall(context).copyWith( style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: _selectedIndex == 0 color: _selectedIndex == 0
? Theme.of(context) ? Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
@ -80,7 +83,10 @@ class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
), ),
), ),
), ),
),
Expanded( Expanded(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: () => _onChanged(1), onTap: () => _onChanged(1),
child: Container( child: Container(
@ -92,7 +98,8 @@ class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
), ),
Text( Text(
"Receive", "Receive",
style: STextStyles.desktopTextExtraSmall(context).copyWith( style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: _selectedIndex == 1 color: _selectedIndex == 1
? Theme.of(context) ? Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
@ -122,6 +129,7 @@ class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
), ),
), ),
), ),
),
], ],
); );
} }

View file

@ -16,8 +16,11 @@ class WalletKeysButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return RawMaterialButton(
onTap: () { shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(1000),
),
onPressed: () {
showDialog<void>( showDialog<void>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
@ -36,17 +39,12 @@ class WalletKeysButton extends StatelessWidget {
}, },
), ),
); );
// showDialog<void>(
// context: context,
// barrierDismissible: false,
// builder: (context) => UnlockWalletKeysDesktop(
// walletId: walletId,
// ),
// );
}, },
child: Container( child: Padding(
color: Colors.transparent, padding: const EdgeInsets.symmetric(
vertical: 19,
horizontal: 32,
),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(

View file

@ -35,11 +35,14 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset( Padding(
Assets.svg.circleLanguage, padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleSliders,
width: 48, width: 48,
height: 48, height: 48,
), ),
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [

View file

@ -52,11 +52,14 @@ class _AppearanceOptionSettings
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset( Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleSun, Assets.svg.circleSun,
width: 48, width: 48,
height: 48, height: 48,
), ),
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [

View file

@ -492,7 +492,11 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
return DropdownMenuItem( return DropdownMenuItem(
value: e, value: e,
child: Text(message), child: Text(
message,
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
); );
}, },
), ),

View file

@ -4,9 +4,9 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/currency_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/currency_view.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class CurrencySettings extends ConsumerStatefulWidget { class CurrencySettings extends ConsumerStatefulWidget {
@ -18,81 +18,7 @@ class CurrencySettings extends ConsumerStatefulWidget {
ConsumerState<CurrencySettings> createState() => _CurrencySettings(); ConsumerState<CurrencySettings> createState() => _CurrencySettings();
} }
class _CurrencySettings extends ConsumerState<CurrencySettings> { Future<void> chooseCurrency(BuildContext context) async {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
right: 30,
),
child: RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset(
Assets.svg.circleDollarSign,
width: 48,
height: 48,
),
Center(
child: Padding(
padding: const EdgeInsets.all(10),
child: RichText(
textAlign: TextAlign.start,
text: TextSpan(
children: [
TextSpan(
text: "Currency",
style: STextStyles.desktopTextSmall(context),
),
TextSpan(
text:
"\n\nProtect your Stack Wallet with a strong password. Stack Wallet does not store "
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
style:
STextStyles.desktopTextExtraExtraSmall(context),
),
],
),
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Padding(
padding: EdgeInsets.all(
10,
),
child: NewPasswordButton(),
),
],
),
],
),
),
),
],
);
}
}
class NewPasswordButton extends ConsumerWidget {
const NewPasswordButton({
Key? key,
}) : super(key: key);
Future<void> chooseCurrency(BuildContext context) async {
// await showDialog<dynamic>(
// context: context,
// useSafeArea: false,
// barrierDismissible: true,
// builder: (context) {
// return CurrencyDialog();
// },
// );
await showDialog<dynamic>( await showDialog<dynamic>(
context: context, context: context,
useSafeArea: false, useSafeArea: false,
@ -125,25 +51,77 @@ class NewPasswordButton extends ConsumerWidget {
); );
}, },
); );
} }
class _CurrencySettings extends ConsumerState<CurrencySettings> {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context) {
return SizedBox( debugPrint("BUILD: $runtimeType");
width: 200, return Column(
children: [
Padding(
padding: const EdgeInsets.only(
right: 30,
),
child: RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleDollarSign,
width: 48,
height: 48, height: 48,
child: TextButton( ),
style: Theme.of(context) ),
.extension<StackColors>()! Center(
.getPrimaryEnabledButtonColor(context), child: Padding(
padding: const EdgeInsets.all(10),
child: RichText(
textAlign: TextAlign.start,
text: TextSpan(
children: [
TextSpan(
text: "Currency",
style: STextStyles.desktopTextSmall(context),
),
TextSpan(
text:
"\n\nSelect a fiat currency to evaluate your crypto assets. We use CoinGecko conversion rates "
"when displaying your balance and transaction amounts.",
style:
STextStyles.desktopTextExtraExtraSmall(context),
),
],
),
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(
10,
),
child: PrimaryButton(
width: 210,
desktopMed: true,
enabled: true,
label: "Change currency",
onPressed: () { onPressed: () {
chooseCurrency(context); chooseCurrency(context);
}, },
child: Text(
"Change currency",
style: STextStyles.button(context),
), ),
), ),
],
),
],
),
),
),
],
); );
} }
} }

View file

@ -4,7 +4,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_dialog.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class LanguageOptionSettings extends ConsumerStatefulWidget { class LanguageOptionSettings extends ConsumerStatefulWidget {
@ -17,6 +17,17 @@ class LanguageOptionSettings extends ConsumerStatefulWidget {
_LanguageOptionSettings(); _LanguageOptionSettings();
} }
Future<void> chooseLanguage(BuildContext context) async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return const LanguageDialog();
},
);
}
class _LanguageOptionSettings extends ConsumerState<LanguageOptionSettings> { class _LanguageOptionSettings extends ConsumerState<LanguageOptionSettings> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -31,11 +42,14 @@ class _LanguageOptionSettings extends ConsumerState<LanguageOptionSettings> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset( Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleLanguage, Assets.svg.circleLanguage,
width: 48, width: 48,
height: 48, height: 48,
), ),
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -63,57 +77,28 @@ class _LanguageOptionSettings extends ConsumerState<LanguageOptionSettings> {
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: const [ children: [
Padding( Padding(
padding: EdgeInsets.all( padding: EdgeInsets.all(
10, 10,
), ),
child: ChangeLanguageButton(), child: PrimaryButton(
), width: 210,
], desktopMed: true,
), enabled: true,
], label: "Change language",
),
),
),
],
);
}
}
class ChangeLanguageButton extends ConsumerWidget {
const ChangeLanguageButton({
Key? key,
}) : super(key: key);
Future<void> chooseLanguage(BuildContext context) async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return const LanguageDialog();
},
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
return SizedBox(
width: 200,
height: 48,
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () { onPressed: () {
chooseLanguage(context); chooseLanguage(context);
}, },
child: Text(
"Change language",
style: STextStyles.button(context),
), ),
), ),
],
),
],
),
),
),
],
); );
} }
} }

View file

@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart';
import 'package:stackwallet/providers/global/node_service_provider.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
@ -11,8 +10,10 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class NodesSettings extends ConsumerStatefulWidget { class NodesSettings extends ConsumerStatefulWidget {
const NodesSettings({Key? key}) : super(key: key); const NodesSettings({Key? key}) : super(key: key);
@ -29,8 +30,22 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
late final TextEditingController searchNodeController; late final TextEditingController searchNodeController;
late final FocusNode searchNodeFocusNode; late final FocusNode searchNodeFocusNode;
late final ScrollController nodeScrollController;
String filter = ""; String filter = "";
List<Coin> _search(String filter, List<Coin> coins) {
if (filter.isEmpty) {
return coins;
}
return coins
.where((coin) =>
coin.prettyName.contains(filter) ||
coin.name.contains(filter) ||
coin.ticker.toLowerCase().contains(filter.toLowerCase()))
.toList();
}
@override @override
void initState() { void initState() {
_coins = _coins.toList(); _coins = _coins.toList();
@ -39,6 +54,8 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
searchNodeController = TextEditingController(); searchNodeController = TextEditingController();
searchNodeFocusNode = FocusNode(); searchNodeFocusNode = FocusNode();
nodeScrollController = ScrollController();
super.initState(); super.initState();
} }
@ -46,12 +63,15 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
void dispose() { void dispose() {
searchNodeController.dispose(); searchNodeController.dispose();
searchNodeFocusNode.dispose(); searchNodeFocusNode.dispose();
nodeScrollController.dispose();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
bool showTestNet = ref.watch( bool showTestNet = ref.watch(
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
); );
@ -60,16 +80,24 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
? _coins ? _coins
: _coins.sublist(0, _coins.length - kTestNetCoinCount); : _coins.sublist(0, _coins.length - kTestNetCoinCount);
debugPrint("BUILD: $runtimeType"); coins = _search(filter, coins);
return Column(
mainAxisSize: MainAxisSize.min, return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Expanded(
child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
right: 30, right: 32,
bottom: 32,
), ),
child: RoundedWhiteContainer( child: RoundedWhiteContainer(
radiusMultiplier: 2,
padding: const EdgeInsets.all(24),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -78,34 +106,24 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
width: 48, width: 48,
height: 48, height: 48,
), ),
Column( const SizedBox(
crossAxisAlignment: CrossAxisAlignment.stretch, height: 16,
mainAxisSize: MainAxisSize.min, ),
children: [ Text(
Padding( "Nodes",
padding: const EdgeInsets.all(10),
child: RichText(
textAlign: TextAlign.start,
text: TextSpan(
children: [
TextSpan(
text: "Nodes",
style: STextStyles.desktopTextSmall(context), style: STextStyles.desktopTextSmall(context),
), ),
TextSpan( const SizedBox(
text: "\n\nSelect a coin to see nodes", height: 8,
style: STextStyles.desktopTextExtraExtraSmall(
context),
), ),
], Text(
"Select a coin to see nodes",
style: STextStyles.desktopTextExtraExtraSmall(context),
), ),
const SizedBox(
height: 20,
), ),
), ClipRRect(
],
),
Padding(
padding: const EdgeInsets.all(10.0),
child: ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
@ -134,17 +152,44 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
height: 16, height: 16,
), ),
), ),
suffixIcon: searchNodeController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
searchNodeController.text = "";
filter = "";
});
},
),
],
),
),
)
: null,
), ),
), ),
), ),
],
), ),
Padding( const SizedBox(
padding: const EdgeInsets.all(10.0), height: 20,
),
Flexible(
child: RoundedWhiteContainer( child: RoundedWhiteContainer(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
borderColor: borderColor: Theme.of(context)
Theme.of(context).extension<StackColors>()!.background, .extension<StackColors>()!
.background,
child: ListView.separated( child: ListView.separated(
controller: nodeScrollController,
physics: const AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
primary: false, primary: false,
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -170,7 +215,8 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
context: context, context: context,
builder: (context) => Navigator( builder: (context) => Navigator(
initialRoute: CoinNodesView.routeName, initialRoute: CoinNodesView.routeName,
onGenerateRoute: RouteGenerator.generateRoute, onGenerateRoute:
RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) { onGenerateInitialRoutes: (_, __) {
return [ return [
FadePageRoute( FadePageRoute(
@ -248,6 +294,7 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
), ),
), ),
), ),
),
], ],
); );
} }

View file

@ -139,38 +139,39 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
return Column( return Column(
children: [ children: [
Row( Padding(
children: [ padding: const EdgeInsets.only(
Expanded( right: 30,
),
child: RoundedWhiteContainer( child: RoundedWhiteContainer(
radiusMultiplier: 2, // radiusMultiplier: 2,
padding: const EdgeInsets.all(24),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset( Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleLock, Assets.svg.circleLock,
width: 48, width: 48,
height: 48, height: 48,
), ),
Column( ),
Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(
height: 16,
),
Text( Text(
"Change Password", "Change Password",
style: STextStyles.desktopTextSmall(context), style: STextStyles.desktopTextSmall(context),
), ),
const SizedBox( const SizedBox(
height: 8, height: 16,
), ),
Text( Text(
"Protect your Stack Wallet with a strong password. Stack Wallet does not store " "Protect your Stack Wallet with a strong password. Stack Wallet does not store "
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.", "your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
style: style: STextStyles.desktopTextExtraExtraSmall(context),
STextStyles.desktopTextExtraExtraSmall(context),
), ),
const SizedBox( const SizedBox(
height: 20, height: 20,
@ -183,8 +184,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
children: [ children: [
Text( Text(
"Current password", "Current password",
style: STextStyles style:
.desktopTextExtraExtraSmall( STextStyles.desktopTextExtraExtraSmall(
context) context)
.copyWith( .copyWith(
color: Theme.of(context) color: Theme.of(context)
@ -233,8 +234,7 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye ? Assets.svg.eye
: Assets.svg.eyeSlash, : Assets.svg.eyeSlash,
color: Theme.of(context) color: Theme.of(context)
.extension< .extension<StackColors>()!
StackColors>()!
.textDark3, .textDark3,
width: 16, width: 16,
height: 16, height: 16,
@ -255,8 +255,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
"New password", "New password",
style: STextStyles style:
.desktopTextExtraExtraSmall( STextStyles.desktopTextExtraExtraSmall(
context) context)
.copyWith( .copyWith(
color: Theme.of(context) color: Theme.of(context)
@ -305,8 +305,7 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye ? Assets.svg.eye
: Assets.svg.eyeSlash, : Assets.svg.eyeSlash,
color: Theme.of(context) color: Theme.of(context)
.extension< .extension<StackColors>()!
StackColors>()!
.textDark3, .textDark3,
width: 16, width: 16,
height: 16, height: 16,
@ -368,9 +367,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 12, left: 12,
right: 12, right: 12,
top: passwordFeedback.isNotEmpty top:
? 4 passwordFeedback.isNotEmpty ? 4 : 0,
: 0,
), ),
child: passwordFeedback.isNotEmpty child: passwordFeedback.isNotEmpty
? Text( ? Text(
@ -416,8 +414,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
"Confirm new password", "Confirm new password",
style: STextStyles style:
.desktopTextExtraExtraSmall( STextStyles.desktopTextExtraExtraSmall(
context) context)
.copyWith( .copyWith(
color: Theme.of(context) color: Theme.of(context)
@ -466,8 +464,7 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye ? Assets.svg.eye
: Assets.svg.eyeSlash, : Assets.svg.eyeSlash,
color: Theme.of(context) color: Theme.of(context)
.extension< .extension<StackColors>()!
StackColors>()!
.textDark3, .textDark3,
width: 16, width: 16,
height: 16, height: 16,
@ -517,15 +514,11 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
), ),
], ],
), ),
],
),
),
),
const SizedBox(
width: 40,
), ),
], ],
), ),
),
),
], ],
); );
} }

View file

@ -2,13 +2,12 @@ import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import '../../../pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart';
class SyncingPreferencesSettings extends ConsumerStatefulWidget { class SyncingPreferencesSettings extends ConsumerStatefulWidget {
const SyncingPreferencesSettings({Key? key}) : super(key: key); const SyncingPreferencesSettings({Key? key}) : super(key: key);
@ -34,11 +33,14 @@ class _SyncingPreferencesSettings
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset( Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
Assets.svg.circleArrowRotate, Assets.svg.circleArrowRotate,
width: 48, width: 48,
height: 48, height: 48,
), ),
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -54,7 +56,7 @@ class _SyncingPreferencesSettings
), ),
TextSpan( TextSpan(
text: text:
"\nSet up your syncing preferences for all wallets in your Stack.", "\n\nSet up your syncing preferences for all wallets in your Stack.",
style: STextStyles.desktopTextExtraExtraSmall( style: STextStyles.desktopTextExtraExtraSmall(
context), context),
), ),
@ -67,49 +69,32 @@ class _SyncingPreferencesSettings
///TODO: ONLY SHOW SYNC OPTIONS ON BUTTON PRESS ///TODO: ONLY SHOW SYNC OPTIONS ON BUTTON PRESS
Column( Column(
children: [ children: const [
SyncingOptionsView(), SyncingOptionsView(),
], ],
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: const [ children: [
Padding( Padding(
padding: EdgeInsets.all( padding: const EdgeInsets.all(
10, 10,
), ),
child: ChangePrefButton(), child: PrimaryButton(
), width: 210,
], desktopMed: true,
), enabled: true,
], label: "Change preferences",
),
),
),
],
);
}
}
class ChangePrefButton extends ConsumerWidget {
const ChangePrefButton({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SizedBox(
width: 200,
height: 48,
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {}, onPressed: () {},
child: Text(
"Change preferences",
style: STextStyles.button(context),
), ),
), ),
],
),
],
),
),
),
],
); );
} }
} }

View file

@ -59,6 +59,7 @@ class _SVG {
String txExchangeFailed(BuildContext context) => String txExchangeFailed(BuildContext context) =>
"assets/svg/${Theme.of(context).extension<StackColors>()!.themeType.name}/tx-exchange-icon-failed.svg"; "assets/svg/${Theme.of(context).extension<StackColors>()!.themeType.name}/tx-exchange-icon-failed.svg";
String get circleSliders => "assets/svg/configuration.svg";
String get circlePlus => "assets/svg/plus-circle.svg"; String get circlePlus => "assets/svg/plus-circle.svg";
String get framedGear => "assets/svg/framed-gear.svg"; String get framedGear => "assets/svg/framed-gear.svg";
String get framedAddressBook => "assets/svg/framed-address-book.svg"; String get framedAddressBook => "assets/svg/framed-address-book.svg";

View file

@ -9,7 +9,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class AddressBookCard extends ConsumerStatefulWidget { class AddressBookCard extends ConsumerStatefulWidget {
@ -59,8 +58,29 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
} }
} }
return ConditionalParent( return RoundedWhiteContainer(
condition: !isDesktop, padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
padding: const EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
showDialog<void>(
context: context,
useSafeArea: true,
barrierDismissible: true,
builder: (_) => ContactPopUp(
contactId: contact.id,
),
);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
children: [ children: [
Container( Container(
@ -129,42 +149,18 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
], ],
), ),
if (isDesktop) const Spacer(), if (isDesktop) const Spacer(),
if (isDesktop) // if (isDesktop)
SvgPicture.asset( // SvgPicture.asset(
widget.indicatorDown == true // widget.indicatorDown == true
? Assets.svg.chevronDown // ? Assets.svg.chevronDown
: Assets.svg.chevronUp, // : Assets.svg.chevronUp,
width: 10, // width: 10,
height: 5, // height: 5,
color: Theme.of(context).extension<StackColors>()!.textSubtitle2, // color:
), // Theme.of(context).extension<StackColors>()!.textSubtitle2,
// ),
], ],
), ),
builder: (child) => RoundedWhiteContainer(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
padding: const EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
showDialog<void>(
context: context,
useSafeArea: true,
barrierDismissible: true,
builder: (_) => ContactPopUp(
contactId: contact.id,
),
);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: child,
),
), ),
), ),
); );

View file

@ -89,13 +89,16 @@ class _ExpandableState extends State<Expandable> with TickerProviderStateMixin {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
GestureDetector( MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: toggle, onTap: toggle,
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
child: widget.header, child: widget.header,
), ),
), ),
),
SizeTransition( SizeTransition(
sizeFactor: animation, sizeFactor: animation,
axisAlignment: 1.0, axisAlignment: 1.0,

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/widgets/table_view/table_view_row.dart';
class TableView extends StatefulWidget { class TableView extends StatefulWidget {
const TableView({ const TableView({
@ -9,7 +8,7 @@ class TableView extends StatefulWidget {
this.shrinkWrap = false, this.shrinkWrap = false,
}) : super(key: key); }) : super(key: key);
final List<TableViewRow> rows; final List<Widget> rows;
final double rowSpacing; final double rowSpacing;
final bool shrinkWrap; final bool shrinkWrap;

View file

@ -26,7 +26,9 @@ class WalletInfoRow extends ConsumerWidget {
.getManagerProvider(walletId)); .getManagerProvider(walletId));
if (Util.isDesktop) { if (Util.isDesktop) {
return GestureDetector( return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: onPressed, onTap: onPressed,
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
@ -42,9 +44,11 @@ class WalletInfoRow extends ConsumerWidget {
), ),
Text( Text(
manager.walletName, manager.walletName,
style: STextStyles.desktopTextExtraSmall(context).copyWith( style:
color: STextStyles.desktopTextExtraSmall(context).copyWith(
Theme.of(context).extension<StackColors>()!.textDark, color: Theme.of(context)
.extension<StackColors>()!
.textDark,
), ),
), ),
], ],
@ -75,6 +79,7 @@ class WalletInfoRow extends ConsumerWidget {
], ],
), ),
), ),
),
); );
} else { } else {
return Row( return Row(

View file

@ -315,6 +315,7 @@ flutter:
- assets/svg/keys.svg - assets/svg/keys.svg
- assets/svg/arrow-down.svg - assets/svg/arrow-down.svg
- assets/svg/plus-circle.svg - assets/svg/plus-circle.svg
- assets/svg/configuration.svg
# coin icons # coin icons
- assets/svg/coin_icons/Bitcoin.svg - assets/svg/coin_icons/Bitcoin.svg
- assets/svg/coin_icons/Litecoin.svg - assets/svg/coin_icons/Litecoin.svg

View file

@ -70,7 +70,7 @@ void main() {
await widgetTester.tap(find.byType(RawMaterialButton)); await widgetTester.tap(find.byType(RawMaterialButton));
expect(find.byType(ContactPopUp), findsOneWidget); expect(find.byType(ContactPopUp), findsOneWidget);
} else if (Util.isDesktop) { } else if (Util.isDesktop) {
expect(find.byType(RawMaterialButton), findsNothing); expect(find.byType(RawMaterialButton), findsOneWidget);
} }
}); });
} }