Merge pull request #257 from cypherstack/desktop

Desktop
This commit is contained in:
Diego Salazar 2022-12-05 20:26:33 -07:00 committed by GitHub
commit d321151e2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
114 changed files with 3441 additions and 2491 deletions

View file

@ -40,8 +40,6 @@ class DB {
String boxNameUsedSerialsCache({required Coin coin}) =>
"${coin.name}_usedSerialsCache";
static bool _initialized = false;
Box<dynamic>? _boxAddressBook;
Box<String>? _boxDebugInfo;
Box<NodeModel>? _boxNodeModels;
@ -88,69 +86,65 @@ class DB {
// open hive boxes
Future<void> init() async {
if (!_initialized) {
if (Hive.isBoxOpen(boxNameDBInfo)) {
_boxDBInfo = Hive.box<dynamic>(boxNameDBInfo);
} else {
_boxDBInfo = await Hive.openBox<dynamic>(boxNameDBInfo);
}
await Hive.openBox<String>(boxNameWalletsToDeleteOnStart);
if (Hive.isBoxOpen(boxNamePrefs)) {
_boxPrefs = Hive.box<dynamic>(boxNamePrefs);
} else {
_boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
}
_boxAddressBook = await Hive.openBox<dynamic>(boxNameAddressBook);
_boxDebugInfo = await Hive.openBox<String>(boxNameDebugInfo);
if (Hive.isBoxOpen(boxNameNodeModels)) {
_boxNodeModels = Hive.box<NodeModel>(boxNameNodeModels);
} else {
_boxNodeModels = await Hive.openBox<NodeModel>(boxNameNodeModels);
}
if (Hive.isBoxOpen(boxNamePrimaryNodes)) {
_boxPrimaryNodes = Hive.box<NodeModel>(boxNamePrimaryNodes);
} else {
_boxPrimaryNodes = await Hive.openBox<NodeModel>(boxNamePrimaryNodes);
}
if (Hive.isBoxOpen(boxNameAllWalletsData)) {
_boxAllWalletsData = Hive.box<dynamic>(boxNameAllWalletsData);
} else {
_boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
}
if (Hive.isBoxOpen(boxNameDesktopData)) {
_boxDesktopData = Hive.box<String>(boxNameDesktopData);
} else {
_boxDesktopData = await Hive.openBox<String>(boxNameDesktopData);
}
_boxNotifications =
await Hive.openBox<NotificationModel>(boxNameNotifications);
_boxWatchedTransactions =
await Hive.openBox<NotificationModel>(boxNameWatchedTransactions);
_boxWatchedTrades =
await Hive.openBox<NotificationModel>(boxNameWatchedTrades);
_boxTrades = await Hive.openBox<ExchangeTransaction>(boxNameTrades);
_boxTradesV2 = await Hive.openBox<Trade>(boxNameTradesV2);
_boxTradeNotes = await Hive.openBox<String>(boxNameTradeNotes);
_boxTradeLookup =
await Hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
_walletInfoSource =
await Hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
_boxFavoriteWallets = await Hive.openBox<String>(boxNameFavoriteWallets);
await Future.wait([
Hive.openBox<dynamic>(boxNamePriceCache),
_loadWalletBoxes(),
_loadSharedCoinCacheBoxes(),
]);
_initialized = true;
if (Hive.isBoxOpen(boxNameDBInfo)) {
_boxDBInfo = Hive.box<dynamic>(boxNameDBInfo);
} else {
_boxDBInfo = await Hive.openBox<dynamic>(boxNameDBInfo);
}
await Hive.openBox<String>(boxNameWalletsToDeleteOnStart);
if (Hive.isBoxOpen(boxNamePrefs)) {
_boxPrefs = Hive.box<dynamic>(boxNamePrefs);
} else {
_boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
}
_boxAddressBook = await Hive.openBox<dynamic>(boxNameAddressBook);
_boxDebugInfo = await Hive.openBox<String>(boxNameDebugInfo);
if (Hive.isBoxOpen(boxNameNodeModels)) {
_boxNodeModels = Hive.box<NodeModel>(boxNameNodeModels);
} else {
_boxNodeModels = await Hive.openBox<NodeModel>(boxNameNodeModels);
}
if (Hive.isBoxOpen(boxNamePrimaryNodes)) {
_boxPrimaryNodes = Hive.box<NodeModel>(boxNamePrimaryNodes);
} else {
_boxPrimaryNodes = await Hive.openBox<NodeModel>(boxNamePrimaryNodes);
}
if (Hive.isBoxOpen(boxNameAllWalletsData)) {
_boxAllWalletsData = Hive.box<dynamic>(boxNameAllWalletsData);
} else {
_boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
}
if (Hive.isBoxOpen(boxNameDesktopData)) {
_boxDesktopData = Hive.box<String>(boxNameDesktopData);
} else {
_boxDesktopData = await Hive.openBox<String>(boxNameDesktopData);
}
_boxNotifications =
await Hive.openBox<NotificationModel>(boxNameNotifications);
_boxWatchedTransactions =
await Hive.openBox<NotificationModel>(boxNameWatchedTransactions);
_boxWatchedTrades =
await Hive.openBox<NotificationModel>(boxNameWatchedTrades);
_boxTrades = await Hive.openBox<ExchangeTransaction>(boxNameTrades);
_boxTradesV2 = await Hive.openBox<Trade>(boxNameTradesV2);
_boxTradeNotes = await Hive.openBox<String>(boxNameTradeNotes);
_boxTradeLookup = await Hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
_walletInfoSource =
await Hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
_boxFavoriteWallets = await Hive.openBox<String>(boxNameFavoriteWallets);
await Future.wait([
Hive.openBox<dynamic>(boxNamePriceCache),
_loadWalletBoxes(),
_loadSharedCoinCacheBoxes(),
]);
}
Future<void> _loadWalletBoxes() async {

View file

@ -32,7 +32,7 @@ import 'package:stackwallet/pages/loading_view.dart';
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_login_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/desktop_login_view.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
import 'package:stackwallet/providers/global/base_currencies_provider.dart';

View file

@ -1,8 +1,9 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/foundation.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
class IncompleteExchangeModel {
class IncompleteExchangeModel extends ChangeNotifier {
final String sendTicker;
final String receiveTicker;
@ -15,12 +16,49 @@ class IncompleteExchangeModel {
final bool reversed;
String? recipientAddress;
String? refundAddress;
String? _recipientAddress;
String? rateId;
String? get recipientAddress => _recipientAddress;
Trade? trade;
set recipientAddress(String? recipientAddress) {
if (_recipientAddress != recipientAddress) {
_recipientAddress = recipientAddress;
notifyListeners();
}
}
String? _refundAddress;
String? get refundAddress => _refundAddress;
set refundAddress(String? refundAddress) {
if (_refundAddress != refundAddress) {
_refundAddress = refundAddress;
notifyListeners();
}
}
String? _rateId;
String? get rateId => _rateId;
set rateId(String? rateId) {
if (_rateId != rateId) {
_rateId = rateId;
notifyListeners();
}
}
Trade? _trade;
Trade? get trade => _trade;
set trade(Trade? trade) {
if (_trade != trade) {
_trade = trade;
notifyListeners();
}
}
IncompleteExchangeModel({
required this.sendTicker,
@ -30,6 +68,6 @@ class IncompleteExchangeModel {
required this.receiveAmount,
required this.rateType,
required this.reversed,
this.rateId,
});
String? rateId,
}) : _rateId = rateId;
}

View file

@ -4,7 +4,7 @@ import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/a
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';

View file

@ -3,7 +3,7 @@ import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';

View file

@ -5,14 +5,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/wallets_service_provider.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/name_generator.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';

View file

@ -9,8 +9,8 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';

View file

@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/recovery_phrase_explanation_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
@ -97,7 +97,8 @@ class _NewWalletRecoveryPhraseWarningViewState
onPressed: () async {
await showDialog<void>(
context: context,
builder: (context) => const RecoveryPhraseExplanationDialog(),
builder: (context) =>
const RecoveryPhraseExplanationDialog(),
);
},
),
@ -179,6 +180,7 @@ class _NewWalletRecoveryPhraseWarningViewState
.extension<StackColors>()!
.textDark,
fontSize: 18,
height: 1.3,
),
),
TextSpan(
@ -188,6 +190,7 @@ class _NewWalletRecoveryPhraseWarningViewState
.extension<StackColors>()!
.accentColorBlue,
fontSize: 18,
height: 1.3,
),
),
TextSpan(
@ -197,6 +200,7 @@ class _NewWalletRecoveryPhraseWarningViewState
.extension<StackColors>()!
.textDark,
fontSize: 18,
height: 1.3,
),
),
TextSpan(
@ -206,6 +210,7 @@ class _NewWalletRecoveryPhraseWarningViewState
.extension<StackColors>()!
.accentColorBlue,
fontSize: 18,
height: 1.3,
),
),
TextSpan(
@ -215,6 +220,7 @@ class _NewWalletRecoveryPhraseWarningViewState
.extension<StackColors>()!
.textDark,
fontSize: 18,
height: 1.3,
),
),
],
@ -367,10 +373,12 @@ class _NewWalletRecoveryPhraseWarningViewState
),
Flexible(
child: Text(
"I understand that Stack Wallet does not keep and cannot restore your recovery phrase, and If I lose my recovery phrase, I will not be able to access my funds.",
"I understand that Stack Wallet does not keep and cannot restore my recovery phrase, and If I lose my recovery phrase, I will not be able to access my funds.",
style: isDesktop
? STextStyles.desktopTextMedium(context)
: STextStyles.baseXS(context),
: STextStyles.baseXS(context).copyWith(
height: 1.3,
),
),
),
],

View file

@ -10,7 +10,7 @@ import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_o
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart';

View file

@ -17,8 +17,8 @@ import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widge
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
@ -32,7 +32,6 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/custom_text_selection_controls.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/enums/form_input_status_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';

View file

@ -7,13 +7,12 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.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/utilities/util.dart';

View file

@ -7,8 +7,7 @@ import 'package:stackwallet/models/trade_wallet_lookup.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';

View file

@ -18,8 +18,6 @@ import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_provider_op
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/rate_type_toggle.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
@ -1022,19 +1020,16 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
ref.read(exchangeSendFromWalletIdStateProvider.state).state =
Tuple2(walletId!, coin!);
if (isDesktop) {
ref.read(ssss.state).state = model;
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
return const DesktopDialog(
maxWidth: 720,
maxHeight: double.infinity,
child: StepScaffold(
step: 2,
model: model,
body: DesktopStep2(
model: model,
),
initialStep: 2,
),
);
},
@ -1051,19 +1046,16 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
ref.read(exchangeSendFromWalletIdStateProvider.state).state = null;
if (isDesktop) {
ref.read(ssss.state).state = model;
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
return const DesktopDialog(
maxWidth: 720,
maxHeight: double.infinity,
child: StepScaffold(
step: 1,
model: model,
body: DesktopStep1(
model: model,
),
initialStep: 1,
),
);
},

View file

@ -2,12 +2,14 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/stack_privacy_calls.dart';
import 'package:stackwallet/pages_desktop_specific/password/create_password_view.dart';
import 'package:stackwallet/utilities/assets.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/background.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:url_launcher/url_launcher.dart';
class IntroView extends StatefulWidget {
@ -135,6 +137,20 @@ class _IntroViewState extends State<IntroView> {
GetStartedButton(
isDesktop: isDesktop,
),
if (isDesktop)
const SizedBox(
height: 20,
),
if (isDesktop)
SecondaryButton(
label: "Restore from Stack backup",
onPressed: () {
Navigator.of(context).pushNamed(
CreatePasswordView.routeName,
arguments: true,
);
},
),
const Spacer(
flex: 65,
),
@ -257,7 +273,7 @@ class GetStartedButton extends StatelessWidget {
),
)
: SizedBox(
width: 328,
width: double.infinity,
height: 70,
child: TextButton(
style: Theme.of(context)
@ -270,7 +286,7 @@ class GetStartedButton extends StatelessWidget {
);
},
child: Text(
"Get started",
"Create new Stack",
style: STextStyles.button(context).copyWith(fontSize: 20),
),
),

View file

@ -62,6 +62,7 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
bool _attemptLock = false;
late Duration _timeout;
static const maxAttemptsBeforeThrottling = 3;
Timer? _timer;
Future<void> _onUnlock() async {
final now = DateTime.now().toUtc();
@ -273,11 +274,11 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
_timeout = const Duration(minutes: 60);
}
unawaited(
Future<void>.delayed(_timeout).then((_) {
_timer?.cancel();
_timer = Timer(_timeout, () {
_attemptLock = false;
_attempts = 0;
}));
});
}
if (_attemptLock) {

View file

@ -8,7 +8,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
import 'package:stackwallet/route_generator.dart';
@ -17,7 +17,6 @@ import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -28,9 +27,12 @@ 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:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class ConfirmTransactionView extends ConsumerStatefulWidget {
const ConfirmTransactionView({
@ -60,6 +62,9 @@ class _ConfirmTransactionViewState
late final String routeOnSuccessName;
late final bool isDesktop;
late final FocusNode _noteFocusNode;
late final TextEditingController noteController;
Future<void> _attemptSend(BuildContext context) async {
unawaited(
showDialog<dynamic>(
@ -72,7 +77,7 @@ class _ConfirmTransactionViewState
),
);
final note = transactionInfo["note"] as String? ?? "";
final note = noteController.text;
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
@ -194,9 +199,20 @@ class _ConfirmTransactionViewState
transactionInfo = widget.transactionInfo;
walletId = widget.walletId;
routeOnSuccessName = widget.routeOnSuccessName;
_noteFocusNode = FocusNode();
noteController = TextEditingController();
noteController.text = transactionInfo["note"] as String? ?? "";
super.initState();
}
@override
void dispose() {
noteController.dispose();
_noteFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final managerProvider = ref.watch(walletsChangeNotifierProvider
@ -563,50 +579,132 @@ class _ConfirmTransactionViewState
],
),
),
Container(
height: 1,
color: Theme.of(context)
.extension<StackColors>()!
.background,
),
Padding(
padding: const EdgeInsets.all(12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Note",
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
const SizedBox(
height: 2,
),
Text(
transactionInfo["note"] as String,
style: STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
)
],
),
),
// Container(
// height: 1,
// color: Theme.of(context)
// .extension<StackColors>()!
// .background,
// ),
// Padding(
// padding: const EdgeInsets.all(12),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Note",
// style: STextStyles.desktopTextExtraExtraSmall(
// context),
// ),
// const SizedBox(
// height: 2,
// ),
// Text(
// transactionInfo["note"] as String,
// style: STextStyles.desktopTextExtraExtraSmall(
// context)
// .copyWith(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textDark,
// ),
// )
// ],
// ),
// ),
],
),
),
),
if (isDesktop)
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Note (optional)",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
textAlign: TextAlign.left,
),
const SizedBox(
height: 10,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
minLines: 1,
maxLines: 5,
autocorrect: isDesktop ? false : true,
enableSuggestions: isDesktop ? false : true,
controller: noteController,
focusNode: _noteFocusNode,
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
),
onChanged: (_) => setState(() {}),
decoration: standardInputDecoration(
"Type something...",
_noteFocusNode,
context,
desktopMed: true,
).copyWith(
contentPadding: const EdgeInsets.only(
left: 16,
top: 11,
bottom: 12,
right: 5,
),
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: 20,
)
],
),
),
if (isDesktop)
Padding(
padding: const EdgeInsets.only(
left: 32,
),
child: Text(
"Transaction fee (estimated)",
"Transaction fee",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),

View file

@ -34,6 +34,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:tuple/tuple.dart';
import 'package:uuid/uuid.dart';
import 'package:wakelock/wakelock.dart';
@ -764,6 +765,10 @@ abstract class SWB {
}
Logging.instance.log("done with SWB restore", level: LogLevel.Warning);
if (Util.isDesktop) {
await Wallets.sharedInstance
.loadAfterStackRestore(_prefs, managers.map((e) => e.item2).toList());
}
return true;
}

View file

@ -12,7 +12,6 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
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';

View file

@ -9,6 +9,9 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_menu.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart';
@ -20,25 +23,23 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import '../../../../../pages_desktop_specific/home/desktop_home_view.dart';
import '../../../../../pages_desktop_specific/home/desktop_menu.dart';
import '../../../../../providers/desktop/current_desktop_menu_item.dart';
import '../../../../../widgets/desktop/primary_button.dart';
class StackRestoreProgressView extends ConsumerStatefulWidget {
const StackRestoreProgressView({
Key? key,
required this.jsonString,
this.fromFile = false,
this.shouldPushToHome = false,
}) : super(key: key);
final String jsonString;
final bool fromFile;
final bool shouldPushToHome;
@override
ConsumerState<StackRestoreProgressView> createState() =>
@ -696,11 +697,21 @@ class _StackRestoreProgressViewState
.state)
.state = keyID;
Navigator.of(context, rootNavigator: true)
.popUntil(
ModalRoute.withName(
DesktopHomeView.routeName),
);
if (widget.shouldPushToHome) {
unawaited(
Navigator.of(context)
.pushNamedAndRemoveUntil(
DesktopHomeView.routeName,
(route) => false,
),
);
} else {
Navigator.of(context, rootNavigator: true)
.popUntil(
ModalRoute.withName(
DesktopHomeView.routeName),
);
}
},
)
: SecondaryButton(

View file

@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/create_password_view.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/global/price_provider.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
@ -141,7 +141,8 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
textAlign: TextAlign.left,
text: TextSpan(
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context)
? STextStyles.desktopTextExtraExtraSmall(
context)
: STextStyles.label(context).copyWith(
fontSize: 12.0,
),
@ -214,8 +215,9 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
children: [
Expanded(
child: PrimaryButton(
label:
!widget.isSettings ? "Continue" : "Save changes",
label: !widget.isSettings
? "Continue"
: "Save changes",
onPressed: () {
ref
.read(prefsChangeNotifierProvider)
@ -228,8 +230,8 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
value: isEasy)
.then((_) {
if (isEasy) {
unawaited(
ExchangeDataLoadingService().loadAll(ref));
unawaited(ExchangeDataLoadingService()
.loadAll(ref));
ref
.read(priceAnd24hChangeNotifierProvider)
.start(true);

View file

@ -3,7 +3,7 @@ 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/wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';

View file

@ -5,8 +5,8 @@ import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_address_book_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_contact_details.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_book_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_contact_details.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart';

View file

@ -49,7 +49,7 @@ class DesktopAddressCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SelectableText(
"${entry.label} (${entry.coin.ticker})",
"${contactId == "default" ? entry.other! : entry.label} (${entry.coin.ticker})",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
),

View file

@ -4,8 +4,8 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/paymint/transactions_model.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_new_contact_address_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_address_card.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_contact_options_menu_popup.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_contact_options_menu_popup.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';

View file

@ -1,51 +1,256 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_exchange_steps_indicator.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'dart:async';
class StepScaffold extends StatefulWidget {
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_exchange_steps_indicator.dart';
import 'package:stackwallet/providers/exchange/exchange_provider.dart';
import 'package:stackwallet/providers/global/trades_service_provider.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/notifications_api.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/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_loading_overlay.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';
import 'package:stackwallet/widgets/desktop/simple_desktop_dialog.dart';
import 'package:stackwallet/widgets/fade_stack.dart';
final ssss = StateProvider<IncompleteExchangeModel?>((_) => null);
final desktopExchangeModelProvider =
ChangeNotifierProvider<IncompleteExchangeModel?>(
(ref) => ref.watch(ssss.state).state);
class StepScaffold extends ConsumerStatefulWidget {
const StepScaffold({
Key? key,
required this.body,
required this.step,
required this.model,
required this.initialStep,
}) : super(key: key);
final Widget body;
final int step;
final IncompleteExchangeModel model;
final int initialStep;
@override
State<StepScaffold> createState() => _StepScaffoldState();
ConsumerState<StepScaffold> createState() => _StepScaffoldState();
}
class _StepScaffoldState extends State<StepScaffold> {
int currentStep = 0;
late final IncompleteExchangeModel model;
class _StepScaffoldState extends ConsumerState<StepScaffold> {
int currentStep = 1;
bool enableNext = false;
late final Duration duration;
void updateEnableNext(bool enableNext) {
if (enableNext != this.enableNext) {
setState(() => this.enableNext = enableNext);
}
}
Future<bool> createTrade() async {
unawaited(
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: Container(
color: Theme.of(context)
.extension<StackColors>()!
.overlay
.withOpacity(0.6),
child: const CustomLoadingOverlay(
message: "Creating a trade",
eventBus: null,
),
),
),
),
);
final ExchangeResponse<Trade> response = await ref
.read(exchangeProvider)
.createTrade(
from: ref.read(desktopExchangeModelProvider)!.sendTicker,
to: ref.read(desktopExchangeModelProvider)!.receiveTicker,
fixedRate: ref.read(desktopExchangeModelProvider)!.rateType !=
ExchangeRateType.estimated,
amount: ref.read(desktopExchangeModelProvider)!.reversed
? ref.read(desktopExchangeModelProvider)!.receiveAmount
: ref.read(desktopExchangeModelProvider)!.sendAmount,
addressTo: ref.read(desktopExchangeModelProvider)!.recipientAddress!,
extraId: null,
addressRefund: ref.read(desktopExchangeModelProvider)!.refundAddress!,
refundExtraId: "",
rateId: ref.read(desktopExchangeModelProvider)!.rateId,
reversed: ref.read(desktopExchangeModelProvider)!.reversed,
);
if (response.value == null) {
if (mounted) {
Navigator.of(context).pop();
}
unawaited(
showDialog<void>(
context: context,
barrierDismissible: true,
builder: (_) => SimpleDesktopDialog(
title: "Failed to create trade",
message: response.exception?.toString() ?? ""),
),
);
return false;
}
// save trade to hive
await ref.read(tradesServiceProvider).add(
trade: response.value!,
shouldNotifyListeners: true,
);
String status = response.value!.status;
ref.read(desktopExchangeModelProvider)!.trade = response.value!;
// extra info if status is waiting
if (status == "Waiting") {
status += " for deposit";
}
if (mounted) {
Navigator.of(context).pop();
}
unawaited(
NotificationApi.showNotification(
changeNowId: ref.read(desktopExchangeModelProvider)!.trade!.tradeId,
title: status,
body:
"Trade ID ${ref.read(desktopExchangeModelProvider)!.trade!.tradeId}",
walletId: "",
iconAssetName: Assets.svg.arrowRotate,
date: ref.read(desktopExchangeModelProvider)!.trade!.timestamp,
shouldWatchForUpdates: true,
coinName: "coinName",
),
);
return true;
// if (mounted) {
// unawaited(
// showDialog<void>(
// context: context,
// barrierColor: Colors.transparent,
// barrierDismissible: false,
// builder: (context) {
// return DesktopDialog(
// maxWidth: 720,
// maxHeight: double.infinity,
// child: StepScaffold(
// initialStep: 4,
// ),
// );
// },
// ),
// );
// }
}
void onBack() {
if (currentStep > 1 && currentStep < 4) {
setState(() => currentStep = currentStep - 1);
} else if (currentStep == 1) {
Navigator.of(context, rootNavigator: true).pop();
}
}
void sendFromStack() {
final trade = ref.read(desktopExchangeModelProvider)!.trade!;
final amount = Decimal.parse(trade.payInAmount);
final address = trade.payInAddress;
final coin = coinFromTickerCaseInsensitive(trade.payInCurrency);
showDialog<void>(
context: context,
builder: (context) => Navigator(
initialRoute: SendFromView.routeName,
onGenerateRoute: RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) {
return [
FadePageRoute(
SendFromView(
coin: coin,
trade: trade,
amount: amount,
address: address,
shouldPopRoot: true,
fromDesktopStep4: true,
),
const RouteSettings(
name: SendFromView.routeName,
),
),
];
},
),
);
}
@override
void initState() {
currentStep = widget.step;
model = widget.model;
duration = const Duration(milliseconds: 250);
currentStep = widget.initialStep;
super.initState();
}
@override
Widget build(BuildContext context) {
final model = ref.watch(desktopExchangeModelProvider);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const AppBarBackButton(
isCompact: true,
iconSize: 23,
),
Text(
"Exchange ${model.sendTicker.toUpperCase()} to ${model.receiveTicker.toUpperCase()}",
style: STextStyles.desktopH3(context),
Row(
children: [
currentStep != 4
? AppBarBackButton(
isCompact: true,
iconSize: 23,
onPressed: onBack,
)
: const SizedBox(
width: 32,
),
Text(
"Exchange ${model?.sendTicker.toUpperCase()} to ${model?.receiveTicker.toUpperCase()}",
style: STextStyles.desktopH3(context),
),
],
),
if (currentStep == 4)
DesktopDialogCloseButton(
onPressedOverride: () {
Navigator.of(context, rootNavigator: true).pop();
},
),
],
),
const SizedBox(
@ -66,7 +271,139 @@ class _StepScaffoldState extends State<StepScaffold> {
padding: const EdgeInsets.symmetric(
horizontal: 32,
),
child: widget.body,
child: FadeStack(
index: currentStep - 1,
children: [
const DesktopStep1(),
DesktopStep2(
enableNextChanged: updateEnableNext,
),
const DesktopStep3(),
const DesktopStep4(),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 20,
left: 32,
right: 32,
bottom: 32,
),
child: Row(
children: [
Expanded(
child: AnimatedCrossFade(
duration: const Duration(milliseconds: 250),
crossFadeState: currentStep == 4
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
firstChild: SecondaryButton(
label: "Back",
buttonHeight: ButtonHeight.l,
onPressed: onBack,
),
secondChild: SecondaryButton(
label: "Send from Stack Wallet",
buttonHeight: ButtonHeight.l,
onPressed: sendFromStack,
),
),
),
const SizedBox(
width: 16,
),
Expanded(
child: AnimatedCrossFade(
duration: const Duration(milliseconds: 250),
crossFadeState: currentStep == 4
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
firstChild: AnimatedCrossFade(
duration: const Duration(milliseconds: 250),
crossFadeState: currentStep == 3
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
firstChild: PrimaryButton(
label: "Next",
enabled: currentStep != 2 ? true : enableNext,
buttonHeight: ButtonHeight.l,
onPressed: () async {
setState(() => currentStep = currentStep + 1);
},
),
secondChild: PrimaryButton(
label: "Confirm",
enabled: currentStep != 2 ? true : enableNext,
buttonHeight: ButtonHeight.l,
onPressed: () async {
if (currentStep == 3) {
final success = await createTrade();
if (!success) {
return;
}
}
setState(() => currentStep = currentStep + 1);
},
),
),
secondChild: PrimaryButton(
label: "Show QR code",
enabled: currentStep != 2 ? true : enableNext,
buttonHeight: ButtonHeight.l,
onPressed: () {
showDialog<dynamic>(
context: context,
barrierColor: Colors.transparent,
barrierDismissible: true,
builder: (_) {
return DesktopDialog(
maxHeight: 720,
maxWidth: 720,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Send ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker))} to this address",
style: STextStyles.desktopH3(context),
),
const SizedBox(
height: 48,
),
Center(
child: QrImage(
// TODO: grab coin uri scheme from somewhere
// data: "${coin.uriScheme}:$receivingAddress",
data: ref.watch(desktopExchangeModelProvider
.select((value) =>
value!.trade!.payInAddress)),
size: 290,
foregroundColor: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
const SizedBox(
height: 48,
),
SecondaryButton(
label: "Cancel",
width: 310,
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
],
),
);
},
);
},
),
),
),
],
),
),
],
);

View file

@ -1,26 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart';
import 'package:stackwallet/providers/providers.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/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class DesktopStep1 extends ConsumerWidget {
const DesktopStep1({
Key? key,
required this.model,
}) : super(key: key);
final IncompleteExchangeModel model;
@override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
@ -55,7 +47,7 @@ class DesktopStep1 extends ConsumerWidget {
DesktopStepItem(
label: "You send",
value:
"${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker.toUpperCase()}",
"${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))}",
),
Container(
height: 1,
@ -64,63 +56,20 @@ class DesktopStep1 extends ConsumerWidget {
DesktopStepItem(
label: "You receive",
value:
"~${model.receiveAmount.toStringAsFixed(8)} ${model.receiveTicker.toUpperCase()}",
"~${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))}",
),
Container(
height: 1,
color: Theme.of(context).extension<StackColors>()!.background,
),
DesktopStepItem(
label: model.rateType == ExchangeRateType.estimated
label: ref.watch(desktopExchangeModelProvider
.select((value) => value!.rateType)) ==
ExchangeRateType.estimated
? "Estimated rate"
: "Fixed rate",
value: model.rateInfo,
),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 20,
bottom: 32,
),
child: Row(
children: [
Expanded(
child: SecondaryButton(
label: "Back",
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Next",
buttonHeight: ButtonHeight.l,
onPressed: () async {
await showDialog<void>(
context: context,
barrierColor: Colors.transparent,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
maxWidth: 720,
maxHeight: double.infinity,
child: StepScaffold(
step: 2,
model: model,
body: DesktopStep2(
model: model,
),
),
);
},
);
},
),
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.rateInfo)),
),
],
),

View file

@ -2,11 +2,9 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_from_stack.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
@ -18,31 +16,29 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.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';
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
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:tuple/tuple.dart';
class DesktopStep2 extends ConsumerStatefulWidget {
const DesktopStep2({
Key? key,
required this.model,
required this.enableNextChanged,
this.clipboard = const ClipboardWrapper(),
}) : super(key: key);
final IncompleteExchangeModel model;
final ClipboardInterface clipboard;
final void Function(bool) enableNextChanged;
@override
ConsumerState<DesktopStep2> createState() => _DesktopStep2State();
}
class _DesktopStep2State extends ConsumerState<DesktopStep2> {
late final IncompleteExchangeModel model;
late final ClipboardInterface clipboard;
late final TextEditingController _toController;
@ -51,8 +47,6 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
late final FocusNode _toFocusNode;
late final FocusNode _refundFocusNode;
bool enableNext = false;
bool isStackCoin(String ticker) {
try {
coinFromTickerCaseInsensitive(ticker);
@ -65,10 +59,10 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
void selectRecipientAddressFromStack() async {
try {
final coin = coinFromTickerCaseInsensitive(
model.receiveTicker,
ref.read(desktopExchangeModelProvider)!.receiveTicker,
);
final address = await showDialog<String?>(
final info = await showDialog<Tuple2<String, String>?>(
context: context,
barrierColor: Colors.transparent,
builder: (context) => DesktopDialog(
@ -83,29 +77,25 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
),
);
if (address is String) {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(address);
_toController.text = manager.walletName;
model.recipientAddress = await manager.currentReceivingAddress;
if (info is Tuple2<String, String>) {
_toController.text = info.item1;
ref.read(desktopExchangeModelProvider)!.recipientAddress = info.item2;
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Info);
}
setState(() {
enableNext =
_toController.text.isNotEmpty && _refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(
_toController.text.isNotEmpty && _refundController.text.isNotEmpty);
}
void selectRefundAddressFromStack() async {
try {
final coin = coinFromTickerCaseInsensitive(
model.sendTicker,
ref.read(desktopExchangeModelProvider)!.sendTicker,
);
final address = await showDialog<String?>(
final info = await showDialog<Tuple2<String, String>?>(
context: context,
barrierColor: Colors.transparent,
builder: (context) => DesktopDialog(
@ -119,25 +109,20 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
),
),
);
if (address is String) {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(address);
_refundController.text = manager.walletName;
model.refundAddress = await manager.currentReceivingAddress;
if (info is Tuple2<String, String>) {
_refundController.text = info.item1;
ref.read(desktopExchangeModelProvider)!.refundAddress = info.item2;
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Info);
}
setState(() {
enableNext =
_toController.text.isNotEmpty && _refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(
_toController.text.isNotEmpty && _refundController.text.isNotEmpty);
}
void selectRecipientFromAddressBook() async {
final coin = coinFromTickerCaseInsensitive(
model.receiveTicker,
ref.read(desktopExchangeModelProvider)!.receiveTicker,
);
final entry = await showDialog<ContactAddressEntry?>(
@ -176,17 +161,15 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
if (entry != null) {
_toController.text = entry.address;
model.recipientAddress = entry.address;
setState(() {
enableNext =
_toController.text.isNotEmpty && _refundController.text.isNotEmpty;
});
ref.read(desktopExchangeModelProvider)!.recipientAddress = entry.address;
widget.enableNextChanged.call(
_toController.text.isNotEmpty && _refundController.text.isNotEmpty);
}
}
void selectRefundFromAddressBook() async {
final coin = coinFromTickerCaseInsensitive(
model.sendTicker,
ref.read(desktopExchangeModelProvider)!.sendTicker,
);
final entry = await showDialog<ContactAddressEntry?>(
@ -225,17 +208,14 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
if (entry != null) {
_refundController.text = entry.address;
model.refundAddress = entry.address;
setState(() {
enableNext =
_toController.text.isNotEmpty && _refundController.text.isNotEmpty;
});
ref.read(desktopExchangeModelProvider)!.refundAddress = entry.address;
widget.enableNextChanged.call(
_toController.text.isNotEmpty && _refundController.text.isNotEmpty);
}
}
@override
void initState() {
model = widget.model;
clipboard = widget.clipboard;
_toController = TextEditingController();
@ -246,7 +226,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
final tuple = ref.read(exchangeSendFromWalletIdStateProvider.state).state;
if (tuple != null) {
if (model.receiveTicker.toLowerCase() ==
if (ref.read(desktopExchangeModelProvider)!.receiveTicker.toLowerCase() ==
tuple.item2.ticker.toLowerCase()) {
ref
.read(walletsChangeNotifierProvider)
@ -254,10 +234,11 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
.currentReceivingAddress
.then((value) {
_toController.text = value;
model.recipientAddress = _toController.text;
ref.read(desktopExchangeModelProvider)!.recipientAddress =
_toController.text;
});
} else {
if (model.sendTicker.toUpperCase() ==
if (ref.read(desktopExchangeModelProvider)!.sendTicker.toUpperCase() ==
tuple.item2.ticker.toUpperCase()) {
ref
.read(walletsChangeNotifierProvider)
@ -265,7 +246,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
.currentReceivingAddress
.then((value) {
_refundController.text = value;
model.refundAddress = _refundController.text;
ref.read(desktopExchangeModelProvider)!.refundAddress =
_refundController.text;
});
}
}
@ -316,7 +298,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
.extension<StackColors>()!
.textFieldActiveSearchIconRight),
),
if (isStackCoin(model.receiveTicker))
if (isStackCoin(ref.watch(desktopExchangeModelProvider
.select((value) => value!.receiveTicker))))
BlueTextButton(
text: "Choose from stack",
onTap: selectRecipientAddressFromStack,
@ -349,13 +332,11 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
focusNode: _toFocusNode,
style: STextStyles.field(context),
onChanged: (value) {
setState(() {
enableNext = _toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
},
decoration: standardInputDecoration(
"Enter the ${model.receiveTicker.toUpperCase()} payout address",
"Enter the ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))} payout address",
_toFocusNode,
context,
desktopMed: true,
@ -380,11 +361,12 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
"sendViewClearAddressFieldButtonKey"),
onTap: () {
_toController.text = "";
model.recipientAddress = _toController.text;
setState(() {
enableNext = _toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
ref
.read(desktopExchangeModelProvider)!
.recipientAddress = _toController.text;
widget.enableNextChanged.call(
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
},
child: const XIcon(),
)
@ -398,12 +380,12 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
data!.text!.isNotEmpty) {
final content = data.text!.trim();
_toController.text = content;
model.recipientAddress = _toController.text;
setState(() {
enableNext =
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
ref
.read(desktopExchangeModelProvider)!
.recipientAddress = _toController.text;
widget.enableNextChanged.call(
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
}
},
child: _toController.text.isEmpty
@ -411,7 +393,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
: const XIcon(),
),
if (_toController.text.isEmpty &&
isStackCoin(model.receiveTicker))
isStackCoin(ref.watch(desktopExchangeModelProvider
.select((value) => value!.receiveTicker))))
TextFieldIconButton(
key: const Key("sendViewAddressBookButtonKey"),
onTap: selectRecipientFromAddressBook,
@ -430,7 +413,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
RoundedWhiteContainer(
borderColor: Theme.of(context).extension<StackColors>()!.background,
child: Text(
"This is the wallet where your ${model.receiveTicker.toUpperCase()} will be sent to.",
"This is the wallet where your ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))} will be sent to.",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
@ -447,7 +430,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
.extension<StackColors>()!
.textFieldActiveSearchIconRight),
),
if (isStackCoin(model.sendTicker))
if (isStackCoin(ref.watch(desktopExchangeModelProvider
.select((value) => value!.sendTicker))))
BlueTextButton(
text: "Choose from stack",
onTap: selectRefundAddressFromStack,
@ -479,13 +463,11 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
focusNode: _refundFocusNode,
style: STextStyles.field(context),
onChanged: (value) {
setState(() {
enableNext = _toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
},
decoration: standardInputDecoration(
"Enter ${model.sendTicker.toUpperCase()} refund address",
"Enter ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} refund address",
_refundFocusNode,
context,
desktopMed: true,
@ -510,12 +492,13 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
"sendViewClearAddressFieldButtonKey"),
onTap: () {
_refundController.text = "";
model.refundAddress = _refundController.text;
ref
.read(desktopExchangeModelProvider)!
.refundAddress = _refundController.text;
setState(() {
enableNext = _toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
},
child: const XIcon(),
)
@ -530,13 +513,13 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
final content = data.text!.trim();
_refundController.text = content;
model.refundAddress = _refundController.text;
ref
.read(desktopExchangeModelProvider)!
.refundAddress = _refundController.text;
setState(() {
enableNext =
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty;
});
widget.enableNextChanged.call(
_toController.text.isNotEmpty &&
_refundController.text.isNotEmpty);
}
},
child: _refundController.text.isEmpty
@ -544,7 +527,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
: const XIcon(),
),
if (_refundController.text.isEmpty &&
isStackCoin(model.sendTicker))
isStackCoin(ref.watch(desktopExchangeModelProvider
.select((value) => value!.sendTicker))))
TextFieldIconButton(
key: const Key("sendViewAddressBookButtonKey"),
onTap: selectRefundFromAddressBook,
@ -567,53 +551,6 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
Padding(
padding: const EdgeInsets.only(
top: 20,
bottom: 32,
),
child: Row(
children: [
Expanded(
child: SecondaryButton(
label: "Back",
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Next",
enabled: enableNext,
buttonHeight: ButtonHeight.l,
onPressed: () async {
await showDialog<void>(
context: context,
barrierColor: Colors.transparent,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
maxWidth: 720,
maxHeight: double.infinity,
child: StepScaffold(
step: 3,
model: model,
body: DesktopStep3(
model: model,
),
),
);
},
);
},
),
),
],
),
),
],
);
}

View file

@ -1,157 +1,23 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart';
import 'package:stackwallet/providers/exchange/current_exchange_name_state_provider.dart';
import 'package:stackwallet/providers/exchange/exchange_provider.dart';
import 'package:stackwallet/providers/global/trades_service_provider.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/notifications_api.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/custom_loading_overlay.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/desktop/simple_desktop_dialog.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class DesktopStep3 extends ConsumerStatefulWidget {
const DesktopStep3({
Key? key,
required this.model,
}) : super(key: key);
final IncompleteExchangeModel model;
@override
ConsumerState<DesktopStep3> createState() => _DesktopStep3State();
}
class _DesktopStep3State extends ConsumerState<DesktopStep3> {
late final IncompleteExchangeModel model;
Future<void> createTrade() async {
unawaited(
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: Container(
color: Theme.of(context)
.extension<StackColors>()!
.overlay
.withOpacity(0.6),
child: const CustomLoadingOverlay(
message: "Creating a trade",
eventBus: null,
),
),
),
),
);
final ExchangeResponse<Trade> response =
await ref.read(exchangeProvider).createTrade(
from: model.sendTicker,
to: model.receiveTicker,
fixedRate: model.rateType != ExchangeRateType.estimated,
amount: model.reversed ? model.receiveAmount : model.sendAmount,
addressTo: model.recipientAddress!,
extraId: null,
addressRefund: model.refundAddress!,
refundExtraId: "",
rateId: model.rateId,
reversed: model.reversed,
);
if (response.value == null) {
if (mounted) {
Navigator.of(context).pop();
}
unawaited(
showDialog<void>(
context: context,
barrierDismissible: true,
builder: (_) => SimpleDesktopDialog(
title: "Failed to create trade",
message: response.exception?.toString() ?? ""),
),
);
return;
}
// save trade to hive
await ref.read(tradesServiceProvider).add(
trade: response.value!,
shouldNotifyListeners: true,
);
String status = response.value!.status;
model.trade = response.value!;
// extra info if status is waiting
if (status == "Waiting") {
status += " for deposit";
}
if (mounted) {
Navigator.of(context).pop();
}
unawaited(
NotificationApi.showNotification(
changeNowId: model.trade!.tradeId,
title: status,
body: "Trade ID ${model.trade!.tradeId}",
walletId: "",
iconAssetName: Assets.svg.arrowRotate,
date: model.trade!.timestamp,
shouldWatchForUpdates: true,
coinName: "coinName",
),
);
if (mounted) {
unawaited(
showDialog<void>(
context: context,
barrierColor: Colors.transparent,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
maxWidth: 720,
maxHeight: double.infinity,
child: StepScaffold(
step: 4,
model: model,
body: DesktopStep4(
model: model,
),
),
);
},
),
);
}
}
@override
void initState() {
model = widget.model;
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
@ -179,7 +45,7 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
DesktopStepItem(
label: "You send",
value:
"${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker.toUpperCase()}",
"${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))}",
),
Container(
height: 1,
@ -188,17 +54,20 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
DesktopStepItem(
label: "You receive",
value:
"~${model.receiveAmount.toStringAsFixed(8)} ${model.receiveTicker.toUpperCase()}",
"~${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))}",
),
Container(
height: 1,
color: Theme.of(context).extension<StackColors>()!.background,
),
DesktopStepItem(
label: model.rateType == ExchangeRateType.estimated
label: ref.watch(desktopExchangeModelProvider
.select((value) => value!.rateType)) ==
ExchangeRateType.estimated
? "Estimated rate"
: "Fixed rate",
value: model.rateInfo,
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.rateInfo)),
),
Container(
height: 1,
@ -206,8 +75,11 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
),
DesktopStepItem(
vertical: true,
label: "Recipient ${model.receiveTicker.toUpperCase()} address",
value: model.recipientAddress!,
label:
"Recipient ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))} address",
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.recipientAddress)) ??
"Error",
),
Container(
height: 1,
@ -215,35 +87,11 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
),
DesktopStepItem(
vertical: true,
label: "Refund ${model.sendTicker.toUpperCase()} address",
value: model.refundAddress!,
),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 20,
bottom: 32,
),
child: Row(
children: [
Expanded(
child: SecondaryButton(
label: "Back",
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Confirm",
buttonHeight: ButtonHeight.l,
onPressed: createTrade,
),
label:
"Refund ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} address",
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.refundAddress)) ??
"Error",
),
],
),

View file

@ -1,38 +1,26 @@
import 'dart:async';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.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/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class DesktopStep4 extends ConsumerStatefulWidget {
const DesktopStep4({
Key? key,
required this.model,
}) : super(key: key);
final IncompleteExchangeModel model;
@override
ConsumerState<DesktopStep4> createState() => _DesktopStep4State();
}
class _DesktopStep4State extends ConsumerState<DesktopStep4> {
late final IncompleteExchangeModel model;
String _statusString = "New";
Timer? _statusTimer;
@ -51,8 +39,13 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
}
Future<void> _updateStatus() async {
final statusResponse =
await ref.read(exchangeProvider).updateTrade(model.trade!);
final trade = ref.read(desktopExchangeModelProvider)?.trade;
if (trade == null) {
return;
}
final statusResponse = await ref.read(exchangeProvider).updateTrade(trade);
String status = "Waiting";
if (statusResponse.value != null) {
status = statusResponse.value!.status;
@ -72,8 +65,6 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
@override
void initState() {
model = widget.model;
_statusTimer = Timer.periodic(const Duration(seconds: 60), (_) {
_updateStatus();
});
@ -93,14 +84,14 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
return Column(
children: [
Text(
"Send ${model.sendTicker.toUpperCase()} to the address below",
"Send ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} to the address below",
style: STextStyles.desktopTextMedium(context),
),
const SizedBox(
height: 8,
),
Text(
"Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ${model.trade!.exchangeName} will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
"Send ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} to the address below. Once it is received, ${ref.watch(desktopExchangeModelProvider.select((value) => value!.trade?.exchangeName))} will send the ${ref.watch(desktopExchangeModelProvider.select((value) => value!.receiveTicker.toUpperCase()))} to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
const SizedBox(
@ -111,7 +102,7 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
child: RichText(
text: TextSpan(
text:
"You must send at least ${model.sendAmount.toString()} ${model.sendTicker}. ",
"You must send at least ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toString()))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker))}. ",
style: STextStyles.label700(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
@ -121,7 +112,7 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
children: [
TextSpan(
text:
"If you send less than ${model.sendAmount.toString()} ${model.sendTicker}, your transaction may not be converted and it may not be refunded.",
"If you send less than ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toString()))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker))}, your transaction may not be converted and it may not be refunded.",
style: STextStyles.label(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
@ -143,8 +134,11 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
children: [
DesktopStepItem(
vertical: true,
label: "Send ${model.sendTicker.toUpperCase()} to this address",
value: model.trade!.payInAddress,
label:
"Send ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} to this address",
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.trade?.payInAddress)) ??
"Error",
),
Container(
height: 1,
@ -153,7 +147,7 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
DesktopStepItem(
label: "Amount",
value:
"${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker.toUpperCase()}",
"${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendAmount.toStringAsFixed(8)))} ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))}",
),
Container(
height: 1,
@ -161,7 +155,9 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
),
DesktopStepItem(
label: "Trade ID",
value: model.trade!.tradeId,
value: ref.watch(desktopExchangeModelProvider
.select((value) => value!.trade?.tradeId)) ??
"Error",
),
Container(
height: 1,
@ -191,110 +187,6 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 20,
bottom: 32,
),
child: Row(
children: [
Expanded(
child: SecondaryButton(
label: "Send from Stack Wallet",
buttonHeight: ButtonHeight.l,
onPressed: () {
final trade = model.trade!;
final amount = Decimal.parse(trade.payInAmount);
final address = trade.payInAddress;
final coin =
coinFromTickerCaseInsensitive(trade.payInCurrency);
showDialog<void>(
context: context,
builder: (context) => Navigator(
initialRoute: SendFromView.routeName,
onGenerateRoute: RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) {
return [
FadePageRoute(
SendFromView(
coin: coin,
trade: trade,
amount: amount,
address: address,
shouldPopRoot: true,
fromDesktopStep4: true,
),
const RouteSettings(
name: SendFromView.routeName,
),
),
];
},
),
);
},
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Show QR code",
buttonHeight: ButtonHeight.l,
onPressed: () {
showDialog<dynamic>(
context: context,
barrierColor: Colors.transparent,
barrierDismissible: true,
builder: (_) {
return DesktopDialog(
maxHeight: 720,
maxWidth: 720,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Send ${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker} to this address",
style: STextStyles.desktopH3(context),
),
const SizedBox(
height: 48,
),
Center(
child: QrImage(
// TODO: grab coin uri scheme from somewhere
// data: "${coin.uriScheme}:$receivingAddress",
data: model.trade!.payInAddress,
size: 290,
foregroundColor: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
const SizedBox(
height: 48,
),
SecondaryButton(
label: "Cancel",
width: 310,
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
],
),
);
},
);
},
),
),
],
),
),
],
);
}

View file

@ -17,6 +17,7 @@ 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/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
import 'package:tuple/tuple.dart';
class DesktopChooseFromStack extends ConsumerStatefulWidget {
const DesktopChooseFromStack({
@ -222,8 +223,18 @@ class _DesktopChooseFromStackState
),
BlueTextButton(
text: "Select wallet",
onTap: () {
Navigator.of(context).pop(manager.walletId);
onTap: () async {
final address =
await manager.currentReceivingAddress;
if (mounted) {
Navigator.of(context).pop(
Tuple2(
manager.walletName,
address,
),
);
}
},
),
],

View file

@ -10,34 +10,58 @@ class DesktopExchangeStepsIndicator extends StatelessWidget {
final int currentStep;
Color getColor(BuildContext context, int step) {
if (currentStep > step) {
if (currentStep >= step) {
return Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
.withOpacity(0.5);
} else if (currentStep < step) {
return Theme.of(context).extension<StackColors>()!.textSubtitle3;
} else {
return Theme.of(context).extension<StackColors>()!.accentColorBlue;
return Theme.of(context).extension<StackColors>()!.textSubtitle3;
}
}
static const double verticalSpacing = 6;
static const double horizontalSpacing = 16;
static const double barHeight = 4;
static const double width = 152;
static const double barWidth = 146;
static const Duration duration = Duration(milliseconds: 250);
@override
Widget build(BuildContext context) {
final double step = double.parse(currentStep.toString());
final double dy = (step - 4) - (-(step - 4) * (horizontalSpacing / width));
return Row(
children: [
Expanded(
SizedBox(
width: width,
child: Column(
children: [
Text(
"Confirm amount",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: getColor(context, 1),
AnimatedCrossFade(
firstChild: Text(
"Confirm amount",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
"Confirm amount",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
.withOpacity(0.5),
),
),
crossFadeState: currentStep == 1
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
const SizedBox(
height: verticalSpacing,
@ -53,14 +77,49 @@ class DesktopExchangeStepsIndicator extends StatelessWidget {
const SizedBox(
width: horizontalSpacing,
),
Expanded(
SizedBox(
width: width,
child: Column(
children: [
Text(
"Enter details",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: getColor(context, 2),
AnimatedCrossFade(
firstChild: Text(
"Enter details",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle3,
),
),
secondChild: AnimatedCrossFade(
firstChild: Text(
"Enter details",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
"Enter details",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
.withOpacity(0.5),
),
),
crossFadeState: currentStep == 2 && currentStep > 1
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
crossFadeState: currentStep < 2
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
const SizedBox(
height: verticalSpacing,
@ -76,14 +135,49 @@ class DesktopExchangeStepsIndicator extends StatelessWidget {
const SizedBox(
width: horizontalSpacing,
),
Expanded(
SizedBox(
width: width,
child: Column(
children: [
Text(
"Confirm details",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: getColor(context, 3),
AnimatedCrossFade(
firstChild: Text(
"Confirm details",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle3,
),
),
secondChild: AnimatedCrossFade(
firstChild: Text(
"Confirm details",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
"Confirm details",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
.withOpacity(0.5),
),
),
crossFadeState: currentStep == 3 && currentStep > 2
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
crossFadeState: currentStep < 3
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
const SizedBox(
height: verticalSpacing,
@ -99,22 +193,56 @@ class DesktopExchangeStepsIndicator extends StatelessWidget {
const SizedBox(
width: horizontalSpacing,
),
Expanded(
SizedBox(
width: width,
child: Column(
children: [
Text(
"Complete exchange",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: getColor(context, 4),
AnimatedCrossFade(
firstChild: Text(
"Complete exchange",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle3,
),
),
secondChild: Text(
"Complete exchange",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
crossFadeState: currentStep < 4
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: duration,
),
const SizedBox(
height: verticalSpacing,
),
RoundedContainer(
color: getColor(context, 4),
height: barHeight,
width: double.infinity,
Stack(
children: [
RoundedContainer(
color: getColor(context, 4),
height: barHeight,
width: double.infinity,
),
AnimatedSlide(
offset: Offset(dy, 0),
duration: duration,
child: RoundedContainer(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
height: barHeight,
width: double.infinity,
),
),
],
),
],
),

View file

@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/desktop_address_book.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/desktop_address_book.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/notifications/desktop_notifications_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_about_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_support_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_menu.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart';
import 'package:stackwallet/pages_desktop_specific/notifications/desktop_notifications_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/desktop_settings_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_about_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_support_view.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
import 'package:stackwallet/providers/global/notifications_provider.dart';
@ -32,13 +32,13 @@ class DesktopHomeView extends ConsumerStatefulWidget {
}
class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
final GlobalKey key = GlobalKey<NavigatorState>();
final GlobalKey myStackViewNavKey = GlobalKey<NavigatorState>();
late final Navigator myStackViewNav;
@override
void initState() {
myStackViewNav = Navigator(
key: key,
key: myStackViewNavKey,
onGenerateRoute: RouteGenerator.generateRoute,
initialRoute: MyStackView.routeName,
);
@ -87,7 +87,7 @@ class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
void onMenuSelectionWillChange(DesktopMenuItemId newKey) {
if (prev == DesktopMenuItemId.myStack && prev == newKey) {
Navigator.of(key.currentContext!)
Navigator.of(myStackViewNavKey.currentContext!)
.popUntil(ModalRoute.withName(MyStackView.routeName));
if (ref.read(currentWalletIdProvider.state).state != null) {
final managerProvider = ref

View file

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu_item.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_menu_item.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -138,22 +138,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
children: [
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.walletDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.myStack ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopMyStackIcon(),
label: "My Stack",
value: DesktopMenuItemId.myStack,
onChanged: updateSelectedMenuItem,
@ -164,22 +149,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.exchangeDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.exchange ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopExchangeIcon(),
label: "Exchange",
value: DesktopMenuItemId.exchange,
onChanged: updateSelectedMenuItem,
@ -201,22 +171,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.addressBookDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.addressBook ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopAddressBookIcon(),
label: "Address Book",
value: DesktopMenuItemId.addressBook,
onChanged: updateSelectedMenuItem,
@ -227,22 +182,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.gear,
width: 20,
height: 20,
color: DesktopMenuItemId.settings ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopSettingsIcon(),
label: "Settings",
value: DesktopMenuItemId.settings,
onChanged: updateSelectedMenuItem,
@ -253,22 +193,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.messageQuestion,
width: 20,
height: 20,
color: DesktopMenuItemId.support ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopSupportIcon(),
label: "Support",
value: DesktopMenuItemId.support,
onChanged: updateSelectedMenuItem,
@ -279,22 +204,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.aboutDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.about ==
ref
.watch(currentDesktopMenuItemProvider.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopAboutIcon(),
label: "About",
value: DesktopMenuItemId.about,
onChanged: updateSelectedMenuItem,
@ -304,15 +214,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
DesktopMenuItem(
duration: duration,
labelLength: 123,
icon: SvgPicture.asset(
Assets.svg.exitDesktop,
width: 20,
height: 20,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
icon: const DesktopExitIcon(),
label: "Exit",
value: 7,
onChanged: (_) {

View file

@ -1,7 +1,7 @@
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/desktop_menu.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_menu.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/providers/global/notifications_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
@ -15,18 +15,51 @@ class DMIController {
}
}
class DesktopNotificationsIcon extends ConsumerStatefulWidget {
class DesktopMyStackIcon extends ConsumerWidget {
const DesktopMyStackIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.walletDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.myStack ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopExchangeIcon extends ConsumerWidget {
const DesktopExchangeIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.exchangeDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.exchange ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopNotificationsIcon extends ConsumerWidget {
const DesktopNotificationsIcon({Key? key}) : super(key: key);
@override
ConsumerState<DesktopNotificationsIcon> createState() =>
_DesktopNotificationsIconState();
}
class _DesktopNotificationsIconState
extends ConsumerState<DesktopNotificationsIcon> {
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
ref.watch(notificationsProvider
.select((value) => value.hasUnreadNotifications))
@ -48,6 +81,103 @@ class _DesktopNotificationsIconState
}
}
class DesktopAddressBookIcon extends ConsumerWidget {
const DesktopAddressBookIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.addressBookDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.addressBook ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopSettingsIcon extends ConsumerWidget {
const DesktopSettingsIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.gear,
width: 20,
height: 20,
color: DesktopMenuItemId.settings ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopSupportIcon extends ConsumerWidget {
const DesktopSupportIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.messageQuestion,
width: 20,
height: 20,
color: DesktopMenuItemId.support ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopAboutIcon extends ConsumerWidget {
const DesktopAboutIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.aboutDesktop,
width: 20,
height: 20,
color: DesktopMenuItemId.about ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopExitIcon extends ConsumerWidget {
const DesktopExitIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset(
Assets.svg.exitDesktop,
width: 20,
height: 20,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopMenuItem<T> extends ConsumerStatefulWidget {
const DesktopMenuItem({
Key? key,
@ -127,7 +257,7 @@ class _DesktopMenuItemState<T> extends ConsumerState<DesktopMenuItem<T>>
@override
Widget build(BuildContext context) {
final group = ref.watch(currentDesktopMenuItemProvider.state).state;
debugPrint("============ value:$value ============ group:$group");
return TextButton(
style: value == group
? Theme.of(context)

View file

@ -1,136 +0,0 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
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<SendReceiveTabMenu> createState() => _SendReceiveTabMenuState();
}
class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
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: MouseRegion(
cursor: SystemMouseCursors.click,
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<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 19,
),
Container(
height: 2,
decoration: BoxDecoration(
color: _selectedIndex == 0
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.background,
),
),
],
),
),
),
),
),
Expanded(
child: MouseRegion(
cursor: SystemMouseCursors.click,
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<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 19,
),
Container(
height: 2,
decoration: BoxDecoration(
color: _selectedIndex == 1
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.background,
),
),
],
),
),
),
),
),
],
);
}
}

View file

@ -1,501 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.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/color_theme.dart';
import 'package:stackwallet/utilities/theme/dark_colors.dart';
import 'package:stackwallet/utilities/theme/light_colors.dart';
import 'package:stackwallet/utilities/theme/ocean_breeze_colors.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class AppearanceOptionSettings extends ConsumerStatefulWidget {
const AppearanceOptionSettings({Key? key}) : super(key: key);
static const String routeName = "/settingsMenuAppearance";
@override
ConsumerState<AppearanceOptionSettings> createState() =>
_AppearanceOptionSettings();
}
class _AppearanceOptionSettings
extends ConsumerState<AppearanceOptionSettings> {
// late bool isLight;
// @override
// void initState() {
//
// super.initState();
// }
//
// @override
// void dispose() {
// super.dispose();
// }
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
right: 30,
),
child: RoundedWhiteContainer(
radiusMultiplier: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: 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<StackColors>()!
.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<StackColors>()!
.textDark),
textAlign: TextAlign.left,
),
],
),
),
const Padding(
padding: EdgeInsets.all(10),
child: ThemeToggle(),
),
],
),
),
),
],
);
}
}
class ThemeToggle extends ConsumerStatefulWidget {
const ThemeToggle({
Key? key,
}) : super(key: key);
// final bool externalCallsEnabled;
// final void Function(bool)? onChanged;
@override
ConsumerState<ThemeToggle> createState() => _ThemeToggle();
}
class _ThemeToggle extends ConsumerState<ThemeToggle> {
// late bool externalCallsEnabled;
late String _selectedTheme;
@override
void initState() {
_selectedTheme =
DB.instance.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme")
as String? ??
"light";
super.initState();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
MaterialButton(
splashColor: Colors.transparent,
hoverColor: Colors.transparent,
padding: const EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.light.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
LightColors(),
);
setState(() {
_selectedTheme = "light";
});
},
child: SizedBox(
width: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: _selectedTheme == "light"
? Theme.of(context)
.extension<StackColors>()!
.infoItemIcons
: Theme.of(context).extension<StackColors>()!.popupBG,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: SvgPicture.asset(
Assets.svg.themeLight,
),
),
const SizedBox(
height: 12,
),
Row(
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: "light",
groupValue: _selectedTheme,
onChanged: (newValue) {
if (newValue is String && newValue == "light") {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.light.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
LightColors(),
);
setState(() {
_selectedTheme = "light";
});
}
},
),
),
const SizedBox(
width: 14,
),
Text(
"Light",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
],
),
),
),
const SizedBox(
width: 10,
),
MaterialButton(
splashColor: Colors.transparent,
hoverColor: Colors.transparent,
padding: const EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.oceanBreeze.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
OceanBreezeColors(),
);
setState(() {
_selectedTheme = "oceanBreeze";
});
},
child: SizedBox(
width: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: _selectedTheme == "oceanBreeze"
? Theme.of(context)
.extension<StackColors>()!
.infoItemIcons
: Theme.of(context).extension<StackColors>()!.popupBG,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: SvgPicture.asset(
Assets.svg.themeOcean,
),
),
const SizedBox(
height: 12,
),
Row(
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: "oceanBreeze",
groupValue: _selectedTheme,
onChanged: (newValue) {
if (newValue is String && newValue == "oceanBreeze") {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.oceanBreeze.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
OceanBreezeColors(),
);
setState(() {
_selectedTheme = "oceanBreeze";
});
}
},
),
),
const SizedBox(
width: 14,
),
Text(
"Ocean Breeze",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
],
),
),
),
const SizedBox(
width: 10,
),
MaterialButton(
splashColor: Colors.transparent,
hoverColor: Colors.transparent,
padding: const EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.dark.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
DarkColors(),
);
setState(() {
_selectedTheme = "dark";
});
},
child: SizedBox(
width: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: _selectedTheme == "dark"
? Theme.of(context)
.extension<StackColors>()!
.infoItemIcons
: Theme.of(context).extension<StackColors>()!.popupBG,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: SvgPicture.asset(
Assets.svg.themeDark,
),
),
const SizedBox(
height: 12,
),
Row(
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: "dark",
groupValue: _selectedTheme,
onChanged: (newValue) {
if (newValue is String && newValue == "dark") {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.dark.name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
DarkColors(),
);
setState(() {
_selectedTheme = "dark";
});
}
},
),
),
const SizedBox(
width: 14,
),
Text(
"Dark",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
],
),
),
),
],
);
}
}

View file

@ -1,200 +0,0 @@
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/settings_menu_item.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class SettingsMenu extends ConsumerStatefulWidget {
const SettingsMenu({
Key? key,
required this.onSelectionChanged,
}) : super(key: key);
final void Function(int)?
onSelectionChanged; //is a function that takes in an int and returns void/.;
static const String routeName = "/settingsMenu";
@override
ConsumerState<ConsumerStatefulWidget> createState() => _SettingsMenuState();
}
class _SettingsMenuState extends ConsumerState<SettingsMenu> {
int selectedMenuItem = 0;
void updateSelectedMenuItem(int index) {
setState(() {
selectedMenuItem = index;
});
widget.onSelectionChanged?.call(index);
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingsMenuItem(
icon: SvgPicture.asset(
Assets.svg.polygon,
width: 11,
height: 11,
color: selectedMenuItem == 0
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Colors.transparent,
),
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,
color: selectedMenuItem == 1
? Theme.of(context)
.extension<StackColors>()!
.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<StackColors>()!
.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<StackColors>()!
.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<StackColors>()!
.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<StackColors>()!
.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<StackColors>()!
.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<StackColors>()!
.accentColorBlue
: Colors.transparent,
),
label: "Advanced",
value: 7,
group: selectedMenuItem,
onChanged: updateSelectedMenuItem,
),
],
),
),
],
);
}
}

View file

@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
@ -10,13 +12,16 @@ import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
class CoinWalletsTable extends ConsumerWidget {
const CoinWalletsTable({
Key? key,
required this.walletIds,
required this.coin,
}) : super(key: key);
final List<String> walletIds;
final Coin coin;
@override
Widget build(BuildContext context, WidgetRef ref) {
final walletIds = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getWalletIdsFor(coin: coin)));
return Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
@ -38,7 +43,7 @@ class CoinWalletsTable extends ConsumerWidget {
children: [
if (i != 0)
const SizedBox(
height: 32,
height: 8,
),
Stack(
children: [

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/wallets_view/sub_widgets/empty_wallets.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_wallets.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_wallets.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -27,29 +27,9 @@ class _MyStackViewState extends ConsumerState<MyStackView> {
return Background(
child: Column(
children: [
DesktopAppBar(
const DesktopAppBar(
isCompactHeight: true,
leading: Row(
children: [
const SizedBox(
width: 24,
),
SizedBox(
width: 32,
height: 32,
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
),
),
const SizedBox(
width: 12,
),
Text(
"My Stack",
style: STextStyles.desktopH3(context),
)
],
),
leading: DesktopMyStackTitle(),
),
Expanded(
child: hasWallets ? const MyWallets() : const EmptyWallets(),
@ -59,3 +39,32 @@ class _MyStackViewState extends ConsumerState<MyStackView> {
);
}
}
class DesktopMyStackTitle extends StatelessWidget {
const DesktopMyStackTitle({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
const SizedBox(
width: 24,
),
SizedBox(
width: 32,
height: 32,
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
),
),
const SizedBox(
width: 12,
),
Text(
"My Stack",
style: STextStyles.desktopH3(context),
)
],
);
}
}

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/desktop_favorite_wallets.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_summary_table.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/desktop_favorite_wallets.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_summary_table.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';

View file

@ -1,7 +1,7 @@
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/coin_wallets_table.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/coin_wallets_table.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
@ -23,6 +23,7 @@ class WalletSummaryTable extends ConsumerStatefulWidget {
class _WalletTableState extends ConsumerState<WalletSummaryTable> {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final providersByCoin = ref
.watch(
walletsChangeNotifierProvider.select(
@ -35,72 +36,75 @@ class _WalletTableState extends ConsumerState<WalletSummaryTable> {
return TableView(
rows: [
for (int i = 0; i < providersByCoin.length; i++)
TableViewRow(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
cells: [
TableViewCell(
flex: 4,
child: Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: providersByCoin[i].key),
width: 28,
height: 28,
Builder(
builder: (context) {
final providers = ref.watch(walletsChangeNotifierProvider.select(
(value) => value
.getManagerProvidersForCoin(providersByCoin[i].key)));
return TableViewRow(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
cells: [
TableViewCell(
flex: 4,
child: Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: providersByCoin[i].key),
width: 28,
height: 28,
),
const SizedBox(
width: 10,
),
Text(
providersByCoin[i].key.prettyName,
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
)
],
),
const SizedBox(
width: 10,
),
Text(
providersByCoin[i].key.prettyName,
),
TableViewCell(
flex: 4,
child: Text(
providers.length == 1
? "${providers.length} wallet"
: "${providers.length} wallets",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
.textSubtitle1,
),
)
],
),
),
TableViewCell(
flex: 4,
child: Text(
providersByCoin[i].value.length == 1
? "${providersByCoin[i].value.length} wallet"
: "${providersByCoin[i].value.length} wallets",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
),
),
TableViewCell(
flex: 6,
child: TablePriceInfo(
TableViewCell(
flex: 6,
child: TablePriceInfo(
coin: providersByCoin[i].key,
),
),
],
expandingChild: CoinWalletsTable(
coin: providersByCoin[i].key,
),
),
],
expandingChild: CoinWalletsTable(
walletIds: ref.watch(
walletsChangeNotifierProvider.select(
(value) => value.getWalletIdsFor(
coin: providersByCoin[i].key,
),
),
),
),
)
);
},
),
],
);
}

View file

@ -8,12 +8,12 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/delete_wallet_button.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/my_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/network_info_button.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/recent_desktop_transactions.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/network_info_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/recent_desktop_transactions.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_button.dart';
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
@ -25,7 +25,6 @@ import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
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';
@ -60,7 +59,6 @@ class DesktopWalletView extends ConsumerStatefulWidget {
class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
late final TextEditingController controller;
late final String walletId;
late final EventBus eventBus;
late final bool _shouldDisableAutoSyncOnLogOut;
@ -75,8 +73,9 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
}
Future<void> _logout() async {
final managerProvider =
ref.read(walletsChangeNotifierProvider).getManagerProvider(walletId);
final managerProvider = ref
.read(walletsChangeNotifierProvider)
.getManagerProvider(widget.walletId);
if (_shouldDisableAutoSyncOnLogOut) {
// disable auto sync if it was enabled only when loading wallet
ref.read(managerProvider).shouldAutoSync = false;
@ -96,7 +95,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
_cnLoadingService.loadAll(ref,
coin: ref
.read(walletsChangeNotifierProvider)
.getManager(walletId)
.getManager(widget.walletId)
.coin);
} else {
Logging.instance.log("User does not want to use external calls",
@ -105,8 +104,9 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
}
void _onExchangePressed(BuildContext context) async {
final managerProvider =
ref.read(walletsChangeNotifierProvider).getManagerProvider(walletId);
final managerProvider = ref
.read(walletsChangeNotifierProvider)
.getManagerProvider(widget.walletId);
unawaited(_cnLoadingService.loadAll(ref));
final coin = ref.read(managerProvider).coin;
@ -128,7 +128,6 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
} else {
ref.read(currentExchangeNameStateProvider.state).state =
ChangeNowExchange.exchangeName;
final walletId = ref.read(managerProvider).walletId;
ref.read(prefsChangeNotifierProvider).exchangeRateType =
ExchangeRateType.estimated;
@ -161,7 +160,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
Navigator.of(context).pushNamed(
WalletInitiatedExchangeView.routeName,
arguments: Tuple3(
walletId,
widget.walletId,
coin,
_loadCNData,
),
@ -172,8 +171,9 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
}
Future<void> attemptAnonymize() async {
final managerProvider =
ref.read(walletsChangeNotifierProvider).getManagerProvider(walletId);
final managerProvider = ref
.read(walletsChangeNotifierProvider)
.getManagerProvider(widget.walletId);
bool shouldPop = false;
unawaited(
@ -284,9 +284,9 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
@override
void initState() {
controller = TextEditingController();
walletId = widget.walletId;
final managerProvider =
ref.read(walletsChangeNotifierProvider).getManagerProvider(walletId);
final managerProvider = ref
.read(walletsChangeNotifierProvider)
.getManagerProvider(widget.walletId);
controller.text = ref.read(managerProvider).walletName;
@ -307,13 +307,19 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)));
.select((value) => value.getManager(widget.walletId)));
final coin = manager.coin;
final managerProvider = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManagerProvider(walletId)));
.select((value) => value.getManagerProvider(widget.walletId)));
return DesktopScaffold(
appBar: DesktopAppBar(
@ -356,47 +362,8 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
minWidth: 48,
),
child: IntrinsicWidth(
child: HoverTextField(
controller: controller,
style: STextStyles.desktopH3(context),
readOnly: true,
onDone: () async {
final currentWalletName =
ref.read(managerProvider).walletName;
final newName = controller.text;
if (newName != currentWalletName) {
final success = await ref
.read(walletsServiceChangeNotifierProvider)
.renameWallet(
from: currentWalletName,
to: newName,
shouldNotifyListeners: true,
);
if (success) {
ref
.read(walletsChangeNotifierProvider)
.getManager(walletId)
.walletName = newName;
unawaited(
showFloatingFlushBar(
type: FlushBarType.success,
message: "Wallet renamed",
context: context,
),
);
} else {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message:
"Wallet named \"$newName\" already exists",
context: context,
),
);
controller.text = currentWalletName;
}
}
},
child: DesktopWalletNameField(
walletId: widget.walletId,
),
),
),
@ -404,20 +371,20 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
Row(
children: [
NetworkInfoButton(
walletId: walletId,
walletId: widget.walletId,
eventBus: eventBus,
),
const SizedBox(
width: 2,
),
WalletKeysButton(
walletId: walletId,
walletId: widget.walletId,
),
const SizedBox(
width: 2,
),
DeleteWalletButton(
walletId: walletId,
walletId: widget.walletId,
),
const SizedBox(
width: 12,
@ -447,7 +414,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
width: 10,
),
DesktopWalletSummary(
walletId: walletId,
walletId: widget.walletId,
managerProvider: managerProvider,
initialSyncStatus: ref.watch(managerProvider
.select((value) => value.isRefreshing))
@ -557,7 +524,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
SizedBox(
width: 450,
child: MyWallet(
walletId: walletId,
walletId: widget.walletId,
),
),
const SizedBox(
@ -565,7 +532,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
),
Expanded(
child: RecentDesktopTransactions(
walletId: walletId,
walletId: widget.walletId,
),
),
],

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';

View file

@ -1,7 +1,7 @@
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/sub_widgets/desktop_delete_wallet_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';

View file

@ -1,6 +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/sub_widgets/delete_wallet_keys_popup.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';

View file

@ -134,8 +134,10 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).extension<StackColors>()!.background,
width: 2,
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
width: 1,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,

View file

@ -11,9 +11,9 @@ import 'package:stackwallet/models/send_view_auto_fill_data.dart';
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.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';
@ -71,16 +71,16 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
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();
String? _note;
Decimal? _amountToSend;
Decimal? _cachedAmountToSend;
String? _address;
@ -255,7 +255,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
sendToController.text = "";
cryptoAmountController.text = "";
baseAmountController.text = "";
noteController.text = "";
});
},
),
@ -325,7 +324,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
context,
rootNavigator: true,
).pop();
txData["note"] = noteController.text;
txData["note"] = _note;
txData["address"] = _address;
unawaited(
@ -633,9 +632,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
// autofill notes field
if (results["message"] != null) {
noteController.text = results["message"]!;
_note = results["message"]!;
} else if (results["label"] != null) {
noteController.text = results["label"]!;
_note = results["label"]!;
}
// autofill amount field
@ -783,7 +782,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
sendToController = TextEditingController();
cryptoAmountController = TextEditingController();
baseAmountController = TextEditingController();
noteController = TextEditingController();
// feeController = TextEditingController();
onCryptoAmountChanged = _cryptoAmountChanged;
@ -828,10 +826,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
sendToController.dispose();
cryptoAmountController.dispose();
baseAmountController.dispose();
noteController.dispose();
// feeController.dispose();
_noteFocusNode.dispose();
_addressFocusNode.dispose();
_cryptoFocus.dispose();
_baseFocus.dispose();
@ -1298,73 +1294,73 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
}
},
),
const SizedBox(
height: 20,
),
Text(
"Note (optional)",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
textAlign: TextAlign.left,
),
const SizedBox(
height: 10,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
minLines: 1,
maxLines: 5,
autocorrect: Util.isDesktop ? false : true,
enableSuggestions: Util.isDesktop ? false : true,
controller: noteController,
focusNode: _noteFocusNode,
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
),
onChanged: (_) => setState(() {}),
decoration: standardInputDecoration(
"Type something...",
_noteFocusNode,
context,
desktopMed: true,
).copyWith(
contentPadding: const EdgeInsets.only(
left: 16,
top: 11,
bottom: 12,
right: 5,
),
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: 20,
// ),
// Text(
// "Note (optional)",
// style: STextStyles.desktopTextExtraSmall(context).copyWith(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textFieldActiveSearchIconRight,
// ),
// textAlign: TextAlign.left,
// ),
// const SizedBox(
// height: 10,
// ),
// ClipRRect(
// borderRadius: BorderRadius.circular(
// Constants.size.circularBorderRadius,
// ),
// child: TextField(
// minLines: 1,
// maxLines: 5,
// autocorrect: Util.isDesktop ? false : true,
// enableSuggestions: Util.isDesktop ? false : true,
// controller: noteController,
// focusNode: _noteFocusNode,
// style: STextStyles.desktopTextExtraSmall(context).copyWith(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textFieldActiveText,
// height: 1.8,
// ),
// onChanged: (_) => setState(() {}),
// decoration: standardInputDecoration(
// "Type something...",
// _noteFocusNode,
// context,
// desktopMed: true,
// ).copyWith(
// contentPadding: const EdgeInsets.only(
// left: 16,
// top: 11,
// bottom: 12,
// right: 5,
// ),
// 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: 20,
),

View file

@ -2,7 +2,7 @@ import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_balance_toggle_button.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_balance_toggle_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';

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_send.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/send_receive_tab_menu.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/send_receive_tab_menu.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -63,24 +63,25 @@ class _MyWalletState extends State<MyWallet> {
),
),
),
child: IndexedStack(
index: _selectedIndex,
children: [
Padding(
key: const Key("desktopSendViewPortKey"),
padding: const EdgeInsets.all(20),
child: DesktopSend(
walletId: widget.walletId,
),
child: AnimatedCrossFade(
firstChild: 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,
),
),
secondChild: Padding(
key: const Key("desktopReceiveViewPortKey"),
padding: const EdgeInsets.all(20),
child: DesktopReceive(
walletId: widget.walletId,
),
],
),
crossFadeState: _selectedIndex == 0
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 250),
),
),
],

View file

@ -0,0 +1,165 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
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<SendReceiveTabMenu> createState() => _SendReceiveTabMenuState();
}
class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
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: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () => _onChanged(0),
child: Container(
color: Colors.transparent,
child: Column(
children: [
const SizedBox(
height: 16,
),
AnimatedCrossFade(
firstChild: Text(
"Send",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
"Send",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
crossFadeState: _selectedIndex == 0
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 250),
),
const SizedBox(
height: 19,
),
Container(
height: 2,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
),
),
],
),
),
),
),
),
Expanded(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () => _onChanged(1),
child: Container(
color: Colors.transparent,
child: Column(
children: [
const SizedBox(
height: 16,
),
AnimatedCrossFade(
firstChild: Text(
"Receive",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
"Receive",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
crossFadeState: _selectedIndex == 1
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 250),
),
const SizedBox(
height: 19,
),
Stack(
children: [
Container(
height: 2,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
),
),
AnimatedSlide(
offset: Offset(_selectedIndex == 0 ? -1 : 0, 0),
duration: const Duration(milliseconds: 250),
child: Container(
height: 2,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue),
),
),
],
),
],
),
),
),
),
),
],
);
}
}

View file

@ -4,12 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.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/desktop/desktop_dialog.dart';

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';

View file

@ -4,11 +4,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.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/desktop/desktop_dialog.dart';

View file

@ -4,7 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/forgotten_passphrase_restore_from_swb.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/providers.dart';
@ -23,9 +24,11 @@ import 'package:zxcvbn/zxcvbn.dart';
class CreatePasswordView extends ConsumerStatefulWidget {
const CreatePasswordView({
Key? key,
this.restoreFromSWB = false,
}) : super(key: key);
static const String routeName = "/createPasswordDesktop";
final bool restoreFromSWB;
@override
ConsumerState<CreatePasswordView> createState() => _CreatePasswordViewState();
@ -84,7 +87,9 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
// load default nodes now as node service requires storage handler to exist
await ref.read(nodeServiceChangeNotifierProvider).updateDefaults();
if (!widget.restoreFromSWB) {
await ref.read(nodeServiceChangeNotifierProvider).updateDefaults();
}
} catch (e) {
unawaited(showFloatingFlushBar(
type: FlushBarType.warning,
@ -95,15 +100,28 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
}
if (mounted) {
unawaited(Navigator.of(context)
.pushReplacementNamed(DesktopHomeView.routeName));
if (widget.restoreFromSWB) {
unawaited(
Navigator.of(context).pushNamed(
ForgottenPassphraseRestoreFromSWB.routeName,
),
);
} else {
unawaited(
Navigator.of(context).pushReplacementNamed(
DesktopHomeView.routeName,
),
);
}
}
unawaited(showFloatingFlushBar(
type: FlushBarType.success,
message: "Your password is set up",
context: context,
));
if (!widget.restoreFromSWB) {
unawaited(showFloatingFlushBar(
type: FlushBarType.success,
message: "Your password is set up",
context: context,
));
}
}
@override

View file

@ -0,0 +1,195 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hive/hive.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/intro_view.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/stack_file_system.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
class DeletePasswordWarningView extends ConsumerStatefulWidget {
const DeletePasswordWarningView({
Key? key,
required this.shouldCreateNew,
}) : super(key: key);
static const String routeName = "/deletePasswordWarning";
final bool shouldCreateNew;
@override
ConsumerState<DeletePasswordWarningView> createState() =>
_ForgotPasswordDesktopViewState();
}
class _ForgotPasswordDesktopViewState
extends ConsumerState<DeletePasswordWarningView> {
bool _deleteInProgress = false;
Future<bool> _deleteStack() async {
final appRoot = await StackFileSystem.applicationRootDirectory();
try {
await Hive.close();
await appRoot.delete(recursive: true);
await DB.instance.init();
} catch (e, s) {
Logging.instance.log(
"$e\n$s",
level: LogLevel.Fatal,
);
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return DesktopScaffold(
appBar: DesktopAppBar(
leading: AppBarBackButton(
onPressed: () async {
if (mounted && !_deleteInProgress) {
Navigator.of(context).pop();
}
},
),
isCompactHeight: false,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 480,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
Assets.svg.stackIcon(context),
width: 100,
),
const SizedBox(
height: 42,
),
Text(
"Warning!",
style: STextStyles.desktopH1(context),
),
const SizedBox(
height: 24,
),
SizedBox(
width: 480,
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
TextSpan(
text: "To ",
style: STextStyles.desktopTextSmall(context),
),
TextSpan(
text: widget.shouldCreateNew
? "create a new Stack"
: "restore from backup",
style: STextStyles.desktopTextSmallBold(context),
),
TextSpan(
text: ", we need to ",
style: STextStyles.desktopTextSmall(context),
),
TextSpan(
text: "delete your old wallets",
style: STextStyles.desktopTextSmallBold(context),
),
TextSpan(
text:
". All wallets will be lost. If you have not written down your recovery phrase for EACH wallet, you may be in danger of losing funds. Continue?",
style: STextStyles.desktopTextSmall(context),
),
],
),
),
),
const SizedBox(
height: 48,
),
PrimaryButton(
label: "Delete and continue",
enabled: !_deleteInProgress,
onPressed: () async {
final shouldDelete = !_deleteInProgress;
setState(() {
_deleteInProgress = true;
});
if (shouldDelete) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.info,
message: "Deleting wallet...",
context: context,
),
);
final success = await _deleteStack();
if (success) {
await showFloatingFlushBar(
type: FlushBarType.success,
message: "Wallet deleted",
context: context,
);
if (mounted) {
await Navigator.of(context).pushNamedAndRemoveUntil(
IntroView.routeName,
(_) => false,
);
}
} else {
await showFloatingFlushBar(
type: FlushBarType.warning,
message: "Something broke badly. Contact developer",
context: context,
);
setState(() {
_deleteInProgress = false;
});
}
}
},
),
const SizedBox(
height: 24,
),
SecondaryButton(
label: "Take me back!",
enabled: !_deleteInProgress,
onPressed: () {
Navigator.of(context).pop();
},
),
const SizedBox(
height: kDesktopAppBarHeight,
),
],
),
),
],
),
);
}
}

View file

@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/forgot_password_desktop_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/forgot_password_desktop_view.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/utilities/assets.dart';

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/password/delete_password_warning_view.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -74,18 +75,26 @@ class _ForgotPasswordDesktopViewState extends State<ForgotPasswordDesktopView> {
height: 48,
),
PrimaryButton(
label: "Create new wallet",
label: "Create new Stack",
onPressed: () {
// // todo delete everything and start fresh?
const shouldCreateNew = true;
Navigator.of(context).pushNamed(
DeletePasswordWarningView.routeName,
arguments: shouldCreateNew,
);
},
),
const SizedBox(
height: 24,
),
SecondaryButton(
label: "Restore from backup",
label: "Restore from Stack backup",
onPressed: () {
// todo SWB restore
const shouldCreateNew = false;
Navigator.of(context).pushNamed(
DeletePasswordWarningView.routeName,
arguments: shouldCreateNew,
);
},
),
const SizedBox(

View file

@ -0,0 +1,406 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/create_password_view.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.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/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:tuple/tuple.dart';
class ForgottenPassphraseRestoreFromSWB extends ConsumerStatefulWidget {
const ForgottenPassphraseRestoreFromSWB({Key? key}) : super(key: key);
static const String routeName = "/forgottenPassphraseRestoreFromSWB";
@override
ConsumerState<ForgottenPassphraseRestoreFromSWB> createState() =>
_ForgottenPassphraseRestoreFromSWBState();
}
class _ForgottenPassphraseRestoreFromSWBState
extends ConsumerState<ForgottenPassphraseRestoreFromSWB> {
late final TextEditingController fileLocationController;
late final TextEditingController passwordController;
late final FocusNode passwordFocusNode;
late final SWBFileSystem stackFileSystem;
bool hidePassword = true;
bool _enableButton = false;
Future<void> restore() async {
final String fileToRestore = fileLocationController.text;
final String passphrase = passwordController.text;
if (!(await File(fileToRestore).exists())) {
await showFloatingFlushBar(
type: FlushBarType.warning,
message: "Backup file does not exist",
context: context,
);
return;
}
bool shouldPop = false;
unawaited(
showDialog<dynamic>(
barrierDismissible: false,
context: context,
builder: (_) => WillPopScope(
onWillPop: () async {
return shouldPop;
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Material(
color: Colors.transparent,
child: Center(
child: Text(
"Decrypting Stack backup file",
style: STextStyles.pageTitleH2(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.textWhite,
),
),
),
),
const SizedBox(
height: 64,
),
const Center(
child: LoadingIndicator(
width: 100,
),
),
],
),
),
),
);
final String? jsonString = await compute(
SWB.decryptStackWalletWithPassphrase,
Tuple2(fileToRestore, passphrase),
debugLabel: "stack wallet decryption compute",
);
if (mounted) {
// pop LoadingIndicator
shouldPop = true;
Navigator.of(context).pop();
passwordController.text = "";
if (jsonString == null) {
await showFloatingFlushBar(
type: FlushBarType.warning,
message: "Failed to decrypt backup file",
context: context,
);
return;
}
ref.read(walletsChangeNotifierProvider);
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (context) {
return DesktopDialog(
maxWidth: 580,
maxHeight: double.infinity,
child: Padding(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Restoring Stack wallet",
style: STextStyles.desktopH3(context),
),
],
),
const SizedBox(
height: 44,
),
StackRestoreProgressView(
jsonString: jsonString,
shouldPushToHome: true,
),
],
),
),
);
},
);
// await Navigator.of(context).push(
// RouteGenerator.getRoute(
// builder: (_) => StackRestoreProgressView(
// jsonString: jsonString,
// ),
// ),
// );
}
}
@override
void initState() {
stackFileSystem = SWBFileSystem();
fileLocationController = TextEditingController();
passwordController = TextEditingController();
passwordFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
fileLocationController.dispose();
passwordController.dispose();
passwordFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return DesktopScaffold(
appBar: DesktopAppBar(
leading: AppBarBackButton(
onPressed: () async {
await (ref.read(secureStoreProvider).store as DesktopSecureStore)
.close();
ref.refresh(secureStoreProvider);
ref.refresh(storageCryptoHandlerProvider);
await Hive.deleteBoxFromDisk(DB.boxNameDesktopData);
await DB.instance.init();
if (mounted) {
Navigator.of(context)
.popUntil(ModalRoute.withName(CreatePasswordView.routeName));
Navigator.of(context).pop();
}
},
),
isCompactHeight: false,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 480,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Restore from backup",
style: STextStyles.desktopH1(context),
),
const SizedBox(
height: 32,
),
Text(
"Use your Stack wallet backup file to restore your wallets, address book, and wallet preferences.",
textAlign: TextAlign.center,
style: STextStyles.desktopTextSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 40,
),
GestureDetector(
onTap: () async {
try {
await stackFileSystem.prepareStorage();
if (mounted) {
await stackFileSystem.openFile(context);
}
if (mounted) {
setState(() {
fileLocationController.text =
stackFileSystem.filePath ?? "";
});
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Error);
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: IgnorePointer(
child: TextField(
autocorrect: false,
enableSuggestions: false,
controller: fileLocationController,
style: STextStyles.field(context),
decoration: InputDecoration(
hintText: "Choose file...",
hintStyle: STextStyles.desktopTextFieldLabel(context),
suffixIcon: SizedBox(
height: 70,
child: UnconstrainedBox(
child: Row(
children: [
const SizedBox(
width: 24,
),
SvgPicture.asset(
Assets.svg.folder,
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
width: 24,
height: 24,
),
const SizedBox(
width: 12,
),
],
),
),
),
),
key: const Key("restoreFromFileLocationTextFieldKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {
setState(() {
_enableButton =
passwordController.text.isNotEmpty &&
fileLocationController.text.isNotEmpty;
});
},
),
),
),
),
const SizedBox(
height: 16,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: const Key("restoreFromFilePasswordFieldKey"),
focusNode: passwordFocusNode,
controller: passwordController,
style: STextStyles.desktopTextMedium(context).copyWith(
height: 2,
),
obscureText: hidePassword,
enableSuggestions: false,
autocorrect: false,
decoration: standardInputDecoration(
"Enter passphrase",
passwordFocusNode,
context,
).copyWith(
suffixIcon: UnconstrainedBox(
child: SizedBox(
height: 70,
child: Row(
children: [
const SizedBox(
width: 24,
),
GestureDetector(
key: const Key(
"restoreFromFilePasswordFieldShowPasswordButtonKey"),
onTap: () async {
setState(() {
hidePassword = !hidePassword;
});
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: SvgPicture.asset(
hidePassword
? Assets.svg.eye
: Assets.svg.eyeSlash,
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
width: 24,
height: 24,
),
),
),
const SizedBox(
width: 12,
),
],
),
),
),
),
onChanged: (newValue) {
setState(() {
_enableButton = passwordController.text.isNotEmpty &&
fileLocationController.text.isNotEmpty;
});
},
),
),
const SizedBox(
height: 24,
),
PrimaryButton(
label: "Restore",
enabled: _enableButton,
onPressed: () {
restore();
},
),
const SizedBox(
height: kDesktopAppBarHeight,
),
],
),
),
],
),
);
}
}

View file

@ -1,14 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/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/backup_and_restore_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/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/pages_desktop_specific/settings/settings_menu.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/language_settings/language_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/nodes_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/security_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/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';
@ -26,7 +26,6 @@ class DesktopSettingsView extends ConsumerStatefulWidget {
}
class _DesktopSettingsViewState extends ConsumerState<DesktopSettingsView> {
int currentViewIndex = 0;
final List<Widget> contentViews = [
const Navigator(
key: Key("settingsBackupRestoreDesktopKey"),
@ -70,12 +69,6 @@ class _DesktopSettingsViewState extends ConsumerState<DesktopSettingsView> {
), //advanced
];
void onMenuSelectionChanged(int newIndex) {
setState(() {
currentViewIndex = newIndex;
});
}
@override
Widget build(BuildContext context) {
return DesktopScaffold(
@ -83,28 +76,36 @@ class _DesktopSettingsViewState extends ConsumerState<DesktopSettingsView> {
appBar: DesktopAppBar(
isCompactHeight: true,
leading: Row(
children: [
const SizedBox(
children: const [
SizedBox(
width: 24,
height: 24,
),
Text(
"Settings",
style: STextStyles.desktopH3(context),
)
DesktopSettingsTitle(),
],
),
),
body: Row(
children: [
SettingsMenu(
onSelectionChanged: onMenuSelectionChanged,
),
const SettingsMenu(),
Expanded(
child: contentViews[currentViewIndex],
child: contentViews[
ref.watch(selectedSettingsMenuItemStateProvider.state).state],
),
],
),
);
}
}
class DesktopSettingsTitle extends StatelessWidget {
const DesktopSettingsTitle({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
"Settings",
style: STextStyles.desktopH3(context),
);
}
}

View file

@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu_item.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
final selectedSettingsMenuItemStateProvider = StateProvider<int>((_) => 0);
class SettingsMenu extends ConsumerStatefulWidget {
const SettingsMenu({
Key? key,
}) : super(key: key);
@override
ConsumerState<ConsumerStatefulWidget> createState() => _SettingsMenuState();
}
class _SettingsMenuState extends ConsumerState<SettingsMenu> {
final List<String> labels = [
"Backup and restore",
"Security",
"Currency",
"Language",
"Nodes",
"Syncing preferences",
"Appearance",
"Advanced",
];
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < labels.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
children: [
if (i > 0)
const SizedBox(
height: 2,
),
SettingsMenuItem<int>(
icon: SvgPicture.asset(
Assets.svg.polygon,
width: 11,
height: 11,
color: ref
.watch(selectedSettingsMenuItemStateProvider
.state)
.state ==
i
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Colors.transparent,
),
label: labels[i],
value: i,
group: ref
.watch(selectedSettingsMenuItemStateProvider.state)
.state,
onChanged: (newValue) => ref
.read(selectedSettingsMenuItemStateProvider.state)
.state = newValue,
),
],
)
// SettingsMenuItem(
// icon: SvgPicture.asset(
// Assets.svg.polygon,
// width: 11,
// height: 11,
// color: selectedMenuItem == 0
// ? Theme.of(context)
// .extension<StackColors>()!
// .accentColorBlue
// : Colors.transparent,
// ),
// 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,
// color: selectedMenuItem == 1
// ? Theme.of(context)
// .extension<StackColors>()!
// .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<StackColors>()!
// .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<StackColors>()!
// .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<StackColors>()!
// .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<StackColors>()!
// .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<StackColors>()!
// .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<StackColors>()!
// .accentColorBlue
// : Colors.transparent,
// ),
// label: "Advanced",
// value: 7,
// group: selectedMenuItem,
// onChanged: updateSelectedMenuItem,
// ),
],
),
),
],
);
}
}

View file

@ -1,8 +1,8 @@
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/pages_desktop_specific/home/settings_menu/advanced_settings/stack_privacy_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/debug_info_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -11,8 +11,6 @@ import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart'
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'debug_info_dialog.dart';
class AdvancedSettings extends ConsumerStatefulWidget {
const AdvancedSettings({Key? key}) : super(key: key);

View file

@ -0,0 +1,271 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.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/color_theme.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class AppearanceOptionSettings extends ConsumerStatefulWidget {
const AppearanceOptionSettings({Key? key}) : super(key: key);
static const String routeName = "/settingsMenuAppearance";
@override
ConsumerState<AppearanceOptionSettings> createState() =>
_AppearanceOptionSettings();
}
class _AppearanceOptionSettings
extends ConsumerState<AppearanceOptionSettings> {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
right: 30,
),
child: RoundedWhiteContainer(
radiusMultiplier: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: 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<StackColors>()!
.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<StackColors>()!
.textDark),
textAlign: TextAlign.left,
),
],
),
),
const Padding(
padding: EdgeInsets.all(10),
child: ThemeToggle(),
),
],
),
),
),
],
);
}
}
class ThemeToggle extends ConsumerStatefulWidget {
const ThemeToggle({
Key? key,
}) : super(key: key);
@override
ConsumerState<ThemeToggle> createState() => _ThemeToggle();
}
class _ThemeToggle extends ConsumerState<ThemeToggle> {
String assetNameFor(ThemeType type) {
switch (type) {
case ThemeType.light:
return Assets.svg.themeLight;
case ThemeType.dark:
return Assets.svg.themeDark;
case ThemeType.oceanBreeze:
return Assets.svg.themeOcean;
}
}
@override
Widget build(BuildContext context) {
return Row(
children: [
for (int i = 0; i < ThemeType.values.length; i++)
Row(
mainAxisSize: MainAxisSize.min,
children: [
if (i > 0)
const SizedBox(
width: 10,
),
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
if (ref.read(colorThemeProvider.state).state.themeType !=
ThemeType.values[i]) {
DB.instance.put<dynamic>(
boxName: DB.boxNameTheme,
key: "colorScheme",
value: ThemeType.values[i].name,
);
ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
ThemeType.values[i].colorTheme);
}
},
child: Container(
width: 200,
color: Colors.transparent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: ref
.read(colorThemeProvider.state)
.state
.themeType ==
ThemeType.values[i]
? Theme.of(context)
.extension<StackColors>()!
.infoItemIcons
: Theme.of(context)
.extension<StackColors>()!
.popupBG,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: SvgPicture.asset(
assetNameFor(ThemeType.values[i]),
),
),
const SizedBox(
height: 12,
),
Row(
children: [
SizedBox(
width: 20,
height: 20,
child: Radio<ThemeType>(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: ThemeType.values[i],
groupValue: ref
.read(colorThemeProvider.state)
.state
.themeType,
onChanged: (_) {},
),
),
const SizedBox(
width: 14,
),
Text(
ThemeType.values[i].prettyName,
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
],
),
),
),
)
],
),
],
);
}
}

View file

@ -6,8 +6,8 @@ import 'package:intl/intl.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/create_auto_backup.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/enable_backup_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/create_auto_backup.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/enable_backup_dialog.dart';
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
import 'package:stackwallet/providers/global/locale_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/create_auto_backup.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/create_auto_backup.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';

View file

@ -1,7 +1,7 @@
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/settings_menu/language_settings/language_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/language_settings/language_dialog.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';

View file

@ -33,7 +33,7 @@ class SettingsMenuItem<T> extends StatelessWidget {
onChanged(value);
},
child: Padding(
padding: EdgeInsets.symmetric(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 16,
),

View file

@ -1,5 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_menu.dart';
final currentDesktopMenuItemProvider =
StateProvider<DesktopMenuItemId>((ref) => DesktopMenuItemId.myStack);

View file

@ -84,33 +84,34 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_deta
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/desktop_address_book.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart';
import 'package:stackwallet/pages_desktop_specific/forgot_password_desktop_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/desktop_address_book.dart';
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/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_notifications_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/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/backup_and_restore_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/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/pages_desktop_specific/home/support_and_about_view/desktop_about_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_support_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
import 'package:stackwallet/pages_desktop_specific/notifications/desktop_notifications_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/create_password_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/delete_password_warning_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/forgot_password_desktop_view.dart';
import 'package:stackwallet/pages_desktop_specific/password/forgotten_passphrase_restore_from_swb.dart';
import 'package:stackwallet/pages_desktop_specific/settings/desktop_settings_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_about_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_support_view.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/language_settings/language_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/nodes_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/security_settings.dart';
import 'package:stackwallet/pages_desktop_specific/settings/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';
@ -1000,6 +1001,17 @@ class RouteGenerator {
// == Desktop specific routes ============================================
case CreatePasswordView.routeName:
if (args is bool) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => CreatePasswordView(
restoreFromSWB: args,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const CreatePasswordView(),
@ -1011,6 +1023,26 @@ class RouteGenerator {
builder: (_) => const ForgotPasswordDesktopView(),
settings: RouteSettings(name: settings.name));
case ForgottenPassphraseRestoreFromSWB.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const ForgottenPassphraseRestoreFromSWB(),
settings: RouteSettings(name: settings.name));
case DeletePasswordWarningView.routeName:
if (args is bool) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => DeletePasswordWarningView(
shouldCreateNew: args,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case DesktopHomeView.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
@ -1061,14 +1093,6 @@ class RouteGenerator {
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case SettingsMenu.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => SettingsMenu(
onSelectionChanged: (int) {},
),
settings: RouteSettings(name: settings.name));
case BackupRestoreSettings.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,

View file

@ -1519,22 +1519,28 @@ class BitcoinWallet extends CoinServiceAPI {
Logging.instance
.log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.bitcoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.bitcoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.bitcoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.bitcoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
}

View file

@ -1405,22 +1405,28 @@ class BitcoinCashWallet extends CoinServiceAPI {
Logging.instance
.log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.bitcoincash:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.bitcoincashTestnet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.bitcoincash:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.bitcoincashTestnet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
}

View file

@ -1268,22 +1268,28 @@ class DogecoinWallet extends CoinServiceAPI {
Logging.instance
.log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.dogecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.dogecoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.dogecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.dogecoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
}

View file

@ -2148,32 +2148,29 @@ class FiroWallet extends CoinServiceAPI {
Logging.instance
.log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.firo:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.firoTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a FiroWallet using a non firo coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.firo:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.firoTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a FiroWallet using a non firo coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
// if (_networkType == BasicNetworkType.main) {
// if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
// throw Exception("genesis hash does not match!");
// }
// } else if (_networkType == BasicNetworkType.test) {
// if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
// throw Exception("genesis hash does not match!");
// }
// }
}
// this should never fail as overwriting a mnemonic is big bad

View file

@ -1521,23 +1521,29 @@ class LitecoinWallet extends CoinServiceAPI {
Logging.instance
.log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.litecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
print(features['genesis_hash']);
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.litecoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a LitecoinWallet using a non litecoin coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.litecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
print(features['genesis_hash']);
throw Exception("genesis hash does not match main net!");
}
break;
case Coin.litecoinTestNet:
if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
throw Exception("genesis hash does not match test net!");
}
break;
default:
throw Exception(
"Attempted to generate a LitecoinWallet using a non litecoin coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
}

View file

@ -344,27 +344,24 @@ class NamecoinWallet extends CoinServiceAPI {
Logging.instance.log("IS_INTEGRATION_TEST: $integrationTestFlag",
level: LogLevel.Info);
if (!integrationTestFlag) {
final features = await electrumXClient.getServerFeatures();
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.namecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
default:
throw Exception(
"Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}");
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 3));
Logging.instance.log("features: $features", level: LogLevel.Info);
switch (coin) {
case Coin.namecoin:
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
throw Exception("genesis hash does not match main net!");
}
break;
default:
throw Exception(
"Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}");
}
} catch (e, s) {
Logging.instance.log("$e/n$s", level: LogLevel.Info);
}
// if (_networkType == BasicNetworkType.main) {
// if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
// throw Exception("genesis hash does not match main net!");
// }
// } else if (_networkType == BasicNetworkType.test) {
// if (features['genesis_hash'] != GENESIS_HASH_TESTNET) {
// throw Exception("genesis hash does not match test net!");
// }
// }
}
// check to make sure we aren't overwriting a mnemonic
// this should never fail

View file

@ -73,6 +73,17 @@ class Wallets extends ChangeNotifier {
return result;
}
List<ChangeNotifierProvider<Manager>> getManagerProvidersForCoin(Coin coin) {
List<ChangeNotifierProvider<Manager>> result = [];
for (final manager in _managerMap.values) {
if (manager.coin == coin) {
result.add(_managerProviderMap[manager.walletId]
as ChangeNotifierProvider<Manager>);
}
}
return result;
}
ChangeNotifierProvider<Manager> getManagerProvider(String walletId) {
return _managerProviderMap[walletId] as ChangeNotifierProvider<Manager>;
}

View file

@ -37,6 +37,15 @@ abstract class SecureStorageInterface {
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
}
class DesktopSecureStore {
@ -54,6 +63,10 @@ class DesktopSecureStore {
);
}
Future<void> close() async {
await isar.close();
}
Future<String?> read({
required String key,
}) async {
@ -192,6 +205,30 @@ class SecureStorageWrapper implements SecureStorageInterface {
);
}
}
@override
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
if (_isDesktop) {
// return (_store as DesktopSecureStore).deleteAll();
throw UnimplementedError();
} else {
return await (_store as FlutterSecureStorage).deleteAll(
iOptions: iOptions,
aOptions: aOptions,
lOptions: lOptions,
webOptions: webOptions,
mOptions: mOptions,
wOptions: wOptions,
);
}
}
}
// Mock class for testing purposes
@ -252,6 +289,20 @@ class FakeSecureStorage implements SecureStorageInterface {
_store.remove(key);
}
@override
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
_interactions++;
_deletes++;
_store.clear();
}
@override
dynamic get store => throw UnimplementedError();
}

Some files were not shown because too many files have changed in this diff Show more