mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-18 16:44:32 +00:00
ui view only wallet changes
This commit is contained in:
parent
53eb6ac8d1
commit
1f0ee995b9
17 changed files with 1501 additions and 430 deletions
|
@ -12,8 +12,6 @@ import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:blockchain_utils/bip/bip/bip39/bip39_mnemonic.dart';
|
|
||||||
import 'package:blockchain_utils/bip/bip/bip39/bip39_mnemonic_generator.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
|
@ -23,6 +23,7 @@ import '../../../../utilities/format.dart';
|
||||||
import '../../../../utilities/text_styles.dart';
|
import '../../../../utilities/text_styles.dart';
|
||||||
import '../../../../utilities/util.dart';
|
import '../../../../utilities/util.dart';
|
||||||
import '../../../../wallets/crypto_currency/crypto_currency.dart';
|
import '../../../../wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
import '../../../../wallets/crypto_currency/interfaces/view_only_option_currency_interface.dart';
|
||||||
import '../../../../widgets/conditional_parent.dart';
|
import '../../../../widgets/conditional_parent.dart';
|
||||||
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import '../../../../widgets/custom_buttons/checkbox_text_button.dart';
|
import '../../../../widgets/custom_buttons/checkbox_text_button.dart';
|
||||||
|
@ -32,7 +33,9 @@ import '../../../../widgets/desktop/desktop_scaffold.dart';
|
||||||
import '../../../../widgets/expandable.dart';
|
import '../../../../widgets/expandable.dart';
|
||||||
import '../../../../widgets/rounded_white_container.dart';
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
import '../../../../widgets/stack_text_field.dart';
|
import '../../../../widgets/stack_text_field.dart';
|
||||||
|
import '../../../../widgets/toggle.dart';
|
||||||
import '../../create_or_restore_wallet_view/sub_widgets/coin_image.dart';
|
import '../../create_or_restore_wallet_view/sub_widgets/coin_image.dart';
|
||||||
|
import '../restore_view_only_wallet_view.dart';
|
||||||
import '../restore_wallet_view.dart';
|
import '../restore_wallet_view.dart';
|
||||||
import '../sub_widgets/mnemonic_word_count_select_sheet.dart';
|
import '../sub_widgets/mnemonic_word_count_select_sheet.dart';
|
||||||
import 'sub_widgets/mobile_mnemonic_length_selector.dart';
|
import 'sub_widgets/mobile_mnemonic_length_selector.dart';
|
||||||
|
@ -69,7 +72,6 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
final bool _nextEnabled = true;
|
final bool _nextEnabled = true;
|
||||||
DateTime? _restoreFromDate;
|
DateTime? _restoreFromDate;
|
||||||
bool hidePassword = true;
|
bool hidePassword = true;
|
||||||
bool _expandedAdavnced = false;
|
|
||||||
|
|
||||||
bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport;
|
bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport;
|
||||||
|
|
||||||
|
@ -99,7 +101,11 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _nextLock = false;
|
||||||
Future<void> nextPressed() async {
|
Future<void> nextPressed() async {
|
||||||
|
if (_nextLock) return;
|
||||||
|
_nextLock = true;
|
||||||
|
try {
|
||||||
if (!isDesktop) {
|
if (!isDesktop) {
|
||||||
// hide keyboard if has focus
|
// hide keyboard if has focus
|
||||||
if (FocusScope.of(context).hasFocus) {
|
if (FocusScope.of(context).hasFocus) {
|
||||||
|
@ -109,6 +115,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
if (!_showViewOnlyOption) {
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
RestoreWalletView.routeName,
|
RestoreWalletView.routeName,
|
||||||
arguments: Tuple6(
|
arguments: Tuple6(
|
||||||
|
@ -120,6 +127,20 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
enableLelantusScanning,
|
enableLelantusScanning,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
RestoreViewOnlyWalletView.routeName,
|
||||||
|
arguments: (
|
||||||
|
walletName: walletName,
|
||||||
|
coin: coin,
|
||||||
|
restoreFromDate: _restoreFromDate,
|
||||||
|
enableLelantusScanning: enableLelantusScanning,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
_nextLock = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,17 +185,12 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _showViewOnlyOption = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType with ${coin.identifier} $walletName");
|
debugPrint("BUILD: $runtimeType with ${coin.identifier} $walletName");
|
||||||
|
|
||||||
final lengths = coin.possibleMnemonicLengths;
|
|
||||||
|
|
||||||
final isMoneroAnd25 = coin is Monero &&
|
|
||||||
ref.watch(mnemonicWordCountStateProvider.state).state == 25;
|
|
||||||
final isWowneroAnd25 = coin is Wownero &&
|
|
||||||
ref.watch(mnemonicWordCountStateProvider.state).state == 25;
|
|
||||||
|
|
||||||
return MasterScaffold(
|
return MasterScaffold(
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
appBar: isDesktop
|
appBar: isDesktop
|
||||||
|
@ -227,45 +243,154 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 40 : 24,
|
height: isDesktop ? 40 : 24,
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (coin is ViewOnlyOptionCurrencyInterface)
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 56 : 48,
|
||||||
|
width: isDesktop ? 490 : null,
|
||||||
|
child: Toggle(
|
||||||
|
key: UniqueKey(),
|
||||||
|
onText: "Seed",
|
||||||
|
offText: "View Only",
|
||||||
|
onColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
offColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldDefaultBG,
|
||||||
|
isOn: _showViewOnlyOption,
|
||||||
|
onValueChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_showViewOnlyOption = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (coin is ViewOnlyOptionCurrencyInterface)
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 40 : 24,
|
||||||
|
),
|
||||||
|
_showViewOnlyOption
|
||||||
|
? ViewOnlyRestoreOption(
|
||||||
|
coin: coin,
|
||||||
|
dateController: _dateController,
|
||||||
|
dateChooserFunction:
|
||||||
|
isDesktop ? chooseDesktopDate : chooseDate,
|
||||||
|
)
|
||||||
|
: SeedRestoreOption(
|
||||||
|
coin: coin,
|
||||||
|
dateController: _dateController,
|
||||||
|
pwController: passwordController,
|
||||||
|
pwFocusNode: passwordFocusNode,
|
||||||
|
supportsMnemonicPassphrase: supportsMnemonicPassphrase,
|
||||||
|
dateChooserFunction:
|
||||||
|
isDesktop ? chooseDesktopDate : chooseDate,
|
||||||
|
chooseMnemonicLength: chooseMnemonicLength,
|
||||||
|
lelScanChanged: (value) {
|
||||||
|
enableLelantusScanning = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isDesktop)
|
||||||
|
const Spacer(
|
||||||
|
flex: 3,
|
||||||
|
),
|
||||||
|
if (isDesktop)
|
||||||
|
const SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
RestoreOptionsNextButton(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
onPressed: _nextEnabled ? nextPressed : null,
|
||||||
|
),
|
||||||
|
if (isDesktop)
|
||||||
|
const Spacer(
|
||||||
|
flex: 15,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SeedRestoreOption extends ConsumerStatefulWidget {
|
||||||
|
const SeedRestoreOption({
|
||||||
|
super.key,
|
||||||
|
required this.coin,
|
||||||
|
required this.dateController,
|
||||||
|
required this.pwController,
|
||||||
|
required this.pwFocusNode,
|
||||||
|
required this.supportsMnemonicPassphrase,
|
||||||
|
required this.dateChooserFunction,
|
||||||
|
required this.chooseMnemonicLength,
|
||||||
|
required this.lelScanChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final CryptoCurrency coin;
|
||||||
|
final TextEditingController dateController;
|
||||||
|
final TextEditingController pwController;
|
||||||
|
final FocusNode pwFocusNode;
|
||||||
|
final bool supportsMnemonicPassphrase;
|
||||||
|
|
||||||
|
final Future<void> Function() dateChooserFunction;
|
||||||
|
final Future<void> Function() chooseMnemonicLength;
|
||||||
|
final void Function(bool) lelScanChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<SeedRestoreOption> createState() => _SeedRestoreOptionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SeedRestoreOptionState extends ConsumerState<SeedRestoreOption> {
|
||||||
|
bool _hidePassword = true;
|
||||||
|
bool _expandedAdvanced = false;
|
||||||
|
bool _enableLelantusScanning = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final lengths = widget.coin.possibleMnemonicLengths;
|
||||||
|
|
||||||
|
final isMoneroAnd25 = widget.coin is Monero &&
|
||||||
|
ref.watch(mnemonicWordCountStateProvider.state).state == 25;
|
||||||
|
final isWowneroAnd25 = widget.coin is Wownero &&
|
||||||
|
ref.watch(mnemonicWordCountStateProvider.state).state == 25;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
Text(
|
Text(
|
||||||
"Choose start date",
|
"Choose start date",
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
color: Theme.of(context)
|
color:
|
||||||
.extension<StackColors>()!
|
Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
.textDark3,
|
|
||||||
)
|
)
|
||||||
: STextStyles.smallMed12(context),
|
: STextStyles.smallMed12(context),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 16 : 8,
|
height: Util.isDesktop ? 16 : 8,
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
if (!isDesktop)
|
|
||||||
RestoreFromDatePicker(
|
RestoreFromDatePicker(
|
||||||
onTap: chooseDate,
|
onTap: widget.dateChooserFunction,
|
||||||
controller: _dateController,
|
controller: widget.dateController,
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
if (isDesktop)
|
|
||||||
// TODO desktop date picker
|
|
||||||
RestoreFromDatePicker(
|
|
||||||
onTap: chooseDesktopDate,
|
|
||||||
controller: _dateController,
|
|
||||||
),
|
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
RoundedWhiteContainer(
|
RoundedWhiteContainer(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Choose the date you made the wallet (approximate is fine)",
|
"Choose the date you made the wallet (approximate is fine)",
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
|
@ -277,29 +402,26 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isMoneroAnd25 || coin is Epiccash || isWowneroAnd25)
|
if (isMoneroAnd25 || widget.coin is Epiccash || isWowneroAnd25)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 24 : 16,
|
height: Util.isDesktop ? 24 : 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Choose recovery phrase length",
|
"Choose recovery phrase length",
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
.extension<StackColors>()!
|
|
||||||
.textDark3,
|
|
||||||
)
|
)
|
||||||
: STextStyles.smallMed12(context),
|
: STextStyles.smallMed12(context),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 16 : 8,
|
height: Util.isDesktop ? 16 : 8,
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (Util.isDesktop)
|
||||||
DropdownButtonHideUnderline(
|
DropdownButtonHideUnderline(
|
||||||
child: DropdownButton2<int>(
|
child: DropdownButton2<int>(
|
||||||
value:
|
value: ref.watch(mnemonicWordCountStateProvider.state).state,
|
||||||
ref.watch(mnemonicWordCountStateProvider.state).state,
|
|
||||||
items: [
|
items: [
|
||||||
...lengths.map(
|
...lengths.map(
|
||||||
(e) => DropdownMenuItem(
|
(e) => DropdownMenuItem(
|
||||||
|
@ -313,8 +435,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
],
|
],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value is int) {
|
if (value is int) {
|
||||||
ref.read(mnemonicWordCountStateProvider.state).state =
|
ref.read(mnemonicWordCountStateProvider.state).state = value;
|
||||||
value;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
|
@ -348,19 +469,19 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!isDesktop)
|
if (!Util.isDesktop)
|
||||||
MobileMnemonicLengthSelector(
|
MobileMnemonicLengthSelector(
|
||||||
chooseMnemonicLength: chooseMnemonicLength,
|
chooseMnemonicLength: widget.chooseMnemonicLength,
|
||||||
),
|
),
|
||||||
if (supportsMnemonicPassphrase)
|
if (widget.supportsMnemonicPassphrase)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 24 : 16,
|
height: Util.isDesktop ? 24 : 16,
|
||||||
),
|
),
|
||||||
if (supportsMnemonicPassphrase)
|
if (widget.supportsMnemonicPassphrase)
|
||||||
Expandable(
|
Expandable(
|
||||||
onExpandChanged: (state) {
|
onExpandChanged: (state) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_expandedAdavnced = state == ExpandableState.expanded;
|
_expandedAdvanced = state == ExpandableState.expanded;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
header: Container(
|
header: Container(
|
||||||
|
@ -376,7 +497,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Advanced",
|
"Advanced",
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextExtraExtraSmall(
|
? STextStyles.desktopTextExtraExtraSmall(
|
||||||
context,
|
context,
|
||||||
).copyWith(
|
).copyWith(
|
||||||
|
@ -388,7 +509,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
_expandedAdavnced
|
_expandedAdvanced
|
||||||
? Assets.svg.chevronUp
|
? Assets.svg.chevronUp
|
||||||
: Assets.svg.chevronDown,
|
: Assets.svg.chevronDown,
|
||||||
width: 12,
|
width: 12,
|
||||||
|
@ -405,16 +526,18 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (coin is Firo)
|
if (widget.coin is Firo)
|
||||||
CheckboxTextButton(
|
CheckboxTextButton(
|
||||||
label: "Scan for Lelantus transactions",
|
label: "Scan for Lelantus transactions",
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
enableLelantusScanning = newValue ?? true;
|
_enableLelantusScanning = newValue ?? true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
widget.lelScanChanged(_enableLelantusScanning);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (coin is Firo)
|
if (widget.coin is Firo)
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
@ -424,25 +547,24 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
key: const Key("mnemonicPassphraseFieldKey1"),
|
key: const Key("mnemonicPassphraseFieldKey1"),
|
||||||
focusNode: passwordFocusNode,
|
focusNode: widget.pwFocusNode,
|
||||||
controller: passwordController,
|
controller: widget.pwController,
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextMedium(context)
|
? STextStyles.desktopTextMedium(context).copyWith(
|
||||||
.copyWith(
|
|
||||||
height: 2,
|
height: 2,
|
||||||
)
|
)
|
||||||
: STextStyles.field(context),
|
: STextStyles.field(context),
|
||||||
obscureText: hidePassword,
|
obscureText: _hidePassword,
|
||||||
enableSuggestions: false,
|
enableSuggestions: false,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
decoration: standardInputDecoration(
|
decoration: standardInputDecoration(
|
||||||
"BIP39 passphrase",
|
"BIP39 passphrase",
|
||||||
passwordFocusNode,
|
widget.pwFocusNode,
|
||||||
context,
|
context,
|
||||||
).copyWith(
|
).copyWith(
|
||||||
suffixIcon: UnconstrainedBox(
|
suffixIcon: UnconstrainedBox(
|
||||||
child: ConditionalParent(
|
child: ConditionalParent(
|
||||||
condition: isDesktop,
|
condition: Util.isDesktop,
|
||||||
builder: (child) => SizedBox(
|
builder: (child) => SizedBox(
|
||||||
height: 70,
|
height: 70,
|
||||||
child: child,
|
child: child,
|
||||||
|
@ -450,7 +572,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: isDesktop ? 24 : 16,
|
width: Util.isDesktop ? 24 : 16,
|
||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
key: const Key(
|
key: const Key(
|
||||||
|
@ -458,18 +580,18 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
hidePassword = !hidePassword;
|
_hidePassword = !_hidePassword;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
hidePassword
|
_hidePassword
|
||||||
? Assets.svg.eye
|
? Assets.svg.eye
|
||||||
: Assets.svg.eyeSlash,
|
: Assets.svg.eyeSlash,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.textDark3,
|
.textDark3,
|
||||||
width: isDesktop ? 24 : 16,
|
width: Util.isDesktop ? 24 : 16,
|
||||||
height: isDesktop ? 24 : 16,
|
height: Util.isDesktop ? 24 : 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
@ -491,7 +613,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
"If the recovery phrase you are about to restore "
|
"If the recovery phrase you are about to restore "
|
||||||
"was created with an optional BIP39 passphrase "
|
"was created with an optional BIP39 passphrase "
|
||||||
"you can enter it here.",
|
"you can enter it here.",
|
||||||
style: isDesktop
|
style: Util.isDesktop
|
||||||
? STextStyles.desktopTextExtraSmall(context)
|
? STextStyles.desktopTextExtraSmall(context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
|
@ -509,26 +631,80 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!isDesktop)
|
|
||||||
const Spacer(
|
|
||||||
flex: 3,
|
|
||||||
),
|
|
||||||
if (isDesktop)
|
|
||||||
const SizedBox(
|
|
||||||
height: 32,
|
|
||||||
),
|
|
||||||
RestoreOptionsNextButton(
|
|
||||||
isDesktop: isDesktop,
|
|
||||||
onPressed: _nextEnabled ? nextPressed : null,
|
|
||||||
),
|
|
||||||
if (isDesktop)
|
|
||||||
const Spacer(
|
|
||||||
flex: 15,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
),
|
}
|
||||||
),
|
}
|
||||||
|
|
||||||
|
class ViewOnlyRestoreOption extends StatefulWidget {
|
||||||
|
const ViewOnlyRestoreOption({
|
||||||
|
super.key,
|
||||||
|
required this.coin,
|
||||||
|
required this.dateController,
|
||||||
|
required this.dateChooserFunction,
|
||||||
|
});
|
||||||
|
|
||||||
|
final CryptoCurrency coin;
|
||||||
|
final TextEditingController dateController;
|
||||||
|
|
||||||
|
final Future<void> Function() dateChooserFunction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ViewOnlyRestoreOption> createState() => _ViewOnlyRestoreOptionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ViewOnlyRestoreOptionState extends State<ViewOnlyRestoreOption> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final showDateOption = widget.coin is ViewOnlyOptionCurrencyInterface;
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (showDateOption)
|
||||||
|
Text(
|
||||||
|
"Choose start date",
|
||||||
|
style: Util.isDesktop
|
||||||
|
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
|
)
|
||||||
|
: STextStyles.smallMed12(context),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
if (showDateOption)
|
||||||
|
SizedBox(
|
||||||
|
height: Util.isDesktop ? 16 : 8,
|
||||||
|
),
|
||||||
|
if (showDateOption)
|
||||||
|
RestoreFromDatePicker(
|
||||||
|
onTap: widget.dateChooserFunction,
|
||||||
|
controller: widget.dateController,
|
||||||
|
),
|
||||||
|
if (showDateOption)
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
if (showDateOption)
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"Choose the date you made the wallet (approximate is fine)",
|
||||||
|
style: Util.isDesktop
|
||||||
|
? STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle1,
|
||||||
|
)
|
||||||
|
: STextStyles.smallMed12(context).copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (showDateOption)
|
||||||
|
SizedBox(
|
||||||
|
height: Util.isDesktop ? 24 : 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,393 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cs_monero/src/deprecated/get_height_by_date.dart'
|
||||||
|
as cs_monero_deprecated;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
|
|
||||||
|
import '../../../pages_desktop_specific/desktop_home_view.dart';
|
||||||
|
import '../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
||||||
|
import '../../../providers/db/main_db_provider.dart';
|
||||||
|
import '../../../providers/global/secure_store_provider.dart';
|
||||||
|
import '../../../providers/providers.dart';
|
||||||
|
import '../../../themes/stack_colors.dart';
|
||||||
|
import '../../../utilities/barcode_scanner_interface.dart';
|
||||||
|
import '../../../utilities/clipboard_interface.dart';
|
||||||
|
import '../../../utilities/text_styles.dart';
|
||||||
|
import '../../../utilities/util.dart';
|
||||||
|
import '../../../wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
import '../../../wallets/isar/models/wallet_info.dart';
|
||||||
|
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
|
||||||
|
import '../../../wallets/wallet/impl/monero_wallet.dart';
|
||||||
|
import '../../../wallets/wallet/impl/wownero_wallet.dart';
|
||||||
|
import '../../../wallets/wallet/wallet.dart';
|
||||||
|
import '../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
|
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
import '../../../widgets/desktop/desktop_app_bar.dart';
|
||||||
|
import '../../../widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import '../../../widgets/desktop/primary_button.dart';
|
||||||
|
import '../../../widgets/stack_text_field.dart';
|
||||||
|
import '../../home_view/home_view.dart';
|
||||||
|
import 'confirm_recovery_dialog.dart';
|
||||||
|
import 'sub_widgets/restore_failed_dialog.dart';
|
||||||
|
import 'sub_widgets/restore_succeeded_dialog.dart';
|
||||||
|
import 'sub_widgets/restoring_dialog.dart';
|
||||||
|
|
||||||
|
class RestoreViewOnlyWalletView extends ConsumerStatefulWidget {
|
||||||
|
const RestoreViewOnlyWalletView({
|
||||||
|
super.key,
|
||||||
|
required this.walletName,
|
||||||
|
required this.coin,
|
||||||
|
required this.restoreFromDate,
|
||||||
|
this.enableLelantusScanning = false,
|
||||||
|
this.barcodeScanner = const BarcodeScannerWrapper(),
|
||||||
|
this.clipboard = const ClipboardWrapper(),
|
||||||
|
});
|
||||||
|
|
||||||
|
static const routeName = "/restoreViewOnlyWallet";
|
||||||
|
|
||||||
|
final String walletName;
|
||||||
|
final CryptoCurrency coin;
|
||||||
|
final DateTime? restoreFromDate;
|
||||||
|
final bool enableLelantusScanning;
|
||||||
|
final BarcodeScannerInterface barcodeScanner;
|
||||||
|
final ClipboardInterface clipboard;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<RestoreViewOnlyWalletView> createState() =>
|
||||||
|
_RestoreViewOnlyWalletViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RestoreViewOnlyWalletViewState
|
||||||
|
extends ConsumerState<RestoreViewOnlyWalletView> {
|
||||||
|
late final TextEditingController addressController;
|
||||||
|
late final TextEditingController viewKeyController;
|
||||||
|
|
||||||
|
bool _enableRestoreButton = false;
|
||||||
|
|
||||||
|
bool _buttonLock = false;
|
||||||
|
|
||||||
|
Future<void> _requestRestore() async {
|
||||||
|
if (_buttonLock) return;
|
||||||
|
_buttonLock = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!Util.isDesktop) {
|
||||||
|
// wait for keyboard to disappear
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
await Future<void>.delayed(
|
||||||
|
const Duration(milliseconds: 100),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
await showDialog<dynamic>(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: false,
|
||||||
|
barrierDismissible: true,
|
||||||
|
builder: (context) {
|
||||||
|
return ConfirmRecoveryDialog(
|
||||||
|
onConfirm: _attemptRestore,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
_buttonLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _attemptRestore() async {
|
||||||
|
int height = 0;
|
||||||
|
final Map<String, dynamic> otherDataJson = {
|
||||||
|
WalletInfoKeys.isViewOnlyKey: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (widget.restoreFromDate != null) {
|
||||||
|
if (widget.coin is Monero) {
|
||||||
|
height = cs_monero_deprecated.getMoneroHeightByDate(
|
||||||
|
date: widget.restoreFromDate!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (widget.coin is Wownero) {
|
||||||
|
height = cs_monero_deprecated.getWowneroHeightByDate(
|
||||||
|
date: widget.restoreFromDate!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (height < 0) {
|
||||||
|
height = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.coin is Firo) {
|
||||||
|
otherDataJson.addAll(
|
||||||
|
{
|
||||||
|
WalletInfoKeys.lelantusCoinIsarRescanRequired: false,
|
||||||
|
WalletInfoKeys.enableLelantusScanning: widget.enableLelantusScanning,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Platform.isLinux && !Util.isDesktop) await WakelockPlus.enable();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final info = WalletInfo.createNew(
|
||||||
|
coin: widget.coin,
|
||||||
|
name: widget.walletName,
|
||||||
|
restoreHeight: height,
|
||||||
|
otherDataJsonString: jsonEncode(otherDataJson),
|
||||||
|
);
|
||||||
|
|
||||||
|
bool isRestoring = true;
|
||||||
|
// show restoring in progress
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
unawaited(
|
||||||
|
showDialog<dynamic>(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: false,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) {
|
||||||
|
return RestoringDialog(
|
||||||
|
onCancel: () async {
|
||||||
|
isRestoring = false;
|
||||||
|
|
||||||
|
await ref.read(pWallets).deleteWallet(
|
||||||
|
info,
|
||||||
|
ref.read(secureStoreProvider),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = ref
|
||||||
|
.read(nodeServiceChangeNotifierProvider)
|
||||||
|
.getPrimaryNodeFor(currency: widget.coin);
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
node = widget.coin.defaultNode;
|
||||||
|
await ref.read(nodeServiceChangeNotifierProvider).setPrimaryNodeFor(
|
||||||
|
coin: widget.coin,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final wallet = await Wallet.create(
|
||||||
|
walletInfo: info,
|
||||||
|
mainDB: ref.read(mainDBProvider),
|
||||||
|
secureStorageInterface: ref.read(secureStoreProvider),
|
||||||
|
nodeService: ref.read(nodeServiceChangeNotifierProvider),
|
||||||
|
prefs: ref.read(prefsChangeNotifierProvider),
|
||||||
|
viewOnlyData: ViewOnlyWalletData(
|
||||||
|
address: addressController.text,
|
||||||
|
privateViewKey: viewKeyController.text,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: extract interface with isRestore param
|
||||||
|
switch (wallet.runtimeType) {
|
||||||
|
case const (EpiccashWallet):
|
||||||
|
await (wallet as EpiccashWallet).init(isRestore: true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case const (MoneroWallet):
|
||||||
|
await (wallet as MoneroWallet).init(isRestore: true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case const (WowneroWallet):
|
||||||
|
await (wallet as WowneroWallet).init(isRestore: true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
await wallet.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
await wallet.recover(isRescan: false);
|
||||||
|
|
||||||
|
// check if state is still active before continuing
|
||||||
|
if (mounted) {
|
||||||
|
// don't remove this setMnemonicVerified thing
|
||||||
|
await wallet.info.setMnemonicVerified(
|
||||||
|
isar: ref.read(mainDBProvider).isar,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pWallets).addWallet(wallet);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
if (Util.isDesktop) {
|
||||||
|
Navigator.of(context).popUntil(
|
||||||
|
ModalRoute.withName(
|
||||||
|
DesktopHomeView.routeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
unawaited(
|
||||||
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||||
|
HomeView.routeName,
|
||||||
|
(route) => false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await showDialog<dynamic>(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: false,
|
||||||
|
barrierDismissible: true,
|
||||||
|
builder: (context) {
|
||||||
|
return const RestoreSucceededDialog();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// check if state is still active and restore wasn't cancelled
|
||||||
|
// before continuing
|
||||||
|
if (mounted && isRestoring) {
|
||||||
|
// pop waiting dialog
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
// show restoring wallet failed dialog
|
||||||
|
await showDialog<dynamic>(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: false,
|
||||||
|
barrierDismissible: true,
|
||||||
|
builder: (context) {
|
||||||
|
return RestoreFailedDialog(
|
||||||
|
errorMessage: e.toString(),
|
||||||
|
walletId: info.walletId,
|
||||||
|
walletName: info.name,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!Platform.isLinux && !Util.isDesktop) await WakelockPlus.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
addressController = TextEditingController();
|
||||||
|
viewKeyController = TextEditingController();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final isDesktop = Util.isDesktop;
|
||||||
|
return MasterScaffold(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
appBar: isDesktop
|
||||||
|
? const DesktopAppBar(
|
||||||
|
isCompactHeight: false,
|
||||||
|
leading: AppBarBackButton(),
|
||||||
|
trailing: ExitToMyStackButton(),
|
||||||
|
)
|
||||||
|
: AppBar(
|
||||||
|
leading: AppBarBackButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (FocusScope.of(context).hasFocus) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
await Future<void>.delayed(
|
||||||
|
const Duration(milliseconds: 50),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
color: Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: constraints.maxHeight,
|
||||||
|
maxWidth: isDesktop ? 480 : double.infinity,
|
||||||
|
),
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (isDesktop)
|
||||||
|
const Spacer(
|
||||||
|
flex: 10,
|
||||||
|
),
|
||||||
|
if (!isDesktop)
|
||||||
|
Text(
|
||||||
|
widget.walletName,
|
||||||
|
style: STextStyles.itemSubtitle(context),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 0 : 4,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Enter view only details",
|
||||||
|
style: isDesktop
|
||||||
|
? STextStyles.desktopH2(context)
|
||||||
|
: STextStyles.pageTitleH1(context),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 24 : 16,
|
||||||
|
),
|
||||||
|
FullTextField(
|
||||||
|
label: "Address",
|
||||||
|
controller: addressController,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
_enableRestoreButton = newValue.isNotEmpty &&
|
||||||
|
viewKeyController.text.isNotEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 16 : 12,
|
||||||
|
),
|
||||||
|
FullTextField(
|
||||||
|
label: "View Key",
|
||||||
|
controller: viewKeyController,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_enableRestoreButton = value.isNotEmpty &&
|
||||||
|
addressController.text.isNotEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isDesktop) const Spacer(),
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 24 : 16,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
enabled: _enableRestoreButton,
|
||||||
|
onPressed: _requestRestore,
|
||||||
|
width: isDesktop ? 480 : null,
|
||||||
|
label: "Restore",
|
||||||
|
),
|
||||||
|
if (isDesktop)
|
||||||
|
const Spacer(
|
||||||
|
flex: 15,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -655,6 +655,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
|
||||||
const Duration(milliseconds: 100),
|
const Duration(milliseconds: 100),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
await showDialog<dynamic>(
|
await showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
|
@ -666,6 +667,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import '../../../wallets/wallet/impl/epiccash_wallet.dart';
|
||||||
import '../../../wallets/wallet/intermediate/lib_monero_wallet.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/extended_keys_interface.dart';
|
||||||
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||||
|
import '../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../widgets/background.dart';
|
import '../../../widgets/background.dart';
|
||||||
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import '../../../widgets/desktop/secondary_button.dart';
|
import '../../../widgets/desktop/secondary_button.dart';
|
||||||
|
@ -273,6 +274,7 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
String keys
|
String keys
|
||||||
})? prevGen,
|
})? prevGen,
|
||||||
})? frostWalletData;
|
})? frostWalletData;
|
||||||
|
ViewOnlyWalletData? voData;
|
||||||
if (wallet is BitcoinFrostWallet) {
|
if (wallet is BitcoinFrostWallet) {
|
||||||
final futures = [
|
final futures = [
|
||||||
wallet.getSerializedKeys(),
|
wallet.getSerializedKeys(),
|
||||||
|
@ -298,10 +300,17 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (wallet
|
||||||
|
is ViewOnlyOptionInterface &&
|
||||||
|
wallet.isViewOnly) {
|
||||||
|
voData = await wallet
|
||||||
|
.getViewOnlyWalletData();
|
||||||
} else if (wallet
|
} else if (wallet
|
||||||
is MnemonicInterface) {
|
is MnemonicInterface) {
|
||||||
mnemonic =
|
mnemonic = await wallet
|
||||||
await wallet.getMnemonicAsWords();
|
.getMnemonicAsWords();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyDataInterface? keyData;
|
KeyDataInterface? keyData;
|
||||||
|
@ -312,6 +321,36 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
if (voData != null) {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute:
|
||||||
|
RouteGenerator
|
||||||
|
.useMaterialPageRoute,
|
||||||
|
builder: (_) => LockscreenView(
|
||||||
|
routeOnSuccessArguments: (
|
||||||
|
walletId: walletId,
|
||||||
|
keyData: keyData,
|
||||||
|
),
|
||||||
|
showBackButton: true,
|
||||||
|
routeOnSuccess:
|
||||||
|
MobileKeyDataView
|
||||||
|
.routeName,
|
||||||
|
biometricsCancelButtonString:
|
||||||
|
"CANCEL",
|
||||||
|
biometricsLocalizedReason:
|
||||||
|
"Authenticate to view recovery data",
|
||||||
|
biometricsAuthenticationTitle:
|
||||||
|
"View recovery data",
|
||||||
|
),
|
||||||
|
settings: const RouteSettings(
|
||||||
|
name:
|
||||||
|
"/viewRecoveryDataLockscreen",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
RouteGenerator.getRoute(
|
RouteGenerator.getRoute(
|
||||||
|
@ -328,7 +367,8 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
),
|
),
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
routeOnSuccess:
|
routeOnSuccess:
|
||||||
WalletBackupView.routeName,
|
WalletBackupView
|
||||||
|
.routeName,
|
||||||
biometricsCancelButtonString:
|
biometricsCancelButtonString:
|
||||||
"CANCEL",
|
"CANCEL",
|
||||||
biometricsLocalizedReason:
|
biometricsLocalizedReason:
|
||||||
|
@ -343,6 +383,7 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
import '../../../../app_config.dart';
|
||||||
|
import '../../../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart';
|
||||||
|
import '../../../../providers/global/secure_store_provider.dart';
|
||||||
|
import '../../../../providers/global/wallets_provider.dart';
|
||||||
|
import '../../../../route_generator.dart';
|
||||||
|
import '../../../../themes/stack_colors.dart';
|
||||||
|
import '../../../../utilities/text_styles.dart';
|
||||||
|
import '../../../../utilities/util.dart';
|
||||||
|
import '../../../../wallets/isar/providers/wallet_info_provider.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
|
import '../../../../widgets/conditional_parent.dart';
|
||||||
|
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
import '../../../../widgets/custom_buttons/simple_copy_button.dart';
|
||||||
|
import '../../../../widgets/desktop/primary_button.dart';
|
||||||
|
import '../../../../widgets/detail_item.dart';
|
||||||
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
|
import '../../../../widgets/stack_dialog.dart';
|
||||||
|
import '../../../home_view/home_view.dart';
|
||||||
|
import '../../../wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
|
|
||||||
|
class DeleteViewOnlyWalletKeysView extends ConsumerStatefulWidget {
|
||||||
|
const DeleteViewOnlyWalletKeysView({
|
||||||
|
super.key,
|
||||||
|
required this.walletId,
|
||||||
|
required this.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
static const routeName = "/deleteWalletViewOnlyData";
|
||||||
|
|
||||||
|
final String walletId;
|
||||||
|
final ViewOnlyWalletData data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DeleteViewOnlyWalletKeysView> createState() =>
|
||||||
|
_DeleteViewOnlyWalletKeysViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeleteViewOnlyWalletKeysViewState
|
||||||
|
extends ConsumerState<DeleteViewOnlyWalletKeysView> {
|
||||||
|
bool _lock = false;
|
||||||
|
void _continuePressed() async {
|
||||||
|
if (_lock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_lock = true;
|
||||||
|
try {
|
||||||
|
if (Util.isDesktop) {
|
||||||
|
await Navigator.of(context).push(
|
||||||
|
RouteGenerator.getRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return ConfirmDelete(
|
||||||
|
walletId: widget.walletId,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
settings: const RouteSettings(
|
||||||
|
name: "/desktopConfirmDelete",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await showDialog<dynamic>(
|
||||||
|
barrierDismissible: true,
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackDialog(
|
||||||
|
title: "Thanks! Your wallet will be deleted.",
|
||||||
|
leftButton: TextButton(
|
||||||
|
style: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.getSecondaryEnabledButtonStyle(context),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"Cancel",
|
||||||
|
style: STextStyles.button(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
rightButton: TextButton(
|
||||||
|
style: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.getPrimaryEnabledButtonStyle(context),
|
||||||
|
onPressed: () async {
|
||||||
|
await ref.read(pWallets).deleteWallet(
|
||||||
|
ref.read(pWalletInfo(widget.walletId)),
|
||||||
|
ref.read(secureStoreProvider),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).popUntil(
|
||||||
|
ModalRoute.withName(HomeView.routeName),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"Ok",
|
||||||
|
style: STextStyles.button(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
_lock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ConditionalParent(
|
||||||
|
condition: !Util.isDesktop,
|
||||||
|
builder: (child) => Scaffold(
|
||||||
|
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: AppBarBackButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, cons) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(minHeight: cons.maxHeight),
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Text(
|
||||||
|
"Please write down your backup data. Keep it safe and "
|
||||||
|
"never share it with anyone. "
|
||||||
|
"Your backup data is the only way you can access your "
|
||||||
|
"wallet if you forget your PIN, lose your phone, etc."
|
||||||
|
"\n\n"
|
||||||
|
"${AppConfig.appName} does not keep nor is able to restore "
|
||||||
|
"your backup data. "
|
||||||
|
"Only you have access to your wallet.",
|
||||||
|
style: STextStyles.label(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
if (widget.data.address != null)
|
||||||
|
DetailItem(
|
||||||
|
title: "Address",
|
||||||
|
detail: widget.data.address!,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: widget.data.address!,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: widget.data.address!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (widget.data.address != null)
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
if (widget.data.privateViewKey != null)
|
||||||
|
DetailItem(
|
||||||
|
title: "Private view key",
|
||||||
|
detail: widget.data.privateViewKey!,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: widget.data.privateViewKey!,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: widget.data.privateViewKey!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop) const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Continue",
|
||||||
|
onPressed: _continuePressed,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,9 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
import '../../../../app_config.dart';
|
import '../../../../app_config.dart';
|
||||||
import '../../../../notifications/show_flush_bar.dart';
|
import '../../../../notifications/show_flush_bar.dart';
|
||||||
import '../../../add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
|
|
||||||
import '../../../home_view/home_view.dart';
|
|
||||||
import '../../../wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
|
||||||
import '../../../../providers/global/secure_store_provider.dart';
|
import '../../../../providers/global/secure_store_provider.dart';
|
||||||
import '../../../../providers/global/wallets_provider.dart';
|
import '../../../../providers/global/wallets_provider.dart';
|
||||||
import '../../../../themes/stack_colors.dart';
|
import '../../../../themes/stack_colors.dart';
|
||||||
|
@ -35,6 +33,9 @@ import '../../../../widgets/desktop/primary_button.dart';
|
||||||
import '../../../../widgets/detail_item.dart';
|
import '../../../../widgets/detail_item.dart';
|
||||||
import '../../../../widgets/rounded_white_container.dart';
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
import '../../../../widgets/stack_dialog.dart';
|
import '../../../../widgets/stack_dialog.dart';
|
||||||
|
import '../../../add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
|
||||||
|
import '../../../home_view/home_view.dart';
|
||||||
|
import '../../../wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
|
|
||||||
class DeleteWalletRecoveryPhraseView extends ConsumerStatefulWidget {
|
class DeleteWalletRecoveryPhraseView extends ConsumerStatefulWidget {
|
||||||
const DeleteWalletRecoveryPhraseView({
|
const DeleteWalletRecoveryPhraseView({
|
||||||
|
@ -69,7 +70,6 @@ class _DeleteWalletRecoveryPhraseViewState
|
||||||
late ClipboardInterface _clipboardInterface;
|
late ClipboardInterface _clipboardInterface;
|
||||||
|
|
||||||
bool _lock = false;
|
bool _lock = false;
|
||||||
|
|
||||||
void _continuePressed() {
|
void _continuePressed() {
|
||||||
if (_lock) {
|
if (_lock) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -17,9 +17,11 @@ import '../../../../themes/stack_colors.dart';
|
||||||
import '../../../../utilities/text_styles.dart';
|
import '../../../../utilities/text_styles.dart';
|
||||||
import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../widgets/background.dart';
|
import '../../../../widgets/background.dart';
|
||||||
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import '../../../../widgets/rounded_container.dart';
|
import '../../../../widgets/rounded_container.dart';
|
||||||
|
import 'delete_view_only_wallet_keys_view.dart';
|
||||||
import 'delete_wallet_recovery_phrase_view.dart';
|
import 'delete_wallet_recovery_phrase_view.dart';
|
||||||
|
|
||||||
class DeleteWalletWarningView extends ConsumerWidget {
|
class DeleteWalletWarningView extends ConsumerWidget {
|
||||||
|
@ -118,6 +120,7 @@ class DeleteWalletWarningView extends ConsumerWidget {
|
||||||
String keys,
|
String keys,
|
||||||
({String config, String keys})? prevGen,
|
({String config, String keys})? prevGen,
|
||||||
})? frostWalletData;
|
})? frostWalletData;
|
||||||
|
ViewOnlyWalletData? viewOnlyData;
|
||||||
|
|
||||||
if (wallet is BitcoinFrostWallet) {
|
if (wallet is BitcoinFrostWallet) {
|
||||||
final futures = [
|
final futures = [
|
||||||
|
@ -142,10 +145,24 @@ class DeleteWalletWarningView extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (wallet is ViewOnlyOptionInterface &&
|
||||||
|
wallet.isViewOnly) {
|
||||||
|
viewOnlyData = await wallet.getViewOnlyWalletData();
|
||||||
} else if (wallet is MnemonicInterface) {
|
} else if (wallet is MnemonicInterface) {
|
||||||
mnemonic = await wallet.getMnemonicAsWords();
|
mnemonic = await wallet.getMnemonicAsWords();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
if (viewOnlyData != null) {
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
DeleteViewOnlyWalletKeysView.routeName,
|
||||||
|
arguments: (
|
||||||
|
walletId: walletId,
|
||||||
|
data: viewOnlyData,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
DeleteWalletRecoveryPhraseView.routeName,
|
DeleteWalletRecoveryPhraseView.routeName,
|
||||||
arguments: (
|
arguments: (
|
||||||
|
@ -155,6 +172,7 @@ class DeleteWalletWarningView extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"View Backup Key",
|
"View Backup Key",
|
||||||
|
|
|
@ -56,6 +56,7 @@ import '../../wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart
|
||||||
import '../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart';
|
import '../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart';
|
||||||
import '../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
import '../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
||||||
import '../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
import '../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
||||||
|
import '../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../widgets/background.dart';
|
import '../../widgets/background.dart';
|
||||||
import '../../widgets/conditional_parent.dart';
|
import '../../widgets/conditional_parent.dart';
|
||||||
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
|
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
@ -524,6 +525,10 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
final prefs = ref.watch(prefsChangeNotifierProvider);
|
final prefs = ref.watch(prefsChangeNotifierProvider);
|
||||||
final showExchange = prefs.enableExchange;
|
final showExchange = prefs.enableExchange;
|
||||||
|
|
||||||
|
final wallet = ref.watch(pWallets).getWallet(walletId);
|
||||||
|
|
||||||
|
final viewOnly = wallet is ViewOnlyOptionInterface && wallet.isViewOnly;
|
||||||
|
|
||||||
return ConditionalParent(
|
return ConditionalParent(
|
||||||
condition: _rescanningOnOpen,
|
condition: _rescanningOnOpen,
|
||||||
builder: (child) {
|
builder: (child) {
|
||||||
|
@ -1026,6 +1031,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
icon: const FrostSignNavIcon(),
|
icon: const FrostSignNavIcon(),
|
||||||
onTap: () => _onFrostSignPressed(context),
|
onTap: () => _onFrostSignPressed(context),
|
||||||
),
|
),
|
||||||
|
if (!viewOnly)
|
||||||
WalletNavigationBarItemData(
|
WalletNavigationBarItemData(
|
||||||
label: "Send",
|
label: "Send",
|
||||||
icon: const SendNavIcon(),
|
icon: const SendNavIcon(),
|
||||||
|
@ -1046,8 +1052,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
Navigator.of(context).pushNamed(
|
Navigator.of(context).pushNamed(
|
||||||
ref.read(pWallets).getWallet(walletId)
|
wallet is BitcoinFrostWallet
|
||||||
is BitcoinFrostWallet
|
|
||||||
? FrostSendView.routeName
|
? FrostSendView.routeName
|
||||||
: SendView.routeName,
|
: SendView.routeName,
|
||||||
arguments: (
|
arguments: (
|
||||||
|
@ -1057,7 +1062,8 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (Constants.enableExchange &&
|
if (!viewOnly &&
|
||||||
|
Constants.enableExchange &&
|
||||||
ref.watch(pWalletCoin(walletId)) is! FrostCurrency &&
|
ref.watch(pWalletCoin(walletId)) is! FrostCurrency &&
|
||||||
AppConfig.hasFeature(AppFeature.swap) &&
|
AppConfig.hasFeature(AppFeature.swap) &&
|
||||||
showExchange)
|
showExchange)
|
||||||
|
@ -1113,12 +1119,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (ref.watch(
|
if (wallet is CoinControlInterface &&
|
||||||
pWallets.select(
|
|
||||||
(value) => value.getWallet(widget.walletId)
|
|
||||||
is CoinControlInterface,
|
|
||||||
),
|
|
||||||
) &&
|
|
||||||
ref.watch(
|
ref.watch(
|
||||||
prefsChangeNotifierProvider.select(
|
prefsChangeNotifierProvider.select(
|
||||||
(value) => value.enableCoinControl,
|
(value) => value.enableCoinControl,
|
||||||
|
@ -1137,12 +1138,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (ref.watch(
|
if (wallet is PaynymInterface)
|
||||||
pWallets.select(
|
|
||||||
(value) =>
|
|
||||||
value.getWallet(widget.walletId) is PaynymInterface,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
WalletNavigationBarItemData(
|
WalletNavigationBarItemData(
|
||||||
label: "PayNym",
|
label: "PayNym",
|
||||||
icon: const PaynymNavIcon(),
|
icon: const PaynymNavIcon(),
|
||||||
|
@ -1213,12 +1209,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (ref.watch(
|
if (wallet is CashFusionInterface && !viewOnly)
|
||||||
pWallets.select(
|
|
||||||
(value) => value.getWallet(widget.walletId)
|
|
||||||
is CashFusionInterface,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
WalletNavigationBarItemData(
|
WalletNavigationBarItemData(
|
||||||
label: "Fusion",
|
label: "Fusion",
|
||||||
icon: const FusionNavIcon(),
|
icon: const FusionNavIcon(),
|
||||||
|
@ -1229,12 +1220,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (ref.watch(
|
if (wallet is LibMoneroWallet && !viewOnly)
|
||||||
pWallets.select(
|
|
||||||
(value) =>
|
|
||||||
value.getWallet(widget.walletId) is LibMoneroWallet,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
WalletNavigationBarItemData(
|
WalletNavigationBarItemData(
|
||||||
label: "Churn",
|
label: "Churn",
|
||||||
icon: const ChurnNavIcon(),
|
icon: const ChurnNavIcon(),
|
||||||
|
|
|
@ -10,18 +10,21 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
import '../../../../app_config.dart';
|
import '../../../../app_config.dart';
|
||||||
import 'delete_wallet_keys_popup.dart';
|
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_view_only_wallet_keys_view.dart';
|
||||||
import '../../../../providers/global/wallets_provider.dart';
|
import '../../../../providers/global/wallets_provider.dart';
|
||||||
import '../../../../themes/stack_colors.dart';
|
import '../../../../themes/stack_colors.dart';
|
||||||
import '../../../../utilities/text_styles.dart';
|
import '../../../../utilities/text_styles.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
import '../../../../widgets/desktop/primary_button.dart';
|
import '../../../../widgets/desktop/primary_button.dart';
|
||||||
import '../../../../widgets/desktop/secondary_button.dart';
|
import '../../../../widgets/desktop/secondary_button.dart';
|
||||||
import '../../../../widgets/rounded_container.dart';
|
import '../../../../widgets/rounded_container.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'delete_wallet_keys_popup.dart';
|
||||||
|
|
||||||
class DesktopAttentionDeleteWallet extends ConsumerStatefulWidget {
|
class DesktopAttentionDeleteWallet extends ConsumerStatefulWidget {
|
||||||
const DesktopAttentionDeleteWallet({
|
const DesktopAttentionDeleteWallet({
|
||||||
|
@ -114,6 +117,58 @@ class _DesktopAttentionDeleteWallet
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final wallet =
|
final wallet =
|
||||||
ref.read(pWallets).getWallet(widget.walletId);
|
ref.read(pWallets).getWallet(widget.walletId);
|
||||||
|
|
||||||
|
if (wallet is ViewOnlyOptionInterface &&
|
||||||
|
wallet.isViewOnly) {
|
||||||
|
final data = await wallet.getViewOnlyWalletData();
|
||||||
|
if (context.mounted) {
|
||||||
|
await Navigator.of(context).push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (builder) => DesktopDialog(
|
||||||
|
maxWidth: 614,
|
||||||
|
maxHeight: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 32,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Wallet keys",
|
||||||
|
style: STextStyles.desktopH3(
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DesktopDialogCloseButton(
|
||||||
|
onPressedOverride: () {
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
rootNavigator: true,
|
||||||
|
).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(32),
|
||||||
|
child: DeleteViewOnlyWalletKeysView(
|
||||||
|
walletId: widget.walletId,
|
||||||
|
data: data,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
|
||||||
// TODO: [prio=med] handle other types wallet deletion
|
// TODO: [prio=med] handle other types wallet deletion
|
||||||
// All wallets currently are mnemonic based
|
// All wallets currently are mnemonic based
|
||||||
if (wallet is MnemonicInterface) {
|
if (wallet is MnemonicInterface) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import '../../../../wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../widgets/custom_loading_overlay.dart';
|
import '../../../../widgets/custom_loading_overlay.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||||
import '../../../../widgets/desktop/primary_button.dart';
|
import '../../../../widgets/desktop/primary_button.dart';
|
||||||
|
@ -380,9 +381,12 @@ class _DesktopWalletFeaturesState extends ConsumerState<DesktopWalletFeatures> {
|
||||||
wallet is OrdinalsInterface ||
|
wallet is OrdinalsInterface ||
|
||||||
wallet is CashFusionInterface;
|
wallet is CashFusionInterface;
|
||||||
|
|
||||||
|
final isViewOnly = wallet is ViewOnlyOptionInterface && wallet.isViewOnly;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (Constants.enableExchange &&
|
if (!isViewOnly &&
|
||||||
|
Constants.enableExchange &&
|
||||||
AppConfig.hasFeature(AppFeature.swap) &&
|
AppConfig.hasFeature(AppFeature.swap) &&
|
||||||
showExchange)
|
showExchange)
|
||||||
SecondaryButton(
|
SecondaryButton(
|
||||||
|
|
|
@ -31,6 +31,7 @@ import '../../../../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface
|
||||||
import '../../../../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
import '../../../../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
||||||
import '../../../../../wallets/wallet/wallet_mixin_interfaces/rbf_interface.dart';
|
import '../../../../../wallets/wallet/wallet_mixin_interfaces/rbf_interface.dart';
|
||||||
import '../../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
import '../../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
||||||
|
import '../../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../../widgets/custom_buttons/draggable_switch_button.dart';
|
import '../../../../../widgets/custom_buttons/draggable_switch_button.dart';
|
||||||
import '../../../../../widgets/desktop/desktop_dialog.dart';
|
import '../../../../../widgets/desktop/desktop_dialog.dart';
|
||||||
import '../../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
import '../../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
|
@ -238,6 +239,8 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final isViewOnly = wallet is ViewOnlyOptionInterface && wallet.isViewOnly;
|
||||||
|
|
||||||
return DesktopDialog(
|
return DesktopDialog(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -257,7 +260,7 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> {
|
||||||
const DesktopDialogCloseButton(),
|
const DesktopDialogCloseButton(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (wallet.info.coin is Firo)
|
if (!isViewOnly && wallet.info.coin is Firo)
|
||||||
_MoreFeaturesItem(
|
_MoreFeaturesItem(
|
||||||
label: "Anonymize funds",
|
label: "Anonymize funds",
|
||||||
detail: "Anonymize funds",
|
detail: "Anonymize funds",
|
||||||
|
@ -300,14 +303,14 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> {
|
||||||
iconAsset: Assets.svg.monkey,
|
iconAsset: Assets.svg.monkey,
|
||||||
onPressed: () async => widget.onMonkeyPressed?.call(),
|
onPressed: () async => widget.onMonkeyPressed?.call(),
|
||||||
),
|
),
|
||||||
if (wallet is CashFusionInterface)
|
if (!isViewOnly && wallet is CashFusionInterface)
|
||||||
_MoreFeaturesItem(
|
_MoreFeaturesItem(
|
||||||
label: "Fusion",
|
label: "Fusion",
|
||||||
detail: "Decentralized mixing protocol",
|
detail: "Decentralized mixing protocol",
|
||||||
iconAsset: Assets.svg.cashFusion,
|
iconAsset: Assets.svg.cashFusion,
|
||||||
onPressed: () async => widget.onFusionPressed?.call(),
|
onPressed: () async => widget.onFusionPressed?.call(),
|
||||||
),
|
),
|
||||||
if (wallet is LibMoneroWallet)
|
if (!isViewOnly && wallet is LibMoneroWallet)
|
||||||
_MoreFeaturesItem(
|
_MoreFeaturesItem(
|
||||||
label: "Churn",
|
label: "Churn",
|
||||||
detail: "Churning",
|
detail: "Churning",
|
||||||
|
|
|
@ -10,20 +10,22 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../frost_route_generator.dart';
|
import '../../../../frost_route_generator.dart';
|
||||||
import '../../../../pages/send_view/frost_ms/frost_send_view.dart';
|
import '../../../../pages/send_view/frost_ms/frost_send_view.dart';
|
||||||
import '../../../../pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart';
|
import '../../../../pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart';
|
||||||
import '../../my_stack_view.dart';
|
|
||||||
import 'desktop_receive.dart';
|
|
||||||
import 'desktop_send.dart';
|
|
||||||
import 'desktop_token_send.dart';
|
|
||||||
import '../../../../providers/global/wallets_provider.dart';
|
import '../../../../providers/global/wallets_provider.dart';
|
||||||
import '../../../../wallets/crypto_currency/crypto_currency.dart';
|
import '../../../../wallets/crypto_currency/crypto_currency.dart';
|
||||||
import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../widgets/custom_tab_view.dart';
|
import '../../../../widgets/custom_tab_view.dart';
|
||||||
import '../../../../widgets/desktop/secondary_button.dart';
|
import '../../../../widgets/desktop/secondary_button.dart';
|
||||||
import '../../../../widgets/frost_scaffold.dart';
|
import '../../../../widgets/frost_scaffold.dart';
|
||||||
import '../../../../widgets/rounded_white_container.dart';
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
|
import '../../my_stack_view.dart';
|
||||||
|
import 'desktop_receive.dart';
|
||||||
|
import 'desktop_send.dart';
|
||||||
|
import 'desktop_token_send.dart';
|
||||||
|
|
||||||
class MyWallet extends ConsumerStatefulWidget {
|
class MyWallet extends ConsumerStatefulWidget {
|
||||||
const MyWallet({
|
const MyWallet({
|
||||||
|
@ -48,6 +50,7 @@ class _MyWalletState extends ConsumerState<MyWallet> {
|
||||||
late final bool isEth;
|
late final bool isEth;
|
||||||
late final CryptoCurrency coin;
|
late final CryptoCurrency coin;
|
||||||
late final bool isFrost;
|
late final bool isFrost;
|
||||||
|
late final bool isViewOnly;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -60,11 +63,34 @@ class _MyWalletState extends ConsumerState<MyWallet> {
|
||||||
titles.add("Transactions");
|
titles.add("Transactions");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isViewOnly = wallet is ViewOnlyOptionInterface && wallet.isViewOnly;
|
||||||
|
if (isViewOnly) {
|
||||||
|
titles.remove("Receive");
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (isViewOnly) {
|
||||||
|
return ListView(
|
||||||
|
primary: false,
|
||||||
|
children: [
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: DesktopReceive(
|
||||||
|
walletId: widget.walletId,
|
||||||
|
contractAddress: widget.contractAddress,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
primary: false,
|
primary: false,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -26,6 +26,7 @@ import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.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/extended_keys_interface.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||||
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
import '../../../../widgets/desktop/primary_button.dart';
|
import '../../../../widgets/desktop/primary_button.dart';
|
||||||
|
@ -99,9 +100,13 @@ class _UnlockWalletKeysDesktopState
|
||||||
} else {
|
} else {
|
||||||
throw Exception("FIXME ~= see todo in code");
|
throw Exception("FIXME ~= see todo in code");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (wallet is ViewOnlyOptionInterface) {
|
||||||
|
// TODO: is something needed here?
|
||||||
} else {
|
} else {
|
||||||
words = await wallet.getMnemonicAsWords();
|
words = await wallet.getMnemonicAsWords();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyDataInterface? keyData;
|
KeyDataInterface? keyData;
|
||||||
if (wallet is ExtendedKeysInterface) {
|
if (wallet is ExtendedKeysInterface) {
|
||||||
|
@ -346,9 +351,13 @@ class _UnlockWalletKeysDesktopState
|
||||||
} else {
|
} else {
|
||||||
throw Exception("FIXME ~= see todo in code");
|
throw Exception("FIXME ~= see todo in code");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (wallet is ViewOnlyOptionInterface) {
|
||||||
|
// TODO: is something needed here?
|
||||||
} else {
|
} else {
|
||||||
words = await wallet.getMnemonicAsWords();
|
words = await wallet.getMnemonicAsWords();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyDataInterface? keyData;
|
KeyDataInterface? keyData;
|
||||||
if (wallet is ExtendedKeysInterface) {
|
if (wallet is ExtendedKeysInterface) {
|
||||||
|
|
|
@ -182,11 +182,12 @@ class WalletKeysDesktopPopup extends ConsumerWidget {
|
||||||
: keyData != null
|
: keyData != null
|
||||||
? CustomTabView(
|
? CustomTabView(
|
||||||
titles: [
|
titles: [
|
||||||
"Mnemonic",
|
if (words.isNotEmpty) "Mnemonic",
|
||||||
if (keyData is XPrivData) "XPriv(s)",
|
if (keyData is XPrivData) "XPriv(s)",
|
||||||
if (keyData is CWKeyData) "Keys",
|
if (keyData is CWKeyData) "Keys",
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
|
if (words.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
padding: const EdgeInsets.only(top: 16),
|
||||||
child: _Mnemonic(
|
child: _Mnemonic(
|
||||||
|
|
|
@ -37,6 +37,7 @@ import 'pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart';
|
||||||
import 'pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
|
import 'pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
|
||||||
import 'pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
|
import 'pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
|
||||||
import 'pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart';
|
import 'pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart';
|
||||||
|
import 'pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart';
|
||||||
import 'pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart';
|
import 'pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart';
|
||||||
import 'pages/add_wallet_views/select_wallet_for_token_view.dart';
|
import 'pages/add_wallet_views/select_wallet_for_token_view.dart';
|
||||||
import 'pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
|
import 'pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
|
||||||
|
@ -130,6 +131,7 @@ import 'pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_bac
|
||||||
import 'pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
import 'pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||||
import 'pages/settings_views/wallet_settings_view/wallet_settings_view.dart';
|
import 'pages/settings_views/wallet_settings_view/wallet_settings_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/change_representative_view.dart';
|
||||||
|
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_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/delete_wallet_warning_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/lelantus_settings_view.dart';
|
||||||
|
@ -203,6 +205,7 @@ import 'wallets/crypto_currency/intermediate/frost_currency.dart';
|
||||||
import 'wallets/models/tx_data.dart';
|
import 'wallets/models/tx_data.dart';
|
||||||
import 'wallets/wallet/wallet.dart';
|
import 'wallets/wallet/wallet.dart';
|
||||||
import 'wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
import 'wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||||
|
import 'wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
|
||||||
import 'widgets/choose_coin_view.dart';
|
import 'widgets/choose_coin_view.dart';
|
||||||
import 'widgets/frost_scaffold.dart';
|
import 'widgets/frost_scaffold.dart';
|
||||||
|
|
||||||
|
@ -1519,6 +1522,28 @@ class RouteGenerator {
|
||||||
}
|
}
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
|
case RestoreViewOnlyWalletView.routeName:
|
||||||
|
if (args is ({
|
||||||
|
String walletName,
|
||||||
|
CryptoCurrency coin,
|
||||||
|
DateTime? restoreFromDate,
|
||||||
|
bool enableLelantusScanning,
|
||||||
|
})) {
|
||||||
|
return getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => RestoreViewOnlyWalletView(
|
||||||
|
walletName: args.walletName,
|
||||||
|
coin: args.coin,
|
||||||
|
restoreFromDate: args.restoreFromDate,
|
||||||
|
enableLelantusScanning: args.enableLelantusScanning,
|
||||||
|
),
|
||||||
|
settings: RouteSettings(
|
||||||
|
name: settings.name,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
case NewWalletRecoveryPhraseView.routeName:
|
case NewWalletRecoveryPhraseView.routeName:
|
||||||
if (args is Tuple2<Wallet, List<String>>) {
|
if (args is Tuple2<Wallet, List<String>>) {
|
||||||
return getRoute(
|
return getRoute(
|
||||||
|
@ -1927,6 +1952,21 @@ class RouteGenerator {
|
||||||
}
|
}
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
|
case DeleteViewOnlyWalletKeysView.routeName:
|
||||||
|
if (args is ({String walletId, ViewOnlyWalletData data})) {
|
||||||
|
return getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => DeleteViewOnlyWalletKeysView(
|
||||||
|
data: args.data,
|
||||||
|
walletId: args.walletId,
|
||||||
|
),
|
||||||
|
settings: RouteSettings(
|
||||||
|
name: settings.name,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
// exchange steps
|
// exchange steps
|
||||||
|
|
||||||
case Step1View.routeName:
|
case Step1View.routeName:
|
||||||
|
|
|
@ -9,10 +9,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import '../themes/stack_colors.dart';
|
import '../themes/stack_colors.dart';
|
||||||
|
import '../utilities/constants.dart';
|
||||||
import '../utilities/text_styles.dart';
|
import '../utilities/text_styles.dart';
|
||||||
import '../utilities/util.dart';
|
import '../utilities/util.dart';
|
||||||
|
import 'icon_widgets/clipboard_icon.dart';
|
||||||
|
import 'icon_widgets/x_icon.dart';
|
||||||
|
import 'textfield_icon_button.dart';
|
||||||
|
|
||||||
InputDecoration standardInputDecoration(
|
InputDecoration standardInputDecoration(
|
||||||
String? labelText,
|
String? labelText,
|
||||||
|
@ -52,3 +57,113 @@ InputDecoration standardInputDecoration(
|
||||||
focusedErrorBorder: InputBorder.none,
|
focusedErrorBorder: InputBorder.none,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FullTextField extends StatefulWidget {
|
||||||
|
const FullTextField({
|
||||||
|
super.key,
|
||||||
|
this.controller,
|
||||||
|
this.focusNode,
|
||||||
|
required this.label,
|
||||||
|
this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
final TextEditingController? controller;
|
||||||
|
final FocusNode? focusNode;
|
||||||
|
|
||||||
|
final void Function(String)? onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FullTextField> createState() => _FullTextFieldState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FullTextFieldState extends State<FullTextField> {
|
||||||
|
late final TextEditingController controller;
|
||||||
|
late final FocusNode focusNode;
|
||||||
|
|
||||||
|
bool _hasValue = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
controller = widget.controller ?? TextEditingController();
|
||||||
|
focusNode = widget.focusNode ?? FocusNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (widget.controller == null) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
controller: controller,
|
||||||
|
autocorrect: false,
|
||||||
|
enableSuggestions: false,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
widget.onChanged?.call(newValue);
|
||||||
|
},
|
||||||
|
focusNode: focusNode,
|
||||||
|
style: STextStyles.field(context),
|
||||||
|
decoration: standardInputDecoration(
|
||||||
|
widget.label,
|
||||||
|
focusNode,
|
||||||
|
context,
|
||||||
|
).copyWith(
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 6,
|
||||||
|
bottom: 8,
|
||||||
|
right: 5,
|
||||||
|
),
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding: controller.text.isEmpty
|
||||||
|
? const EdgeInsets.only(right: 8)
|
||||||
|
: const EdgeInsets.only(right: 0),
|
||||||
|
child: UnconstrainedBox(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
TextFieldIconButton(
|
||||||
|
onTap: () async {
|
||||||
|
if (_hasValue) {
|
||||||
|
controller.text = "";
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_hasValue = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
final data =
|
||||||
|
await Clipboard.getData(Clipboard.kTextPlain);
|
||||||
|
if (data?.text != null && data!.text!.isNotEmpty) {
|
||||||
|
final content = data.text!.trim();
|
||||||
|
|
||||||
|
controller.text = content;
|
||||||
|
setState(() {
|
||||||
|
_hasValue = content.isNotEmpty;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.onChanged?.call(controller.text);
|
||||||
|
},
|
||||||
|
child: _hasValue ? const XIcon() : const ClipboardIcon(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue