feat: allow setting the restore/refresh height in xmr/wow wallets

This commit is contained in:
julian 2024-12-10 14:51:19 -06:00
parent 937550cb04
commit 71609c34b0
4 changed files with 360 additions and 1 deletions

View file

@ -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,
),
],
),
),
);
}
}

View file

@ -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,
),

View file

@ -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,

View file

@ -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) {