mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-19 05:58:50 +02:00
Merge branch 'main' into CAKE-330-unspent-coins-details-UI
# Conflicts: # lib/router.dart # lib/routes.dart
This commit is contained in:
@@ -1,20 +1,23 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:cake_wallet/view_model/wyre_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WyrePage extends BasePage {
|
||||
WyrePage(this.wyreViewModel,
|
||||
{@required this.ordersStore, @required this.url});
|
||||
class BuyWebViewPage extends BasePage {
|
||||
BuyWebViewPage({@required this.buyViewModel,
|
||||
@required this.ordersStore, @required this.url});
|
||||
|
||||
final OrdersStore ordersStore;
|
||||
final String url;
|
||||
final WyreViewModel wyreViewModel;
|
||||
final BuyViewModel buyViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy;
|
||||
@@ -27,26 +30,27 @@ class WyrePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
WyrePageBody(wyreViewModel, ordersStore: ordersStore, url: url);
|
||||
BuyWebViewPageBody(buyViewModel, ordersStore: ordersStore, url: url);
|
||||
}
|
||||
|
||||
class WyrePageBody extends StatefulWidget {
|
||||
WyrePageBody(this.wyreViewModel, {this.ordersStore, this.url});
|
||||
class BuyWebViewPageBody extends StatefulWidget {
|
||||
BuyWebViewPageBody(this.buyViewModel, {this.ordersStore, this.url});
|
||||
|
||||
final OrdersStore ordersStore;
|
||||
final String url;
|
||||
final WyreViewModel wyreViewModel;
|
||||
final BuyViewModel buyViewModel;
|
||||
|
||||
@override
|
||||
WyrePageBodyState createState() => WyrePageBodyState();
|
||||
BuyWebViewPageBodyState createState() => BuyWebViewPageBodyState();
|
||||
}
|
||||
|
||||
class WyrePageBodyState extends State<WyrePageBody> {
|
||||
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||
String orderId;
|
||||
WebViewController _webViewController;
|
||||
GlobalKey _webViewkey;
|
||||
Timer _timer;
|
||||
bool _isSaving;
|
||||
BuyProvider _provider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -54,35 +58,17 @@ class WyrePageBodyState extends State<WyrePageBody> {
|
||||
_webViewkey = GlobalKey();
|
||||
_isSaving = false;
|
||||
widget.ordersStore.orderId = '';
|
||||
_provider = widget.buyViewModel.selectedProvider;
|
||||
|
||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
||||
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
if (_provider is WyreBuyProvider) {
|
||||
_saveOrder(keyword: 'completed', splitSymbol: '/');
|
||||
}
|
||||
|
||||
try {
|
||||
if (_webViewController == null || _isSaving) {
|
||||
return;
|
||||
}
|
||||
|
||||
final url = await _webViewController.currentUrl();
|
||||
|
||||
if (url.contains('completed')) {
|
||||
final urlParts = url.split('/');
|
||||
orderId = urlParts.last;
|
||||
widget.ordersStore.orderId = orderId;
|
||||
|
||||
if (orderId.isNotEmpty) {
|
||||
_isSaving = true;
|
||||
await widget.wyreViewModel.saveOrder(orderId);
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_isSaving = false;
|
||||
print(e);
|
||||
}
|
||||
});
|
||||
if (_provider is MoonPayBuyProvider) {
|
||||
_saveOrder(keyword: 'transactionId', splitSymbol: '=');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -94,4 +80,33 @@ class WyrePageBodyState extends State<WyrePageBody> {
|
||||
onWebViewCreated: (WebViewController controller) =>
|
||||
setState(() => _webViewController = controller));
|
||||
}
|
||||
|
||||
void _saveOrder({String keyword, String splitSymbol}) {
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
|
||||
try {
|
||||
if (_webViewController == null || _isSaving) {
|
||||
return;
|
||||
}
|
||||
|
||||
final url = await _webViewController.currentUrl();
|
||||
|
||||
if (url.contains(keyword)) {
|
||||
final urlParts = url.split(splitSymbol);
|
||||
orderId = urlParts.last;
|
||||
widget.ordersStore.orderId = orderId;
|
||||
|
||||
if (orderId.isNotEmpty) {
|
||||
_isSaving = true;
|
||||
await widget.buyViewModel.saveOrder(orderId);
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_isSaving = false;
|
||||
print(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
import 'dart:ui';
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/widgets/buy_list_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class PreOrderPage extends BasePage {
|
||||
PreOrderPage({@required this.buyViewModel})
|
||||
: _amountFocus = FocusNode(),
|
||||
_amountController = TextEditingController() {
|
||||
|
||||
_amountController.addListener(() {
|
||||
final amount = _amountController.text;
|
||||
|
||||
if (amount != buyViewModel.buyAmountViewModel.amount) {
|
||||
buyViewModel.buyAmountViewModel.amount = amount;
|
||||
buyViewModel.selectedProvider = null;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => buyViewModel.buyAmountViewModel.amount, (String amount) {
|
||||
if (_amountController.text != amount) {
|
||||
_amountController.text = amount;
|
||||
}
|
||||
if (amount.isEmpty) {
|
||||
buyViewModel.selectedProvider = null;
|
||||
buyViewModel.isShowProviderButtons = false;
|
||||
} else {
|
||||
buyViewModel.isShowProviderButtons = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
|
||||
|
||||
final BuyViewModel buyViewModel;
|
||||
final FocusNode _amountFocus;
|
||||
final TextEditingController _amountController;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy + ' ' + walletTypeToString(buyViewModel.wallet.type);
|
||||
|
||||
@override
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
Widget trailing(context) => TrailButton(
|
||||
caption: S.of(context).clear,
|
||||
onPressed: () => buyViewModel.reset());
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).accentTextTheme.body2
|
||||
.backgroundColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _amountFocus,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
height: 0,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Observer(builder: (_) => Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(colors: [
|
||||
Theme.of(context).primaryTextTheme.subhead.color,
|
||||
Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subhead
|
||||
.decorationColor,
|
||||
], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 100, bottom: 65),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 210,
|
||||
child: BaseTextFormField(
|
||||
focusNode: _amountFocus,
|
||||
controller: _amountController,
|
||||
keyboardType:
|
||||
TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter
|
||||
.allow(RegExp(_amountPattern))
|
||||
],
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child:
|
||||
Text(buyViewModel.fiatCurrency.title + ': ',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
hintText: '0.00',
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.body2
|
||||
.decorationColor,
|
||||
borderWidth: 0.5,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 36),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
if (buyViewModel.isShowProviderButtons) Padding(
|
||||
padding: EdgeInsets.only(top: 38, bottom: 18),
|
||||
child: Text(
|
||||
S.of(context).buy_with + ':',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
)
|
||||
),
|
||||
if (buyViewModel.isShowProviderButtons)
|
||||
...buyViewModel.items.map(
|
||||
(item) => Observer(builder: (_) =>
|
||||
FutureBuilder<BuyAmount>(
|
||||
future: item.buyAmount,
|
||||
builder: (context, AsyncSnapshot<BuyAmount> snapshot) {
|
||||
double sourceAmount;
|
||||
double destAmount;
|
||||
int minAmount;
|
||||
|
||||
if (snapshot.hasData) {
|
||||
sourceAmount = snapshot.data.sourceAmount;
|
||||
destAmount = snapshot.data.destAmount;
|
||||
minAmount = snapshot.data.minAmount;
|
||||
} else {
|
||||
sourceAmount = 0.0;
|
||||
destAmount = 0.0;
|
||||
minAmount = 0;
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 15, top: 20, right: 15),
|
||||
child: Observer(builder: (_) {
|
||||
return BuyListItem(
|
||||
selectedProvider:
|
||||
buyViewModel.selectedProvider,
|
||||
provider: item.provider,
|
||||
sourceAmount: sourceAmount,
|
||||
sourceCurrency: buyViewModel.fiatCurrency,
|
||||
destAmount: destAmount,
|
||||
destCurrency: buyViewModel.cryptoCurrency,
|
||||
onTap: ((buyViewModel.doubleAmount != 0.0)
|
||||
&& (snapshot.hasData)) ? () =>
|
||||
onSelectBuyProvider(
|
||||
context: context,
|
||||
provider: item.provider,
|
||||
sourceAmount: sourceAmount,
|
||||
minAmount: minAmount
|
||||
) : null
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
))
|
||||
)
|
||||
],
|
||||
)),
|
||||
bottomSectionPadding:
|
||||
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () => onPresentProvider(context: context),
|
||||
text: buyViewModel.selectedProvider == null
|
||||
? S.of(context).buy
|
||||
: S.of(context).buy_with +
|
||||
' ${buyViewModel.selectedProvider
|
||||
.description.title}',
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white,
|
||||
isLoading: buyViewModel.isRunning,
|
||||
isDisabled: (buyViewModel.selectedProvider == null) ||
|
||||
buyViewModel.isDisabled
|
||||
);
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void onSelectBuyProvider({BuildContext context, BuyProvider provider,
|
||||
double sourceAmount, int minAmount}) {
|
||||
|
||||
if ((provider is MoonPayBuyProvider)&&
|
||||
(buyViewModel.buyAmountViewModel.doubleAmount < minAmount)) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: 'MoonPay',
|
||||
alertContent: S.of(context).moonpay_alert_text(
|
||||
minAmount.toString(),
|
||||
buyViewModel.fiatCurrency.toString()),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
return;
|
||||
}
|
||||
buyViewModel.selectedProvider = provider;
|
||||
sourceAmount > 0
|
||||
? buyViewModel.isDisabled = false
|
||||
: buyViewModel.isDisabled = true;
|
||||
}
|
||||
|
||||
Future<void> onPresentProvider({BuildContext context}) async {
|
||||
if (buyViewModel.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
buyViewModel.isRunning = true;
|
||||
final url = await buyViewModel.fetchUrl();
|
||||
|
||||
if (url.isNotEmpty) {
|
||||
if (buyViewModel.selectedProvider is MoonPayBuyProvider) {
|
||||
if (await canLaunch(url)) await launch(url);
|
||||
} else {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.buyWebView,
|
||||
arguments: [url, buyViewModel]);
|
||||
}
|
||||
}
|
||||
|
||||
buyViewModel.reset();
|
||||
buyViewModel.isRunning = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BuyListItem extends StatelessWidget {
|
||||
BuyListItem({
|
||||
@required this.selectedProvider,
|
||||
@required this.provider,
|
||||
@required this.sourceAmount,
|
||||
@required this.sourceCurrency,
|
||||
@required this.destAmount,
|
||||
@required this.destCurrency,
|
||||
@required this.onTap
|
||||
});
|
||||
|
||||
final BuyProvider selectedProvider;
|
||||
final BuyProvider provider;
|
||||
final double sourceAmount;
|
||||
final FiatCurrency sourceCurrency;
|
||||
final double destAmount;
|
||||
final CryptoCurrency destCurrency;
|
||||
final void Function() onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isSelected = selectedProvider?.description == provider.description;
|
||||
|
||||
final providerIcon = getBuyProviderIcon(provider.description,
|
||||
isWhiteIconColor: isSelected);
|
||||
|
||||
final backgroundColor = isSelected
|
||||
? Palette.greyBlueCraiola
|
||||
: Palette.shadowWhite;
|
||||
|
||||
final primaryTextColor = isSelected
|
||||
? Colors.white
|
||||
: Palette.darkGray;
|
||||
|
||||
final secondaryTextColor = isSelected
|
||||
? Colors.white
|
||||
: Palette.darkBlueCraiola;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => onTap?.call(),
|
||||
child: Container(
|
||||
height: 102,
|
||||
padding: EdgeInsets.only(
|
||||
left: 20,
|
||||
//top: 33,
|
||||
right: 20
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(25)),
|
||||
color: backgroundColor
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 33,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (providerIcon != null) Padding(
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: providerIcon
|
||||
),
|
||||
Text(
|
||||
provider.description.title,
|
||||
style: TextStyle(
|
||||
color: secondaryTextColor,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'${destAmount?.toString()} ${destCurrency.title}',
|
||||
style: TextStyle(
|
||||
color: secondaryTextColor,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
Positioned(
|
||||
top: 65,
|
||||
right: 0,
|
||||
child: Text(
|
||||
'${sourceAmount?.toString()} ${sourceCurrency.title}',
|
||||
style: TextStyle(
|
||||
color: primaryTextColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -132,29 +132,12 @@ class DashboardPage extends BasePage {
|
||||
image: exchangeImage,
|
||||
title: S.of(context).exchange,
|
||||
route: Routes.exchange),
|
||||
Observer(
|
||||
builder: (_) => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.topCenter,
|
||||
children: [
|
||||
if (walletViewModel.isRunningWebView)
|
||||
Positioned(
|
||||
top: -5,
|
||||
child: SpinKitRing(
|
||||
color: Theme.of(context).buttonColor,
|
||||
lineWidth: 3,
|
||||
size: 70.0,
|
||||
),
|
||||
),
|
||||
ActionButton(
|
||||
image: buyImage,
|
||||
title: S.of(context).buy,
|
||||
onClick: walletViewModel.isRunningWebView
|
||||
? null
|
||||
: () async =>
|
||||
await _onClickBuyButton(context))
|
||||
],
|
||||
)),
|
||||
ActionButton(
|
||||
image: buyImage,
|
||||
title: S.of(context).buy,
|
||||
onClick: () async =>
|
||||
await _onClickBuyButton(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -167,7 +150,8 @@ class DashboardPage extends BasePage {
|
||||
return;
|
||||
}
|
||||
|
||||
pages.add(AddressPage(addressListViewModel: addressListViewModel));
|
||||
pages.add(AddressPage(addressListViewModel: addressListViewModel,
|
||||
walletViewModel: walletViewModel));
|
||||
pages.add(BalancePage(dashboardViewModel: walletViewModel));
|
||||
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
|
||||
|
||||
@@ -183,7 +167,7 @@ class DashboardPage extends BasePage {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).pre_seed_title,
|
||||
alertContent:
|
||||
S.of(context).outdated_electrum_wallet_desceription,
|
||||
S.of(context).outdated_electrum_wallet_description,
|
||||
buttonText: S.of(context).understand,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
@@ -196,17 +180,7 @@ class DashboardPage extends BasePage {
|
||||
final walletType = walletViewModel.type;
|
||||
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
try {
|
||||
walletViewModel.isRunningWebView = true;
|
||||
final url = await walletViewModel.wyreViewModel.wyreUrl;
|
||||
await Navigator.of(context).pushNamed(Routes.wyre, arguments: url);
|
||||
walletViewModel.isRunningWebView = false;
|
||||
} catch (_) {
|
||||
walletViewModel.isRunningWebView = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case WalletType.monero:
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
@@ -217,6 +191,9 @@ class DashboardPage extends BasePage {
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
Navigator.of(context).pushNamed(Routes.preOrder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart';
|
||||
@@ -7,17 +13,43 @@ import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class AddressPage extends StatelessWidget {
|
||||
AddressPage({@required this.addressListViewModel})
|
||||
AddressPage({@required this.addressListViewModel,
|
||||
this.walletViewModel})
|
||||
: _cryptoAmountFocus = FocusNode();
|
||||
|
||||
final WalletAddressListViewModel addressListViewModel;
|
||||
final DashboardViewModel walletViewModel;
|
||||
|
||||
final FocusNode _cryptoAmountFocus;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
autorun((_) async {
|
||||
if (!walletViewModel.isOutdatedElectrumWallet
|
||||
|| !walletViewModel.settingsStore.shouldShowReceiveWarning) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Future<void>.delayed(Duration(seconds: 1));
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).pre_seed_title,
|
||||
alertContent: S.of(context).outdated_electrum_wallet_receive_warning,
|
||||
leftButtonText: S.of(context).understand,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
rightButtonText: S.of(context).do_not_show_me,
|
||||
actionRightButton: () {
|
||||
walletViewModel.settingsStore.setShouldShowReceiveWarning(false);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return KeyboardActions(
|
||||
autoScroll: false,
|
||||
disableScroll: true,
|
||||
@@ -42,7 +74,8 @@ class AddressPage extends StatelessWidget {
|
||||
child: Observer(builder: (_) => QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
isAmountFieldShow: !addressListViewModel.hasAccounts))
|
||||
isAmountFieldShow: !addressListViewModel.hasAccounts,
|
||||
isBright: walletViewModel.settingsStore.currentTheme.type == ThemeType.bright))
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
return addressListViewModel.hasAddressList
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
|
||||
class OrderRow extends StatelessWidget {
|
||||
OrderRow({
|
||||
@required this.onTap,
|
||||
@required this.provider,
|
||||
this.from,
|
||||
this.to,
|
||||
this.createdAtFormattedDate,
|
||||
this.formattedAmount});
|
||||
final VoidCallback onTap;
|
||||
final BuyProviderDescription provider;
|
||||
final String from;
|
||||
final String to;
|
||||
final String createdAtFormattedDate;
|
||||
final String formattedAmount;
|
||||
final wyreImage =
|
||||
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currentTheme = getIt.get<SettingsStore>().currentTheme;
|
||||
final isWhiteIconColor = currentTheme.type != ThemeType.light;
|
||||
|
||||
final providerIcon = getBuyProviderIcon(provider,
|
||||
isWhiteIconColor: isWhiteIconColor);
|
||||
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
@@ -26,8 +37,10 @@ class OrderRow extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
wyreImage,
|
||||
SizedBox(width: 12),
|
||||
if (providerIcon != null) Padding(
|
||||
padding: EdgeInsets.only(right: 12),
|
||||
child: providerIcon,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
@@ -84,6 +84,7 @@ class TransactionsPage extends StatelessWidget {
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.orderDetails,
|
||||
arguments: order),
|
||||
provider: order.provider,
|
||||
from: order.from,
|
||||
to: order.to,
|
||||
createdAtFormattedDate:
|
||||
|
||||
@@ -52,7 +52,7 @@ class ExchangePage extends BasePage {
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@@ -37,7 +37,7 @@ class ExchangeTemplatePage extends BasePage {
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
@@ -176,7 +176,7 @@ class ExchangeTemplatePage extends BasePage {
|
||||
initialIsAddressEditable:
|
||||
exchangeViewModel.isReceiveAddressEnabled,
|
||||
isAmountEstimated: true,
|
||||
currencies: CryptoCurrency.all,
|
||||
currencies: exchangeViewModel.receiveCurrencies,
|
||||
onCurrencySelected: (currency) =>
|
||||
exchangeViewModel.changeReceiveCurrency(
|
||||
currency: currency),
|
||||
|
||||
@@ -45,6 +45,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
||||
color: Palette.darkBlueCraiola,
|
||||
);
|
||||
final int crossAxisCount = 3;
|
||||
final int maxNumberItemsInAlert = 12;
|
||||
final int itemsCount;
|
||||
final double backgroundHeight = 280;
|
||||
final double thumbHeight = 72;
|
||||
@@ -148,6 +149,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
||||
);
|
||||
})
|
||||
),
|
||||
if (itemsCount > maxNumberItemsInAlert)
|
||||
CakeScrollbar(
|
||||
backgroundHeight: backgroundHeight,
|
||||
thumbHeight: thumbHeight,
|
||||
|
||||
@@ -98,6 +98,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
showInformation(widget.exchangeTradeViewModel, context);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
widget.exchangeTradeViewModel.timer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final copyImage = Image.asset('assets/images/copy_content.png',
|
||||
|
||||
@@ -19,7 +19,33 @@ class OrderDetailsPage extends BasePage {
|
||||
final OrderDetailsViewModel orderDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
Widget body(BuildContext context) =>
|
||||
OrderDetailsPageBody(orderDetailsViewModel);
|
||||
}
|
||||
|
||||
class OrderDetailsPageBody extends StatefulWidget {
|
||||
OrderDetailsPageBody(this.orderDetailsViewModel);
|
||||
|
||||
final OrderDetailsViewModel orderDetailsViewModel;
|
||||
|
||||
@override
|
||||
OrderDetailsPageBodyState createState() =>
|
||||
OrderDetailsPageBodyState(orderDetailsViewModel);
|
||||
}
|
||||
|
||||
class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
|
||||
OrderDetailsPageBodyState(this.orderDetailsViewModel);
|
||||
|
||||
final OrderDetailsViewModel orderDetailsViewModel;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
orderDetailsViewModel.timer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
@@ -44,4 +70,5 @@ class OrderDetailsPage extends BasePage {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
@@ -34,6 +35,9 @@ class ReceivePage extends BasePage {
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.transparent;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
final FocusNode _cryptoAmountFocus;
|
||||
|
||||
@override
|
||||
@@ -124,7 +128,8 @@ class ReceivePage extends BasePage {
|
||||
child: QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
isAmountFieldShow: true,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus),
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
isBright: currentTheme.type == ThemeType.bright),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
|
||||
@@ -13,7 +13,8 @@ class QRWidget extends StatelessWidget {
|
||||
QRWidget(
|
||||
{@required this.addressListViewModel,
|
||||
this.isAmountFieldShow = false,
|
||||
this.amountTextFieldFocusNode})
|
||||
this.amountTextFieldFocusNode,
|
||||
this.isBright})
|
||||
: amountController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>() {
|
||||
amountController.addListener(() => addressListViewModel.amount =
|
||||
@@ -25,6 +26,7 @@ class QRWidget extends StatelessWidget {
|
||||
final TextEditingController amountController;
|
||||
final FocusNode amountTextFieldFocusNode;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final bool isBright;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -55,7 +57,7 @@ class QRWidget extends StatelessWidget {
|
||||
),
|
||||
child: QrImage(
|
||||
data: addressListViewModel.uri.toString(),
|
||||
backgroundColor: Colors.transparent,
|
||||
backgroundColor: isBright ? Colors.black : Colors.transparent,
|
||||
foregroundColor: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor,
|
||||
),
|
||||
|
||||
@@ -67,7 +67,7 @@ class SendPage extends BasePage {
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@@ -34,7 +34,7 @@ class SendTemplatePage extends BasePage {
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@@ -19,7 +19,33 @@ class TradeDetailsPage extends BasePage {
|
||||
final TradeDetailsViewModel tradeDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
Widget body(BuildContext context) =>
|
||||
TradeDetailsPageBody(tradeDetailsViewModel);
|
||||
}
|
||||
|
||||
class TradeDetailsPageBody extends StatefulWidget {
|
||||
TradeDetailsPageBody(this.tradeDetailsViewModel);
|
||||
|
||||
final TradeDetailsViewModel tradeDetailsViewModel;
|
||||
|
||||
@override
|
||||
TradeDetailsPageBodyState createState() =>
|
||||
TradeDetailsPageBodyState(tradeDetailsViewModel);
|
||||
}
|
||||
|
||||
class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
|
||||
TradeDetailsPageBodyState(this.tradeDetailsViewModel);
|
||||
|
||||
final TradeDetailsViewModel tradeDetailsViewModel;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
tradeDetailsViewModel.timer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
@@ -44,4 +70,5 @@ class TradeDetailsPage extends BasePage {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ class BaseTextFormField extends StatelessWidget {
|
||||
this.placeholderTextStyle,
|
||||
this.maxLength,
|
||||
this.focusNode,
|
||||
this.initialValue});
|
||||
this.initialValue,
|
||||
this.borderWidth = 1.0});
|
||||
|
||||
final TextEditingController controller;
|
||||
final TextInputType keyboardType;
|
||||
@@ -52,6 +53,7 @@ class BaseTextFormField extends StatelessWidget {
|
||||
final bool readOnly;
|
||||
final bool enableInteractiveSelection;
|
||||
final String initialValue;
|
||||
final double borderWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -88,17 +90,17 @@ class BaseTextFormField extends StatelessWidget {
|
||||
borderSide: BorderSide(
|
||||
color: borderColor ??
|
||||
Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
width: 1.0)),
|
||||
width: borderWidth)),
|
||||
disabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: borderColor ??
|
||||
Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
width: 1.0)),
|
||||
width: borderWidth)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: borderColor ??
|
||||
Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
width: 1.0))),
|
||||
width: borderWidth))),
|
||||
validator: validator,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user