mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
commit
d6a91b78c7
16 changed files with 766 additions and 173 deletions
|
@ -42,6 +42,11 @@ class _RestoreFromDatePickerState extends State<RestoreFromDatePicker> {
|
|||
style: STextStyles.field(context),
|
||||
decoration: InputDecoration(
|
||||
hintText: "Restore from...",
|
||||
hintStyle: STextStyles.fieldLabel(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultSearchIconLeft,
|
||||
),
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
|
|
|
@ -393,13 +393,15 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
|
|||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: SvgPicture.asset(Assets.svg.pencil,
|
||||
width: 12,
|
||||
height: 12,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.pencil,
|
||||
width: 14,
|
||||
height: 14,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -421,13 +423,15 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
|
|||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: SvgPicture.asset(Assets.svg.copy,
|
||||
width: 12,
|
||||
height: 12,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
|
|||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/send_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart';
|
||||
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
||||
|
@ -19,6 +20,9 @@ import 'package:stackwallet/widgets/rounded_container.dart';
|
|||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
final exchangeFromAddressBookAddressStateProvider =
|
||||
StateProvider<String>((ref) => "");
|
||||
|
||||
class ContactPopUp extends ConsumerWidget {
|
||||
const ContactPopUp({
|
||||
Key? key,
|
||||
|
@ -268,11 +272,11 @@ class ContactPopUp extends ConsumerWidget {
|
|||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding: const EdgeInsets.all(4),
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 12,
|
||||
height: 12,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
|
@ -280,6 +284,45 @@ class ContactPopUp extends ConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (isExchangeFlow)
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
if (isExchangeFlow)
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
exchangeFromAddressBookAddressStateProvider
|
||||
.state)
|
||||
.state = e.address;
|
||||
Navigator.of(context).popUntil(
|
||||
ModalRoute.withName(
|
||||
Step2View.routeName));
|
||||
},
|
||||
child: RoundedContainer(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding:
|
||||
const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.chevronRight,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (contact.id != "default" &&
|
||||
hasActiveWallet &&
|
||||
!isExchangeFlow)
|
||||
|
|
128
lib/pages/exchange_view/choose_from_stack_view.dart
Normal file
128
lib/pages/exchange_view/choose_from_stack_view.dart
Normal file
|
@ -0,0 +1,128 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart';
|
||||
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
|
||||
|
||||
class ChooseFromStackView extends ConsumerStatefulWidget {
|
||||
const ChooseFromStackView({
|
||||
Key? key,
|
||||
required this.coin,
|
||||
}) : super(key: key);
|
||||
|
||||
final Coin coin;
|
||||
|
||||
static const String routeName = "/chooseFromStack";
|
||||
|
||||
@override
|
||||
ConsumerState<ChooseFromStackView> createState() =>
|
||||
_ChooseFromStackViewState();
|
||||
}
|
||||
|
||||
class _ChooseFromStackViewState extends ConsumerState<ChooseFromStackView> {
|
||||
late final Coin coin;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
coin = widget.coin;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletIds = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getWalletIdsFor(coin: coin)));
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: const AppBarBackButton(),
|
||||
title: Text(
|
||||
"Choose your ${coin.ticker.toUpperCase()} wallet",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: walletIds.isEmpty
|
||||
? Column(
|
||||
children: [
|
||||
RoundedWhiteContainer(
|
||||
child: Center(
|
||||
child: Text(
|
||||
"No ${coin.ticker.toUpperCase()} wallets",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: walletIds.length,
|
||||
itemBuilder: (context, index) {
|
||||
final manager = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletIds[index])));
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: RawMaterialButton(
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
// color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
elevation: 0,
|
||||
onPressed: () async {
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop(manager.walletId);
|
||||
}
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
// color: Colors.transparent,
|
||||
child: Row(
|
||||
children: [
|
||||
WalletInfoCoinIcon(coin: coin),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12(context),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
WalletInfoRowBalanceFuture(
|
||||
walletId: walletIds[index],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -132,6 +132,7 @@ class _ConfirmChangeNowSendViewState
|
|||
final managerProvider = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManagerProvider(walletId)));
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
leading: AppBarBackButton(
|
||||
|
@ -327,7 +328,12 @@ class _ConfirmChangeNowSendViewState
|
|||
children: [
|
||||
Text(
|
||||
"Total amount",
|
||||
style: STextStyles.titleBold12(context),
|
||||
style:
|
||||
STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(
|
||||
|
@ -341,7 +347,12 @@ class _ConfirmChangeNowSendViewState
|
|||
managerProvider
|
||||
.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/address_book_view.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||
import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart';
|
||||
|
@ -17,6 +19,7 @@ import 'package:stackwallet/utilities/logger.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
||||
|
@ -54,6 +57,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
late final FocusNode _toFocusNode;
|
||||
late final FocusNode _refundFocusNode;
|
||||
|
||||
bool isStackCoin(String ticker) {
|
||||
try {
|
||||
coinFromTickerCaseInsensitive(ticker);
|
||||
return true;
|
||||
} on ArgumentError catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
model = widget.model;
|
||||
|
@ -74,7 +86,22 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(tuple.item1)
|
||||
.currentReceivingAddress
|
||||
.then((value) => _toController.text = value);
|
||||
.then((value) {
|
||||
_toController.text = value;
|
||||
model.recipientAddress = _toController.text;
|
||||
});
|
||||
} else {
|
||||
if (model.sendTicker.toUpperCase() ==
|
||||
tuple.item2.ticker.toUpperCase()) {
|
||||
ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(tuple.item1)
|
||||
.currentReceivingAddress
|
||||
.then((value) {
|
||||
_refundController.text = value;
|
||||
model.refundAddress = _refundController.text;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,15 +185,36 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"Recipient Wallet",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// // TODO: choose from stack?
|
||||
// },
|
||||
// child: Text(
|
||||
// "Choose from Stack",
|
||||
// style: STextStyles.link2(context),
|
||||
// ),
|
||||
// ),
|
||||
if (isStackCoin(model.receiveTicker))
|
||||
BlueTextButton(
|
||||
text: "Choose from stack",
|
||||
onTap: () {
|
||||
try {
|
||||
final coin = coinFromTickerCaseInsensitive(
|
||||
model.receiveTicker,
|
||||
);
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
ChooseFromStackView.routeName,
|
||||
arguments: coin,
|
||||
)
|
||||
.then((value) async {
|
||||
if (value is String) {
|
||||
final manager = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(value);
|
||||
|
||||
_toController.text = manager.walletName;
|
||||
model.recipientAddress = await manager
|
||||
.currentReceivingAddress;
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("$e\n$s", level: LogLevel.Info);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -195,6 +243,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
),
|
||||
focusNode: _toFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
decoration: standardInputDecoration(
|
||||
"Enter the ${model.receiveTicker.toUpperCase()} payout address",
|
||||
_toFocusNode,
|
||||
|
@ -221,6 +272,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"sendViewClearAddressFieldButtonKey"),
|
||||
onTap: () {
|
||||
_toController.text = "";
|
||||
model.recipientAddress =
|
||||
_toController.text;
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
|
@ -239,6 +292,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
data.text!.trim();
|
||||
|
||||
_toController.text = content;
|
||||
model.recipientAddress =
|
||||
_toController.text;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -259,13 +314,31 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
.state = true;
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
AddressBookView.routeName,
|
||||
)
|
||||
.then((_) => ref
|
||||
AddressBookView.routeName,
|
||||
)
|
||||
.then((_) {
|
||||
ref
|
||||
.read(
|
||||
exchangeFlowIsActiveStateProvider
|
||||
.state)
|
||||
.state = false;
|
||||
|
||||
final address = ref
|
||||
.read(
|
||||
exchangeFromAddressBookAddressStateProvider
|
||||
.state)
|
||||
.state;
|
||||
if (address.isNotEmpty) {
|
||||
_toController.text = address;
|
||||
model.recipientAddress =
|
||||
_toController.text;
|
||||
ref
|
||||
.read(
|
||||
exchangeFlowIsActiveStateProvider
|
||||
exchangeFromAddressBookAddressStateProvider
|
||||
.state)
|
||||
.state = false);
|
||||
.state = "";
|
||||
}
|
||||
});
|
||||
},
|
||||
child: const AddressBookIcon(),
|
||||
),
|
||||
|
@ -299,11 +372,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
// auto fill address
|
||||
_toController.text =
|
||||
results["address"] ?? "";
|
||||
model.recipientAddress =
|
||||
_toController.text;
|
||||
|
||||
setState(() {});
|
||||
} else {
|
||||
_toController.text =
|
||||
qrResult.rawContent;
|
||||
model.recipientAddress =
|
||||
_toController.text;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -348,15 +425,37 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"Refund Wallet (required)",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// // TODO: choose from stack?
|
||||
// },
|
||||
// child: Text(
|
||||
// "Choose from Stack",
|
||||
// style: STextStyles.link2(context),
|
||||
// ),
|
||||
// ),
|
||||
if (isStackCoin(model.sendTicker))
|
||||
BlueTextButton(
|
||||
text: "Choose from stack",
|
||||
onTap: () {
|
||||
try {
|
||||
final coin = coinFromTickerCaseInsensitive(
|
||||
model.sendTicker,
|
||||
);
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
ChooseFromStackView.routeName,
|
||||
arguments: coin,
|
||||
)
|
||||
.then((value) async {
|
||||
if (value is String) {
|
||||
final manager = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(value);
|
||||
|
||||
_refundController.text =
|
||||
manager.walletName;
|
||||
model.refundAddress = await manager
|
||||
.currentReceivingAddress;
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("$e\n$s", level: LogLevel.Info);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -384,6 +483,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
),
|
||||
focusNode: _refundFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
decoration: standardInputDecoration(
|
||||
"Enter ${model.sendTicker.toUpperCase()} refund address",
|
||||
_refundFocusNode,
|
||||
|
@ -410,6 +512,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"sendViewClearAddressFieldButtonKey"),
|
||||
onTap: () {
|
||||
_refundController.text = "";
|
||||
model.refundAddress =
|
||||
_refundController.text;
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
|
@ -429,6 +533,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
|
||||
_refundController.text =
|
||||
content;
|
||||
model.refundAddress =
|
||||
_refundController.text;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -450,13 +556,26 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
.state = true;
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
AddressBookView.routeName,
|
||||
)
|
||||
.then((_) => ref
|
||||
.read(
|
||||
exchangeFlowIsActiveStateProvider
|
||||
.state)
|
||||
.state = false);
|
||||
AddressBookView.routeName,
|
||||
)
|
||||
.then((_) {
|
||||
ref
|
||||
.read(
|
||||
exchangeFlowIsActiveStateProvider
|
||||
.state)
|
||||
.state = false;
|
||||
final address = ref
|
||||
.read(
|
||||
exchangeFromAddressBookAddressStateProvider
|
||||
.state)
|
||||
.state;
|
||||
if (address.isNotEmpty) {
|
||||
_refundController.text =
|
||||
address;
|
||||
model.refundAddress =
|
||||
_refundController.text;
|
||||
}
|
||||
});
|
||||
},
|
||||
child: const AddressBookIcon(),
|
||||
),
|
||||
|
@ -490,11 +609,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
// auto fill address
|
||||
_refundController.text =
|
||||
results["address"] ?? "";
|
||||
model.refundAddress =
|
||||
_refundController.text;
|
||||
|
||||
setState(() {});
|
||||
} else {
|
||||
_refundController.text =
|
||||
qrResult.rawContent;
|
||||
model.refundAddress =
|
||||
_refundController.text;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -556,9 +679,6 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
model.recipientAddress = _toController.text;
|
||||
model.refundAddress = _refundController.text;
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
Step3View.routeName,
|
||||
arguments: model);
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/clipboard_interface.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
|
@ -222,6 +223,26 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => WillPopScope(
|
||||
onWillPop: () async => false,
|
||||
child: Container(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.overlay
|
||||
.withOpacity(0.6),
|
||||
child: const CustomLoadingOverlay(
|
||||
message: "Creating a trade",
|
||||
eventBus: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
ChangeNowResponse<ExchangeTransaction>
|
||||
response;
|
||||
if (model.rateType ==
|
||||
|
@ -251,6 +272,10 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
}
|
||||
|
||||
if (response.value == null) {
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
unawaited(showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
|
@ -273,8 +298,6 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
.getTransactionStatus(
|
||||
id: response.value!.id);
|
||||
|
||||
debugPrint("WTF: $statusResponse");
|
||||
|
||||
String status = "Waiting";
|
||||
if (statusResponse.value != null) {
|
||||
status = statusResponse.value!.status.name;
|
||||
|
@ -290,6 +313,10 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
status += " for deposit";
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
unawaited(NotificationApi.showNotification(
|
||||
changeNowId: model.trade!.id,
|
||||
title: status,
|
||||
|
|
|
@ -232,7 +232,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
|||
? ref.read(estimatedRateExchangeFormProvider).fromAmountString
|
||||
: ref.read(fixedRateExchangeFormProvider).fromAmountString;
|
||||
_receiveController.text = isEstimated
|
||||
? ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
: ref.read(fixedRateExchangeFormProvider).toAmountString;
|
||||
|
||||
_sendFocusNode.addListener(() async {
|
||||
|
@ -325,7 +325,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
|||
: fixedRateExchangeFormProvider.select(
|
||||
(value) => value.toAmountString), (previous, String next) {
|
||||
if (!_receiveFocusNode.hasFocus) {
|
||||
_receiveController.text = next;
|
||||
_receiveController.text = isEstimated ? "-" : next;
|
||||
debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED");
|
||||
if (_swapLock) {
|
||||
_sendController.text = isEstimated
|
||||
|
@ -345,7 +345,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
|||
debugPrint("SEND AMOUNT LISTENER ACTIVATED");
|
||||
if (_swapLock) {
|
||||
_receiveController.text = isEstimated
|
||||
? ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
: ref.read(fixedRateExchangeFormProvider).toAmountString;
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
|||
.exchangeRateType ==
|
||||
ExchangeRateType.estimated,
|
||||
onTap: () {
|
||||
if (_receiveController.text == "-") {
|
||||
if (!isEstimated && _receiveController.text == "-") {
|
||||
_receiveController.text = "";
|
||||
}
|
||||
},
|
||||
|
|
|
@ -48,6 +48,26 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
|
|||
late final String address;
|
||||
late final ExchangeTransaction trade;
|
||||
|
||||
String formatAmount(Decimal amount, Coin coin) {
|
||||
switch (coin) {
|
||||
case Coin.bitcoin:
|
||||
case Coin.bitcoincash:
|
||||
case Coin.dogecoin:
|
||||
case Coin.epicCash:
|
||||
case Coin.firo:
|
||||
case Coin.namecoin:
|
||||
case Coin.bitcoinTestNet:
|
||||
case Coin.bitcoincashTestnet:
|
||||
case Coin.dogecoinTestNet:
|
||||
case Coin.firoTestNet:
|
||||
return amount.toStringAsFixed(Constants.decimalPlaces);
|
||||
case Coin.monero:
|
||||
return amount.toStringAsFixed(Constants.decimalPlacesMonero);
|
||||
case Coin.wownero:
|
||||
return amount.toStringAsFixed(Constants.decimalPlacesWownero);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
coin = widget.coin;
|
||||
|
@ -59,6 +79,11 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
final walletIds = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getWalletIdsFor(coin: coin)));
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
|
@ -68,44 +93,41 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
|
|||
},
|
||||
),
|
||||
title: Text(
|
||||
"Send ",
|
||||
"Send from",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Wrap(
|
||||
// crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Choose your ${coin.ticker} wallet",
|
||||
style: STextStyles.pageTitleH1(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Text(
|
||||
"You need to send ${amount.toStringAsFixed(coin == Coin.monero ? Constants.satsPerCoinMonero : coin == Coin.wownero ? Constants.satsPerCoinWownero : Constants.satsPerCoin)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"You need to send ${formatAmount(amount, coin)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
...ref
|
||||
.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.managers))
|
||||
.where((element) => element.coin == coin)
|
||||
.map((e) => SendFromCard(
|
||||
walletId: e.walletId,
|
||||
amount: amount,
|
||||
address: address,
|
||||
trade: trade,
|
||||
))
|
||||
.toList(growable: false)
|
||||
],
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: walletIds.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: SendFromCard(
|
||||
walletId: walletIds[index],
|
||||
amount: amount,
|
||||
address: address,
|
||||
trade: trade,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -163,7 +185,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
child: MaterialButton(
|
||||
splashColor: Theme.of(context).extension<StackColors>()!.highlight,
|
||||
key: Key("walletsSheetItemButtonKey_$walletId"),
|
||||
padding: const EdgeInsets.all(5),
|
||||
padding: const EdgeInsets.all(8),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
|
@ -276,59 +298,61 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(coin: coin),
|
||||
width: 20,
|
||||
height: 20,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: coin == Coin.monero
|
||||
? Constants.satsPerCoinMonero
|
||||
: coin == Coin.wownero
|
||||
? Constants.satsPerCoinWownero
|
||||
: Constants.satsPerCoin,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: coin == Coin.monero
|
||||
? Constants.decimalPlacesMonero
|
||||
: coin == Coin.wownero
|
||||
? Constants.decimalPlacesWownero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction_stat
|
|||
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
|
@ -24,6 +25,7 @@ import 'package:stackwallet/utilities/format.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
@ -60,6 +62,15 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
|
||||
String _note = "";
|
||||
|
||||
bool isStackCoin(String ticker) {
|
||||
try {
|
||||
coinFromTickerCaseInsensitive(ticker);
|
||||
return true;
|
||||
} on ArgumentError catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
initState() {
|
||||
tradeId = widget.tradeId;
|
||||
|
@ -345,9 +356,48 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Send ${trade.fromCurrency.toUpperCase()} to this address",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Send ${trade.fromCurrency.toUpperCase()} to this address",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final address = trade.payinAddress;
|
||||
await Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: address,
|
||||
),
|
||||
);
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
context: context,
|
||||
));
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 12,
|
||||
height: 12,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
Text(
|
||||
"Copy",
|
||||
style: STextStyles.link2(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
|
@ -717,6 +767,32 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (isStackCoin(trade.fromCurrency) &&
|
||||
trade.statusObject != null &&
|
||||
(trade.statusObject!.status ==
|
||||
ChangeNowTransactionStatus.New ||
|
||||
trade.statusObject!.status ==
|
||||
ChangeNowTransactionStatus.Waiting))
|
||||
SecondaryButton(
|
||||
label: "Send from Stack",
|
||||
onPressed: () {
|
||||
final amount = sendAmount;
|
||||
final address = trade.payinAddress;
|
||||
|
||||
final coin =
|
||||
coinFromTickerCaseInsensitive(trade.fromCurrency);
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
SendFromView.routeName,
|
||||
arguments: Tuple4(
|
||||
coin,
|
||||
amount,
|
||||
address,
|
||||
trade,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -83,8 +83,8 @@ class _WalletInitiatedExchangeViewState
|
|||
child: Container(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark
|
||||
.withOpacity(0.8),
|
||||
.overlay
|
||||
.withOpacity(0.6),
|
||||
child: const CustomLoadingOverlay(
|
||||
message: "Updating exchange rate",
|
||||
eventBus: null,
|
||||
|
@ -329,7 +329,7 @@ class _WalletInitiatedExchangeViewState
|
|||
: fixedRateExchangeFormProvider.select(
|
||||
(value) => value.toAmountString), (previous, String next) {
|
||||
if (!_receiveFocusNode.hasFocus) {
|
||||
_receiveController.text = next;
|
||||
_receiveController.text = isEstimated ? "-" : next;
|
||||
debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED");
|
||||
if (_swapLock) {
|
||||
_sendController.text = isEstimated
|
||||
|
@ -349,7 +349,7 @@ class _WalletInitiatedExchangeViewState
|
|||
debugPrint("SEND AMOUNT LISTENER ACTIVATED");
|
||||
if (_swapLock) {
|
||||
_receiveController.text = isEstimated
|
||||
? ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||
: ref.read(fixedRateExchangeFormProvider).toAmountString;
|
||||
}
|
||||
}
|
||||
|
@ -808,7 +808,8 @@ class _WalletInitiatedExchangeViewState
|
|||
.exchangeRateType ==
|
||||
ExchangeRateType.estimated,
|
||||
onTap: () {
|
||||
if (_receiveController.text == "-") {
|
||||
if (!isEstimated &&
|
||||
_receiveController.text == "-") {
|
||||
_receiveController.text = "";
|
||||
}
|
||||
},
|
||||
|
|
|
@ -209,6 +209,10 @@ abstract class SWB {
|
|||
Logging.instance.log(
|
||||
"...createStackWalletJSON DB.instance.mutex acquired",
|
||||
level: LogLevel.Info);
|
||||
Logging.instance.log(
|
||||
"SWB backing up nodes",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
try {
|
||||
var primaryNodes = nodeService.primaryNodes.map((e) async {
|
||||
final map = e.toMap();
|
||||
|
@ -231,6 +235,11 @@ abstract class SWB {
|
|||
Logging.instance.log("$e $s", level: LogLevel.Error);
|
||||
}
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB backing up prefs",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
Map<String, dynamic> prefs = {};
|
||||
final _prefs = Prefs.instance;
|
||||
await _prefs.init();
|
||||
|
@ -251,11 +260,21 @@ abstract class SWB {
|
|||
|
||||
backupJson['prefs'] = prefs;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB backing up addressbook",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
AddressBookService addressBookService = AddressBookService();
|
||||
var addresses = await addressBookService.addressBookEntries;
|
||||
backupJson['addressBookEntries'] =
|
||||
addresses.map((e) => e.toMap()).toList();
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB backing up wallets",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
List<dynamic> backupWallets = [];
|
||||
for (var manager in _wallets.managers) {
|
||||
Map<String, dynamic> backupWallet = {};
|
||||
|
@ -283,6 +302,11 @@ abstract class SWB {
|
|||
}
|
||||
backupJson['wallets'] = backupWallets;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB backing up trades",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
// back up trade history
|
||||
final tradesService = TradesService();
|
||||
final trades =
|
||||
|
@ -295,6 +319,11 @@ abstract class SWB {
|
|||
tradeTxidLookupDataService.all.map((e) => e.toMap()).toList();
|
||||
backupJson["tradeTxidLookupData"] = lookupData;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB backing up trade notes",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
// back up trade notes
|
||||
final tradeNotesService = TradeNotesService();
|
||||
final tradeNotes = tradeNotesService.all;
|
||||
|
@ -357,7 +386,7 @@ abstract class SWB {
|
|||
final notes = walletbackup["notes"] as Map?;
|
||||
if (notes != null) {
|
||||
for (final note in notes.entries) {
|
||||
notesService.editOrAddNote(
|
||||
await notesService.editOrAddNote(
|
||||
txid: note.key as String, note: note.value as String);
|
||||
}
|
||||
}
|
||||
|
@ -432,11 +461,19 @@ abstract class SWB {
|
|||
|
||||
uiState?.preferences = StackRestoringStatus.restoring;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB restoring prefs",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restorePrefs(prefs);
|
||||
|
||||
uiState?.preferences = StackRestoringStatus.success;
|
||||
uiState?.addressBook = StackRestoringStatus.restoring;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB restoring addressbook",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
if (addressBookEntries != null) {
|
||||
await _restoreAddressBook(addressBookEntries);
|
||||
}
|
||||
|
@ -444,6 +481,10 @@ abstract class SWB {
|
|||
uiState?.addressBook = StackRestoringStatus.success;
|
||||
uiState?.nodes = StackRestoringStatus.restoring;
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB restoring nodes",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restoreNodes(nodes, primaryNodes);
|
||||
|
||||
uiState?.nodes = StackRestoringStatus.success;
|
||||
|
@ -451,17 +492,29 @@ abstract class SWB {
|
|||
|
||||
// restore trade history
|
||||
if (trades != null) {
|
||||
Logging.instance.log(
|
||||
"SWB restoring trades",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restoreTrades(trades);
|
||||
}
|
||||
|
||||
// restore trade history lookup data for trades send from stack wallet
|
||||
if (tradeTxidLookupData != null) {
|
||||
Logging.instance.log(
|
||||
"SWB restoring trade look up data",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restoreTradesLookUpData(tradeTxidLookupData, oldToNewWalletIdMap);
|
||||
}
|
||||
|
||||
// restore trade notes
|
||||
|
||||
if (tradeNotes != null) {
|
||||
Logging.instance.log(
|
||||
"SWB restoring trade notes",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restoreTradesNotes(tradeNotes);
|
||||
}
|
||||
|
||||
|
@ -490,9 +543,17 @@ abstract class SWB {
|
|||
String jsonBackup,
|
||||
StackRestoringUIState? uiState,
|
||||
) async {
|
||||
if (!Platform.isLinux) Wakelock.enable();
|
||||
if (!Platform.isLinux) await Wakelock.enable();
|
||||
|
||||
Logging.instance.log(
|
||||
"SWB creating temp backup",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
final preRestoreJSON = await createStackWalletJSON();
|
||||
Logging.instance.log(
|
||||
"SWB temp backup created",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
List<String> _currentWalletIds = Map<String, dynamic>.from(DB.instance
|
||||
.get<dynamic>(
|
||||
|
@ -814,13 +875,13 @@ abstract class SWB {
|
|||
}
|
||||
await asyncRestore(epicCashWallets[i], uiState, walletsService);
|
||||
}
|
||||
if (!Platform.isLinux) Wakelock.disable();
|
||||
if (!Platform.isLinux) await Wakelock.disable();
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.instance.log("done with SWB restore", level: LogLevel.Info);
|
||||
Logging.instance.log("done with SWB restore", level: LogLevel.Warning);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -849,7 +910,7 @@ abstract class SWB {
|
|||
// if no contacts were present before attempted restore then delete any that
|
||||
// could have been added before the restore was cancelled
|
||||
for (final String idToDelete in allContactIds) {
|
||||
addressBookService.removeContact(idToDelete);
|
||||
await addressBookService.removeContact(idToDelete);
|
||||
}
|
||||
} else {
|
||||
final Map<String, dynamic> preContactMap = {};
|
||||
|
@ -886,7 +947,7 @@ abstract class SWB {
|
|||
);
|
||||
} else {
|
||||
// otherwise remove it as it was not there before attempting SWB restore
|
||||
addressBookService.removeContact(id);
|
||||
await addressBookService.removeContact(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -898,7 +959,7 @@ abstract class SWB {
|
|||
// no pre nodes found so we delete all but defaults
|
||||
for (final node in currentNodes) {
|
||||
if (!node.isDefault) {
|
||||
nodeService.delete(node.id, true);
|
||||
await nodeService.delete(node.id, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -912,7 +973,7 @@ abstract class SWB {
|
|||
if (nodeData != null) {
|
||||
// node existed before restore attempt
|
||||
// revert to pre restore node
|
||||
nodeService.edit(
|
||||
await nodeService.edit(
|
||||
node.copyWith(
|
||||
host: nodeData['host'] as String,
|
||||
port: nodeData['port'] as int,
|
||||
|
@ -927,7 +988,7 @@ abstract class SWB {
|
|||
nodeData['password'] as String?,
|
||||
true);
|
||||
} else {
|
||||
nodeService.delete(node.id, true);
|
||||
await nodeService.delete(node.id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -951,7 +1012,7 @@ abstract class SWB {
|
|||
// no trade history found pre restore attempt so we delete anything that
|
||||
// was added during the restore attempt
|
||||
for (final tradeTx in currentTrades) {
|
||||
tradesService.delete(trade: tradeTx, shouldNotifyListeners: true);
|
||||
await tradesService.delete(trade: tradeTx, shouldNotifyListeners: true);
|
||||
}
|
||||
} else {
|
||||
final Map<String, dynamic> preTradeMap = {};
|
||||
|
@ -964,13 +1025,14 @@ abstract class SWB {
|
|||
if (tradeData != null) {
|
||||
// trade existed before attempted restore so we don't delete it, only
|
||||
// revert data to pre restore state
|
||||
tradesService.edit(
|
||||
await tradesService.edit(
|
||||
trade: ExchangeTransaction.fromJson(
|
||||
tradeData as Map<String, dynamic>),
|
||||
shouldNotifyListeners: true);
|
||||
} else {
|
||||
// trade did not exist before so we delete it
|
||||
tradesService.delete(trade: tradeTx, shouldNotifyListeners: true);
|
||||
await tradesService.delete(
|
||||
trade: tradeTx, shouldNotifyListeners: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -982,7 +1044,7 @@ abstract class SWB {
|
|||
|
||||
if (tradeNotes == null) {
|
||||
for (final noteEntry in currentNotes.entries) {
|
||||
tradeNotesService.delete(tradeId: noteEntry.key);
|
||||
await tradeNotesService.delete(tradeId: noteEntry.key);
|
||||
}
|
||||
} else {
|
||||
// grab all trade IDs of (reverted to pre state) trades
|
||||
|
@ -991,7 +1053,7 @@ abstract class SWB {
|
|||
// delete all notes that don't correspond to an id that we have
|
||||
for (final noteEntry in currentNotes.entries) {
|
||||
if (!idsToKeep.contains(noteEntry.key)) {
|
||||
tradeNotesService.delete(tradeId: noteEntry.key);
|
||||
await tradeNotesService.delete(tradeId: noteEntry.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1009,7 +1071,7 @@ abstract class SWB {
|
|||
for (int i = 0; i < tradeTxidLookupData.length; i++) {
|
||||
final json = Map<String, dynamic>.from(tradeTxidLookupData[i] as Map);
|
||||
TradeWalletLookup lookup = TradeWalletLookup.fromJson(json);
|
||||
tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
|
||||
await tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1127,14 +1189,14 @@ abstract class SWB {
|
|||
) async {
|
||||
final tradesService = TradesService();
|
||||
for (int i = 0; i < trades.length - 1; i++) {
|
||||
tradesService.add(
|
||||
await tradesService.add(
|
||||
trade: ExchangeTransaction.fromJson(trades[i] as Map<String, dynamic>),
|
||||
shouldNotifyListeners: false,
|
||||
);
|
||||
}
|
||||
// only call notifyListeners on last one added
|
||||
if (trades.isNotEmpty) {
|
||||
tradesService.add(
|
||||
await tradesService.add(
|
||||
trade:
|
||||
ExchangeTransaction.fromJson(trades.last as Map<String, dynamic>),
|
||||
shouldNotifyListeners: true,
|
||||
|
@ -1177,7 +1239,7 @@ abstract class SWB {
|
|||
}
|
||||
}
|
||||
|
||||
tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
|
||||
await tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1248,8 @@ abstract class SWB {
|
|||
) async {
|
||||
final tradeNotesService = TradeNotesService();
|
||||
for (final note in tradeNotes.entries) {
|
||||
tradeNotesService.set(tradeId: note.key, note: note.value as String);
|
||||
await tradeNotesService.set(
|
||||
tradeId: note.key, note: note.value as String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,12 @@ import 'package:stackwallet/services/coins/manager.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
import 'package:stackwallet/widgets/trade_card.dart';
|
||||
import 'package:stackwallet/widgets/transaction_card.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import '../../../providers/global/trades_service_provider.dart';
|
||||
import '../../exchange_view/trade_details_view.dart';
|
||||
|
||||
class TransactionsList extends ConsumerStatefulWidget {
|
||||
const TransactionsList({
|
||||
|
@ -125,18 +130,67 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
|||
radius = _borderRadiusFirst;
|
||||
}
|
||||
final tx = list[index];
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
borderRadius: radius,
|
||||
),
|
||||
child: TransactionCard(
|
||||
// this may mess with combined firo transactions
|
||||
key: Key(tx.toString()), //
|
||||
transaction: tx,
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
);
|
||||
|
||||
final matchingTrades = ref
|
||||
.read(tradesServiceProvider)
|
||||
.trades
|
||||
.where((e) =>
|
||||
e.statusObject != null &&
|
||||
(e.statusObject!.payinHash == tx.txid ||
|
||||
e.statusObject!.payoutHash == tx.txid));
|
||||
if (tx.txType == "Sent" && matchingTrades.isNotEmpty) {
|
||||
final trade = matchingTrades.first;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
borderRadius: radius,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TransactionCard(
|
||||
// this may mess with combined firo transactions
|
||||
key: Key(tx.toString()), //
|
||||
transaction: tx,
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
TradeCard(
|
||||
// this may mess with combined firo transactions
|
||||
key: Key(tx.toString() + trade.uuid), //
|
||||
trade: trade,
|
||||
onTap: () {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
TradeDetailsView.routeName,
|
||||
arguments: Tuple4(
|
||||
trade.id,
|
||||
tx,
|
||||
widget.walletId,
|
||||
ref.read(managerProvider).walletName,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
borderRadius: radius,
|
||||
),
|
||||
child: TransactionCard(
|
||||
// this may mess with combined firo transactions
|
||||
key: Key(tx.toString()), //
|
||||
transaction: tx,
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/contact_address_entry.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
||||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||
|
@ -20,12 +22,14 @@ import 'package:stackwallet/pages/address_book_views/subviews/address_book_filte
|
|||
import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
|
@ -879,6 +883,37 @@ class RouteGenerator {
|
|||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case ChooseFromStackView.routeName:
|
||||
if (args is Coin) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => ChooseFromStackView(
|
||||
coin: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case SendFromView.routeName:
|
||||
if (args is Tuple4<Coin, Decimal, String, ExchangeTransaction>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => SendFromView(
|
||||
coin: args.item1,
|
||||
amount: args.item2,
|
||||
trade: args.item4,
|
||||
address: args.item3,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
// == Desktop specific routes ============================================
|
||||
case CreatePasswordView.routeName:
|
||||
return getRoute(
|
||||
|
|
|
@ -51,7 +51,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 10;
|
||||
const int MINIMUM_CONFIRMATIONS = 4;
|
||||
|
||||
//https://github.com/wownero-project/wownero/blob/8361d60aef6e17908658128284899e3a11d808d4/src/cryptonote_config.h#L162
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
|
|
|
@ -21,6 +21,8 @@ abstract class Constants {
|
|||
static const int satsPerCoinWownero = 100000000000;
|
||||
static const int satsPerCoin = 100000000;
|
||||
static const int decimalPlaces = 8;
|
||||
static const int decimalPlacesWownero = 11;
|
||||
static const int decimalPlacesMonero = 12;
|
||||
|
||||
static const int notificationsMax = 0xFFFFFFFF;
|
||||
static const Duration networkAliveTimerDuration = Duration(seconds: 10);
|
||||
|
|
Loading…
Reference in a new issue