Merge branch 'main' into CAKE-330-unspent-coins-details-UI

# Conflicts:
#	lib/router.dart
#	lib/routes.dart
This commit is contained in:
OleksandrSobol
2021-07-01 12:39:37 +03:00
90 changed files with 2015 additions and 567 deletions
@@ -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);
}
});
}
}
+287
View File
@@ -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
),
),
)
],
)
)
);
}
}
+13 -36
View File
@@ -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:
+1 -1
View File
@@ -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 {
});
});
}
}
+6 -1
View File
@@ -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,
),
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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 {
});
});
}
}
+6 -4
View File
@@ -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,
);
}