mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-02-02 11:16:36 +00:00
feat: allow setting the restore/refresh height in xmr/wow wallets
This commit is contained in:
parent
937550cb04
commit
71609c34b0
4 changed files with 360 additions and 1 deletions
|
@ -0,0 +1,238 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../../notifications/show_flush_bar.dart';
|
||||
import '../../../../providers/db/main_db_provider.dart';
|
||||
import '../../../../providers/global/wallets_provider.dart';
|
||||
import '../../../../themes/stack_colors.dart';
|
||||
import '../../../../utilities/constants.dart';
|
||||
import '../../../../utilities/text_styles.dart';
|
||||
import '../../../../utilities/util.dart';
|
||||
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
|
||||
import '../../../../widgets/background.dart';
|
||||
import '../../../../widgets/conditional_parent.dart';
|
||||
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import '../../../../widgets/desktop/primary_button.dart';
|
||||
import '../../../../widgets/icon_widgets/x_icon.dart';
|
||||
import '../../../../widgets/stack_text_field.dart';
|
||||
import '../../../../widgets/textfield_icon_button.dart';
|
||||
|
||||
class EditRefreshHeightView extends ConsumerStatefulWidget {
|
||||
const EditRefreshHeightView({
|
||||
super.key,
|
||||
required this.walletId,
|
||||
});
|
||||
|
||||
static const String routeName = "/editRefreshHeightView";
|
||||
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
ConsumerState<EditRefreshHeightView> createState() =>
|
||||
_EditRefreshHeightViewState();
|
||||
}
|
||||
|
||||
class _EditRefreshHeightViewState extends ConsumerState<EditRefreshHeightView> {
|
||||
late final LibMoneroWallet _wallet;
|
||||
late final TextEditingController _controller;
|
||||
final _focusNode = FocusNode();
|
||||
|
||||
bool _saveLock = false;
|
||||
|
||||
void _save() async {
|
||||
if (_saveLock) return;
|
||||
_saveLock = true;
|
||||
try {
|
||||
String? errMessage;
|
||||
try {
|
||||
final newHeight = int.tryParse(_controller.text);
|
||||
if (newHeight != null && newHeight >= 0) {
|
||||
await _wallet.info.updateRestoreHeight(
|
||||
newRestoreHeight: newHeight,
|
||||
isar: ref.read(mainDBProvider).isar,
|
||||
);
|
||||
_wallet.libMoneroWallet!.setRefreshFromBlockHeight(newHeight);
|
||||
} else {
|
||||
errMessage = "Invalid height: ${_controller.text}";
|
||||
}
|
||||
} catch (e) {
|
||||
errMessage = e.toString();
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
if (errMessage == null) {
|
||||
Navigator.of(context).pop();
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
message: "Refresh height updated",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: errMessage,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_saveLock = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_wallet = ref.read(pWallets).getWallet(widget.walletId) as LibMoneroWallet;
|
||||
_controller = TextEditingController()
|
||||
..text = _wallet.libMoneroWallet!.getRefreshFromBlockHeight().toString();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConditionalParent(
|
||||
condition: Util.isDesktop,
|
||||
builder: (child) {
|
||||
return DesktopDialog(
|
||||
maxWidth: 500,
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: child,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 32,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ConditionalParent(
|
||||
condition: !Util.isDesktop,
|
||||
builder: (child) {
|
||||
return Background(
|
||||
child: Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Restore height",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key("restoreHeightFieldKey"),
|
||||
controller: _controller,
|
||||
focusNode: _focusNode,
|
||||
style: Util.isDesktop
|
||||
? STextStyles.desktopTextMedium(context).copyWith(
|
||||
height: 2,
|
||||
)
|
||||
: STextStyles.field(context),
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
autofocus: true,
|
||||
onSubmitted: (_) => _save(),
|
||||
onChanged: (_) => setState(() {}),
|
||||
decoration: standardInputDecoration(
|
||||
"Restore height",
|
||||
_focusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: _controller.text.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: ConditionalParent(
|
||||
condition: Util.isDesktop,
|
||||
builder: (child) => SizedBox(
|
||||
height: 70,
|
||||
child: child,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
_controller.text = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Util.isDesktop
|
||||
? const SizedBox(
|
||||
height: 70,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
Util.isDesktop
|
||||
? const SizedBox(
|
||||
height: 32,
|
||||
)
|
||||
: const Spacer(),
|
||||
PrimaryButton(
|
||||
label: "Save",
|
||||
onPressed: _save,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import '../../../../utilities/constants.dart';
|
|||
import '../../../../utilities/text_styles.dart';
|
||||
import '../../../../wallets/isar/models/wallet_info.dart';
|
||||
import '../../../../wallets/isar/providers/wallet_info_provider.dart';
|
||||
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/multi_address_interface.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/rbf_interface.dart';
|
||||
|
@ -32,6 +33,7 @@ import '../../../../widgets/rounded_white_container.dart';
|
|||
import '../../../../widgets/stack_dialog.dart';
|
||||
import '../../../pinpad_views/lock_screen_view.dart';
|
||||
import 'delete_wallet_warning_view.dart';
|
||||
import 'edit_refresh_height_view.dart';
|
||||
import 'lelantus_settings_view.dart';
|
||||
import 'rbf_settings_view.dart';
|
||||
import 'rename_wallet_view.dart';
|
||||
|
@ -354,6 +356,42 @@ class _WalletSettingsWalletSettingsViewState
|
|||
),
|
||||
),
|
||||
),
|
||||
if (wallet is LibMoneroWallet)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (wallet is LibMoneroWallet)
|
||||
RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
EditRefreshHeightView.routeName,
|
||||
arguments: widget.walletId,
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0,
|
||||
vertical: 20,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"Restore height",
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:flutter_svg/svg.dart';
|
|||
|
||||
import '../../../../pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart';
|
||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
|
||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/edit_refresh_height_view.dart';
|
||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
|
||||
import '../../../../providers/global/wallets_provider.dart';
|
||||
import '../../../../route_generator.dart';
|
||||
|
@ -30,6 +31,7 @@ import '../../../../wallets/crypto_currency/coins/firo.dart';
|
|||
import '../../../../wallets/crypto_currency/intermediate/frost_currency.dart';
|
||||
import '../../../../wallets/crypto_currency/intermediate/nano_currency.dart';
|
||||
import '../../../../wallets/isar/providers/wallet_info_provider.dart';
|
||||
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||
import '../../../addresses/desktop_wallet_addresses_view.dart';
|
||||
|
@ -44,7 +46,8 @@ enum _WalletOptions {
|
|||
showXpub,
|
||||
lelantusCoins,
|
||||
sparkCoins,
|
||||
frostOptions;
|
||||
frostOptions,
|
||||
refreshFromHeight;
|
||||
|
||||
String get prettyName {
|
||||
switch (this) {
|
||||
|
@ -62,6 +65,8 @@ enum _WalletOptions {
|
|||
return "Spark Coins";
|
||||
case _WalletOptions.frostOptions:
|
||||
return "FROST settings";
|
||||
case _WalletOptions.refreshFromHeight:
|
||||
return "Refresh height";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +116,9 @@ class WalletOptionsButton extends ConsumerWidget {
|
|||
onFrostMSWalletOptionsPressed: () async {
|
||||
Navigator.of(context).pop(_WalletOptions.frostOptions);
|
||||
},
|
||||
onRefreshHeightPressed: () async {
|
||||
Navigator.of(context).pop(_WalletOptions.refreshFromHeight);
|
||||
},
|
||||
walletId: walletId,
|
||||
);
|
||||
},
|
||||
|
@ -243,6 +251,26 @@ class WalletOptionsButton extends ConsumerWidget {
|
|||
),
|
||||
);
|
||||
break;
|
||||
|
||||
case _WalletOptions.refreshFromHeight:
|
||||
if (Util.isDesktop) {
|
||||
unawaited(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => EditRefreshHeightView(
|
||||
walletId: walletId,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
EditRefreshHeightView.routeName,
|
||||
arguments: walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -278,6 +306,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
required this.onFiroShowLelantusCoins,
|
||||
required this.onFiroShowSparkCoins,
|
||||
required this.onFrostMSWalletOptionsPressed,
|
||||
required this.onRefreshHeightPressed,
|
||||
required this.walletId,
|
||||
});
|
||||
|
||||
|
@ -288,6 +317,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
final VoidCallback onFiroShowLelantusCoins;
|
||||
final VoidCallback onFiroShowSparkCoins;
|
||||
final VoidCallback onFrostMSWalletOptionsPressed;
|
||||
final VoidCallback onRefreshHeightPressed;
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
|
@ -307,6 +337,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
final bool canChangeRep = coin is NanoCurrency;
|
||||
|
||||
final bool isFrost = coin is FrostCurrency;
|
||||
final bool isMoneroWow = wallet is LibMoneroWallet;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
|
@ -509,6 +540,43 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (isMoneroWow)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isMoneroWow)
|
||||
TransparentButton(
|
||||
onPressed: onRefreshHeightPressed,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.addressBookDesktop,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveSearchIconLeft,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_WalletOptions.refreshFromHeight.prettyName,
|
||||
style: STextStyles.desktopTextExtraExtraSmall(
|
||||
context,
|
||||
).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (xpubEnabled)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
|
|
|
@ -135,6 +135,7 @@ import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_setting
|
|||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_view_only_wallet_keys_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/edit_refresh_height_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rbf_settings_view.dart';
|
||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart';
|
||||
|
@ -2140,6 +2141,20 @@ class RouteGenerator {
|
|||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case EditRefreshHeightView.routeName:
|
||||
if (args is String) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => EditRefreshHeightView(
|
||||
walletId: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
// == Desktop specific routes ============================================
|
||||
case CreatePasswordView.routeName:
|
||||
if (args is bool) {
|
||||
|
|
Loading…
Reference in a new issue