mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-16 17:27:39 +00:00
Merge branch 'staging' into add_frost
This commit is contained in:
commit
5644d763c2
10 changed files with 481 additions and 425 deletions
|
@ -56,6 +56,7 @@ import 'package:stackwallet/wallets/wallet/impl/monero_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/wownero_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/wownero_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/supporting/epiccash_wallet_info_extension.dart';
|
import 'package:stackwallet/wallets/wallet/supporting/epiccash_wallet_info_extension.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet.dart';
|
import 'package:stackwallet/wallets/wallet/wallet.dart';
|
||||||
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
@ -723,353 +724,376 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
color: Theme.of(context).extension<StackColors>()!.background,
|
color: Theme.of(context).extension<StackColors>()!.background,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
controller: controller,
|
||||||
children: [
|
child: Column(
|
||||||
/*if (isDesktop)
|
children: [
|
||||||
|
/*if (isDesktop)
|
||||||
const Spacer(
|
const Spacer(
|
||||||
flex: 10,
|
flex: 10,
|
||||||
),*/
|
),*/
|
||||||
if (!isDesktop)
|
if (!isDesktop)
|
||||||
Text(
|
Text(
|
||||||
widget.walletName,
|
widget.walletName,
|
||||||
style: STextStyles.itemSubtitle(context),
|
style: STextStyles.itemSubtitle(context),
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: isDesktop ? 0 : 4,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Recovery phrase",
|
|
||||||
style: isDesktop
|
|
||||||
? STextStyles.desktopH2(context)
|
|
||||||
: STextStyles.pageTitleH1(context),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: isDesktop ? 16 : 8,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Enter your $_seedWordCount-word recovery phrase.",
|
|
||||||
style: isDesktop
|
|
||||||
? STextStyles.desktopSubtitleH2(context)
|
|
||||||
: STextStyles.subtitle(context),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: isDesktop ? 16 : 10,
|
|
||||||
),
|
|
||||||
if (isDesktop)
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: pasteMnemonic,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16.0,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
Assets.svg.clipboard,
|
|
||||||
width: 22,
|
|
||||||
height: 22,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.buttonTextSecondary,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Paste",
|
|
||||||
style: STextStyles
|
|
||||||
.desktopButtonSmallSecondaryEnabled(context),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
SizedBox(
|
||||||
),
|
height: isDesktop ? 0 : 4,
|
||||||
if (isDesktop)
|
|
||||||
const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
if (isDesktop)
|
|
||||||
ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 1008,
|
|
||||||
),
|
),
|
||||||
child: Builder(
|
Text(
|
||||||
builder: (BuildContext context) {
|
"Recovery phrase",
|
||||||
const cols = 4;
|
style: isDesktop
|
||||||
final int rows = _seedWordCount ~/ cols;
|
? STextStyles.desktopH2(context)
|
||||||
final int remainder = _seedWordCount % cols;
|
: STextStyles.pageTitleH1(context),
|
||||||
|
),
|
||||||
return Column(
|
SizedBox(
|
||||||
children: [
|
height: isDesktop ? 16 : 8,
|
||||||
Form(
|
),
|
||||||
key: _formKey,
|
Text(
|
||||||
child: TableView(
|
"Enter your $_seedWordCount-word recovery phrase.",
|
||||||
shrinkWrap: true,
|
style: isDesktop
|
||||||
rowSpacing: 20,
|
? STextStyles.desktopSubtitleH2(context)
|
||||||
rows: [
|
: STextStyles.subtitle(context),
|
||||||
for (int i = 0; i < rows; i++)
|
),
|
||||||
TableViewRow(
|
SizedBox(
|
||||||
crossAxisAlignment:
|
height: isDesktop ? 16 : 10,
|
||||||
CrossAxisAlignment.start,
|
),
|
||||||
spacing: 16,
|
if (isDesktop)
|
||||||
cells: [
|
Row(
|
||||||
for (int j = 1; j <= cols; j++)
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
TableViewCell(
|
children: [
|
||||||
flex: 1,
|
TextButton(
|
||||||
child: Column(
|
onPressed: pasteMnemonic,
|
||||||
children: [
|
child: Padding(
|
||||||
TextFormField(
|
padding: const EdgeInsets.symmetric(
|
||||||
autocorrect: !isDesktop,
|
horizontal: 16.0,
|
||||||
enableSuggestions: !isDesktop,
|
vertical: 12,
|
||||||
textCapitalization:
|
),
|
||||||
TextCapitalization.none,
|
child: Row(
|
||||||
key: Key(
|
children: [
|
||||||
"restoreMnemonicFormField_$i"),
|
SvgPicture.asset(
|
||||||
decoration:
|
Assets.svg.clipboard,
|
||||||
_getInputDecorationFor(
|
width: 22,
|
||||||
_inputStatuses[
|
height: 22,
|
||||||
i * 4 + j - 1],
|
color: Theme.of(context)
|
||||||
"${i * 4 + j}"),
|
.extension<StackColors>()!
|
||||||
autovalidateMode:
|
.buttonTextSecondary,
|
||||||
AutovalidateMode
|
),
|
||||||
.onUserInteraction,
|
const SizedBox(
|
||||||
selectionControls:
|
width: 8,
|
||||||
i * 4 + j - 1 == 1
|
),
|
||||||
? textSelectionControls
|
Text(
|
||||||
: null,
|
"Paste",
|
||||||
// focusNode:
|
style: STextStyles
|
||||||
// _focusNodes[i * 4 + j - 1],
|
.desktopButtonSmallSecondaryEnabled(
|
||||||
onChanged: (value) {
|
context),
|
||||||
final FormInputStatus
|
)
|
||||||
formInputStatus;
|
|
||||||
|
|
||||||
if (value.isEmpty) {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.empty;
|
|
||||||
} else if (_isValidMnemonicWord(
|
|
||||||
value
|
|
||||||
.trim()
|
|
||||||
.toLowerCase())) {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.valid;
|
|
||||||
} else {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (formInputStatus ==
|
|
||||||
// FormInputStatus.valid) {
|
|
||||||
// if (i * 4 + j <
|
|
||||||
// _focusNodes.length) {
|
|
||||||
// _focusNodes[i * 4 + j]
|
|
||||||
// .requestFocus();
|
|
||||||
// } else if (i * 4 + j ==
|
|
||||||
// _focusNodes.length) {
|
|
||||||
// _focusNodes[i * 4 + j - 1]
|
|
||||||
// .unfocus();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
setState(() {
|
|
||||||
_inputStatuses[i * 4 +
|
|
||||||
j -
|
|
||||||
1] = formInputStatus;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
controller:
|
|
||||||
_controllers[i * 4 + j - 1],
|
|
||||||
style:
|
|
||||||
STextStyles.field(context)
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.textRestore,
|
|
||||||
fontSize: isDesktop ? 16 : 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_inputStatuses[
|
|
||||||
i * 4 + j - 1] ==
|
|
||||||
FormInputStatus.invalid)
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(
|
|
||||||
left: 12.0,
|
|
||||||
bottom: 4.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
"Please check spelling",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: STextStyles.label(
|
|
||||||
context)
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<
|
|
||||||
StackColors>()!
|
|
||||||
.textError,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
expandingChild: null,
|
|
||||||
),
|
|
||||||
if (remainder > 0)
|
|
||||||
TableViewRow(
|
|
||||||
spacing: 16,
|
|
||||||
cells: [
|
|
||||||
for (int i = rows * cols;
|
|
||||||
i < _seedWordCount;
|
|
||||||
i++) ...[
|
|
||||||
TableViewCell(
|
|
||||||
flex: 1,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
TextFormField(
|
|
||||||
autocorrect: !isDesktop,
|
|
||||||
enableSuggestions: !isDesktop,
|
|
||||||
textCapitalization:
|
|
||||||
TextCapitalization.none,
|
|
||||||
key: Key(
|
|
||||||
"restoreMnemonicFormField_$i"),
|
|
||||||
decoration:
|
|
||||||
_getInputDecorationFor(
|
|
||||||
_inputStatuses[i],
|
|
||||||
"${i + 1}"),
|
|
||||||
autovalidateMode:
|
|
||||||
AutovalidateMode
|
|
||||||
.onUserInteraction,
|
|
||||||
selectionControls: i == 1
|
|
||||||
? textSelectionControls
|
|
||||||
: null,
|
|
||||||
// focusNode: _focusNodes[i],
|
|
||||||
onChanged: (value) {
|
|
||||||
final FormInputStatus
|
|
||||||
formInputStatus;
|
|
||||||
|
|
||||||
if (value.isEmpty) {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.empty;
|
|
||||||
} else if (_isValidMnemonicWord(
|
|
||||||
value
|
|
||||||
.trim()
|
|
||||||
.toLowerCase())) {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.valid;
|
|
||||||
} else {
|
|
||||||
formInputStatus =
|
|
||||||
FormInputStatus.invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (formInputStatus ==
|
|
||||||
// FormInputStatus
|
|
||||||
// .valid &&
|
|
||||||
// (i - 1) <
|
|
||||||
// _focusNodes.length) {
|
|
||||||
// Focus.of(context)
|
|
||||||
// .requestFocus(
|
|
||||||
// _focusNodes[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (formInputStatus ==
|
|
||||||
// FormInputStatus.valid) {
|
|
||||||
// if (i + 1 <
|
|
||||||
// _focusNodes.length) {
|
|
||||||
// _focusNodes[i + 1]
|
|
||||||
// .requestFocus();
|
|
||||||
// } else if (i + 1 ==
|
|
||||||
// _focusNodes.length) {
|
|
||||||
// _focusNodes[i].unfocus();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
controller: _controllers[i],
|
|
||||||
style:
|
|
||||||
STextStyles.field(context)
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.overlay,
|
|
||||||
fontSize: isDesktop ? 16 : 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_inputStatuses[i] ==
|
|
||||||
FormInputStatus.invalid)
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(
|
|
||||||
left: 12.0,
|
|
||||||
bottom: 4.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
"Please check spelling",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: STextStyles.label(
|
|
||||||
context)
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<
|
|
||||||
StackColors>()!
|
|
||||||
.textError,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
for (int i = remainder;
|
|
||||||
i < cols;
|
|
||||||
i++) ...[
|
|
||||||
TableViewCell(
|
|
||||||
flex: 1,
|
|
||||||
child: Container(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
expandingChild: null,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
),
|
||||||
height: 32,
|
],
|
||||||
),
|
),
|
||||||
PrimaryButton(
|
if (isDesktop)
|
||||||
label: "Restore wallet",
|
const SizedBox(
|
||||||
width: 480,
|
height: 20,
|
||||||
onPressed: requestRestore,
|
),
|
||||||
),
|
if (isDesktop)
|
||||||
],
|
ConstrainedBox(
|
||||||
);
|
constraints: const BoxConstraints(
|
||||||
},
|
maxWidth: 1008,
|
||||||
),
|
),
|
||||||
),
|
child: Builder(
|
||||||
/*if (isDesktop)
|
builder: (BuildContext context) {
|
||||||
|
const cols = 4;
|
||||||
|
final int rows = _seedWordCount ~/ cols;
|
||||||
|
final int remainder = _seedWordCount % cols;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: TableView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
rowSpacing: 20,
|
||||||
|
rows: [
|
||||||
|
for (int i = 0; i < rows; i++)
|
||||||
|
TableViewRow(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
spacing: 16,
|
||||||
|
cells: [
|
||||||
|
for (int j = 1; j <= cols; j++)
|
||||||
|
TableViewCell(
|
||||||
|
flex: 1,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
autocorrect: !isDesktop,
|
||||||
|
enableSuggestions:
|
||||||
|
!isDesktop,
|
||||||
|
textCapitalization:
|
||||||
|
TextCapitalization.none,
|
||||||
|
key: Key(
|
||||||
|
"restoreMnemonicFormField_$i"),
|
||||||
|
decoration:
|
||||||
|
_getInputDecorationFor(
|
||||||
|
_inputStatuses[
|
||||||
|
i * 4 + j - 1],
|
||||||
|
"${i * 4 + j}"),
|
||||||
|
autovalidateMode:
|
||||||
|
AutovalidateMode
|
||||||
|
.onUserInteraction,
|
||||||
|
selectionControls: i * 4 +
|
||||||
|
j -
|
||||||
|
1 ==
|
||||||
|
1
|
||||||
|
? textSelectionControls
|
||||||
|
: null,
|
||||||
|
// focusNode:
|
||||||
|
// _focusNodes[i * 4 + j - 1],
|
||||||
|
onChanged: (value) {
|
||||||
|
final FormInputStatus
|
||||||
|
formInputStatus;
|
||||||
|
|
||||||
|
if (value.isEmpty) {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.empty;
|
||||||
|
} else if (_isValidMnemonicWord(
|
||||||
|
value
|
||||||
|
.trim()
|
||||||
|
.toLowerCase())) {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.valid;
|
||||||
|
} else {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (formInputStatus ==
|
||||||
|
// FormInputStatus.valid) {
|
||||||
|
// if (i * 4 + j <
|
||||||
|
// _focusNodes.length) {
|
||||||
|
// _focusNodes[i * 4 + j]
|
||||||
|
// .requestFocus();
|
||||||
|
// } else if (i * 4 + j ==
|
||||||
|
// _focusNodes.length) {
|
||||||
|
// _focusNodes[i * 4 + j - 1]
|
||||||
|
// .unfocus();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
setState(() {
|
||||||
|
_inputStatuses[
|
||||||
|
i * 4 + j - 1] =
|
||||||
|
formInputStatus;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
controller: _controllers[
|
||||||
|
i * 4 + j - 1],
|
||||||
|
style: STextStyles.field(
|
||||||
|
context)
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<
|
||||||
|
StackColors>()!
|
||||||
|
.textRestore,
|
||||||
|
fontSize:
|
||||||
|
isDesktop ? 16 : 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_inputStatuses[
|
||||||
|
i * 4 + j - 1] ==
|
||||||
|
FormInputStatus.invalid)
|
||||||
|
Align(
|
||||||
|
alignment:
|
||||||
|
Alignment.topLeft,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets
|
||||||
|
.only(
|
||||||
|
left: 12.0,
|
||||||
|
bottom: 4.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Please check spelling",
|
||||||
|
textAlign:
|
||||||
|
TextAlign.left,
|
||||||
|
style:
|
||||||
|
STextStyles.label(
|
||||||
|
context)
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context)
|
||||||
|
.extension<
|
||||||
|
StackColors>()!
|
||||||
|
.textError,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
expandingChild: null,
|
||||||
|
),
|
||||||
|
if (remainder > 0)
|
||||||
|
TableViewRow(
|
||||||
|
spacing: 16,
|
||||||
|
cells: [
|
||||||
|
for (int i = rows * cols;
|
||||||
|
i < _seedWordCount;
|
||||||
|
i++) ...[
|
||||||
|
TableViewCell(
|
||||||
|
flex: 1,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
autocorrect: !isDesktop,
|
||||||
|
enableSuggestions:
|
||||||
|
!isDesktop,
|
||||||
|
textCapitalization:
|
||||||
|
TextCapitalization.none,
|
||||||
|
key: Key(
|
||||||
|
"restoreMnemonicFormField_$i"),
|
||||||
|
decoration:
|
||||||
|
_getInputDecorationFor(
|
||||||
|
_inputStatuses[i],
|
||||||
|
"${i + 1}"),
|
||||||
|
autovalidateMode:
|
||||||
|
AutovalidateMode
|
||||||
|
.onUserInteraction,
|
||||||
|
selectionControls: i == 1
|
||||||
|
? textSelectionControls
|
||||||
|
: null,
|
||||||
|
// focusNode: _focusNodes[i],
|
||||||
|
onChanged: (value) {
|
||||||
|
final FormInputStatus
|
||||||
|
formInputStatus;
|
||||||
|
|
||||||
|
if (value.isEmpty) {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.empty;
|
||||||
|
} else if (_isValidMnemonicWord(
|
||||||
|
value
|
||||||
|
.trim()
|
||||||
|
.toLowerCase())) {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.valid;
|
||||||
|
} else {
|
||||||
|
formInputStatus =
|
||||||
|
FormInputStatus
|
||||||
|
.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (formInputStatus ==
|
||||||
|
// FormInputStatus
|
||||||
|
// .valid &&
|
||||||
|
// (i - 1) <
|
||||||
|
// _focusNodes.length) {
|
||||||
|
// Focus.of(context)
|
||||||
|
// .requestFocus(
|
||||||
|
// _focusNodes[i]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (formInputStatus ==
|
||||||
|
// FormInputStatus.valid) {
|
||||||
|
// if (i + 1 <
|
||||||
|
// _focusNodes.length) {
|
||||||
|
// _focusNodes[i + 1]
|
||||||
|
// .requestFocus();
|
||||||
|
// } else if (i + 1 ==
|
||||||
|
// _focusNodes.length) {
|
||||||
|
// _focusNodes[i].unfocus();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
controller: _controllers[i],
|
||||||
|
style: STextStyles.field(
|
||||||
|
context)
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<
|
||||||
|
StackColors>()!
|
||||||
|
.overlay,
|
||||||
|
fontSize:
|
||||||
|
isDesktop ? 16 : 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_inputStatuses[i] ==
|
||||||
|
FormInputStatus.invalid)
|
||||||
|
Align(
|
||||||
|
alignment:
|
||||||
|
Alignment.topLeft,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets
|
||||||
|
.only(
|
||||||
|
left: 12.0,
|
||||||
|
bottom: 4.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Please check spelling",
|
||||||
|
textAlign:
|
||||||
|
TextAlign.left,
|
||||||
|
style:
|
||||||
|
STextStyles.label(
|
||||||
|
context)
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context)
|
||||||
|
.extension<
|
||||||
|
StackColors>()!
|
||||||
|
.textError,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
for (int i = remainder;
|
||||||
|
i < cols;
|
||||||
|
i++) ...[
|
||||||
|
TableViewCell(
|
||||||
|
flex: 1,
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
expandingChild: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Restore wallet",
|
||||||
|
width: 480,
|
||||||
|
onPressed: requestRestore,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
/*if (isDesktop)
|
||||||
const Spacer(
|
const Spacer(
|
||||||
flex: 15,
|
flex: 15,
|
||||||
),*/
|
),*/
|
||||||
if (!isDesktop)
|
if (!isDesktop)
|
||||||
Expanded(
|
Padding(
|
||||||
child: SingleChildScrollView(
|
|
||||||
controller: controller,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
|
@ -1169,13 +1193,11 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1048,7 +1048,7 @@ class _TransactionV2DetailsViewState
|
||||||
pTransactionNote(
|
pTransactionNote(
|
||||||
(
|
(
|
||||||
txid: (coin == Coin.epicCash) ?
|
txid: (coin == Coin.epicCash) ?
|
||||||
_transaction.slateId as String
|
_transaction.slateId.toString()
|
||||||
: _transaction.txid,
|
: _transaction.txid,
|
||||||
walletId: walletId
|
walletId: walletId
|
||||||
),
|
),
|
||||||
|
|
|
@ -612,7 +612,7 @@ abstract class EthereumAPI {
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
url: Uri.parse(
|
url: Uri.parse(
|
||||||
// "$stackBaseServer/tokens?addrs=$contractAddress&parts=all",
|
// "$stackBaseServer/tokens?addrs=$contractAddress&parts=all",
|
||||||
"$stackBaseServer/names?terms=$contractAddress",
|
"$stackBaseServer/names?terms=$contractAddress&all",
|
||||||
),
|
),
|
||||||
proxyInfo: Prefs.instance.useTor
|
proxyInfo: Prefs.instance.useTor
|
||||||
? TorService.sharedInstance.getProxyInfo()
|
? TorService.sharedInstance.getProxyInfo()
|
||||||
|
|
|
@ -17,7 +17,7 @@ abstract class DefaultEpicBoxes {
|
||||||
static List<String> get defaultIds => ['americas', 'asia', 'europe'];
|
static List<String> get defaultIds => ['americas', 'asia', 'europe'];
|
||||||
|
|
||||||
static EpicBoxServerModel get americas => EpicBoxServerModel(
|
static EpicBoxServerModel get americas => EpicBoxServerModel(
|
||||||
host: 'stackwallet.epicbox.com',
|
host: 'epicbox.stackwallet.com',
|
||||||
port: 443,
|
port: 443,
|
||||||
name: 'Americas',
|
name: 'Americas',
|
||||||
id: 'americas',
|
id: 'americas',
|
||||||
|
|
|
@ -185,7 +185,8 @@ class Ecash extends Bip39HDCurrency {
|
||||||
addr = cashAddr.split(":").last;
|
addr = cashAddr.split(":").last;
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr.startsWith("q") || addr.startsWith("p");
|
return addr.startsWith("q") /*|| addr.startsWith("p")*/;
|
||||||
|
// Do not validate "p" (P2SH) addresses.
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
|
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||||
|
import 'package:stackwallet/wallets/isar/models/spark_coin.dart';
|
||||||
import 'package:tezart/tezart.dart' as tezart;
|
import 'package:tezart/tezart.dart' as tezart;
|
||||||
import 'package:web3dart/web3dart.dart' as web3dart;
|
import 'package:web3dart/web3dart.dart' as web3dart;
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@ class TxData {
|
||||||
bool isChange,
|
bool isChange,
|
||||||
})>? sparkRecipients;
|
})>? sparkRecipients;
|
||||||
final List<TxData>? sparkMints;
|
final List<TxData>? sparkMints;
|
||||||
|
final List<SparkCoin>? usedSparkCoins;
|
||||||
|
|
||||||
final TransactionV2? tempTx;
|
final TransactionV2? tempTx;
|
||||||
|
|
||||||
|
@ -105,6 +107,7 @@ class TxData {
|
||||||
this.tezosOperationsList,
|
this.tezosOperationsList,
|
||||||
this.sparkRecipients,
|
this.sparkRecipients,
|
||||||
this.sparkMints,
|
this.sparkMints,
|
||||||
|
this.usedSparkCoins,
|
||||||
this.tempTx,
|
this.tempTx,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -187,6 +190,7 @@ class TxData {
|
||||||
})>?
|
})>?
|
||||||
sparkRecipients,
|
sparkRecipients,
|
||||||
List<TxData>? sparkMints,
|
List<TxData>? sparkMints,
|
||||||
|
List<SparkCoin>? usedSparkCoins,
|
||||||
TransactionV2? tempTx,
|
TransactionV2? tempTx,
|
||||||
}) {
|
}) {
|
||||||
return TxData(
|
return TxData(
|
||||||
|
@ -224,6 +228,7 @@ class TxData {
|
||||||
tezosOperationsList: tezosOperationsList ?? this.tezosOperationsList,
|
tezosOperationsList: tezosOperationsList ?? this.tezosOperationsList,
|
||||||
sparkRecipients: sparkRecipients ?? this.sparkRecipients,
|
sparkRecipients: sparkRecipients ?? this.sparkRecipients,
|
||||||
sparkMints: sparkMints ?? this.sparkMints,
|
sparkMints: sparkMints ?? this.sparkMints,
|
||||||
|
usedSparkCoins: usedSparkCoins ?? this.usedSparkCoins,
|
||||||
tempTx: tempTx ?? this.tempTx,
|
tempTx: tempTx ?? this.tempTx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -262,6 +267,7 @@ class TxData {
|
||||||
'tezosOperationsList: $tezosOperationsList, '
|
'tezosOperationsList: $tezosOperationsList, '
|
||||||
'sparkRecipients: $sparkRecipients, '
|
'sparkRecipients: $sparkRecipients, '
|
||||||
'sparkMints: $sparkMints, '
|
'sparkMints: $sparkMints, '
|
||||||
|
'usedSparkCoins: $usedSparkCoins, '
|
||||||
'tempTx: $tempTx, '
|
'tempTx: $tempTx, '
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,46 +103,30 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<EpicBoxConfigModel> getEpicBoxConfig() async {
|
Future<EpicBoxConfigModel> getEpicBoxConfig() async {
|
||||||
EpicBoxConfigModel? _epicBoxConfig;
|
EpicBoxConfigModel? _epicBoxConfig =
|
||||||
// read epicbox config from secure store
|
EpicBoxConfigModel.fromServer(DefaultEpicBoxes.defaultEpicBoxServer);
|
||||||
String? storedConfig =
|
|
||||||
await secureStorageInterface.read(key: '${walletId}_epicboxConfig');
|
|
||||||
|
|
||||||
// we should move to storing the primary server model like we do with nodes, and build the config from that (see epic-mobile)
|
//Get the default Epicbox server and check if it's conected
|
||||||
// EpicBoxServerModel? _epicBox = epicBox ??
|
// bool isEpicboxConnected = await _testEpicboxServer(
|
||||||
// DB.instance.get<EpicBoxServerModel>(
|
// DefaultEpicBoxes.defaultEpicBoxServer.host, DefaultEpicBoxes.defaultEpicBoxServer.port ?? 443);
|
||||||
// boxName: DB.boxNamePrimaryEpicBox, key: 'primary');
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "Read primary Epic Box config: ${jsonEncode(_epicBox)}",
|
|
||||||
// level: LogLevel.Info);
|
|
||||||
|
|
||||||
if (storedConfig == null) {
|
// if (isEpicboxConnected) {
|
||||||
// if no config stored, use the default epicbox server as config
|
//Use default server for as Epicbox config
|
||||||
_epicBoxConfig =
|
|
||||||
EpicBoxConfigModel.fromServer(DefaultEpicBoxes.defaultEpicBoxServer);
|
|
||||||
} else {
|
|
||||||
// if a config is stored, test it
|
|
||||||
|
|
||||||
_epicBoxConfig = EpicBoxConfigModel.fromString(
|
// }
|
||||||
storedConfig); // fromString handles checking old config formats
|
// else {
|
||||||
}
|
// //Use Europe config
|
||||||
|
// _epicBoxConfig = EpicBoxConfigModel.fromServer(DefaultEpicBoxes.europe);
|
||||||
bool isEpicboxConnected = await _testEpicboxServer(
|
// }
|
||||||
_epicBoxConfig.host, _epicBoxConfig.port ?? 443);
|
// // example of selecting another random server from the default list
|
||||||
|
// // alternative servers: copy list of all default EB servers but remove the default default
|
||||||
if (!isEpicboxConnected) {
|
// // List<EpicBoxServerModel> alternativeServers = DefaultEpicBoxes.all;
|
||||||
// default Epicbox is not connected, default to Europe
|
// // alternativeServers.removeWhere((opt) => opt.name == DefaultEpicBoxes.defaultEpicBoxServer.name);
|
||||||
_epicBoxConfig = EpicBoxConfigModel.fromServer(DefaultEpicBoxes.europe);
|
// // alternativeServers.shuffle(); // randomize which server is used
|
||||||
|
// // _epicBoxConfig = EpicBoxConfigModel.fromServer(alternativeServers.first);
|
||||||
// example of selecting another random server from the default list
|
//
|
||||||
// alternative servers: copy list of all default EB servers but remove the default default
|
// // TODO test this connection before returning it
|
||||||
// List<EpicBoxServerModel> alternativeServers = DefaultEpicBoxes.all;
|
// }
|
||||||
// alternativeServers.removeWhere((opt) => opt.name == DefaultEpicBoxes.defaultEpicBoxServer.name);
|
|
||||||
// alternativeServers.shuffle(); // randomize which server is used
|
|
||||||
// _epicBoxConfig = EpicBoxConfigModel.fromServer(alternativeServers.first);
|
|
||||||
|
|
||||||
// TODO test this connection before returning it
|
|
||||||
}
|
|
||||||
|
|
||||||
return _epicBoxConfig;
|
return _epicBoxConfig;
|
||||||
}
|
}
|
||||||
|
@ -334,36 +318,50 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
int index,
|
int index,
|
||||||
) async {
|
) async {
|
||||||
Address? address = await getCurrentReceivingAddress();
|
Address? address = await getCurrentReceivingAddress();
|
||||||
|
EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
|
||||||
|
|
||||||
if (address == null) {
|
if (address != null) {
|
||||||
final wallet =
|
final splitted = address.value.split('@');
|
||||||
await secureStorageInterface.read(key: '${walletId}_wallet');
|
//Check if the address is the same as the current epicbox domain
|
||||||
EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
|
//Since we're only using one epicbpox now this doesn't apply but will be
|
||||||
|
// useful in the future
|
||||||
final walletAddress = await epiccash.LibEpiccash.getAddressInfo(
|
if (splitted[1] != epicboxConfig.host) {
|
||||||
wallet: wallet!,
|
//Update the address
|
||||||
index: index,
|
address = await thisWalletAddress(index, epicboxConfig);
|
||||||
epicboxConfig: epicboxConfig.toString(),
|
}
|
||||||
);
|
} else {
|
||||||
|
address = await thisWalletAddress(index, epicboxConfig);
|
||||||
Logging.instance.log(
|
|
||||||
"WALLET_ADDRESS_IS $walletAddress",
|
|
||||||
level: LogLevel.Info,
|
|
||||||
);
|
|
||||||
|
|
||||||
address = Address(
|
|
||||||
walletId: walletId,
|
|
||||||
value: walletAddress,
|
|
||||||
derivationIndex: index,
|
|
||||||
derivationPath: null,
|
|
||||||
type: AddressType.mimbleWimble,
|
|
||||||
subType: AddressSubType.receiving,
|
|
||||||
publicKey: [], // ??
|
|
||||||
);
|
|
||||||
|
|
||||||
await mainDB.updateOrPutAddresses([address]);
|
|
||||||
}
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Address> thisWalletAddress(int index, EpicBoxConfigModel epicboxConfig) async {
|
||||||
|
final wallet =
|
||||||
|
await secureStorageInterface.read(key: '${walletId}_wallet');
|
||||||
|
// EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
|
||||||
|
|
||||||
|
final walletAddress = await epiccash.LibEpiccash.getAddressInfo(
|
||||||
|
wallet: wallet!,
|
||||||
|
index: index,
|
||||||
|
epicboxConfig: epicboxConfig.toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Logging.instance.log(
|
||||||
|
"WALLET_ADDRESS_IS $walletAddress",
|
||||||
|
level: LogLevel.Info,
|
||||||
|
);
|
||||||
|
|
||||||
|
final address = Address(
|
||||||
|
walletId: walletId,
|
||||||
|
value: walletAddress,
|
||||||
|
derivationIndex: index,
|
||||||
|
derivationPath: null,
|
||||||
|
type: AddressType.mimbleWimble,
|
||||||
|
subType: AddressSubType.receiving,
|
||||||
|
publicKey: [], // ??
|
||||||
|
);
|
||||||
|
|
||||||
|
await mainDB.updateOrPutAddresses([address]);
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,6 +934,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
.findAll();
|
.findAll();
|
||||||
final myAddressesSet = myAddresses.toSet();
|
final myAddressesSet = myAddresses.toSet();
|
||||||
|
|
||||||
|
|
||||||
final transactions = await epiccash.LibEpiccash.getTransactions(
|
final transactions = await epiccash.LibEpiccash.getTransactions(
|
||||||
wallet: wallet!,
|
wallet: wallet!,
|
||||||
refreshFromNode: refreshFromNode,
|
refreshFromNode: refreshFromNode,
|
||||||
|
|
|
@ -499,6 +499,27 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final List<SparkCoin> usedSparkCoins = [];
|
||||||
|
|
||||||
|
for (final usedCoin in spend.usedCoins) {
|
||||||
|
try {
|
||||||
|
usedSparkCoins.add(coins
|
||||||
|
.firstWhere((e) =>
|
||||||
|
usedCoin.height == e.height &&
|
||||||
|
usedCoin.groupId == e.groupId &&
|
||||||
|
base64Decode(e.serializedCoinB64!)
|
||||||
|
.toHex
|
||||||
|
.startsWith(base64Decode(usedCoin.serializedCoin).toHex))
|
||||||
|
.copyWith(
|
||||||
|
isUsed: true,
|
||||||
|
));
|
||||||
|
} catch (_) {
|
||||||
|
throw Exception(
|
||||||
|
"Unexpectedly did not find used spark coin. This should never happen.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return txData.copyWith(
|
return txData.copyWith(
|
||||||
raw: rawTxHex,
|
raw: rawTxHex,
|
||||||
vSize: extractedTx.virtualSize(),
|
vSize: extractedTx.virtualSize(),
|
||||||
|
@ -523,7 +544,7 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
height: null,
|
height: null,
|
||||||
version: 3,
|
version: 3,
|
||||||
),
|
),
|
||||||
// TODO used coins
|
usedSparkCoins: usedSparkCoins,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,17 +561,17 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
|
Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
|
||||||
|
|
||||||
txData = txData.copyWith(
|
txData = txData.copyWith(
|
||||||
// TODO mark spark coins as spent locally and update balance before waiting to check via electrumx?
|
|
||||||
|
|
||||||
// usedUTXOs:
|
|
||||||
// txData.usedUTXOs!.map((e) => e.copyWith(used: true)).toList(),
|
|
||||||
|
|
||||||
// TODO revisit setting these both
|
// TODO revisit setting these both
|
||||||
txHash: txHash,
|
txHash: txHash,
|
||||||
txid: txHash,
|
txid: txHash,
|
||||||
);
|
);
|
||||||
// // mark utxos as used
|
|
||||||
// await mainDB.putUTXOs(txData.usedUTXOs!);
|
// Update used spark coins as used in database. They should already have
|
||||||
|
// been marked as isUsed.
|
||||||
|
// TODO: [prio=med] Could (probably should) throw an exception here if txData.usedSparkCoins is null or empty
|
||||||
|
if (txData.usedSparkCoins != null && txData.usedSparkCoins!.isNotEmpty) {
|
||||||
|
await _addOrUpdateSparkCoins(txData.usedSparkCoins!);
|
||||||
|
}
|
||||||
|
|
||||||
return await updateSentCachedTxData(txData: txData);
|
return await updateSentCachedTxData(txData: txData);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -1499,6 +1520,13 @@ Future<
|
||||||
Uint8List serializedSpendPayload,
|
Uint8List serializedSpendPayload,
|
||||||
List<Uint8List> outputScripts,
|
List<Uint8List> outputScripts,
|
||||||
int fee,
|
int fee,
|
||||||
|
List<
|
||||||
|
({
|
||||||
|
int groupId,
|
||||||
|
int height,
|
||||||
|
String serializedCoin,
|
||||||
|
String serializedCoinContext
|
||||||
|
})> usedCoins,
|
||||||
})> _createSparkSend(
|
})> _createSparkSend(
|
||||||
({
|
({
|
||||||
String privateKeyHex,
|
String privateKeyHex,
|
||||||
|
|
|
@ -528,8 +528,8 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "0a34f7f48d921fb33f551cb11dfc9b2930522240"
|
ref: "2897c6448e131241d4d91fe23fdab83305134225"
|
||||||
resolved-ref: "0a34f7f48d921fb33f551cb11dfc9b2930522240"
|
resolved-ref: "2897c6448e131241d4d91fe23fdab83305134225"
|
||||||
url: "https://github.com/cypherstack/electrum_adapter.git"
|
url: "https://github.com/cypherstack/electrum_adapter.git"
|
||||||
source: git
|
source: git
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
@ -674,8 +674,8 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: fb50031056fbea0326f7dd76ad59d165c1e5eee5
|
ref: "3f986ca1a94bdac5d31373454c989cc2f5842de8"
|
||||||
resolved-ref: fb50031056fbea0326f7dd76ad59d165c1e5eee5
|
resolved-ref: "3f986ca1a94bdac5d31373454c989cc2f5842de8"
|
||||||
url: "https://github.com/cypherstack/flutter_libsparkmobile.git"
|
url: "https://github.com/cypherstack/flutter_libsparkmobile.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
|
|
|
@ -11,7 +11,7 @@ description: Stack Wallet
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 1.10.1+209
|
version: 1.10.2+213
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.2 <4.0.0"
|
sdk: ">=3.0.2 <4.0.0"
|
||||||
|
@ -33,7 +33,7 @@ dependencies:
|
||||||
flutter_libsparkmobile:
|
flutter_libsparkmobile:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cypherstack/flutter_libsparkmobile.git
|
url: https://github.com/cypherstack/flutter_libsparkmobile.git
|
||||||
ref: fb50031056fbea0326f7dd76ad59d165c1e5eee5
|
ref: 3f986ca1a94bdac5d31373454c989cc2f5842de8
|
||||||
|
|
||||||
flutter_libmonero:
|
flutter_libmonero:
|
||||||
path: ./crypto_plugins/flutter_libmonero
|
path: ./crypto_plugins/flutter_libmonero
|
||||||
|
@ -179,7 +179,7 @@ dependencies:
|
||||||
electrum_adapter:
|
electrum_adapter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cypherstack/electrum_adapter.git
|
url: https://github.com/cypherstack/electrum_adapter.git
|
||||||
ref: 0a34f7f48d921fb33f551cb11dfc9b2930522240
|
ref: 2897c6448e131241d4d91fe23fdab83305134225
|
||||||
stream_channel: ^2.1.0
|
stream_channel: ^2.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
Loading…
Reference in a new issue