diff --git a/assets/svg/Button.svg b/assets/svg/Button.svg
new file mode 100644
index 000000000..37e0d359b
--- /dev/null
+++ b/assets/svg/Button.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/svg/about-desktop.svg b/assets/svg/about-desktop.svg
new file mode 100644
index 000000000..a80067d9c
--- /dev/null
+++ b/assets/svg/about-desktop.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/address-book-desktop.svg b/assets/svg/address-book-desktop.svg
new file mode 100644
index 000000000..fb85e3e11
--- /dev/null
+++ b/assets/svg/address-book-desktop.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/dark/dark-theme.svg b/assets/svg/dark/dark-theme.svg
new file mode 100644
index 000000000..47b5e2d5e
--- /dev/null
+++ b/assets/svg/dark/dark-theme.svg
@@ -0,0 +1,24 @@
+
diff --git a/assets/svg/dollar-sign-circle.svg b/assets/svg/dollar-sign-circle.svg
new file mode 100644
index 000000000..03aacffea
--- /dev/null
+++ b/assets/svg/dollar-sign-circle.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/svg/exchange-desktop.svg b/assets/svg/exchange-desktop.svg
new file mode 100644
index 000000000..8eacfa84e
--- /dev/null
+++ b/assets/svg/exchange-desktop.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/exit-desktop.svg b/assets/svg/exit-desktop.svg
new file mode 100644
index 000000000..abba264cd
--- /dev/null
+++ b/assets/svg/exit-desktop.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/language-circle.svg b/assets/svg/language-circle.svg
new file mode 100644
index 000000000..700ffede4
--- /dev/null
+++ b/assets/svg/language-circle.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/svg/light/light-mode.svg b/assets/svg/light/light-mode.svg
new file mode 100644
index 000000000..4ff9e2696
--- /dev/null
+++ b/assets/svg/light/light-mode.svg
@@ -0,0 +1,24 @@
+
diff --git a/assets/svg/lock-circle.svg b/assets/svg/lock-circle.svg
new file mode 100644
index 000000000..f8fd71831
--- /dev/null
+++ b/assets/svg/lock-circle.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/svg/node-circle.svg b/assets/svg/node-circle.svg
new file mode 100644
index 000000000..bd9353a2b
--- /dev/null
+++ b/assets/svg/node-circle.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/svg/rotate-circle.svg b/assets/svg/rotate-circle.svg
new file mode 100644
index 000000000..1940da5f5
--- /dev/null
+++ b/assets/svg/rotate-circle.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/svg/sun-circle.svg b/assets/svg/sun-circle.svg
new file mode 100644
index 000000000..eba7d031d
--- /dev/null
+++ b/assets/svg/sun-circle.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/svg/wallet-desktop.svg b/assets/svg/wallet-desktop.svg
new file mode 100644
index 000000000..0b0acdae3
--- /dev/null
+++ b/assets/svg/wallet-desktop.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/main.dart b/lib/main.dart
index eb7cd8e64..aa2155478 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -68,6 +68,9 @@ final openedFromSWBFileStringStateProvider =
void main() async {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
GoogleFonts.config.allowRuntimeFetching = false;
+ if(Platform.isIOS){
+ Util.libraryPath = await getLibraryDirectory();
+ }
if (Util.isDesktop) {
setWindowTitle('Stack Wallet');
diff --git a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
index ae72e1846..df5c44d18 100644
--- a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
+++ b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
@@ -90,6 +90,8 @@ class _AddWalletViewState extends State {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchFieldController,
focusNode: _searchFocusNode,
onChanged: (value) {
diff --git a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
index f7dbe3d33..8bc01b124 100644
--- a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
+++ b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
@@ -194,6 +194,8 @@ class _NameYourWalletViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onChanged: (string) {
if (string.isEmpty) {
if (_nextEnabled) {
diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart
index 49896e107..4f5b76fab 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart
@@ -7,6 +7,8 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class MobileMnemonicLengthSelector extends ConsumerWidget {
const MobileMnemonicLengthSelector({
Key? key,
@@ -19,7 +21,9 @@ class MobileMnemonicLengthSelector extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
return Stack(
children: [
- const TextField(
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
// controller: _lengthController,
readOnly: true,
textInputAction: TextInputAction.none,
diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart
index e5637cfc6..803e9b03b 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart
@@ -4,6 +4,8 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class RestoreFromDatePicker extends StatefulWidget {
const RestoreFromDatePicker({
Key? key,
@@ -35,6 +37,8 @@ class _RestoreFromDatePickerState extends State {
return Container(
color: Colors.transparent,
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onTap: onTap,
controller: _dateController,
style: STextStyles.field(context),
diff --git a/lib/pages/address_book_views/address_book_view.dart b/lib/pages/address_book_views/address_book_view.dart
index b70ef19ed..c9dd72d72 100644
--- a/lib/pages/address_book_views/address_book_view.dart
+++ b/lib/pages/address_book_views/address_book_view.dart
@@ -21,6 +21,8 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class AddressBookView extends ConsumerStatefulWidget {
const AddressBookView({Key? key, this.coin}) : super(key: key);
@@ -198,6 +200,8 @@ class _AddressBookViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: (value) {
diff --git a/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart b/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart
index 4fa89908c..74f3dfde8 100644
--- a/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart
+++ b/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart
@@ -22,6 +22,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class AddAddressBookEntryView extends ConsumerStatefulWidget {
const AddAddressBookEntryView({
Key? key,
@@ -279,6 +281,8 @@ class _AddAddressBookEntryViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: nameController,
focusNode: nameFocusNode,
style: STextStyles.field(context),
diff --git a/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart b/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart
index 45c23b13c..fff01eee3 100644
--- a/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart
+++ b/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart
@@ -13,6 +13,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class EditContactNameEmojiView extends ConsumerStatefulWidget {
const EditContactNameEmojiView({
Key? key,
@@ -200,6 +202,8 @@ class _EditContactNameEmojiViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: nameController,
focusNode: nameFocusNode,
style: STextStyles.field(context),
diff --git a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
index 73de8b0aa..ce98cee10 100644
--- a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
+++ b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
@@ -20,6 +20,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class NewContactAddressEntryForm extends ConsumerStatefulWidget {
const NewContactAddressEntryForm({
Key? key,
@@ -71,6 +73,8 @@ class _NewContactAddressEntryFormState
return Column(
children: [
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
readOnly: true,
style: STextStyles.field(context),
decoration: InputDecoration(
@@ -154,6 +158,8 @@ class _NewContactAddressEntryFormState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
focusNode: addressLabelFocusNode,
controller: addressLabelController,
style: STextStyles.field(context),
@@ -197,6 +203,7 @@ class _NewContactAddressEntryFormState
Constants.size.circularBorderRadius,
),
child: TextField(
+ enableSuggestions: Util.isDesktop ? false : true,
focusNode: addressFocusNode,
controller: addressController,
style: STextStyles.field(context),
@@ -324,7 +331,6 @@ class _NewContactAddressEntryFormState
key: const Key("addAddressBookEntryViewAddressField"),
readOnly: false,
autocorrect: false,
- enableSuggestions: false,
// inputFormatters: [
// FilteringTextInputFormatter.allow(RegExp("[a-zA-Z0-9]{34}")),
// ],
diff --git a/lib/pages/exchange_view/edit_trade_note_view.dart b/lib/pages/exchange_view/edit_trade_note_view.dart
index 5e1571b73..e2a72d1b4 100644
--- a/lib/pages/exchange_view/edit_trade_note_view.dart
+++ b/lib/pages/exchange_view/edit_trade_note_view.dart
@@ -9,6 +9,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class EditTradeNoteView extends ConsumerStatefulWidget {
const EditTradeNoteView({
Key? key,
@@ -85,6 +87,8 @@ class _EditNoteViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _noteController,
style: STextStyles.field(context),
focusNode: noteFieldFocusNode,
diff --git a/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart
index d7577e960..80bdcda62 100644
--- a/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart
+++ b/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart
@@ -16,6 +16,8 @@ import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:tuple/tuple.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class FixedRateMarketPairCoinSelectionView extends ConsumerStatefulWidget {
const FixedRateMarketPairCoinSelectionView({
Key? key,
@@ -152,6 +154,8 @@ class _FixedRateMarketPairCoinSelectionViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: filter,
diff --git a/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart
index 7c3b935b7..e1c1addd2 100644
--- a/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart
+++ b/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart
@@ -13,6 +13,8 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class FloatingRateCurrencySelectionView extends StatefulWidget {
const FloatingRateCurrencySelectionView({
Key? key,
@@ -108,6 +110,8 @@ class _FloatingRateCurrencySelectionViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: filter,
diff --git a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
index 744d8b53c..3e29612d1 100644
--- a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
+++ b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
@@ -19,6 +19,7 @@ import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.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/rounded_white_container.dart';
@@ -160,6 +161,8 @@ class _GenerateUriQrCodeViewState extends State {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: amountController,
focusNode: _amountFocusNode,
style: STextStyles.field(context),
@@ -209,6 +212,8 @@ class _GenerateUriQrCodeViewState extends State {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: noteController,
focusNode: _noteFocusNode,
style: STextStyles.field(context),
diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart
index 5e689a580..d91b7a3ea 100644
--- a/lib/pages/send_view/send_view.dart
+++ b/lib/pages/send_view/send_view.dart
@@ -41,6 +41,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class SendView extends ConsumerStatefulWidget {
const SendView({
Key? key,
@@ -885,7 +887,10 @@ class _SendViewState extends ConsumerState {
if (coin == Coin.firo)
Stack(
children: [
- const TextField(
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions:
+ Util.isDesktop ? false : true,
readOnly: true,
textInputAction: TextInputAction.none,
),
@@ -1061,6 +1066,8 @@ class _SendViewState extends ConsumerState {
height: 8,
),
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
style: STextStyles.smallMed14(context).copyWith(
color: Theme.of(context)
.extension()!
@@ -1114,6 +1121,8 @@ class _SendViewState extends ConsumerState {
),
if (Prefs.instance.externalCalls)
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
style: STextStyles.smallMed14(context).copyWith(
color: Theme.of(context)
.extension()!
@@ -1238,6 +1247,8 @@ class _SendViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: noteController,
focusNode: _noteFocusNode,
style: STextStyles.field(context),
@@ -1283,6 +1294,8 @@ class _SendViewState extends ConsumerState {
Stack(
children: [
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: feeController,
readOnly: true,
textInputAction: TextInputAction.none,
diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart
index 06815bd41..a3aa925a0 100644
--- a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart
+++ b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart
@@ -36,6 +36,8 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back
import 'package:stackwallet/utilities/clipboard_interface.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class DebugView extends ConsumerStatefulWidget {
const DebugView({Key? key}) : super(key: key);
@@ -228,6 +230,8 @@ class _DebugViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: (newString) {
diff --git a/lib/pages/settings_views/global_settings_view/currency_view.dart b/lib/pages/settings_views/global_settings_view/currency_view.dart
index cae947caa..e884393bd 100644
--- a/lib/pages/settings_views/global_settings_view/currency_view.dart
+++ b/lib/pages/settings_views/global_settings_view/currency_view.dart
@@ -13,6 +13,8 @@ import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class BaseCurrencySettingsView extends ConsumerStatefulWidget {
const BaseCurrencySettingsView({Key? key}) : super(key: key);
@@ -140,6 +142,8 @@ class _CurrencyViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: (newString) {
diff --git a/lib/pages/settings_views/global_settings_view/language_view.dart b/lib/pages/settings_views/global_settings_view/language_view.dart
index 75a2751a2..b617546e4 100644
--- a/lib/pages/settings_views/global_settings_view/language_view.dart
+++ b/lib/pages/settings_views/global_settings_view/language_view.dart
@@ -13,6 +13,8 @@ import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class LanguageSettingsView extends ConsumerStatefulWidget {
const LanguageSettingsView({Key? key}) : super(key: key);
@@ -138,6 +140,8 @@ class _LanguageViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: (newString) {
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 143b1e84d..100c03e1b 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -27,6 +27,8 @@ import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:uuid/uuid.dart';
+import 'package:stackwallet/utilities/util.dart';
+
enum AddEditNodeViewType { add, edit }
class AddEditNodeView extends ConsumerStatefulWidget {
@@ -648,6 +650,8 @@ class _NodeFormState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key: const Key("addCustomNodeNodeNameFieldKey"),
readOnly: widget.readOnly,
enabled: enableField(_nameController),
@@ -695,6 +699,8 @@ class _NodeFormState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key: const Key("addCustomNodeNodeAddressFieldKey"),
readOnly: widget.readOnly,
enabled: enableField(_hostController),
@@ -746,6 +752,8 @@ class _NodeFormState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key: const Key("addCustomNodeNodePortFieldKey"),
readOnly: widget.readOnly,
enabled: enableField(_portController),
@@ -797,6 +805,8 @@ class _NodeFormState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _usernameController,
readOnly: widget.readOnly,
enabled: enableField(_usernameController),
@@ -844,6 +854,8 @@ class _NodeFormState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _passwordController,
readOnly: widget.readOnly,
enabled: enableField(_passwordController),
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart
index 12573042e..e3743d54e 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart
@@ -7,7 +7,10 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.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/desktop_dialog_close_button.dart';
import 'package:tuple/tuple.dart';
class CoinNodesView extends ConsumerStatefulWidget {
@@ -37,69 +40,139 @@ class _CoinNodesViewState extends ConsumerState {
@override
Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Theme.of(context).extension()!.background,
- appBar: AppBar(
- leading: AppBarBackButton(
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- title: Text(
- "${widget.coin.prettyName} nodes",
- style: STextStyles.navBarTitle(context),
- ),
- actions: [
- Padding(
- padding: const EdgeInsets.only(
- top: 10,
- bottom: 10,
- right: 10,
- ),
- child: AspectRatio(
- aspectRatio: 1,
- child: AppBarIconButton(
- key: const Key("manageNodesAddNewNodeButtonKey"),
- size: 36,
- shadows: const [],
- color: Theme.of(context).extension()!.background,
- icon: SvgPicture.asset(
- Assets.svg.plus,
- color: Theme.of(context)
- .extension()!
- .accentColorDark,
- width: 20,
- height: 20,
+ if (Util.isDesktop) {
+ return DesktopDialog(
+ child: Column(
+ children: [
+ Row(
+ children: [
+ const SizedBox(
+ width: 32,
),
- onPressed: () {
- Navigator.of(context).pushNamed(
- AddEditNodeView.routeName,
- arguments: Tuple4(
- AddEditNodeViewType.add,
- widget.coin,
- null,
- CoinNodesView.routeName,
+ SvgPicture.asset(
+ Assets.svg.iconFor(coin: widget.coin),
+ width: 24,
+ height: 24,
+ ),
+ const SizedBox(
+ width: 12,
+ ),
+ Text(
+ "${widget.coin.prettyName} nodes",
+ style: STextStyles.desktopH3(context),
+ textAlign: TextAlign.center,
+ ),
+ Expanded(
+ child: const DesktopDialogCloseButton(),
+ ),
+ ],
+ ),
+ Padding(
+ padding: EdgeInsets.only(
+ left: 32,
+ right: 32,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "${widget.coin.prettyName} nodes",
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color:
+ Theme.of(context).extension()!.textDark3,
),
- );
- },
+ textAlign: TextAlign.left,
+ ),
+ RichText(
+ text: TextSpan(
+ text: 'Add new nodes',
+ style:
+ STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: Colors.blueAccent,
+ ),
+ ),
+ ),
+ ],
),
),
- ),
- ],
- ),
- body: Padding(
- padding: const EdgeInsets.only(
- top: 12,
- left: 12,
- right: 12,
+ const SizedBox(
+ width: 12,
+ ),
+ Padding(
+ padding: const EdgeInsets.all(20),
+ child: NodesList(
+ coin: widget.coin,
+ popBackToRoute: CoinNodesView.routeName,
+ ),
+ ),
+ ],
),
- child: SingleChildScrollView(
- child: NodesList(
- coin: widget.coin,
- popBackToRoute: CoinNodesView.routeName,
+ );
+ } else {
+ return Scaffold(
+ backgroundColor: Theme.of(context).extension()!.background,
+ appBar: AppBar(
+ leading: AppBarBackButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ title: Text(
+ "${widget.coin.prettyName} nodes",
+ style: STextStyles.navBarTitle(context),
+ ),
+ actions: [
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 10,
+ bottom: 10,
+ right: 10,
+ ),
+ child: AspectRatio(
+ aspectRatio: 1,
+ child: AppBarIconButton(
+ key: const Key("manageNodesAddNewNodeButtonKey"),
+ size: 36,
+ shadows: const [],
+ color: Theme.of(context).extension()!.background,
+ icon: SvgPicture.asset(
+ Assets.svg.plus,
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark,
+ width: 20,
+ height: 20,
+ ),
+ onPressed: () {
+ Navigator.of(context).pushNamed(
+ AddEditNodeView.routeName,
+ arguments: Tuple4(
+ AddEditNodeViewType.add,
+ widget.coin,
+ null,
+ CoinNodesView.routeName,
+ ),
+ );
+ },
+ ),
+ ),
+ ),
+ ],
+ ),
+ body: Padding(
+ padding: const EdgeInsets.only(
+ top: 12,
+ left: 12,
+ right: 12,
+ ),
+ child: SingleChildScrollView(
+ child: NodesList(
+ coin: widget.coin,
+ popBackToRoute: CoinNodesView.routeName,
+ ),
),
),
- ),
- );
+ );
+ }
}
}
diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart
index 3f832a4af..a94375742 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart
@@ -19,6 +19,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:url_launcher/url_launcher.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class AutoBackupView extends ConsumerStatefulWidget {
const AutoBackupView({Key? key}) : super(key: key);
@@ -423,6 +425,8 @@ class _AutoBackupViewState extends ConsumerState {
height: 10,
),
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key: const Key("backupFrequencyFieldKey"),
controller: frequencyController,
enabled: false,
diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart
index b44a473b4..3b5dbd0b0 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart
@@ -27,6 +27,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:zxcvbn/zxcvbn.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class CreateAutoBackupView extends ConsumerStatefulWidget {
const CreateAutoBackupView({
Key? key,
@@ -146,6 +148,8 @@ class _EnableAutoBackupViewState extends ConsumerState {
),
if (!Platform.isAndroid)
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onTap: Platform.isAndroid
? null
: () async {
@@ -411,7 +415,9 @@ class _EnableAutoBackupViewState extends ConsumerState {
),
Stack(
children: [
- const TextField(
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
readOnly: true,
textInputAction: TextInputAction.none,
),
diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart
index 8dfc7588c..9242c0482 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart
@@ -14,6 +14,7 @@ import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/progress_bar.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
@@ -129,6 +130,8 @@ class _RestoreFromFileViewState extends State {
return Container(
color: Colors.transparent,
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onTap: Platform.isAndroid
? null
: () async {
diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart
index 9368d3b77..105146aa0 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart
@@ -27,6 +27,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:zxcvbn/zxcvbn.dart';
+import '../../../../utilities/util.dart';
+
class EditAutoBackupView extends ConsumerStatefulWidget {
const EditAutoBackupView({
Key? key,
@@ -148,6 +150,8 @@ class _EditAutoBackupViewState extends ConsumerState {
),
if (!Platform.isAndroid)
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onTap: Platform.isAndroid
? null
: () async {
@@ -413,7 +417,9 @@ class _EditAutoBackupViewState extends ConsumerState {
),
Stack(
children: [
- const TextField(
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
readOnly: true,
textInputAction: TextInputAction.none,
),
diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart
index cec114023..232be9028 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart
@@ -20,6 +20,8 @@ import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:tuple/tuple.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class RestoreFromFileView extends ConsumerStatefulWidget {
const RestoreFromFileView({Key? key}) : super(key: key);
@@ -96,6 +98,8 @@ class _RestoreFromFileViewState extends ConsumerState {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
onTap: () async {
try {
await stackFileSystem.prepareStorage();
diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
index 6e5cdd5ed..2d8909245 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
@@ -30,6 +30,8 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
+import 'package:stackwallet/utilities/util.dart';
+
/// [eventBus] should only be set during testing
class WalletSettingsView extends StatefulWidget {
const WalletSettingsView({
@@ -374,6 +376,8 @@ class _EpiBoxInfoFormState extends ConsumerState {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: hostController,
decoration: const InputDecoration(hintText: "Host"),
),
@@ -381,6 +385,8 @@ class _EpiBoxInfoFormState extends ConsumerState {
height: 8,
),
TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: portController,
decoration: const InputDecoration(hintText: "Port"),
keyboardType: const TextInputType.numberWithOptions(),
diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart
index b876216e0..e9eb14868 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart
@@ -11,6 +11,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class RenameWalletView extends ConsumerStatefulWidget {
const RenameWalletView({
Key? key,
@@ -74,6 +76,8 @@ class _RenameWalletViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _controller,
focusNode: _focusNode,
style: STextStyles.field(context),
diff --git a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart
index 78f24ba6a..4194a7307 100644
--- a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart
+++ b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart
@@ -21,6 +21,8 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/transaction_card.dart';
import 'package:tuple/tuple.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class AllTransactionsView extends ConsumerStatefulWidget {
const AllTransactionsView({
Key? key,
@@ -234,6 +236,8 @@ class _TransactionDetailsViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
diff --git a/lib/pages/wallet_view/transaction_views/edit_note_view.dart b/lib/pages/wallet_view/transaction_views/edit_note_view.dart
index aa085429b..b811dc62d 100644
--- a/lib/pages/wallet_view/transaction_views/edit_note_view.dart
+++ b/lib/pages/wallet_view/transaction_views/edit_note_view.dart
@@ -9,6 +9,8 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:stackwallet/utilities/util.dart';
+
class EditNoteView extends ConsumerStatefulWidget {
const EditNoteView({
Key? key,
@@ -87,6 +89,8 @@ class _EditNoteViewState extends ConsumerState {
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
controller: _noteController,
style: STextStyles.field(context),
focusNode: noteFieldFocusNode,
diff --git a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart
index 8175597f6..f9932c672 100644
--- a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart
+++ b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart
@@ -569,6 +569,8 @@ class _TransactionSearchViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key: const Key("transactionSearchViewAmountFieldKey"),
controller: _amountTextEditingController,
focusNode: amountTextFieldFocusNode,
@@ -636,6 +638,8 @@ class _TransactionSearchViewState
Constants.size.circularBorderRadius,
),
child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
key:
const Key("transactionSearchViewKeywordFieldKey"),
controller: _keywordTextEditingController,
diff --git a/lib/pages_desktop_specific/home/desktop_home_view.dart b/lib/pages_desktop_specific/home/desktop_home_view.dart
index 4ca78894b..6aa104081 100644
--- a/lib/pages_desktop_specific/home/desktop_home_view.dart
+++ b/lib/pages_desktop_specific/home/desktop_home_view.dart
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart';
+import 'package:stackwallet/pages_desktop_specific/home/desktop_settings_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart';
-import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@@ -19,6 +19,7 @@ class _DesktopHomeViewState extends ConsumerState {
int currentViewIndex = 0;
final List contentViews = [
const Navigator(
+ key: Key("desktopStackHomeKey"),
onGenerateRoute: RouteGenerator.generateRoute,
initialRoute: MyStackView.routeName,
),
@@ -32,8 +33,9 @@ class _DesktopHomeViewState extends ConsumerState {
color: Colors.orange,
),
const Navigator(
+ key: Key("desktopSettingHomeKey"),
onGenerateRoute: RouteGenerator.generateRoute,
- initialRoute: SettingsMenu.routeName,
+ initialRoute: DesktopSettingsView.routeName,
),
Container(
color: Colors.blue,
@@ -41,9 +43,6 @@ class _DesktopHomeViewState extends ConsumerState {
Container(
color: Colors.pink,
),
- Container(
- color: Colors.purple,
- ),
];
void onMenuSelectionChanged(int newIndex) {
@@ -61,6 +60,10 @@ class _DesktopHomeViewState extends ConsumerState {
DesktopMenu(
onSelectionChanged: onMenuSelectionChanged,
),
+ Container(
+ width: 1,
+ color: Theme.of(context).extension()!.background,
+ ),
Expanded(
child: contentViews[currentViewIndex],
),
diff --git a/lib/pages_desktop_specific/home/desktop_menu.dart b/lib/pages_desktop_specific/home/desktop_menu.dart
index b71c20f6e..7409a4156 100644
--- a/lib/pages_desktop_specific/home/desktop_menu.dart
+++ b/lib/pages_desktop_specific/home/desktop_menu.dart
@@ -1,3 +1,5 @@
+import 'dart:io';
+
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -70,136 +72,197 @@ class _DesktopMenuState extends ConsumerState {
const SizedBox(
height: 60,
),
- SizedBox(
- width: _width == expandedWidth
- ? _width - 32 // 16 padding on either side
- : _width - 16, // 8 padding on either side
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.walletFa,
- width: 20,
- height: 20,
+ Expanded(
+ child: SizedBox(
+ width: _width == expandedWidth
+ ? _width - 32 // 16 padding on either side
+ : _width - 16, // 8 padding on either side
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.walletDesktop,
+ width: 20,
+ height: 20,
+ color: 0 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "My Stack",
+ value: 0,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
),
- label: "My Stack",
- value: 0,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.exchange3,
- width: 20,
- height: 20,
+ const SizedBox(
+ height: 2,
),
- label: "Exchange",
- value: 1,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.bell,
- width: 20,
- height: 20,
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.exchangeDesktop,
+ width: 20,
+ height: 20,
+ color: 1 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Exchange",
+ value: 1,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
),
- label: "Notifications",
- value: 2,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.addressBook2,
- width: 20,
- height: 20,
+ const SizedBox(
+ height: 2,
),
- label: "Address Book",
- value: 3,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.gear,
- width: 20,
- height: 20,
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.bell,
+ width: 20,
+ height: 20,
+ color: 2 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Notifications",
+ value: 2,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
),
- label: "Settings",
- value: 4,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.messageQuestion,
- width: 20,
- height: 20,
+ const SizedBox(
+ height: 2,
),
- label: "Support",
- value: 5,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.messageQuestion,
- width: 20,
- height: 20,
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.addressBookDesktop,
+ width: 20,
+ height: 20,
+ color: 3 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Address Book",
+ value: 3,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
),
- label: "About",
- value: 6,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- const SizedBox(
- height: 2,
- ),
- DesktopMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.messageQuestion,
- width: 20,
- height: 20,
+ const SizedBox(
+ height: 2,
),
- label: "Exit",
- value: 7,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- iconOnly: _width == minimizedWidth,
- ),
- ],
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.gear,
+ width: 20,
+ height: 20,
+ color: 4 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Settings",
+ value: 4,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.messageQuestion,
+ width: 20,
+ height: 20,
+ color: 5 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Support",
+ value: 5,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.aboutDesktop,
+ width: 20,
+ height: 20,
+ color: 6 == selectedMenuItem
+ ? Theme.of(context)
+ .extension()!
+ .textDark
+ : Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "About",
+ value: 6,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ iconOnly: _width == minimizedWidth,
+ ),
+ const Spacer(),
+ DesktopMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.exitDesktop,
+ width: 20,
+ height: 20,
+ color: Theme.of(context)
+ .extension()!
+ .textDark
+ .withOpacity(0.8),
+ ),
+ label: "Exit",
+ value: 7,
+ group: selectedMenuItem,
+ onChanged: (_) {
+ // todo: save stuff/ notify before exit?
+ exit(0);
+ },
+ iconOnly: _width == minimizedWidth,
+ ),
+ ],
+ ),
),
),
- const Spacer(),
Row(
- mainAxisAlignment: MainAxisAlignment.end,
children: [
const Spacer(),
IconButton(
@@ -212,7 +275,7 @@ class _DesktopMenuState extends ConsumerState {
),
),
],
- )
+ ),
],
),
),
diff --git a/lib/pages_desktop_specific/home/desktop_settings_view.dart b/lib/pages_desktop_specific/home/desktop_settings_view.dart
index bfe9272f2..7aff94b66 100644
--- a/lib/pages_desktop_specific/home/desktop_settings_view.dart
+++ b/lib/pages_desktop_specific/home/desktop_settings_view.dart
@@ -1,7 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/syncing_preferences_settings.dart';
+import 'package:stackwallet/route_generator.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
class DesktopSettingsView extends ConsumerStatefulWidget {
const DesktopSettingsView({Key? key}) : super(key: key);
@@ -16,29 +28,45 @@ class DesktopSettingsView extends ConsumerStatefulWidget {
class _DesktopSettingsViewState extends ConsumerState {
int currentViewIndex = 0;
final List contentViews = [
- Container(
- color: Colors.lime,
+ const Navigator(
+ key: Key("settingsBackupRestoreDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: BackupRestoreSettings.routeName,
), //b+r
- Container(
- color: Colors.green,
+ const Navigator(
+ key: Key("settingsSecurityDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: SecuritySettings.routeName,
), //security
- Container(
- color: Colors.red,
+ const Navigator(
+ key: Key("settingsCurrencyDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: CurrencySettings.routeName,
), //currency
- Container(
- color: Colors.orange,
+ const Navigator(
+ key: Key("settingsLanguageDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: LanguageOptionSettings.routeName,
), //language
- Container(
- color: Colors.yellow,
+ const Navigator(
+ key: Key("settingsNodesDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: NodesSettings.routeName,
), //nodes
- Container(
- color: Colors.blue,
+ const Navigator(
+ key: Key("settingsSyncingPreferencesDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: SyncingPreferencesSettings.routeName,
), //syncing prefs
- Container(
- color: Colors.pink,
+ const Navigator(
+ key: Key("settingsAppearanceDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: AppearanceOptionSettings.routeName,
), //appearance
- Container(
- color: Colors.purple,
+ const Navigator(
+ key: Key("settingsAdvancedDesktopKey"),
+ onGenerateRoute: RouteGenerator.generateRoute,
+ initialRoute: AdvancedSettings.routeName,
), //advanced
];
@@ -48,12 +76,26 @@ class _DesktopSettingsViewState extends ConsumerState {
});
}
- // will have a row with two items: SettingsMenu and settings contentxd
@override
Widget build(BuildContext context) {
- return Material(
- color: Theme.of(context).extension()!.background,
- child: Row(
+ return DesktopScaffold(
+ background: Theme.of(context).extension()!.background,
+ appBar: DesktopAppBar(
+ isCompactHeight: true,
+ leading: Row(
+ children: [
+ const SizedBox(
+ width: 24,
+ height: 24,
+ ),
+ Text(
+ "Settings",
+ style: STextStyles.desktopH3(context),
+ )
+ ],
+ ),
+ ),
+ body: Row(
children: [
SettingsMenu(
onSelectionChanged: onMenuSelectionChanged,
diff --git a/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart b/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart
index 64e4a23d3..b16a9bc58 100644
--- a/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart
+++ b/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
@@ -37,6 +38,12 @@ class CoinWalletsTable extends ConsumerWidget {
),
WalletInfoRow(
walletId: walletIds[i],
+ onPressed: () async {
+ await Navigator.of(context).pushNamed(
+ DesktopWalletView.routeName,
+ arguments: walletIds[i],
+ );
+ },
),
],
),
diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_summary.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_summary.dart
new file mode 100644
index 000000000..fe2cfa7b2
--- /dev/null
+++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_summary.dart
@@ -0,0 +1,283 @@
+import 'package:decimal/decimal.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart';
+import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
+import 'package:stackwallet/providers/providers.dart';
+import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
+import 'package:stackwallet/services/coins/manager.dart';
+import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.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 DesktopWalletSummary extends StatefulWidget {
+ const DesktopWalletSummary({
+ Key? key,
+ required this.walletId,
+ required this.managerProvider,
+ required this.initialSyncStatus,
+ }) : super(key: key);
+
+ final String walletId;
+ final ChangeNotifierProvider managerProvider;
+ final WalletSyncStatus initialSyncStatus;
+
+ @override
+ State createState() => _WDesktopWalletSummaryState();
+}
+
+class _WDesktopWalletSummaryState extends State {
+ late final String walletId;
+ late final ChangeNotifierProvider managerProvider;
+
+ void showSheet() {
+ showModalBottomSheet(
+ backgroundColor: Colors.transparent,
+ context: context,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(
+ top: Radius.circular(20),
+ ),
+ ),
+ builder: (_) => WalletBalanceToggleSheet(walletId: walletId),
+ );
+ }
+
+ Decimal? _balanceTotalCached;
+ Decimal? _balanceCached;
+
+ @override
+ void initState() {
+ walletId = widget.walletId;
+ managerProvider = widget.managerProvider;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ debugPrint("BUILD: $runtimeType");
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ children: [
+ Consumer(
+ builder: (_, ref, __) {
+ final Coin coin =
+ ref.watch(managerProvider.select((value) => value.coin));
+ final externalCalls = ref.watch(prefsChangeNotifierProvider
+ .select((value) => value.externalCalls));
+
+ Future? totalBalanceFuture;
+ Future? availableBalanceFuture;
+ if (coin == Coin.firo || coin == Coin.firoTestNet) {
+ final firoWallet =
+ ref.watch(managerProvider.select((value) => value.wallet))
+ as FiroWallet;
+ totalBalanceFuture = firoWallet.availablePublicBalance();
+ availableBalanceFuture = firoWallet.availablePrivateBalance();
+ } else {
+ totalBalanceFuture = ref.watch(
+ managerProvider.select((value) => value.totalBalance));
+
+ availableBalanceFuture = ref.watch(managerProvider
+ .select((value) => value.availableBalance));
+ }
+
+ final locale = ref.watch(localeServiceChangeNotifierProvider
+ .select((value) => value.locale));
+
+ final baseCurrency = ref.watch(prefsChangeNotifierProvider
+ .select((value) => value.currency));
+
+ final priceTuple = ref.watch(priceAnd24hChangeNotifierProvider
+ .select((value) => value.getPrice(coin)));
+
+ final _showAvailable =
+ ref.watch(walletBalanceToggleStateProvider.state).state ==
+ WalletBalanceToggleState.available;
+
+ return FutureBuilder(
+ future: _showAvailable
+ ? availableBalanceFuture
+ : totalBalanceFuture,
+ builder: (fbContext, AsyncSnapshot snapshot) {
+ if (snapshot.connectionState == ConnectionState.done &&
+ snapshot.hasData &&
+ snapshot.data != null) {
+ if (_showAvailable) {
+ _balanceCached = snapshot.data!;
+ } else {
+ _balanceTotalCached = snapshot.data!;
+ }
+ }
+ Decimal? balanceToShow =
+ _showAvailable ? _balanceCached : _balanceTotalCached;
+
+ if (balanceToShow != null) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ GestureDetector(
+ onTap: showSheet,
+ child: Row(
+ children: [
+ if (coin == Coin.firo ||
+ coin == Coin.firoTestNet)
+ Text(
+ "${_showAvailable ? "Private" : "Public"} Balance",
+ style: STextStyles.subtitle500(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ if (coin != Coin.firo &&
+ coin != Coin.firoTestNet)
+ Text(
+ "${_showAvailable ? "Available" : "Full"} Balance",
+ style: STextStyles.subtitle500(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ SvgPicture.asset(
+ Assets.svg.chevronDown,
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ width: 8,
+ height: 4,
+ ),
+ ],
+ ),
+ ),
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Text(
+ "${Format.localizedStringAsFixed(
+ value: balanceToShow,
+ locale: locale,
+ decimalPlaces: 8,
+ )} ${coin.ticker}",
+ style: STextStyles.desktopH3(context),
+ ),
+ ),
+ if (externalCalls)
+ Text(
+ "${Format.localizedStringAsFixed(
+ value: priceTuple.item1 * balanceToShow,
+ locale: locale,
+ decimalPlaces: 2,
+ )} $baseCurrency",
+ style: STextStyles.desktopTextExtraSmall(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ ),
+ ],
+ );
+ } else {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ GestureDetector(
+ onTap: showSheet,
+ child: Row(
+ children: [
+ if (coin == Coin.firo ||
+ coin == Coin.firoTestNet)
+ Text(
+ "${_showAvailable ? "Private" : "Public"} Balance",
+ style: STextStyles.subtitle500(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ if (coin != Coin.firo &&
+ coin != Coin.firoTestNet)
+ Text(
+ "${_showAvailable ? "Available" : "Full"} Balance",
+ style: STextStyles.subtitle500(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ SvgPicture.asset(
+ Assets.svg.chevronDown,
+ width: 8,
+ height: 4,
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ],
+ ),
+ ),
+ AnimatedText(
+ stringsToLoopThrough: const [
+ "Loading balance ",
+ "Loading balance. ",
+ "Loading balance.. ",
+ "Loading balance..."
+ ],
+ style: STextStyles.desktopH3(context).copyWith(
+ fontSize: 24,
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ AnimatedText(
+ stringsToLoopThrough: const [
+ "Loading balance ",
+ "Loading balance. ",
+ "Loading balance.. ",
+ "Loading balance..."
+ ],
+ style: STextStyles.desktopTextExtraSmall(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ ),
+ ],
+ );
+ }
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ WalletRefreshButton(
+ walletId: walletId,
+ initialSyncStatus: widget.initialSyncStatus,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart
new file mode 100644
index 000000000..7f13c7fd8
--- /dev/null
+++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart
@@ -0,0 +1,485 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_summary.dart';
+import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/receive/desktop_receive.dart';
+import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/send/desktop_send.dart';
+import 'package:stackwallet/providers/providers.dart';
+import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class DesktopWalletView extends ConsumerStatefulWidget {
+ const DesktopWalletView({
+ Key? key,
+ required this.walletId,
+ }) : super(key: key);
+
+ static const String routeName = "/desktopWalletView";
+
+ final String walletId;
+
+ @override
+ ConsumerState createState() => _DesktopWalletViewState();
+}
+
+class _DesktopWalletViewState extends ConsumerState {
+ late final String walletId;
+
+ Future onBackPressed() async {
+ // TODO log out and close wallet before popping back
+ Navigator.of(context).pop();
+ }
+
+ @override
+ void initState() {
+ walletId = widget.walletId;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final manager = ref.watch(walletsChangeNotifierProvider
+ .select((value) => value.getManager(walletId)));
+ final coin = manager.coin;
+ final managerProvider = ref.watch(walletsChangeNotifierProvider
+ .select((value) => value.getManagerProvider(walletId)));
+
+ return DesktopScaffold(
+ appBar: DesktopAppBar(
+ background: Theme.of(context).extension()!.popupBG,
+ leading: Row(
+ children: [
+ const SizedBox(
+ width: 32,
+ ),
+ AppBarIconButton(
+ size: 32,
+ color: Theme.of(context)
+ .extension()!
+ .textFieldDefaultBG,
+ shadows: const [],
+ icon: SvgPicture.asset(
+ Assets.svg.arrowLeft,
+ width: 18,
+ height: 18,
+ color: Theme.of(context)
+ .extension()!
+ .topNavIconPrimary,
+ ),
+ onPressed: onBackPressed,
+ ),
+ const SizedBox(
+ width: 15,
+ ),
+ SvgPicture.asset(
+ Assets.svg.iconFor(coin: coin),
+ width: 32,
+ height: 32,
+ ),
+ const SizedBox(
+ width: 12,
+ ),
+ Text(
+ manager.walletName,
+ style: STextStyles.desktopH3(context),
+ ),
+ ],
+ ),
+ trailing: Row(
+ children: const [
+ NetworkInfoButton(),
+ SizedBox(
+ width: 12,
+ ),
+ WalletKeysButton(),
+ SizedBox(
+ width: 32,
+ ),
+ ],
+ ),
+ isCompactHeight: true,
+ ),
+ body: Padding(
+ padding: const EdgeInsets.all(24),
+ child: Column(
+ children: [
+ RoundedWhiteContainer(
+ padding: const EdgeInsets.all(20),
+ child: Row(
+ children: [
+ SvgPicture.asset(
+ Assets.svg.iconFor(coin: coin),
+ width: 40,
+ height: 40,
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ DesktopWalletSummary(
+ walletId: walletId,
+ managerProvider: managerProvider,
+ initialSyncStatus: ref.watch(managerProvider
+ .select((value) => value.isRefreshing))
+ ? WalletSyncStatus.syncing
+ : WalletSyncStatus.synced,
+ ),
+ // Column(
+ // crossAxisAlignment: CrossAxisAlignment.start,
+ // mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // children: [
+ // Row(
+ // children: [
+ // Text(
+ // "TODO: balance",
+ // style: STextStyles.desktopH3(context),
+ // ),
+ // const SizedBox(
+ // width: 8,
+ // ),
+ // Container(
+ // color: Colors.red,
+ // width: 20,
+ // height: 20,
+ // ),
+ // ],
+ // ),
+ // Text(
+ // "todo: fiat balance",
+ // style:
+ // STextStyles.desktopTextExtraSmall(context).copyWith(
+ // color: Theme.of(context)
+ // .extension()!
+ // .textSubtitle1,
+ // ),
+ // )
+ // ],
+ // ),
+ const Spacer(),
+ SecondaryButton(
+ width: 180,
+ height: 56,
+ onPressed: () {
+ // todo: go to wallet initiated exchange
+ },
+ label: "Exchange",
+ icon: Container(
+ color: Colors.red,
+ width: 20,
+ height: 20,
+ ),
+ )
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 24,
+ ),
+ Expanded(
+ child: Row(
+ children: [
+ SizedBox(
+ width: 450,
+ child: MyWallet(
+ walletId: walletId,
+ ),
+ ),
+ const SizedBox(
+ width: 16,
+ ),
+ Expanded(
+ child: RecentDesktopTransactions(),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class MyWallet extends StatefulWidget {
+ const MyWallet({
+ Key? key,
+ required this.walletId,
+ }) : super(key: key);
+
+ final String walletId;
+
+ @override
+ State createState() => _MyWalletState();
+}
+
+class _MyWalletState extends State {
+ int _selectedIndex = 0;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "My wallet",
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFieldActiveSearchIconLeft,
+ ),
+ ),
+ const SizedBox(
+ height: 16,
+ ),
+ Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context).extension()!.popupBG,
+ borderRadius: BorderRadius.vertical(
+ top: Radius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ ),
+ ),
+ child: SendReceiveTabMenu(
+ onChanged: (index) {
+ setState(() {
+ _selectedIndex = index;
+ });
+ },
+ ),
+ ),
+ Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context).extension()!.popupBG,
+ borderRadius: BorderRadius.vertical(
+ bottom: Radius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ ),
+ ),
+ child: IndexedStack(
+ index: _selectedIndex,
+ children: [
+ Padding(
+ key: const Key("desktopSendViewPortKey"),
+ padding: const EdgeInsets.all(20),
+ child: DesktopSend(
+ walletId: widget.walletId,
+ ),
+ ),
+ Padding(
+ key: const Key("desktopReceiveViewPortKey"),
+ padding: const EdgeInsets.all(20),
+ child: DesktopReceive(
+ walletId: widget.walletId,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const Spacer(),
+ ],
+ );
+ }
+}
+
+class SendReceiveTabMenu extends StatefulWidget {
+ const SendReceiveTabMenu({
+ Key? key,
+ this.initialIndex = 0,
+ this.onChanged,
+ }) : super(key: key);
+
+ final int initialIndex;
+ final void Function(int)? onChanged;
+
+ @override
+ State createState() => _SendReceiveTabMenuState();
+}
+
+class _SendReceiveTabMenuState extends State {
+ late int _selectedIndex;
+
+ void _onChanged(int newIndex) {
+ if (_selectedIndex != newIndex) {
+ setState(() {
+ _selectedIndex = newIndex;
+ });
+ widget.onChanged?.call(_selectedIndex);
+ }
+ }
+
+ @override
+ void initState() {
+ _selectedIndex = widget.initialIndex;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ Expanded(
+ child: GestureDetector(
+ onTap: () => _onChanged(0),
+ child: Container(
+ color: Colors.transparent,
+ child: Column(
+ children: [
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ "Send",
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: _selectedIndex == 0
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ ),
+ const SizedBox(
+ height: 19,
+ ),
+ Container(
+ height: 2,
+ decoration: BoxDecoration(
+ color: _selectedIndex == 0
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Theme.of(context)
+ .extension()!
+ .background,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Expanded(
+ child: GestureDetector(
+ onTap: () => _onChanged(1),
+ child: Container(
+ color: Colors.transparent,
+ child: Column(
+ children: [
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ "Receive",
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: _selectedIndex == 1
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ ),
+ const SizedBox(
+ height: 19,
+ ),
+ Container(
+ height: 2,
+ decoration: BoxDecoration(
+ color: _selectedIndex == 1
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Theme.of(context)
+ .extension()!
+ .background,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class RecentDesktopTransactions extends StatefulWidget {
+ const RecentDesktopTransactions({Key? key}) : super(key: key);
+
+ @override
+ State createState() =>
+ _RecentDesktopTransactionsState();
+}
+
+class _RecentDesktopTransactionsState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Recent transactions",
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFieldActiveSearchIconLeft,
+ ),
+ ),
+ BlueTextButton(
+ text: "See all",
+ onTap: () {
+ // todo: show all txns
+ },
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 16,
+ ),
+ Expanded(
+ child: RoundedWhiteContainer(
+ padding: const EdgeInsets.all(0),
+ child: Container(),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class NetworkInfoButton extends StatelessWidget {
+ const NetworkInfoButton({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ child: Text("todo: sync status"),
+ );
+ }
+}
+
+class WalletKeysButton extends StatelessWidget {
+ const WalletKeysButton({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ child: Text("todo: wallet keys"),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/receive/desktop_receive.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/receive/desktop_receive.dart
new file mode 100644
index 000000000..79e3b81cf
--- /dev/null
+++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/receive/desktop_receive.dart
@@ -0,0 +1,236 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
+import 'package:stackwallet/providers/providers.dart';
+import 'package:stackwallet/route_generator.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/clipboard_interface.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/custom_loading_overlay.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class DesktopReceive extends ConsumerStatefulWidget {
+ const DesktopReceive({
+ Key? key,
+ required this.walletId,
+ this.clipboard = const ClipboardWrapper(),
+ }) : super(key: key);
+
+ final String walletId;
+ final ClipboardInterface clipboard;
+
+ @override
+ ConsumerState createState() => _DesktopReceiveState();
+}
+
+class _DesktopReceiveState extends ConsumerState {
+ late final Coin coin;
+ late final String walletId;
+ late final ClipboardInterface clipboard;
+
+ Future generateNewAddress() async {
+ bool shouldPop = false;
+ unawaited(
+ showDialog(
+ context: context,
+ builder: (_) {
+ return WillPopScope(
+ onWillPop: () async => shouldPop,
+ child: Container(
+ color: Theme.of(context)
+ .extension()!
+ .overlay
+ .withOpacity(0.5),
+ child: const CustomLoadingOverlay(
+ message: "Generating address",
+ eventBus: null,
+ ),
+ ),
+ );
+ },
+ ),
+ );
+
+ await ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(walletId)
+ .generateNewAddress();
+
+ shouldPop = true;
+
+ if (mounted) {
+ Navigator.of(context, rootNavigator: true).pop();
+ }
+ }
+
+ String receivingAddress = "";
+
+ @override
+ void initState() {
+ walletId = widget.walletId;
+ coin = ref.read(walletsChangeNotifierProvider).getManager(walletId).coin;
+ clipboard = widget.clipboard;
+
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+ final address = await ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(walletId)
+ .currentReceivingAddress;
+ setState(() {
+ receivingAddress = address;
+ });
+ });
+
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ debugPrint("BUILD: $runtimeType");
+
+ ref.listen(
+ ref
+ .read(walletsChangeNotifierProvider)
+ .getManagerProvider(walletId)
+ .select((value) => value.currentReceivingAddress),
+ (previous, next) {
+ if (next is Future) {
+ next.then((value) => setState(() => receivingAddress = value));
+ }
+ });
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ GestureDetector(
+ onTap: () {
+ clipboard.setData(
+ ClipboardData(text: receivingAddress),
+ );
+ showFloatingFlushBar(
+ type: FlushBarType.info,
+ message: "Copied to clipboard",
+ iconAsset: Assets.svg.copy,
+ context: context,
+ );
+ },
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: Theme.of(context).extension()!.background,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ ),
+ child: RoundedWhiteContainer(
+ child: Column(
+ children: [
+ Row(
+ children: [
+ Text(
+ "Your ${coin.ticker} address",
+ style: STextStyles.itemSubtitle(context),
+ ),
+ const Spacer(),
+ Row(
+ children: [
+ SvgPicture.asset(
+ Assets.svg.copy,
+ width: 10,
+ height: 10,
+ color: Theme.of(context)
+ .extension()!
+ .infoItemIcons,
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ Text(
+ "Copy",
+ style: STextStyles.link2(context),
+ ),
+ ],
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 4,
+ ),
+ Row(
+ children: [
+ Expanded(
+ child: Text(
+ receivingAddress,
+ style: STextStyles.itemSubtitle12(context),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ if (coin != Coin.epicCash)
+ const SizedBox(
+ height: 20,
+ ),
+ if (coin != Coin.epicCash)
+ SecondaryButton(
+ height: 56,
+ onPressed: generateNewAddress,
+ label: "Generate new address",
+ ),
+ const SizedBox(
+ height: 32,
+ ),
+ Center(
+ child: QrImage(
+ data: "${coin.uriScheme}:$receivingAddress",
+ size: 200,
+ foregroundColor:
+ Theme.of(context).extension()!.accentColorDark,
+ ),
+ ),
+ const SizedBox(
+ height: 32,
+ ),
+ Center(
+ child: BlueTextButton(
+ text: "Create new QR code",
+ onTap: () async {
+ unawaited(
+ Navigator.of(context).push(
+ RouteGenerator.getRoute(
+ shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
+ builder: (_) => GenerateUriQrCodeView(
+ coin: coin,
+ receivingAddress: receivingAddress,
+ ),
+ settings: const RouteSettings(
+ name: GenerateUriQrCodeView.routeName,
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/send/desktop_send.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/send/desktop_send.dart
new file mode 100644
index 000000000..1579b2367
--- /dev/null
+++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/send/desktop_send.dart
@@ -0,0 +1,1164 @@
+import 'dart:async';
+
+import 'package:decimal/decimal.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:stackwallet/models/send_view_auto_fill_data.dart';
+import 'package:stackwallet/pages/address_book_views/address_book_view.dart';
+import 'package:stackwallet/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart';
+import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
+import 'package:stackwallet/providers/providers.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/wallet/public_private_balance_state_provider.dart';
+import 'package:stackwallet/route_generator.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
+import 'package:stackwallet/services/coins/manager.dart';
+import 'package:stackwallet/utilities/address_utils.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
+import 'package:stackwallet/utilities/clipboard_interface.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/logger.dart';
+import 'package:stackwallet/utilities/prefs.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/animated_text.dart';
+import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/addressbook_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/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+import '../../../../../pages/send_view/confirm_transaction_view.dart';
+import '../../../../../pages/send_view/sub_widgets/building_transaction_dialog.dart';
+
+class DesktopSend extends ConsumerStatefulWidget {
+ const DesktopSend({
+ Key? key,
+ required this.walletId,
+ this.autoFillData,
+ this.clipboard = const ClipboardWrapper(),
+ this.barcodeScanner = const BarcodeScannerWrapper(),
+ }) : super(key: key);
+
+ final String walletId;
+ final SendViewAutoFillData? autoFillData;
+ final ClipboardInterface clipboard;
+ final BarcodeScannerInterface barcodeScanner;
+
+ @override
+ ConsumerState createState() => _DesktopSendState();
+}
+
+class _DesktopSendState extends ConsumerState {
+ late final String walletId;
+ late final Coin coin;
+ late final ClipboardInterface clipboard;
+ late final BarcodeScannerInterface scanner;
+
+ late TextEditingController sendToController;
+ late TextEditingController cryptoAmountController;
+ late TextEditingController baseAmountController;
+ late TextEditingController noteController;
+ late TextEditingController feeController;
+
+ late final SendViewAutoFillData? _data;
+
+ final _addressFocusNode = FocusNode();
+ final _noteFocusNode = FocusNode();
+ final _cryptoFocus = FocusNode();
+ final _baseFocus = FocusNode();
+
+ Decimal? _amountToSend;
+ Decimal? _cachedAmountToSend;
+ String? _address;
+
+ String? _privateBalanceString;
+ String? _publicBalanceString;
+
+ bool _addressToggleFlag = false;
+
+ bool _cryptoAmountChangeLock = false;
+ late VoidCallback onCryptoAmountChanged;
+
+ Decimal? _cachedBalance;
+
+ Future previewSend() async {
+ // wait for keyboard to disappear
+ FocusScope.of(context).unfocus();
+ await Future.delayed(
+ const Duration(milliseconds: 100),
+ );
+ final manager =
+ ref.read(walletsChangeNotifierProvider).getManager(walletId);
+
+ // TODO: remove the need for this!!
+ final bool isOwnAddress = await manager.isOwnAddress(_address!);
+ if (isOwnAddress) {
+ await showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return StackDialog(
+ title: "Transaction failed",
+ message: "Sending to self is currently disabled",
+ rightButton: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getSecondaryEnabledButtonColor(context),
+ child: Text(
+ "Ok",
+ style: STextStyles.button(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ );
+ },
+ );
+ return;
+ }
+
+ final amount = Format.decimalAmountToSatoshis(_amountToSend!);
+ int availableBalance;
+ if ((coin == Coin.firo || coin == Coin.firoTestNet)) {
+ if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+ "Private") {
+ availableBalance = Format.decimalAmountToSatoshis(
+ await (manager.wallet as FiroWallet).availablePrivateBalance());
+ } else {
+ availableBalance = Format.decimalAmountToSatoshis(
+ await (manager.wallet as FiroWallet).availablePublicBalance());
+ }
+ } else {
+ availableBalance =
+ Format.decimalAmountToSatoshis(await manager.availableBalance);
+ }
+
+ // confirm send all
+ if (amount == availableBalance) {
+ final bool? shouldSendAll = await showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return StackDialog(
+ title: "Confirm send all",
+ message:
+ "You are about to send your entire balance. Would you like to continue?",
+ leftButton: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getSecondaryEnabledButtonColor(context),
+ child: Text(
+ "Cancel",
+ style: STextStyles.button(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop(false);
+ },
+ ),
+ rightButton: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getPrimaryEnabledButtonColor(context),
+ child: Text(
+ "Yes",
+ style: STextStyles.button(context),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop(true);
+ },
+ ),
+ );
+ },
+ );
+
+ if (shouldSendAll == null || shouldSendAll == false) {
+ // cancel preview
+ return;
+ }
+ }
+
+ try {
+ bool wasCancelled = false;
+
+ unawaited(showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: false,
+ builder: (context) {
+ return BuildingTransactionDialog(
+ onCancel: () {
+ wasCancelled = true;
+
+ Navigator.of(context).pop();
+ },
+ );
+ },
+ ));
+
+ Map txData;
+
+ if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+ ref.read(publicPrivateBalanceStateProvider.state).state !=
+ "Private") {
+ txData = await (manager.wallet as FiroWallet).prepareSendPublic(
+ address: _address!,
+ satoshiAmount: amount,
+ args: {"feeRate": ref.read(feeRateTypeStateProvider)},
+ );
+ } else {
+ txData = await manager.prepareSend(
+ address: _address!,
+ satoshiAmount: amount,
+ args: {"feeRate": ref.read(feeRateTypeStateProvider)},
+ );
+ }
+
+ if (!wasCancelled && mounted) {
+ // pop building dialog
+ Navigator.of(context).pop();
+ txData["note"] = noteController.text;
+ txData["address"] = _address;
+
+ unawaited(Navigator.of(context).push(
+ RouteGenerator.getRoute(
+ shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
+ builder: (_) => ConfirmTransactionView(
+ transactionInfo: txData,
+ walletId: walletId,
+ ),
+ settings: const RouteSettings(
+ name: ConfirmTransactionView.routeName,
+ ),
+ ),
+ ));
+ }
+ } catch (e) {
+ if (mounted) {
+ // pop building dialog
+ Navigator.of(context).pop();
+
+ unawaited(showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return StackDialog(
+ title: "Transaction failed",
+ message: e.toString(),
+ rightButton: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getSecondaryEnabledButtonColor(context),
+ child: Text(
+ "Ok",
+ style: STextStyles.button(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ );
+ },
+ ));
+ }
+ }
+ }
+
+ void _cryptoAmountChanged() async {
+ if (!_cryptoAmountChangeLock) {
+ final String cryptoAmount = cryptoAmountController.text;
+ if (cryptoAmount.isNotEmpty &&
+ cryptoAmount != "." &&
+ cryptoAmount != ",") {
+ _amountToSend = cryptoAmount.contains(",")
+ ? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
+ : Decimal.parse(cryptoAmount);
+ if (_cachedAmountToSend != null &&
+ _cachedAmountToSend == _amountToSend) {
+ return;
+ }
+ _cachedAmountToSend = _amountToSend;
+ Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend",
+ level: LogLevel.Info);
+
+ final price =
+ ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
+
+ if (price > Decimal.zero) {
+ final String fiatAmountString = Format.localizedStringAsFixed(
+ value: _amountToSend! * price,
+ locale: ref.read(localeServiceChangeNotifierProvider).locale,
+ decimalPlaces: 2,
+ );
+
+ baseAmountController.text = fiatAmountString;
+ }
+ } else {
+ _amountToSend = null;
+ baseAmountController.text = "";
+ }
+
+ _updatePreviewButtonState(_address, _amountToSend);
+ }
+ }
+
+ String? _updateInvalidAddressText(String address, Manager manager) {
+ if (_data != null && _data!.contactLabel == address) {
+ return null;
+ }
+ if (address.isNotEmpty && !manager.validateAddress(address)) {
+ return "Invalid address";
+ }
+ return null;
+ }
+
+ void _updatePreviewButtonState(String? address, Decimal? amount) {
+ final isValidAddress = ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(walletId)
+ .validateAddress(address ?? "");
+ ref.read(previewTxButtonStateProvider.state).state =
+ (isValidAddress && amount != null && amount > Decimal.zero);
+ }
+
+ late Future _calculateFeesFuture;
+
+ Map cachedFees = {};
+ Map cachedFiroPrivateFees = {};
+ Map cachedFiroPublicFees = {};
+
+ Future calculateFees(int amount) async {
+ if (amount <= 0) {
+ return "0";
+ }
+
+ if (coin == Coin.firo || coin == Coin.firoTestNet) {
+ if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+ "Private") {
+ if (cachedFiroPrivateFees[amount] != null) {
+ return cachedFiroPrivateFees[amount]!;
+ }
+ } else {
+ if (cachedFiroPublicFees[amount] != null) {
+ return cachedFiroPublicFees[amount]!;
+ }
+ }
+ } else if (cachedFees[amount] != null) {
+ return cachedFees[amount]!;
+ }
+
+ final manager =
+ ref.read(walletsChangeNotifierProvider).getManager(walletId);
+ final feeObject = await manager.fees;
+
+ late final int feeRate;
+
+ switch (ref.read(feeRateTypeStateProvider.state).state) {
+ case FeeRateType.fast:
+ feeRate = feeObject.fast;
+ break;
+ case FeeRateType.average:
+ feeRate = feeObject.medium;
+ break;
+ case FeeRateType.slow:
+ feeRate = feeObject.slow;
+ break;
+ }
+
+ int fee;
+
+ if (coin == Coin.firo || coin == Coin.firoTestNet) {
+ if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+ "Private") {
+ fee = await manager.estimateFeeFor(amount, feeRate);
+
+ cachedFiroPrivateFees[amount] = Format.satoshisToAmount(fee)
+ .toStringAsFixed(Constants.decimalPlaces);
+
+ return cachedFiroPrivateFees[amount]!;
+ } else {
+ fee = await (manager.wallet as FiroWallet)
+ .estimateFeeForPublic(amount, feeRate);
+
+ cachedFiroPublicFees[amount] = Format.satoshisToAmount(fee)
+ .toStringAsFixed(Constants.decimalPlaces);
+
+ return cachedFiroPublicFees[amount]!;
+ }
+ } else {
+ fee = await manager.estimateFeeFor(amount, feeRate);
+ cachedFees[amount] =
+ Format.satoshisToAmount(fee).toStringAsFixed(Constants.decimalPlaces);
+
+ return cachedFees[amount]!;
+ }
+ }
+
+ Future _firoBalanceFuture(
+ ChangeNotifierProvider provider, String locale) async {
+ final wallet = ref.read(provider).wallet as FiroWallet?;
+
+ if (wallet != null) {
+ Decimal? balance;
+ if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+ "Private") {
+ balance = await wallet.availablePrivateBalance();
+ } else {
+ balance = await wallet.availablePublicBalance();
+ }
+
+ return Format.localizedStringAsFixed(
+ value: balance, locale: locale, decimalPlaces: 8);
+ }
+
+ return null;
+ }
+
+ @override
+ void initState() {
+ ref.refresh(feeSheetSessionCacheProvider);
+
+ _calculateFeesFuture = calculateFees(0);
+ _data = widget.autoFillData;
+ walletId = widget.walletId;
+ coin = ref.read(walletsChangeNotifierProvider).getManager(walletId).coin;
+ clipboard = widget.clipboard;
+ scanner = widget.barcodeScanner;
+
+ sendToController = TextEditingController();
+ cryptoAmountController = TextEditingController();
+ baseAmountController = TextEditingController();
+ noteController = TextEditingController();
+ feeController = TextEditingController();
+
+ onCryptoAmountChanged = _cryptoAmountChanged;
+ cryptoAmountController.addListener(onCryptoAmountChanged);
+
+ if (_data != null) {
+ if (_data!.amount != null) {
+ cryptoAmountController.text = _data!.amount!.toString();
+ }
+ sendToController.text = _data!.contactLabel;
+ _address = _data!.address;
+ _addressToggleFlag = true;
+ }
+
+ _cryptoFocus.addListener(() {
+ if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
+ if (_amountToSend == null) {
+ setState(() {
+ _calculateFeesFuture = calculateFees(0);
+ });
+ } else {
+ setState(() {
+ _calculateFeesFuture =
+ calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
+ });
+ }
+ }
+ });
+
+ _baseFocus.addListener(() {
+ if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
+ if (_amountToSend == null) {
+ setState(() {
+ _calculateFeesFuture = calculateFees(0);
+ });
+ } else {
+ setState(() {
+ _calculateFeesFuture =
+ calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
+ });
+ }
+ }
+ });
+
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ cryptoAmountController.removeListener(onCryptoAmountChanged);
+
+ sendToController.dispose();
+ cryptoAmountController.dispose();
+ baseAmountController.dispose();
+ noteController.dispose();
+ feeController.dispose();
+
+ _noteFocusNode.dispose();
+ _addressFocusNode.dispose();
+ _cryptoFocus.dispose();
+ _baseFocus.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ debugPrint("BUILD: $runtimeType");
+ final provider = ref.watch(walletsChangeNotifierProvider
+ .select((value) => value.getManagerProvider(walletId)));
+ final String locale = ref.watch(
+ localeServiceChangeNotifierProvider.select((value) => value.locale));
+
+ if (coin == Coin.firo || coin == Coin.firoTestNet) {
+ ref.listen(publicPrivateBalanceStateProvider, (previous, next) {
+ if (_amountToSend == null) {
+ setState(() {
+ _calculateFeesFuture = calculateFees(0);
+ });
+ } else {
+ setState(() {
+ _calculateFeesFuture =
+ calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
+ });
+ }
+ });
+ }
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(
+ height: 4,
+ ),
+ if (coin == Coin.firo)
+ Text(
+ "Send from",
+ style: STextStyles.smallMed12(context),
+ textAlign: TextAlign.left,
+ ),
+ if (coin == Coin.firo)
+ const SizedBox(
+ height: 10,
+ ),
+ if (coin == Coin.firo)
+ Stack(
+ children: [
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
+ readOnly: true,
+ textInputAction: TextInputAction.none,
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 12,
+ ),
+ child: RawMaterialButton(
+ splashColor:
+ Theme.of(context).extension()!.highlight,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ ),
+ onPressed: () {
+ showModalBottomSheet(
+ backgroundColor: Colors.transparent,
+ context: context,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(
+ top: Radius.circular(20),
+ ),
+ ),
+ builder: (_) => FiroBalanceSelectionSheet(
+ walletId: walletId,
+ ),
+ );
+ },
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Text(
+ "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
+ style: STextStyles.itemSubtitle12(context),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ FutureBuilder(
+ future: _firoBalanceFuture(provider, locale),
+ builder:
+ (context, AsyncSnapshot snapshot) {
+ if (snapshot.connectionState ==
+ ConnectionState.done &&
+ snapshot.hasData) {
+ if (ref
+ .read(publicPrivateBalanceStateProvider
+ .state)
+ .state ==
+ "Private") {
+ _privateBalanceString = snapshot.data!;
+ } else {
+ _publicBalanceString = snapshot.data!;
+ }
+ }
+ if (ref
+ .read(
+ publicPrivateBalanceStateProvider
+ .state)
+ .state ==
+ "Private" &&
+ _privateBalanceString != null) {
+ return Text(
+ "$_privateBalanceString ${coin.ticker}",
+ style: STextStyles.itemSubtitle(context),
+ );
+ } else if (ref
+ .read(
+ publicPrivateBalanceStateProvider
+ .state)
+ .state ==
+ "Public" &&
+ _publicBalanceString != null) {
+ return Text(
+ "$_publicBalanceString ${coin.ticker}",
+ style: STextStyles.itemSubtitle(context),
+ );
+ } else {
+ return AnimatedText(
+ stringsToLoopThrough: const [
+ "Loading balance",
+ "Loading balance.",
+ "Loading balance..",
+ "Loading balance...",
+ ],
+ style: STextStyles.itemSubtitle(context),
+ );
+ }
+ },
+ ),
+ ],
+ ),
+ SvgPicture.asset(
+ Assets.svg.chevronDown,
+ width: 8,
+ height: 4,
+ color: Theme.of(context)
+ .extension()!
+ .textSubtitle2,
+ ),
+ ],
+ ),
+ ),
+ )
+ ],
+ ),
+ if (coin == Coin.firo)
+ const SizedBox(
+ height: 20,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Amount",
+ style: STextStyles.smallMed12(context),
+ textAlign: TextAlign.left,
+ ),
+ BlueTextButton(
+ text: "Send all ${coin.ticker}",
+ onTap: () async {
+ if (coin == Coin.firo || coin == Coin.firoTestNet) {
+ final firoWallet = ref.read(provider).wallet as FiroWallet;
+ if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+ "Private") {
+ cryptoAmountController.text =
+ (await firoWallet.availablePrivateBalance())
+ .toStringAsFixed(Constants.decimalPlaces);
+ } else {
+ cryptoAmountController.text =
+ (await firoWallet.availablePublicBalance())
+ .toStringAsFixed(Constants.decimalPlaces);
+ }
+ } else {
+ cryptoAmountController.text =
+ (await ref.read(provider).availableBalance)
+ .toStringAsFixed(Constants.decimalPlaces);
+ }
+ },
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
+ style: STextStyles.smallMed14(context).copyWith(
+ color: Theme.of(context).extension()!.textDark,
+ ),
+ key: const Key("amountInputFieldCryptoTextFieldKey"),
+ controller: cryptoAmountController,
+ focusNode: _cryptoFocus,
+ keyboardType: const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
+ textAlign: TextAlign.right,
+ inputFormatters: [
+ // regex to validate a crypto amount with 8 decimal places
+ TextInputFormatter.withFunction((oldValue, newValue) =>
+ RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$')
+ .hasMatch(newValue.text)
+ ? newValue
+ : oldValue),
+ ],
+ decoration: InputDecoration(
+ contentPadding: const EdgeInsets.only(
+ top: 12,
+ right: 12,
+ ),
+ hintText: "0",
+ hintStyle: STextStyles.fieldLabel(context).copyWith(
+ fontSize: 14,
+ ),
+ prefixIcon: FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Padding(
+ padding: const EdgeInsets.all(12),
+ child: Text(
+ coin.ticker,
+ style: STextStyles.smallMed14(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark),
+ ),
+ ),
+ ),
+ ),
+ ),
+ if (Prefs.instance.externalCalls)
+ const SizedBox(
+ height: 10,
+ ),
+ if (Prefs.instance.externalCalls)
+ TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
+ style: STextStyles.smallMed14(context).copyWith(
+ color: Theme.of(context).extension()!.textDark,
+ ),
+ key: const Key("amountInputFieldFiatTextFieldKey"),
+ controller: baseAmountController,
+ focusNode: _baseFocus,
+ keyboardType: const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
+ textAlign: TextAlign.right,
+ inputFormatters: [
+ // regex to validate a fiat amount with 2 decimal places
+ TextInputFormatter.withFunction((oldValue, newValue) =>
+ RegExp(r'^([0-9]*[,.]?[0-9]{0,2}|[,.][0-9]{0,2})$')
+ .hasMatch(newValue.text)
+ ? newValue
+ : oldValue),
+ ],
+ onChanged: (baseAmountString) {
+ if (baseAmountString.isNotEmpty &&
+ baseAmountString != "." &&
+ baseAmountString != ",") {
+ final baseAmount = baseAmountString.contains(",")
+ ? Decimal.parse(baseAmountString.replaceFirst(",", "."))
+ : Decimal.parse(baseAmountString);
+
+ var _price = ref
+ .read(priceAnd24hChangeNotifierProvider)
+ .getPrice(coin)
+ .item1;
+
+ if (_price == Decimal.zero) {
+ _amountToSend = Decimal.zero;
+ } else {
+ _amountToSend = baseAmount <= Decimal.zero
+ ? Decimal.zero
+ : (baseAmount / _price).toDecimal(
+ scaleOnInfinitePrecision: Constants.decimalPlaces);
+ }
+ if (_cachedAmountToSend != null &&
+ _cachedAmountToSend == _amountToSend) {
+ return;
+ }
+ _cachedAmountToSend = _amountToSend;
+ Logging.instance.log(
+ "it changed $_amountToSend $_cachedAmountToSend",
+ level: LogLevel.Info);
+
+ final amountString = Format.localizedStringAsFixed(
+ value: _amountToSend!,
+ locale: ref.read(localeServiceChangeNotifierProvider).locale,
+ decimalPlaces: Constants.decimalPlaces,
+ );
+
+ _cryptoAmountChangeLock = true;
+ cryptoAmountController.text = amountString;
+ _cryptoAmountChangeLock = false;
+ } else {
+ _amountToSend = Decimal.zero;
+ _cryptoAmountChangeLock = true;
+ cryptoAmountController.text = "";
+ _cryptoAmountChangeLock = false;
+ }
+ // setState(() {
+ // _calculateFeesFuture = calculateFees(
+ // Format.decimalAmountToSatoshis(
+ // _amountToSend!));
+ // });
+ _updatePreviewButtonState(_address, _amountToSend);
+ },
+ decoration: InputDecoration(
+ contentPadding: const EdgeInsets.only(
+ top: 12,
+ right: 12,
+ ),
+ hintText: "0",
+ hintStyle: STextStyles.fieldLabel(context).copyWith(
+ fontSize: 14,
+ ),
+ prefixIcon: FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Padding(
+ padding: const EdgeInsets.all(12),
+ child: Text(
+ ref.watch(prefsChangeNotifierProvider
+ .select((value) => value.currency)),
+ style: STextStyles.smallMed14(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .accentColorDark),
+ ),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Text(
+ "Send to",
+ style: STextStyles.smallMed12(context),
+ textAlign: TextAlign.left,
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ ClipRRect(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ child: TextField(
+ key: const Key("sendViewAddressFieldKey"),
+ controller: sendToController,
+ readOnly: false,
+ autocorrect: false,
+ enableSuggestions: false,
+ // inputFormatters: [
+ // FilteringTextInputFormatter.allow(
+ // RegExp("[a-zA-Z0-9]{34}")),
+ // ],
+ toolbarOptions: const ToolbarOptions(
+ copy: false,
+ cut: false,
+ paste: true,
+ selectAll: false,
+ ),
+ onChanged: (newValue) {
+ _address = newValue;
+ _updatePreviewButtonState(_address, _amountToSend);
+
+ setState(() {
+ _addressToggleFlag = newValue.isNotEmpty;
+ });
+ },
+ focusNode: _addressFocusNode,
+ style: STextStyles.field(context),
+ decoration: standardInputDecoration(
+ "Enter ${coin.ticker} address",
+ _addressFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: sendToController.text.isEmpty
+ ? const EdgeInsets.only(right: 8)
+ : const EdgeInsets.only(right: 0),
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _addressToggleFlag
+ ? TextFieldIconButton(
+ key: const Key(
+ "sendViewClearAddressFieldButtonKey"),
+ onTap: () {
+ sendToController.text = "";
+ _address = "";
+ _updatePreviewButtonState(
+ _address, _amountToSend);
+ setState(() {
+ _addressToggleFlag = false;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "sendViewPasteAddressFieldButtonKey"),
+ onTap: () async {
+ final ClipboardData? data = await clipboard
+ .getData(Clipboard.kTextPlain);
+ if (data?.text != null &&
+ data!.text!.isNotEmpty) {
+ String content = data.text!.trim();
+ if (content.contains("\n")) {
+ content = content.substring(
+ 0, content.indexOf("\n"));
+ }
+
+ sendToController.text = content;
+ _address = content;
+
+ _updatePreviewButtonState(
+ _address, _amountToSend);
+ setState(() {
+ _addressToggleFlag =
+ sendToController.text.isNotEmpty;
+ });
+ }
+ },
+ child: sendToController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (sendToController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key("sendViewAddressBookButtonKey"),
+ onTap: () {
+ Navigator.of(context).pushNamed(
+ AddressBookView.routeName,
+ arguments: coin,
+ );
+ },
+ child: const AddressBookIcon(),
+ ),
+ if (sendToController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key("sendViewScanQrButtonKey"),
+ onTap: () async {
+ try {
+ if (FocusScope.of(context).hasFocus) {
+ FocusScope.of(context).unfocus();
+ await Future.delayed(
+ const Duration(milliseconds: 75));
+ }
+
+ final qrResult = await scanner.scan();
+
+ Logging.instance.log(
+ "qrResult content: ${qrResult.rawContent}",
+ level: LogLevel.Info);
+
+ final results =
+ AddressUtils.parseUri(qrResult.rawContent);
+
+ Logging.instance.log("qrResult parsed: $results",
+ level: LogLevel.Info);
+
+ if (results.isNotEmpty &&
+ results["scheme"] == coin.uriScheme) {
+ // auto fill address
+ _address = results["address"] ?? "";
+ sendToController.text = _address!;
+
+ // autofill notes field
+ if (results["message"] != null) {
+ noteController.text = results["message"]!;
+ } else if (results["label"] != null) {
+ noteController.text = results["label"]!;
+ }
+
+ // autofill amount field
+ if (results["amount"] != null) {
+ final amount =
+ Decimal.parse(results["amount"]!);
+ cryptoAmountController.text =
+ Format.localizedStringAsFixed(
+ value: amount,
+ locale: ref
+ .read(
+ localeServiceChangeNotifierProvider)
+ .locale,
+ decimalPlaces: Constants.decimalPlaces,
+ );
+ amount.toString();
+ _amountToSend = amount;
+ }
+
+ _updatePreviewButtonState(
+ _address, _amountToSend);
+ setState(() {
+ _addressToggleFlag =
+ sendToController.text.isNotEmpty;
+ });
+
+ // now check for non standard encoded basic address
+ } else if (ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(walletId)
+ .validateAddress(qrResult.rawContent)) {
+ _address = qrResult.rawContent;
+ sendToController.text = _address ?? "";
+
+ _updatePreviewButtonState(
+ _address, _amountToSend);
+ setState(() {
+ _addressToggleFlag =
+ sendToController.text.isNotEmpty;
+ });
+ }
+ } on PlatformException catch (e, s) {
+ // here we ignore the exception caused by not giving permission
+ // to use the camera to scan a qr code
+ Logging.instance.log(
+ "Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
+ level: LogLevel.Warning);
+ }
+ },
+ child: const QrCodeIcon(),
+ )
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ Builder(
+ builder: (_) {
+ final error = _updateInvalidAddressText(
+ _address ?? "",
+ ref.read(walletsChangeNotifierProvider).getManager(walletId),
+ );
+
+ if (error == null || error.isEmpty) {
+ return Container();
+ } else {
+ return Align(
+ alignment: Alignment.topLeft,
+ child: Padding(
+ padding: const EdgeInsets.only(
+ left: 12.0,
+ top: 4.0,
+ ),
+ child: Text(
+ error,
+ textAlign: TextAlign.left,
+ style: STextStyles.label(context).copyWith(
+ color:
+ Theme.of(context).extension()!.textError,
+ ),
+ ),
+ ),
+ );
+ }
+ },
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Text(
+ "Note (optional)",
+ style: STextStyles.smallMed12(context),
+ textAlign: TextAlign.left,
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ ClipRRect(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ child: TextField(
+ autocorrect: Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop ? false : true,
+ controller: noteController,
+ focusNode: _noteFocusNode,
+ style: STextStyles.field(context),
+ onChanged: (_) => setState(() {}),
+ decoration: standardInputDecoration(
+ "Type something...",
+ _noteFocusNode,
+ context,
+ ).copyWith(
+ suffixIcon: noteController.text.isNotEmpty
+ ? Padding(
+ padding: const EdgeInsets.only(right: 0),
+ child: UnconstrainedBox(
+ child: Row(
+ children: [
+ TextFieldIconButton(
+ child: const XIcon(),
+ onTap: () async {
+ setState(() {
+ noteController.text = "";
+ });
+ },
+ ),
+ ],
+ ),
+ ),
+ )
+ : null,
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 36,
+ ),
+ PrimaryButton(
+ height: 56,
+ label: "Preview send",
+ enabled: ref.watch(previewTxButtonStateProvider.state).state,
+ onPressed: ref.watch(previewTxButtonStateProvider.state).state
+ ? previewSend
+ : null,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/advanced_settings.dart b/lib/pages_desktop_specific/home/settings_menu/advanced_settings.dart
new file mode 100644
index 000000000..e470a73aa
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/advanced_settings.dart
@@ -0,0 +1,104 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class AdvancedSettings extends ConsumerStatefulWidget {
+ const AdvancedSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuAdvanced";
+
+ @override
+ ConsumerState createState() => _AdvancedSettings();
+}
+
+class _AdvancedSettings extends ConsumerState {
+ @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.circleLanguage,
+ width: 48,
+ height: 48,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Advanced",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nConfigurate these settings only if you know what you are doing!",
+ style: STextStyles.desktopTextExtraExtraSmall(
+ context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: ShowLogsButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class ShowLogsButton extends ConsumerWidget {
+ const ShowLogsButton({
+ 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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Show logs",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/appearance_settings.dart b/lib/pages_desktop_specific/home/settings_menu/appearance_settings.dart
new file mode 100644
index 000000000..d524453e2
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/appearance_settings.dart
@@ -0,0 +1,315 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+import '../../../providers/global/prefs_provider.dart';
+import '../../../utilities/constants.dart';
+import '../../../widgets/custom_buttons/draggable_switch_button.dart';
+
+class AppearanceOptionSettings extends ConsumerStatefulWidget {
+ const AppearanceOptionSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuAppearance";
+
+ @override
+ ConsumerState createState() =>
+ _AppearanceOptionSettings();
+}
+
+class _AppearanceOptionSettings
+ extends ConsumerState {
+ @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.circleSun,
+ width: 48,
+ height: 48,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.left,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Appearances",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nCustomize how your Stack Wallet looks according to your preferences.",
+ style: STextStyles.desktopTextExtraExtraSmall(
+ context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Padding(
+ padding: EdgeInsets.all(10.0),
+ child: Divider(
+ thickness: 0.5,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(10.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Display favorite wallets",
+ style: STextStyles.desktopTextExtraSmall(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark),
+ textAlign: TextAlign.left,
+ ),
+ SizedBox(
+ height: 20,
+ width: 40,
+ child: DraggableSwitchButton(
+ isOn: ref.watch(
+ prefsChangeNotifierProvider
+ .select((value) => value.showFavoriteWallets),
+ ),
+ onValueChanged: (newValue) {
+ ref
+ .read(prefsChangeNotifierProvider)
+ .showFavoriteWallets = newValue;
+ },
+ ),
+ )
+ ],
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.all(10.0),
+ child: Divider(
+ thickness: 0.5,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(10.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Choose theme",
+ style: STextStyles.desktopTextExtraSmall(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark),
+ textAlign: TextAlign.left,
+ ),
+ ],
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.only(
+ left: 10,
+ right: 10,
+ ),
+ child: ThemeToggle(),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class ThemeToggle extends StatefulWidget {
+ const ThemeToggle({
+ Key? key,
+ }) : super(key: key);
+
+ // final bool externalCallsEnabled;
+ // final void Function(bool)? onChanged;
+
+ @override
+ State createState() => _ThemeToggle();
+}
+
+class _ThemeToggle extends State {
+ // late bool externalCallsEnabled;
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ // mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: RawMaterialButton(
+ elevation: 0,
+ hoverColor: Colors.transparent,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius * 2,
+ ),
+ ),
+ onPressed: () {}, //onPressed
+ child: Stack(
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 24,
+ ),
+ child: SvgPicture.asset(
+ Assets.svg.themeLight,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 50,
+ top: 12,
+ ),
+ child: Text(
+ "Light",
+ style:
+ STextStyles.desktopTextExtraSmall(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark,
+ ),
+ ),
+ )
+ ],
+ ),
+ // if (externalCallsEnabled)
+ Positioned(
+ bottom: 0,
+ left: 6,
+ child: SvgPicture.asset(
+ Assets.svg.checkCircle,
+ width: 20,
+ height: 20,
+ color: Theme.of(context)
+ .extension()!
+ .infoItemIcons,
+ ),
+ ),
+ // if (!externalCallsEnabled)
+ // Positioned(
+ // top: 4,
+ // right: 4,
+ // child: Container(
+ // width: 20,
+ // height: 20,
+ // decoration: BoxDecoration(
+ // borderRadius: BorderRadius.circular(1000),
+ // color: Theme.of(context)
+ // .extension()!
+ // .textFieldDefaultBG,
+ // ),
+ // ),
+ // ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 1,
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: RawMaterialButton(
+ elevation: 0,
+ hoverColor: Colors.transparent,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius * 2,
+ ),
+ ),
+ onPressed: () {}, //onPressed
+ child: Stack(
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SvgPicture.asset(
+ Assets.svg.themeDark,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 50,
+ top: 12,
+ ),
+ child: Text(
+ "Dark",
+ style: STextStyles.desktopTextExtraSmall(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark,
+ ),
+ ),
+ ),
+ ],
+ ),
+ // if (externalCallsEnabled)
+ Positioned(
+ bottom: 0,
+ left: 0,
+ child: SvgPicture.asset(
+ Assets.svg.checkCircle,
+ width: 20,
+ height: 20,
+ color: Theme.of(context)
+ .extension()!
+ .infoItemIcons,
+ ),
+ ),
+ // if (!externalCallsEnabled)
+ // Positioned(
+ // top: 4,
+ // right: 4,
+ // child: Container(
+ // width: 20,
+ // height: 20,
+ // decoration: BoxDecoration(
+ // borderRadius: BorderRadius.circular(1000),
+ // color: Theme.of(context)
+ // .extension()!
+ // .textFieldDefaultBG,
+ // ),
+ // ),
+ // ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/backup_and_restore.dart b/lib/pages_desktop_specific/home/settings_menu/backup_and_restore.dart
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/pages_desktop_specific/home/settings_menu/backup_and_restore_settings.dart b/lib/pages_desktop_specific/home/settings_menu/backup_and_restore_settings.dart
new file mode 100644
index 000000000..04c23ee83
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/backup_and_restore_settings.dart
@@ -0,0 +1,282 @@
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class BackupRestoreSettings extends ConsumerStatefulWidget {
+ const BackupRestoreSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuBackupRestore";
+
+ @override
+ ConsumerState createState() =>
+ _BackupRestoreSettings();
+}
+
+class _BackupRestoreSettings extends ConsumerState {
+ @override
+ Widget build(BuildContext context) {
+ debugPrint("BUILD: $runtimeType");
+ return ListView(
+ shrinkWrap: true,
+ scrollDirection: Axis.vertical,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(
+ right: 30,
+ ),
+ child: RoundedWhiteContainer(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SvgPicture.asset(
+ Assets.svg.backupAuto,
+ width: 48,
+ height: 48,
+ ),
+ Center(
+ child: Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Auto Backup",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nAuto backup is a custom Stack Wallet feature that offers a convenient backup of your data."
+ "To ensure maximum security, we recommend using a unique password that you haven't used anywhere "
+ "else on the internet before. Your password is not stored.",
+ style:
+ STextStyles.desktopTextExtraExtraSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nFor more information, please see our website ",
+ style:
+ STextStyles.desktopTextExtraExtraSmall(context),
+ ),
+ TextSpan(
+ text: "stackwallet.com",
+ style: STextStyles.richLink(context)
+ .copyWith(fontSize: 14),
+ recognizer: TapGestureRecognizer()
+ ..onTap = () {
+ launchUrl(
+ Uri.parse("https://stackwallet.com/"),
+ mode: LaunchMode.externalApplication,
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: AutoBackupButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 25,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ right: 30,
+ ),
+ child: RoundedWhiteContainer(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SvgPicture.asset(
+ Assets.svg.backupAdd,
+ width: 48,
+ height: 48,
+ alignment: Alignment.topLeft,
+ ),
+ Center(
+ child: Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Manual Backup",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nCreate manual backup to easily transfer your data between devices. "
+ "You will create a backup file that can be later used in the Restore option. "
+ "Use a strong password to encrypt your data.",
+ style:
+ STextStyles.desktopTextExtraExtraSmall(context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: ManualBackupButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 25,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ right: 30,
+ ),
+ child: RoundedWhiteContainer(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SvgPicture.asset(
+ Assets.svg.backupRestore,
+ width: 48,
+ height: 48,
+ alignment: Alignment.topLeft,
+ ),
+ Center(
+ child: Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Restore Backup",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nUse your Stack Wallet backup file to restore your wallets, address book "
+ "and wallet preferences.",
+ style:
+ STextStyles.desktopTextExtraExtraSmall(context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: ManualBackupButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class AutoBackupButton extends ConsumerWidget {
+ const AutoBackupButton({
+ 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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Enable auto backup",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
+
+class ManualBackupButton extends ConsumerWidget {
+ const ManualBackupButton({
+ 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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Create manual backup",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
+
+class RestoreBackupButton extends ConsumerWidget {
+ const RestoreBackupButton({
+ 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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Restore backup",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/currency_settings.dart b/lib/pages_desktop_specific/home/settings_menu/currency_settings.dart
new file mode 100644
index 000000000..4327b320b
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/currency_settings.dart
@@ -0,0 +1,102 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class CurrencySettings extends ConsumerStatefulWidget {
+ const CurrencySettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuCurrency";
+
+ @override
+ ConsumerState createState() => _CurrencySettings();
+}
+
+class _CurrencySettings extends ConsumerState {
+ @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);
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return SizedBox(
+ width: 200,
+ height: 48,
+ child: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Set up new password",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/enable_backup_dialog.dart b/lib/pages_desktop_specific/home/settings_menu/enable_backup_dialog.dart
new file mode 100644
index 000000000..4925177c3
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/enable_backup_dialog.dart
@@ -0,0 +1,73 @@
+import 'package:flutter/material.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_close_button.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+
+class EnableBackupDialog extends StatelessWidget {
+ const EnableBackupDialog({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return DesktopDialog(
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(32),
+ child: Text(
+ "Enable Auto Backup",
+ style: STextStyles.desktopH3(context),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ const SizedBox(
+ height: 30,
+ ),
+ Text(
+ "To enable Auto Backup, you need to create a backup file.",
+ style: STextStyles.desktopTextSmall(context).copyWith(
+ color: Theme.of(context).extension()!.textDark3,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const Spacer(),
+ Padding(
+ padding: const EdgeInsets.all(32),
+ child: Row(
+ children: [
+ Expanded(
+ child: SecondaryButton(
+ label: "Cancel",
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ ),
+ const SizedBox(
+ width: 16,
+ ),
+ Expanded(
+ child: PrimaryButton(
+ label: "Continue",
+ onPressed: () {
+ // Navigator.of(context).pop();
+ // onConfirm.call();
+ },
+ ),
+ )
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/language_settings.dart b/lib/pages_desktop_specific/home/settings_menu/language_settings.dart
new file mode 100644
index 000000000..7655188e1
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/language_settings.dart
@@ -0,0 +1,105 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class LanguageOptionSettings extends ConsumerStatefulWidget {
+ const LanguageOptionSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuLanguage";
+
+ @override
+ ConsumerState createState() =>
+ _LanguageOptionSettings();
+}
+
+class _LanguageOptionSettings extends ConsumerState {
+ @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.circleLanguage,
+ width: 48,
+ height: 48,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Language",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\n\nSelect the language of your wallet. We use your system language by default.",
+ style: STextStyles.desktopTextExtraExtraSmall(
+ context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: ChangeLanguageButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class ChangeLanguageButton extends ConsumerWidget {
+ const ChangeLanguageButton({
+ 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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Change language",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/nodes_settings.dart b/lib/pages_desktop_specific/home/settings_menu/nodes_settings.dart
new file mode 100644
index 000000000..f354927c4
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/nodes_settings.dart
@@ -0,0 +1,180 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/providers/global/node_service_provider.dart';
+import 'package:stackwallet/providers/global/prefs_provider.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+import '../../../pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart';
+import '../../../utilities/constants.dart';
+
+class NodesSettings extends ConsumerStatefulWidget {
+ const NodesSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuNodes";
+
+ @override
+ ConsumerState createState() => _NodesSettings();
+}
+
+class _NodesSettings extends ConsumerState {
+ List _coins = [...Coin.values];
+
+ @override
+ void initState() {
+ _coins = _coins.toList();
+ _coins.remove(Coin.firoTestNet);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ bool showTestNet = ref.watch(
+ prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
+ );
+
+ List coins = showTestNet
+ ? _coins
+ : _coins.sublist(0, _coins.length - kTestNetCoinCount);
+
+ 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.circleNode,
+ width: 48,
+ height: 48,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Nodes",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text: "\n\nSelect a coin to see nodes",
+ style: STextStyles.desktopTextExtraExtraSmall(
+ context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ //TODO: add search bar
+ SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ ...coins.map(
+ (coin) {
+ final count = ref
+ .watch(nodeServiceChangeNotifierProvider
+ .select((value) => value.getNodesFor(coin)))
+ .length;
+
+ return Padding(
+ padding: const EdgeInsets.all(0),
+ child: RawMaterialButton(
+ // splashColor: Theme.of(context).extension()!.highlight,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ Constants.size.circularBorderRadius,
+ ),
+ // side: BorderSide(
+ // color: Theme.of(context)
+ // .extension()!
+ // .shadow),
+ ),
+ materialTapTargetSize:
+ MaterialTapTargetSize.shrinkWrap,
+ onPressed: () {
+ Navigator.of(context).pushNamed(
+ CoinNodesView.routeName,
+ arguments: coin,
+ );
+ },
+ child: Padding(
+ padding: const EdgeInsets.all(
+ 12.0,
+ ),
+ child: Row(
+ children: [
+ Row(
+ children: [
+ SvgPicture.asset(
+ Assets.svg.iconFor(coin: coin),
+ width: 24,
+ height: 24,
+ ),
+ const SizedBox(
+ width: 12,
+ ),
+ Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ Text(
+ "${coin.prettyName} nodes",
+ style: STextStyles.titleBold12(
+ context),
+ ),
+ Text(
+ count > 1
+ ? "$count nodes"
+ : "Default",
+ style: STextStyles.label(context),
+ ),
+ ],
+ ),
+ ],
+ ),
+ Expanded(
+ child: SvgPicture.asset(
+ Assets.svg.chevronRight,
+ alignment: Alignment.centerRight,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/security_settings.dart b/lib/pages_desktop_specific/home/settings_menu/security_settings.dart
new file mode 100644
index 000000000..7c36be8cd
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/security_settings.dart
@@ -0,0 +1,141 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+import '../../../utilities/theme/stack_colors.dart';
+import 'enable_backup_dialog.dart';
+
+class SecuritySettings extends ConsumerStatefulWidget {
+ const SecuritySettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuSecurity";
+
+ @override
+ ConsumerState createState() => _SecuritySettings();
+}
+
+class _SecuritySettings extends ConsumerState {
+ Future enableAutoBackup() async {
+ // wait for keyboard to disappear
+ FocusScope.of(context).unfocus();
+ await Future.delayed(
+ const Duration(milliseconds: 100),
+ );
+
+ await showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return EnableBackupDialog();
+ },
+ );
+ }
+
+ @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.circleLock,
+ width: 48,
+ height: 48,
+ ),
+ Center(
+ child: Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Change Password",
+ 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);
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ Future enableAutoBackup() async {
+ // wait for keyboard to disappear
+ FocusScope.of(context).unfocus();
+ await Future.delayed(
+ const Duration(milliseconds: 100),
+ );
+
+ await showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return EnableBackupDialog();
+ },
+ );
+ }
+
+ return SizedBox(
+ width: 200,
+ height: 48,
+ child: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {
+ enableAutoBackup();
+ },
+ child: Text(
+ "Set up new password",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages_desktop_specific/home/settings_menu/settings_menu.dart b/lib/pages_desktop_specific/home/settings_menu/settings_menu.dart
index de800b51f..b743fdb39 100644
--- a/lib/pages_desktop_specific/home/settings_menu/settings_menu.dart
+++ b/lib/pages_desktop_specific/home/settings_menu/settings_menu.dart
@@ -3,7 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu_item.dart';
import 'package:stackwallet/utilities/assets.dart';
-import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class SettingsMenu extends ConsumerStatefulWidget {
@@ -35,155 +34,167 @@ class _SettingsMenuState extends ConsumerState {
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
- return Material(
- color: Theme.of(context).extension()!.background,
- child: SizedBox(
- width: 300,
- child: Padding(
- padding: const EdgeInsets.fromLTRB(24.0, 10.0, 0, 0),
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SizedBox(
- height: 20,
- // width: 300,
- ),
- Text(
- "Settings",
- style: STextStyles.desktopH3(context).copyWith(
- fontSize: 24,
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 0
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
),
+ label: "Backup and restore",
+ value: 0,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
),
- Row(
- children: [
- Padding(
- padding: const EdgeInsets.fromLTRB(
- 3.0,
- 30.0,
- 55.0,
- 0,
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Backup and restore",
- value: 0,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Security",
- value: 1,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Currency",
- value: 2,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Language",
- value: 3,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Nodes",
- value: 4,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Syncing preferences",
- value: 5,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Appearance",
- value: 6,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- const SizedBox(
- height: 2,
- ),
- SettingsMenuItem(
- icon: SvgPicture.asset(
- Assets.svg.polygon,
- width: 11,
- height: 11,
- ),
- label: "Advanced",
- value: 7,
- group: selectedMenuItem,
- onChanged: updateSelectedMenuItem,
- ),
- ],
- ),
- ),
- ],
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 1
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Security",
+ value: 1,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 2
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Currency",
+ value: 2,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 3
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Language",
+ value: 3,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 4
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Nodes",
+ value: 4,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 5
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Syncing preferences",
+ value: 5,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 6
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Appearance",
+ value: 6,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ SettingsMenuItem(
+ icon: SvgPicture.asset(
+ Assets.svg.polygon,
+ width: 11,
+ height: 11,
+ color: selectedMenuItem == 7
+ ? Theme.of(context)
+ .extension()!
+ .accentColorBlue
+ : Colors.transparent,
+ ),
+ label: "Advanced",
+ value: 7,
+ group: selectedMenuItem,
+ onChanged: updateSelectedMenuItem,
),
],
),
),
- ),
+ ],
);
}
}
diff --git a/lib/pages_desktop_specific/home/settings_menu/syncing_preferences_settings.dart b/lib/pages_desktop_specific/home/settings_menu/syncing_preferences_settings.dart
new file mode 100644
index 000000000..9b6c6c85c
--- /dev/null
+++ b/lib/pages_desktop_specific/home/settings_menu/syncing_preferences_settings.dart
@@ -0,0 +1,106 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class SyncingPreferencesSettings extends ConsumerStatefulWidget {
+ const SyncingPreferencesSettings({Key? key}) : super(key: key);
+
+ static const String routeName = "/settingsMenuSyncingPref";
+
+ @override
+ ConsumerState createState() =>
+ _SyncingPreferencesSettings();
+}
+
+class _SyncingPreferencesSettings
+ extends ConsumerState {
+ @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.circleArrowRotate,
+ width: 48,
+ height: 48,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(10),
+ child: RichText(
+ textAlign: TextAlign.start,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: "Syncing Preferences",
+ style: STextStyles.desktopTextSmall(context),
+ ),
+ TextSpan(
+ text:
+ "\nSet up your syncing preferences for all wallets in your Stack.",
+ style: STextStyles.desktopTextExtraExtraSmall(
+ context),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Padding(
+ padding: EdgeInsets.all(
+ 10,
+ ),
+ child: ChangePrefButton(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+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()!
+ .getPrimaryEnabledButtonColor(context),
+ onPressed: () {},
+ child: Text(
+ "Change preferences",
+ style: STextStyles.button(context),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index d318b85a6..f915e7837 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -86,7 +86,16 @@ import 'package:stackwallet/pages_desktop_specific/create_password/create_passwo
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_settings_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart';
+import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
+import 'package:stackwallet/pages_desktop_specific/home/settings_menu/syncing_preferences_settings.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
@@ -957,11 +966,11 @@ class RouteGenerator {
builder: (_) => const DesktopHomeView(),
settings: RouteSettings(name: settings.name));
- // case DesktopSettingsView.routeName:
- // return getRoute(
- // shouldUseMaterialRoute: useMaterialPageRoute,
- // builder: (_) => const DesktopSettingsView(),
- // settings: RouteSettings(name: settings.name));
+ case DesktopSettingsView.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const DesktopSettingsView(),
+ settings: RouteSettings(name: settings.name));
case MyStackView.routeName:
return getRoute(
@@ -969,6 +978,20 @@ class RouteGenerator {
builder: (_) => const MyStackView(),
settings: RouteSettings(name: settings.name));
+ case DesktopWalletView.routeName:
+ if (args is String) {
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => DesktopWalletView(
+ walletId: args,
+ ),
+ settings: RouteSettings(
+ name: settings.name,
+ ),
+ );
+ }
+ return _routeError("${settings.name} invalid args: ${args.toString()}");
+
case SettingsMenu.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
@@ -977,6 +1000,54 @@ class RouteGenerator {
),
settings: RouteSettings(name: settings.name));
+ case BackupRestoreSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const BackupRestoreSettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case SecuritySettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const SecuritySettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case CurrencySettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const CurrencySettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case LanguageOptionSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const LanguageOptionSettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case NodesSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const NodesSettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case SyncingPreferencesSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const SyncingPreferencesSettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case AppearanceOptionSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const AppearanceOptionSettings(),
+ settings: RouteSettings(name: settings.name));
+
+ case AdvancedSettings.routeName:
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => const AdvancedSettings(),
+ settings: RouteSettings(name: settings.name));
+
// == End of desktop specific routes =====================================
default:
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
index 1410d6442..ebe2d9848 100644
--- a/lib/utilities/assets.dart
+++ b/lib/utilities/assets.dart
@@ -59,6 +59,15 @@ class _SVG {
String txExchangeFailed(BuildContext context) =>
"assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-exchange-icon-failed.svg";
+ String get themeLight => "assets/svg/light/light-mode.svg";
+ String get themeDark => "assets/svg/dark/dark-theme.svg";
+ String get circleNode => "assets/svg/node-circle.svg";
+ String get circleSun => "assets/svg/sun-circle.svg";
+ String get circleArrowRotate => "assets/svg/rotate-circle.svg";
+ String get circleLanguage => "assets/svg/language-circle.svg";
+ String get circleDollarSign => "assets/svg/dollar-sign-circle.svg";
+ String get circleLock => "assets/svg/lock-circle.svg";
+ String get disableButton => "assets/svg/Button.svg";
String get polygon => "assets/svg/Polygon.svg";
String get personaIncognito => "assets/svg/persona-incognito-1.svg";
String get personaEasy => "assets/svg/persona-easy-1.svg";
@@ -130,6 +139,11 @@ class _SVG {
String get anonymize => "assets/svg/tx-icon-anonymize.svg";
String get anonymizePending => "assets/svg/tx-icon-anonymize-pending.svg";
String get anonymizeFailed => "assets/svg/tx-icon-anonymize-failed.svg";
+ String get addressBookDesktop => "assets/svg/address-book-desktop.svg";
+ String get exchangeDesktop => "assets/svg/exchange-desktop.svg";
+ String get aboutDesktop => "assets/svg/about-desktop.svg";
+ String get walletDesktop => "assets/svg/wallet-desktop.svg";
+ String get exitDesktop => "assets/svg/exit-desktop.svg";
String get ellipse1 => "assets/svg/Ellipse-43.svg";
String get ellipse2 => "assets/svg/Ellipse-42.svg";
diff --git a/lib/utilities/text_styles.dart b/lib/utilities/text_styles.dart
index c3a6929fe..82e2ad349 100644
--- a/lib/utilities/text_styles.dart
+++ b/lib/utilities/text_styles.dart
@@ -679,6 +679,25 @@ class STextStyles {
}
}
+ static TextStyle desktopTextSmall(BuildContext context) {
+ switch (_theme(context).themeType) {
+ case ThemeType.light:
+ return GoogleFonts.inter(
+ color: _theme(context).textDark,
+ fontWeight: FontWeight.w500,
+ fontSize: 18,
+ height: 27 / 18,
+ );
+ case ThemeType.dark:
+ return GoogleFonts.inter(
+ color: _theme(context).buttonTextPrimaryDisabled,
+ fontWeight: FontWeight.w500,
+ fontSize: 18,
+ height: 27 / 18,
+ );
+ }
+ }
+
static TextStyle desktopTextExtraSmall(BuildContext context) {
switch (_theme(context).themeType) {
case ThemeType.light:
diff --git a/lib/utilities/theme/stack_colors.dart b/lib/utilities/theme/stack_colors.dart
index 0481268b5..67f1601f1 100644
--- a/lib/utilities/theme/stack_colors.dart
+++ b/lib/utilities/theme/stack_colors.dart
@@ -1519,5 +1519,8 @@ class StackColors extends ThemeExtension {
backgroundColor: MaterialStateProperty.all(
background,
),
+ overlayColor: MaterialStateProperty.all(
+ Colors.transparent,
+ ),
);
}
diff --git a/lib/utilities/util.dart b/lib/utilities/util.dart
index 8a98787f2..5963bfee9 100644
--- a/lib/utilities/util.dart
+++ b/lib/utilities/util.dart
@@ -1,9 +1,14 @@
import 'dart:io';
import 'package:flutter/material.dart';
+import 'package:path_provider/path_provider.dart';
abstract class Util {
+ static Directory? libraryPath;
static bool get isDesktop {
+ if(Platform.isIOS && libraryPath != null && !libraryPath!.path.contains("/var/mobile/")){
+ return true;
+ }
return Platform.isLinux || Platform.isMacOS || Platform.isWindows;
}
diff --git a/lib/widgets/wallet_info_row/wallet_info_row.dart b/lib/widgets/wallet_info_row/wallet_info_row.dart
index 4840e9b01..d5e42e814 100644
--- a/lib/widgets/wallet_info_row/wallet_info_row.dart
+++ b/lib/widgets/wallet_info_row/wallet_info_row.dart
@@ -25,9 +25,13 @@ class WalletInfoRow extends ConsumerWidget {
.watch(walletsChangeNotifierProvider.notifier)
.getManagerProvider(walletId));
- return Row(
- children: Util.isDesktop
- ? [
+ if (Util.isDesktop) {
+ return GestureDetector(
+ onTap: onPressed,
+ child: Container(
+ color: Colors.transparent,
+ child: Row(
+ children: [
Expanded(
flex: 4,
child: Row(
@@ -38,11 +42,9 @@ class WalletInfoRow extends ConsumerWidget {
),
Text(
manager.walletName,
- style:
- STextStyles.desktopTextExtraSmall(context).copyWith(
- color: Theme.of(context)
- .extension()!
- .textDark,
+ style: STextStyles.desktopTextExtraSmall(context).copyWith(
+ color:
+ Theme.of(context).extension()!.textDark,
),
),
],
@@ -70,29 +72,35 @@ class WalletInfoRow extends ConsumerWidget {
],
),
)
- ]
- : [
- WalletInfoCoinIcon(coin: manager.coin),
- const SizedBox(
- width: 12,
- ),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- manager.walletName,
- style: STextStyles.titleBold12(context),
- ),
- const SizedBox(
- height: 2,
- ),
- WalletInfoRowBalanceFuture(walletId: walletId),
- ],
- ),
- ),
],
- );
+ ),
+ ),
+ );
+ } else {
+ return Row(
+ children: [
+ WalletInfoCoinIcon(coin: manager.coin),
+ const SizedBox(
+ width: 12,
+ ),
+ Expanded(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ manager.walletName,
+ style: STextStyles.titleBold12(context),
+ ),
+ const SizedBox(
+ height: 2,
+ ),
+ WalletInfoRowBalanceFuture(walletId: walletId),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
}
}
diff --git a/pubspec.lock b/pubspec.lock
index 2a680284c..394d1ec8e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -42,7 +42,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
- version: "3.3.0"
+ version: "3.1.11"
args:
dependency: transitive
description:
@@ -63,7 +63,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.9.0"
+ version: "2.8.2"
barcode_scan2:
dependency: "direct main"
description:
@@ -190,7 +190,14 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.1"
+ version: "1.2.0"
+ charcode:
+ dependency: transitive
+ description:
+ name: charcode
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.1"
checked_yaml:
dependency: transitive
description:
@@ -204,7 +211,7 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.1"
+ version: "1.1.0"
code_builder:
dependency: transitive
description:
@@ -274,7 +281,7 @@ packages:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
- version: "1.5.0"
+ version: "1.2.0"
cross_file:
dependency: transitive
description:
@@ -428,7 +435,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.1"
+ version: "1.3.0"
ffi:
dependency: "direct main"
description:
@@ -543,7 +550,7 @@ packages:
name: flutter_native_splash
url: "https://pub.dartlang.org"
source: hosted
- version: "2.2.11"
+ version: "2.2.9"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@@ -816,6 +823,13 @@ packages:
relative: true
source: path
version: "0.0.1"
+ lint:
+ dependency: transitive
+ description:
+ name: lint
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.10.0"
lints:
dependency: transitive
description:
@@ -843,28 +857,28 @@ packages:
name: lottie
url: "https://pub.dartlang.org"
source: hosted
- version: "1.4.3"
+ version: "1.4.2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.12"
+ version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
- version: "0.1.5"
+ version: "0.1.4"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.0"
+ version: "1.7.0"
mime:
dependency: transitive
description:
@@ -976,7 +990,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.2"
+ version: "1.8.1"
path_drawing:
dependency: transitive
description:
@@ -1352,7 +1366,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.9.0"
+ version: "1.8.2"
stack_trace:
dependency: transitive
description:
@@ -1410,42 +1424,42 @@ packages:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
- version: "0.3.1"
+ version: "0.3.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.1"
+ version: "1.2.0"
test:
dependency: transitive
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
- version: "1.21.4"
+ version: "1.21.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.12"
+ version: "0.4.9"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.16"
+ version: "0.4.13"
time:
dependency: transitive
description:
name: time
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.3"
+ version: "2.1.2"
timezone:
dependency: transitive
description:
@@ -1487,7 +1501,7 @@ packages:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.1"
+ version: "1.3.0"
universal_io:
dependency: transitive
description:
@@ -1571,7 +1585,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
- version: "9.0.0"
+ version: "8.2.2"
wakelock:
dependency: "direct main"
description:
@@ -1687,5 +1701,5 @@ packages:
source: hosted
version: "1.0.0"
sdks:
- dart: ">=2.18.0 <3.0.0"
- flutter: ">=3.3.0"
+ dart: ">=2.17.5 <3.0.0"
+ flutter: ">=3.0.1"
diff --git a/pubspec.yaml b/pubspec.yaml
index 3858c5a70..42934fd5c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -294,6 +294,20 @@ flutter:
- assets/svg/Polygon.svg
- assets/svg/persona-easy-1.svg
- assets/svg/persona-incognito-1.svg
+ - assets/svg/Button.svg
+ - assets/svg/lock-circle.svg
+ - assets/svg/dollar-sign-circle.svg
+ - assets/svg/language-circle.svg
+ - assets/svg/rotate-circle.svg
+ - assets/svg/sun-circle.svg
+ - assets/svg/node-circle.svg
+ - assets/svg/dark/dark-theme.svg
+ - assets/svg/light/light-mode.svg
+ - assets/svg/address-book-desktop.svg
+ - assets/svg/about-desktop.svg
+ - assets/svg/exchange-desktop.svg
+ - assets/svg/wallet-desktop.svg
+ - assets/svg/exit-desktop.svg
# coin icons
- assets/svg/coin_icons/Bitcoin.svg
- assets/svg/coin_icons/Bitcoincash.svg