merged with 4.0.8

This commit is contained in:
Tanner Silva
2020-11-19 20:38:23 -06:00
117 changed files with 2660 additions and 1637 deletions
+2 -1
View File
@@ -40,13 +40,14 @@ class AuthPageState extends State<AuthPage> {
reaction((_) => widget.authViewModel.state, (ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_authBar?.dismiss();
if (widget.onAuthenticationFinished != null) {
widget.onAuthenticationFinished(true, this);
} else {
_authBar?.dismiss();
showBar<void>(context, S.of(context).authenticated);
}
});
setState(() {});
}
if (state is IsExecutingState) {
+5 -4
View File
@@ -48,14 +48,15 @@ abstract class BasePage extends StatelessWidget {
return null;
}
final _backButton = Image.asset('assets/images/back_arrow.png',
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color);
final _backButton = Icon(Icons.arrow_back_ios,
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color,
size: 16,);
final _closeButton =
isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage;
return SizedBox(
height: 37,
width: isModalBackButton ? 37 : 20,
width: 37,
child: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(
@@ -76,7 +77,7 @@ abstract class BasePage extends StatelessWidget {
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: titleColor ??
Theme.of(context).primaryTextTheme.title.color),
);
@@ -33,7 +33,7 @@ class FilterWidget extends StatelessWidget {
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
@@ -74,7 +74,7 @@ class FilterWidget extends StatelessWidget {
color: Theme.of(context).accentTextTheme.subhead.color,
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none
),
),
@@ -97,7 +97,7 @@ class FilterWidget extends StatelessWidget {
final item = section[index2];
final content = item.onChanged != null
? CheckboxWidget(
value: item.value,
value: item.value(),
caption: item.caption,
onChanged: item.onChanged
)
@@ -127,7 +127,7 @@ class FilterWidget extends StatelessWidget {
style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
decoration: TextDecoration.none
),
+250 -242
View File
@@ -62,261 +62,269 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
child: Column(
children: <Widget>[
SizedBox(height: 10.0),
Expanded(
child: Stack(
return WillPopScope(
onWillPop: () async => false,
child: Container(
color: Theme.of(context).backgroundColor,
child: Column(
children: <Widget>[
SingleChildScrollView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
Row(
SizedBox(height: 10.0),
Expanded(
child: Stack(
children: <Widget>[
SingleChildScrollView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
Expanded(
child: Text(
'Terms and conditions',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
SizedBox(
height: 20.0,
),
Row(
children: <Widget>[
Expanded(
child: Text(
'Legal Disclaimer\nAnd\nTerms of Use',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
SizedBox(
height: 16.0,
),
Row(
children: <Widget>[
Expanded(
child: Text(
_fileText,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(
'Other Terms and Conditions',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(xmrtoUrl),
child: Text(
xmrtoUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(changenowUrl),
child: Text(
changenowUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(morphUrl),
child: Text(
morphUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
)
],
),
),
Container(
alignment: Alignment.bottomCenter,
child: Container(
height: 12.0,
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context)
.backgroundColor
.withOpacity(0.0),
Theme.of(context).backgroundColor,
],
begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomCenter,
),
),
),
),
),
),
)
],
)),
if (!widget.isReadOnly) ...[
Row(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
child: InkWell(
onTap: () {
setState(() {
_checked = !_checked;
});
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
Row(
children: <Widget>[
Container(
height: 24.0,
width: 24.0,
margin: EdgeInsets.only(
right: 10.0,
Expanded(
child: Text(
'Terms and conditions',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.primaryTextTheme
.caption
.color,
width: 1.0),
borderRadius:
BorderRadius.all(Radius.circular(8.0)),
color: Theme.of(context).backgroundColor),
child: _checked
? Icon(
Icons.check,
color: Colors.blue,
size: 20.0,
)
: null,
),
Text(
'I agree to Terms of Use',
)
],
),
SizedBox(
height: 20.0,
),
Row(
children: <Widget>[
Expanded(
child: Text(
'Legal Disclaimer\nAnd\nTerms of Use',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
SizedBox(
height: 16.0,
),
Row(
children: <Widget>[
Expanded(
child: Text(
_fileText,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
fontSize: 12.0,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(
'Other Terms and Conditions',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
)),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(xmrtoUrl),
child: Text(
xmrtoUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(changenowUrl),
child: Text(
changenowUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () => launchUrl(morphUrl),
child: Text(
morphUrl,
textAlign: TextAlign.left,
style: TextStyle(
color: Palette.blueCraiola,
fontSize: 14.0,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline),
),
))
],
),
SizedBox(
height: 16.0,
)
],
),
),
Container(
alignment: Alignment.bottomCenter,
child: Container(
height: 12.0,
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context)
.backgroundColor
.withOpacity(0.0),
Theme.of(context).backgroundColor,
],
begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomCenter,
),
),
),
),
),
),
)
],
)),
if (!widget.isReadOnly) ...[
Row(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
child: InkWell(
onTap: () {
setState(() {
_checked = !_checked;
});
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
height: 24.0,
width: 24.0,
margin: EdgeInsets.only(
right: 10.0,
),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.primaryTextTheme
.caption
.color,
width: 1.0),
borderRadius: BorderRadius.all(
Radius.circular(8.0)),
color: Theme.of(context).backgroundColor),
child: _checked
? Icon(
Icons.check,
color: Colors.blue,
size: 20.0,
)
: null,
),
Text(
'I agree to Terms of Use',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)
],
),
)),
),
],
),
Container(
padding:
EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
child: PrimaryButton(
onPressed: _checked
? () => Navigator.of(context)
.popAndPushNamed(Routes.welcome)
: null,
text: 'Accept',
color: Theme.of(context)
.accentTextTheme
.subtitle
.decorationColor,
textColor: Theme.of(context)
.accentTextTheme
.headline
.decorationColor),
),
],
),
Container(
padding: EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
child: PrimaryButton(
onPressed: _checked
? () =>
Navigator.of(context).popAndPushNamed(Routes.welcome)
: null,
text: 'Accept',
color: Colors.green,
textColor: Colors.white,
),
),
],
],
),
);
],
),
));
}
}
+31 -17
View File
@@ -1,4 +1,5 @@
import 'dart:ui';
import 'package:cake_wallet/entities/sync_status.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -61,7 +62,10 @@ class ExchangePage extends BasePage {
@override
Widget trailing(BuildContext context) => TrailButton(
caption: S.of(context).reset, onPressed: () => exchangeViewModel.reset());
caption: S.of(context).reset, onPressed: () {
_formKey.currentState.reset();
exchangeViewModel.reset();
});
@override
Widget body(BuildContext context) {
@@ -373,13 +377,12 @@ class ExchangePage extends BasePage {
child: Observer(builder: (_) {
final description =
exchangeViewModel.provider is XMRTOExchangeProvider
? exchangeViewModel.isReceiveAmountEntered
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
return Center(
child: Text(
description,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
@@ -392,19 +395,30 @@ class ExchangePage extends BasePage {
}),
),
Observer(
builder: (_) => LoadingPrimaryButton(
text: S.of(context).exchange,
onPressed: () {
if (_formKey.currentState.validate()) {
exchangeViewModel.createTrade();
}
},
color:
Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading: exchangeViewModel.tradeState
is TradeIsCreating,
)),
builder: (_) => LoadingPrimaryButton(
text: S.of(context).exchange,
onPressed: () {
if (_formKey.currentState.validate()) {
if ((exchangeViewModel.depositCurrency == CryptoCurrency.xmr)
&&(!(exchangeViewModel.status is SyncedSyncStatus))) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).exchange,
alertContent: S.of(context).exchange_sync_alert_content,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
} else {
exchangeViewModel.createTrade();
}
}
},
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading: exchangeViewModel.tradeState
is TradeIsCreating)),
]),
)),
));
@@ -205,13 +205,12 @@ class ExchangeTemplatePage extends BasePage {
child: Observer(builder: (_) {
final description =
exchangeViewModel.provider is XMRTOExchangeProvider
? exchangeViewModel.isReceiveAmountEntered
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
return Center(
child: Text(
description,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
@@ -74,7 +74,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white
@@ -95,6 +95,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
alignment: Alignment.center,
children: <Widget>[
GridView.count(
padding: EdgeInsets.all(0),
controller: controller,
crossAxisCount: crossAxisCount,
childAspectRatio: 1.25,
@@ -136,7 +137,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
item.toString(),
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
color: textColor
@@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
@@ -14,8 +15,8 @@ class PresentProviderPicker extends StatelessWidget {
@override
Widget build(BuildContext context) {
final arrowBottom =
Image.asset('assets/images/arrow_bottom_purple_icon.png',
final arrowBottom = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
height: 6);
@@ -50,8 +51,7 @@ class PresentProviderPicker extends StatelessWidget {
child: arrowBottom,
)
],
)
);
));
}
void _presentProviderPicker(BuildContext context) {
@@ -64,7 +64,6 @@ class PresentProviderPicker extends StatelessWidget {
switch (provider.description) {
case ExchangeProviderDescription.xmrto:
images.add(Image.asset('assets/images/xmr_btc.png'));
description = S.of(context).picker_description;
break;
case ExchangeProviderDescription.changeNow:
images.add(Image.asset('assets/images/change_now.png'));
@@ -76,14 +75,25 @@ class PresentProviderPicker extends StatelessWidget {
}
showPopUp<void>(
builder: (_) => Picker(
builder: (BuildContext popUpContext) => Picker(
items: items,
images: images,
selectedAtIndex: selectedItem,
title: S.of(context).change_exchange_provider,
description: description,
onItemSelected: (ExchangeProvider provider) =>
exchangeViewModel.changeProvider(provider: provider)),
onItemSelected: (ExchangeProvider provider) {
if (!provider.isAvailable) {
showPopUp<void>(
builder: (BuildContext popUpContext) => AlertWithOneAction(
alertTitle: 'Error',
alertContent: 'The exchange is blocked in your region.',
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()),
context: context);
return;
}
exchangeViewModel.changeProvider(provider: provider);
}),
context: context);
}
}
}
@@ -1,31 +1,26 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
import 'dart:ui';
import 'package:mobx/mobx.dart';
import 'package:provider/provider.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
// import 'package:cake_wallet/src/stores/exchange_trade/exchange_trade_store.dart';
// import 'package:cake_wallet/src/stores/send/send_store.dart';
// import 'package:cake_wallet/src/stores/send/sending_state.dart';
// import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/exchange_trade/widgets/timer_widget.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/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
void showInformation(
ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
@@ -110,7 +105,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
width: 16,
color: Theme.of(context).primaryTextTheme.overline.color);
//_setEffects(context);
_setEffects(context);
return Container(
child: ScrollableWithBottomSection(
@@ -227,30 +222,25 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
);
}),
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
bottomSection: PrimaryButton(
onPressed: () {},
text: S.of(context).confirm,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white)
/*Observer(
builder: (_) => tradeStore.trade.from == CryptoCurrency.xmr &&
!(sendStore.state is TransactionCommitted)
bottomSection: Observer(builder: (_) {
final trade = widget.exchangeTradeViewModel.trade;
final sendingState =
widget.exchangeTradeViewModel.sendViewModel.state;
return trade.from == CryptoCurrency.xmr && !(sendingState is TransactionCommitted)
? LoadingPrimaryButton(
isDisabled: tradeStore.trade.inputAddress == null ||
tradeStore.trade.inputAddress.isEmpty,
isLoading: sendStore.state is CreatingTransaction ||
sendStore.state is TransactionCommitted,
onPressed: () => sendStore.createTransaction(
address: tradeStore.trade.inputAddress,
amount: tradeStore.trade.amount),
text: tradeStore.trade.provider ==
ExchangeProviderDescription.xmrto
? S.of(context).confirm
: S.of(context).send_xmr,
color: Colors.blue,
textColor: Colors.white)
: Offstage()),*/
),
isDisabled: trade.inputAddress == null ||
trade.inputAddress.isEmpty,
isLoading: sendingState is IsExecutingState,
onPressed: () =>
widget.exchangeTradeViewModel.confirmSending(),
text: trade.provider == ExchangeProviderDescription.xmrto
? S.of(context).confirm
: S.of(context).send_xmr,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white)
: Offstage();
})),
);
}
@@ -259,10 +249,9 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
return;
}
/*final sendStore = Provider.of<SendStore>(context);
reaction((_) => sendStore.state, (SendingState state) {
if (state is SendingFailed) {
reaction((_) => this.widget.exchangeTradeViewModel.sendViewModel.state,
(ExecutionState state) {
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
@@ -271,30 +260,126 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
alertTitle: S.of(context).error,
alertContent: state.error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()
);
buttonAction: () => Navigator.of(context).pop());
});
});
}
if (state is TransactionCreatedSuccessfully) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending,
alertContent: S.of(context).commit_transaction_amount_fee(
sendStore.pendingTransaction.amount,
sendStore.pendingTransaction.fee),
leftButtonText: S.of(context).ok,
rightButtonText: S.of(context).cancel,
actionLeftButton: () {
amount: S.of(context).send_amount,
amountValue: widget.exchangeTradeViewModel.sendViewModel
.pendingTransaction.amountFormatted,
fee: S.of(context).send_fee,
feeValue: widget.exchangeTradeViewModel.sendViewModel
.pendingTransaction.feeFormatted,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
Navigator.of(context).pop();
sendStore.commitTransaction();
widget.exchangeTradeViewModel.sendViewModel
.commitTransaction();
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return Observer(builder: (_) {
final state = widget
.exchangeTradeViewModel.sendViewModel.state;
if (state is TransactionCommitted) {
return Stack(
children: <Widget>[
Container(
color: Theme.of(context).backgroundColor,
child: Center(
child: Image.asset(
'assets/images/birthday_cake.png'),
),
),
Center(
child: Padding(
padding: EdgeInsets.only(
top: 220, left: 24, right: 24),
child: Text(
S.of(context).send_success,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
decoration: TextDecoration.none,
),
),
),
),
Positioned(
left: 24,
right: 24,
bottom: 24,
child: PrimaryButton(
onPressed: () =>
Navigator.of(context).pop(),
text: S.of(context).send_got_it,
color: Theme.of(context)
.accentTextTheme
.body2
.color,
textColor: Colors.white))
],
);
}
return Stack(
children: <Widget>[
Container(
color: Theme.of(context).backgroundColor,
child: Center(
child: Image.asset(
'assets/images/birthday_cake.png'),
),
),
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.backgroundColor
.withOpacity(0.25)),
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 220),
child: Text(
S.of(context).send_sending,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
decoration: TextDecoration.none,
),
),
),
),
),
)
],
);
});
});
},
actionRightButton: () => Navigator.of(context).pop()
);
actionLeftButton: () => Navigator.of(context).pop());
});
});
}
@@ -308,12 +393,11 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
alertTitle: S.of(context).sending,
alertContent: S.of(context).transaction_sent,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()
);
buttonAction: () => Navigator.of(context).pop());
});
});
}
});*/
});
_effectsInstalled = true;
}
@@ -33,7 +33,7 @@ class InformationPage extends StatelessWidget {
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: Theme.of(context).accentTextTheme.caption.decorationColor
),
@@ -56,7 +56,7 @@ class MoneroAccountEditOrCreatePage extends BasePage {
text: moneroAccountCreationViewModel.isEdit
? S.of(context).rename
: S.of(context).add,
color: Colors.green,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading: moneroAccountCreationViewModel.state
is IsExecutingState,
@@ -53,7 +53,7 @@ class MoneroAccountListPage extends StatelessWidget {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: Colors.white
),
@@ -141,7 +141,7 @@ class MoneroAccountListPage extends StatelessWidget {
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Colors.white,
decoration: TextDecoration.none,
),
@@ -32,7 +32,7 @@ class AccountTile extends StatelessWidget {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: textColor,
decoration: TextDecoration.none,
),
+108 -88
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -15,9 +16,10 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_h
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.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';
import 'package:keyboard_actions/keyboard_actions.dart';
class ReceivePage extends BasePage {
ReceivePage({this.addressListViewModel});
ReceivePage({this.addressListViewModel}) : _cryptoAmountFocus = FocusNode();
final WalletAddressListViewModel addressListViewModel;
@@ -33,6 +35,8 @@ class ReceivePage extends BasePage {
@override
Color get titleColor => Colors.white;
final FocusNode _cryptoAmountFocus;
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) => Container(
@@ -67,93 +71,109 @@ class ReceivePage extends BasePage {
@override
Widget body(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(24, 80, 24, 40),
child: QRWidget(
addressListViewModel: addressListViewModel,
isAmountFieldShow: true,
),
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
nextFocus: false,
actions: [
KeyboardActionsItem(
focusNode: _cryptoAmountFocus,
toolbarButtons: [(_) => KeyboardDoneButton()],
)
]),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(24, 80, 24, 40),
child: QRWidget(
addressListViewModel: addressListViewModel,
isAmountFieldShow: true,
amountTextFieldFocusNode: _cryptoAmountFocus),
),
Observer(
builder: (_) => ListView.separated(
padding: EdgeInsets.all(0),
separatorBuilder: (context, _) => Container(
height: 1, color: Theme.of(context).dividerColor),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: addressListViewModel.items.length,
itemBuilder: (context, index) {
final item = addressListViewModel.items[index];
Widget cell = Container();
if (item is WalletAccountListHeader) {
cell = HeaderTile(
onTap: () async => await showPopUp<void>(
context: context,
builder: (_) =>
getIt.get<MoneroAccountListPage>()),
title: S.of(context).accounts,
icon: Icon(
Icons.arrow_forward_ios,
size: 14,
color:
Theme.of(context).textTheme.display1.color,
));
}
if (item is WalletAddressListHeader) {
cell = HeaderTile(
onTap: () => Navigator.of(context)
.pushNamed(Routes.newSubaddress),
title: S.of(context).addresses,
icon: Icon(
Icons.add,
size: 20,
color:
Theme.of(context).textTheme.display1.color,
));
}
if (item is WalletAddressListItem) {
cell = Observer(builder: (_) {
final isCurrent = item.address ==
addressListViewModel.address.address;
final backgroundColor = isCurrent
? Theme.of(context)
.textTheme
.display3
.decorationColor
: Theme.of(context)
.textTheme
.display2
.decorationColor;
final textColor = isCurrent
? Theme.of(context).textTheme.display3.color
: Theme.of(context).textTheme.display2.color;
return AddressCell.fromItem(item,
isCurrent: isCurrent,
backgroundColor: backgroundColor,
textColor: textColor,
onTap: (_) =>
addressListViewModel.setAddress(item),
onEdit: () => Navigator.of(context).pushNamed(
Routes.newSubaddress,
arguments: item));
});
}
return index != 0
? cell
: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)),
child: cell,
);
})),
],
),
Observer(
builder: (_) => ListView.separated(
padding: EdgeInsets.all(0),
separatorBuilder: (context, _) => Container(
height: 1, color: Theme.of(context).dividerColor),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: addressListViewModel.items.length,
itemBuilder: (context, index) {
final item = addressListViewModel.items[index];
Widget cell = Container();
if (item is WalletAccountListHeader) {
cell = HeaderTile(
onTap: () async => await showPopUp<void>(
context: context,
builder: (_) =>
getIt.get<MoneroAccountListPage>()),
title: S.of(context).accounts,
icon: Icon(
Icons.arrow_forward_ios,
size: 14,
color: Theme.of(context).textTheme.display1.color,
));
}
if (item is WalletAddressListHeader) {
cell = HeaderTile(
onTap: () => Navigator.of(context)
.pushNamed(Routes.newSubaddress),
title: S.of(context).addresses,
icon: Icon(
Icons.add,
size: 20,
color: Theme.of(context).textTheme.display1.color,
));
}
if (item is WalletAddressListItem) {
cell = Observer(builder: (_) {
final isCurrent = item.address ==
addressListViewModel.address.address;
final backgroundColor = isCurrent
? Theme.of(context)
.textTheme
.display3
.decorationColor
: Theme.of(context)
.textTheme
.display2
.decorationColor;
final textColor = isCurrent
? Theme.of(context).textTheme.display3.color
: Theme.of(context).textTheme.display2.color;
return AddressCell.fromItem(item,
isCurrent: isCurrent,
backgroundColor: backgroundColor,
textColor: textColor,
onTap: (_) => addressListViewModel.setAddress(item),
onEdit: () => Navigator.of(context).pushNamed(
Routes.newSubaddress,
arguments: item));
});
}
return index != 0
? cell
: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)),
child: cell,
);
})),
],
),
);
));
}
}
@@ -11,7 +11,9 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_v
class QRWidget extends StatelessWidget {
QRWidget(
{@required this.addressListViewModel, this.isAmountFieldShow = false})
{@required this.addressListViewModel,
this.isAmountFieldShow = false,
this.amountTextFieldFocusNode})
: amountController = TextEditingController(),
_formKey = GlobalKey<FormState>() {
amountController.addListener(() => addressListViewModel.amount =
@@ -21,6 +23,7 @@ class QRWidget extends StatelessWidget {
final WalletAddressListViewModel addressListViewModel;
final bool isAmountFieldShow;
final TextEditingController amountController;
final FocusNode amountTextFieldFocusNode;
final GlobalKey<FormState> _formKey;
@override
@@ -45,7 +48,7 @@ class QRWidget extends StatelessWidget {
data: addressListViewModel.uri.toString(),
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
//Theme.of(context).textTheme.headline.color,
//Theme.of(context).textTheme.headline.color,
))))),
Spacer(flex: 3)
]),
@@ -68,6 +71,7 @@ class QRWidget extends StatelessWidget {
child: Form(
key: _formKey,
child: BaseTextFormField(
focusNode: amountTextFieldFocusNode,
controller: amountController,
keyboardType: TextInputType.numberWithOptions(
decimal: true),
+4 -17
View File
@@ -21,23 +21,9 @@ class RescanPage extends BasePage {
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
child:
Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Column(
children: <Widget>[
BlockchainHeightWidget(key: _blockchainHeightWidgetKey),
Padding(
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
child: Text(
S.of(context).restore_from_date_or_blockheight,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context).hintColor
),
),
)
],
),
BlockchainHeightWidget(key: _blockchainHeightWidgetKey,
onHeightOrDateEntered: (value) =>
_rescanViewModel.isButtonEnabled = value),
Observer(
builder: (_) => LoadingPrimaryButton(
isLoading:
@@ -51,6 +37,7 @@ class RescanPage extends BasePage {
},
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isDisabled: !_rescanViewModel.isButtonEnabled,
))
]),
);
@@ -6,7 +6,10 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class WalletRestoreFromKeysFrom extends StatefulWidget {
WalletRestoreFromKeysFrom({Key key}) : super(key: key);
WalletRestoreFromKeysFrom({Key key, this.onHeightOrDateEntered})
: super(key: key);
final Function (bool) onHeightOrDateEntered;
@override
WalletRestoreFromKeysFromState createState() =>
@@ -63,7 +66,9 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
hintText: S.of(context).restore_spend_key_private,
maxLines: null)),
BlockchainHeightWidget(
key: blockchainHeightKey, onHeightChange: (_) => null)
key: blockchainHeightKey,
onHeightChange: (_) => null,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
]),
));
}
@@ -7,10 +7,12 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
class WalletRestoreFromSeedForm extends StatefulWidget {
WalletRestoreFromSeedForm({Key key, this.blockHeightFocusNode})
WalletRestoreFromSeedForm({Key key, this.blockHeightFocusNode,
this.onHeightOrDateEntered})
: super(key: key);
final FocusNode blockHeightFocusNode;
final Function (bool) onHeightOrDateEntered;
@override
WalletRestoreFromSeedFormState createState() =>
@@ -46,6 +48,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
context: context,
builder: (BuildContext context) =>
SeedLanguagePicker(selected: language));
if (selected == null || selected.isEmpty) {
return;
}
_changeLanguage(selected);
},
child: Container(
@@ -58,7 +65,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
readOnly: true)))),
BlockchainHeightWidget(
focusNode: widget.blockHeightFocusNode,
key: blockchainHeightKey)
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
]));
}
@@ -28,8 +28,12 @@ class WalletRestorePage extends BasePage {
_pages.addAll([
WalletRestoreFromSeedForm(
key: walletRestoreFromSeedFormKey,
blockHeightFocusNode: _blockHeightFocusNode),
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey)
blockHeightFocusNode: _blockHeightFocusNode,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value),
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value)
]);
}
@@ -42,14 +46,11 @@ class WalletRestorePage extends BasePage {
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: titleColor ??
Theme.of(context).primaryTextTheme.title.color),
));
@override
String get title => S.current.restore_title_from_seed;
final WalletRestoreViewModel walletRestoreViewModel;
final PageController _controller;
final List<Widget> _pages;
@@ -75,6 +76,21 @@ class WalletRestorePage extends BasePage {
}
});
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode)
{
walletRestoreViewModel.isButtonEnabled = false;
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
});
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Expanded(
child: PageView.builder(
@@ -105,10 +121,19 @@ class WalletRestorePage extends BasePage {
return LoadingPrimaryButton(
onPressed: () =>
walletRestoreViewModel.create(options: _credentials()),
text: S.of(context).seed_language_next,
color: Colors.green,
textColor: Colors.white,
isLoading: walletRestoreViewModel.state is IsExecutingState);
text: S.of(context).restore_recover,
color: Theme
.of(context)
.accentTextTheme
.subtitle
.decorationColor,
textColor: Theme
.of(context)
.accentTextTheme
.headline
.decorationColor,
isLoading: walletRestoreViewModel.state is IsExecutingState,
isDisabled: !walletRestoreViewModel.isButtonEnabled,);
},
))
]);
+4 -6
View File
@@ -32,13 +32,11 @@ class WalletSeedPage extends BasePage {
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
// FIXME: add translations
return AlertWithTwoActions(
alertTitle: 'Attention',
alertContent:
'The seed is the only way to recover your wallet. Have you written it down?',
leftButtonText: 'Go back',
rightButtonText: 'Yes, I have',
alertTitle: S.of(context).seed_alert_title,
alertContent: S.of(context).seed_alert_content,
leftButtonText: S.of(context).seed_alert_back,
rightButtonText: S.of(context).seed_alert_yes,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () => Navigator.of(context).pop(true));
}) ??
@@ -77,7 +77,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: Colors.white
),
@@ -92,6 +92,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
width: 300,
color: Theme.of(context).accentTextTheme.title.backgroundColor,
child: GridView.count(
padding: EdgeInsets.all(0),
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1,
@@ -171,7 +172,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: textColor
),
+172 -144
View File
@@ -70,7 +70,11 @@ class SendPage extends BasePage {
@override
Widget trailing(context) => TrailButton(
caption: S.of(context).clear, onPressed: () => sendViewModel.reset());
caption: S.of(context).clear,
onPressed: () {
_formKey.currentState.reset();
sendViewModel.reset();
});
@override
Widget body(BuildContext context) {
@@ -163,72 +167,75 @@ class SendPage extends BasePage {
.decorationColor),
validator: sendViewModel.addressValidator,
),
Observer(builder: (_) => Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: _cryptoAmountFocus,
controller: _cryptoAmountController,
keyboardType:
TextInputType.numberWithOptions(
signed: false, decimal: true),
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendViewModel.currency.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
suffixIcon: Container(
height: 32,
width: 32,
margin: EdgeInsets.only(
left: 14, top: 4, bottom: 10),
decoration: BoxDecoration(
color: Theme.of(context)
.primaryTextTheme
.display1
.color,
borderRadius: BorderRadius.all(
Radius.circular(6))),
child: InkWell(
onTap: () =>
sendViewModel.setSendAll(),
child: Center(
child: Text(S.of(context).all,
textAlign: TextAlign.center,
Observer(
builder: (_) => Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: _cryptoAmountFocus,
controller: _cryptoAmountController,
keyboardType:
TextInputType.numberWithOptions(
signed: false, decimal: true),
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendViewModel.currency.title +
':',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.display1
.decorationColor)),
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
),
),
hintText: '0.0000',
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
suffixIcon: Container(
height: 32,
width: 32,
margin: EdgeInsets.only(
left: 14, top: 4, bottom: 10),
decoration: BoxDecoration(
color: Theme.of(context)
.primaryTextTheme
.display1
.color,
borderRadius: BorderRadius.all(
Radius.circular(6))),
child: InkWell(
onTap: () =>
sendViewModel.setSendAll(),
child: Center(
child: Text(S.of(context).all,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight:
FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.display1
.decorationColor)),
),
),
),
hintText: '0.0000',
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator:
sendViewModel.sendAll
? sendViewModel.allAmountValidator
: sendViewModel.amountValidator))),
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendViewModel.sendAll
? sendViewModel.allAmountValidator
: sendViewModel
.amountValidator))),
Observer(
builder: (_) => Padding(
padding: EdgeInsets.only(top: 10),
@@ -420,53 +427,60 @@ class SendPage extends BasePage {
)),
),
),
Observer(
builder: (_) {
final templates = sendViewModel.templates;
final itemCount = templates.length;
Observer(builder: (_) {
final templates = sendViewModel.templates;
final itemCount = templates.length;
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: itemCount,
itemBuilder: (context, index) {
final template = templates[index];
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: itemCount,
itemBuilder: (context, index) {
final template = templates[index];
return TemplateTile(
key: UniqueKey(),
to: template.name,
amount: template.amount,
from: template.cryptoCurrency,
onTap: () {
_addressController.text = template.address;
_cryptoAmountController.text = template.amount;
getOpenaliasRecord(context);
},
onRemove: () {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return AlertWithTwoActions(
alertTitle: S.of(context).template,
alertContent: S.of(context).confirm_delete_template,
rightButtonText: S.of(context).delete,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
Navigator.of(dialogContext).pop();
sendViewModel.removeTemplate(template: template);
sendViewModel.updateTemplate();
},
actionLeftButton: () => Navigator.of(dialogContext).pop()
);
}
);
},
);
}
);
}
)
return TemplateTile(
key: UniqueKey(),
to: template.name,
amount: template.amount,
from: template.cryptoCurrency,
onTap: () {
_addressController.text =
template.address;
_cryptoAmountController.text =
template.amount;
getOpenaliasRecord(context);
},
onRemove: () {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return AlertWithTwoActions(
alertTitle:
S.of(context).template,
alertContent: S
.of(context)
.confirm_delete_template,
rightButtonText:
S.of(context).delete,
leftButtonText:
S.of(context).cancel,
actionRightButton: () {
Navigator.of(dialogContext)
.pop();
sendViewModel.removeTemplate(
template: template);
sendViewModel
.updateTemplate();
},
actionLeftButton: () =>
Navigator.of(dialogContext)
.pop());
});
},
);
});
})
],
),
),
@@ -483,8 +497,14 @@ class SendPage extends BasePage {
}
},
text: S.of(context).send,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
color: Theme.of(context)
.accentTextTheme
.subtitle
.decorationColor,
textColor: Theme.of(context)
.accentTextTheme
.headline
.decorationColor,
isLoading: sendViewModel.state is IsExecutingState ||
sendViewModel.state is TransactionCommitting,
isDisabled:
@@ -595,6 +615,10 @@ class SendPage extends BasePage {
return Observer(builder: (_) {
final state = sendViewModel.state;
if (state is FailureState) {
Navigator.of(context).pop();
}
if (state is TransactionCommitted) {
return Stack(
children: <Widget>[
@@ -641,45 +665,49 @@ class SendPage extends BasePage {
);
}
return Stack(
children: <Widget>[
Container(
color: Theme.of(context).backgroundColor,
child: Center(
child: Image.asset(
'assets/images/birthday_cake.png'),
),
),
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.backgroundColor
.withOpacity(0.25)),
if (state is TransactionCommitting) {
return Stack(
children: <Widget>[
Container(
color: Theme.of(context).backgroundColor,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 220),
child: Text(
S.of(context).send_sending,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
decoration: TextDecoration.none,
child: Image.asset(
'assets/images/birthday_cake.png'),
),
),
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.backgroundColor
.withOpacity(0.25)),
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 220),
child: Text(
S.of(context).send_sending,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
decoration: TextDecoration.none,
),
),
),
),
),
),
)
],
);
)
],
);
}
return Container();
});
});
},
+183 -155
View File
@@ -1,15 +1,17 @@
import 'package:cake_wallet/src/widgets/address_text_field.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:mobx/mobx.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/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/widgets/address_text_field.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class SendTemplatePage extends BasePage {
SendTemplatePage({@required this.sendViewModel});
@@ -20,6 +22,8 @@ class SendTemplatePage extends BasePage {
final _fiatAmountController = TextEditingController();
final _nameController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final FocusNode _cryptoAmountFocus = FocusNode();
final FocusNode _fiatAmountFocus = FocusNode();
bool _effectsInstalled = false;
@@ -42,94 +46,153 @@ class SendTemplatePage extends BasePage {
Widget body(BuildContext context) {
_setEffects(context);
return Container(
color: Theme.of(context).backgroundColor,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: 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: Form(
key: _formKey,
child: Column(children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(24, 90, 24, 32),
child: Column(
children: <Widget>[
BaseTextFormField(
controller: _nameController,
hintText: S.of(context).send_name,
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendViewModel.templateValidator,
),
Padding(
padding: EdgeInsets.only(top: 20),
child: AddressTextField(
controller: _addressController,
onURIScanned: (uri) {
var address = '';
var amount = '';
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
nextFocus: false,
actions: [
KeyboardActionsItem(
focusNode: _cryptoAmountFocus,
toolbarButtons: [(_) => KeyboardDoneButton()],
),
KeyboardActionsItem(
focusNode: _fiatAmountFocus,
toolbarButtons: [(_) => KeyboardDoneButton()],
)
]),
child: Container(
height: 0,
color: Theme.of(context).backgroundColor,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: 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: Form(
key: _formKey,
child: Column(children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(24, 90, 24, 32),
child: Column(
children: <Widget>[
BaseTextFormField(
controller: _nameController,
hintText: S.of(context).send_name,
borderColor:
Theme.of(context).primaryTextTheme.headline.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendViewModel.templateValidator,
),
Padding(
padding: EdgeInsets.only(top: 20),
child: AddressTextField(
controller: _addressController,
onURIScanned: (uri) {
var address = '';
var amount = '';
if (uri != null) {
address = uri.path;
amount = uri.queryParameters['tx_amount'];
} else {
address = uri.toString();
}
if (uri != null) {
address = uri.path;
amount = uri.queryParameters['tx_amount'];
} else {
address = uri.toString();
}
_addressController.text = address;
_cryptoAmountController.text = amount;
},
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
buttonColor:
Theme.of(context).primaryTextTheme.display1.color,
borderColor:
Theme.of(context).primaryTextTheme.headline.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
hintStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
_addressController.text = address;
_cryptoAmountController.text = amount;
},
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
buttonColor: Theme.of(context)
.primaryTextTheme
.display1
.color,
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor),
validator: sendViewModel.addressValidator,
),
),
Observer(builder: (_) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
controller: _cryptoAmountController,
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
hintStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor),
validator: sendViewModel.addressValidator,
),
),
Observer(builder: (_) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: _cryptoAmountFocus,
controller: _cryptoAmountController,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
BlacklistingTextInputFormatter(
RegExp('[\\-|\\ ]'))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child:
Text(sendViewModel.currency.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
hintText: '0.0000',
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendViewModel.amountValidator));
}),
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: _fiatAmountFocus,
controller: _fiatAmountController,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
@@ -138,15 +201,14 @@ class SendTemplatePage extends BasePage {
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child:
Text(sendViewModel.currency.title + ':',
child: Text(sendViewModel.fiat.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
hintText: '0.0000',
hintText: '0.00',
borderColor: Theme.of(context)
.primaryTextTheme
.headline
@@ -162,68 +224,34 @@ class SendTemplatePage extends BasePage {
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendViewModel.amountValidator));
}),
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
controller: _fiatAmountController,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
BlacklistingTextInputFormatter(
RegExp('[\\-|\\ ]'))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(sendViewModel.fiat.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
hintText: '0.00',
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
)),
],
),
)
]),
)),
],
),
)
]),
),
),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: PrimaryButton(
onPressed: () {
if (_formKey.currentState.validate()) {
sendViewModel.addTemplate(
name: _nameController.text,
address: _addressController.text,
cryptoCurrency: sendViewModel.currency.title,
amount: _cryptoAmountController.text);
sendViewModel.updateTemplate();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Theme.of(context).accentTextTheme.subtitle.decorationColor,
textColor:
Theme.of(context).accentTextTheme.headline.decorationColor,
),
),
),
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: PrimaryButton(
onPressed: () {
if (_formKey.currentState.validate()) {
sendViewModel.addTemplate(
name: _nameController.text,
address: _addressController.text,
cryptoCurrency: sendViewModel.currency.title,
amount: _cryptoAmountController.text);
sendViewModel.updateTemplate();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white),
),
);
));
}
void _setEffects(BuildContext context) {
@@ -55,7 +55,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
),
@@ -65,7 +65,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
),
@@ -81,7 +81,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
),
@@ -91,7 +91,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
),
@@ -60,7 +60,7 @@ class AddressEditOrCreatePage extends BasePage {
text: addressEditOrCreateViewModel.isEdit
? S.of(context).rename
: S.of(context).new_subaddress_create,
color: Colors.green,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading:
addressEditOrCreateViewModel.state is AddressIsSaving,
@@ -13,29 +13,29 @@ import 'package:cake_wallet/src/widgets/standart_list_row.dart';
class TradeDetailsPage extends BasePage {
TradeDetailsPage(this.trade) : _items = [] {
final dateFormat = DateFormatter.withCurrentLocal();
final items = [
_items.addAll([
StandartListItem(title: S.current.trade_details_id, value: trade.id),
StandartListItem(
title: S.current.trade_details_state,
value: trade.state != null
? trade.state.toString()
: S.current.trade_details_fetching)
];
]);
if (trade.provider != null) {
items.add(StandartListItem(
_items.add(StandartListItem(
title: S.current.trade_details_provider,
value: trade.provider.toString()));
}
if (trade.createdAt != null) {
items.add(StandartListItem(
_items.add(StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(trade.createdAt).toString()));
}
if (trade.from != null && trade.to != null) {
items.add(StandartListItem(
_items.add(StandartListItem(
title: S.current.trade_details_pair,
value: '${trade.from.toString()} → ${trade.to.toString()}'));
}
@@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -9,10 +10,15 @@ import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:hive/hive.dart';
class TransactionDetailsPage extends BasePage {
TransactionDetailsPage(this.transactionInfo) : _items = [] {
TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress,
Box<TransactionDescription> transactionDescriptionBox)
: _items = [] {
final dateFormat = DateFormatter.withCurrentLocal();
final tx = transactionInfo;
@@ -31,16 +37,23 @@ class TransactionDetailsPage extends BasePage {
StandartListItem(
title: "View in Block Explorer",
value: "https://localmonero.co/blocks/search/${tx.id}"),
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
];
// FIXME
// if (widget.settingsStore.shouldSaveRecipientAddress &&
// tx.recipientAddress != null) {
// items.add(StandartListItem(
// title: S.current.transaction_details_recipient_address,
// value: tx.recipientAddress));
// }
if (tx.key?.isNotEmpty) {
if (showRecipientAddress) {
final recipientAddress = transactionDescriptionBox.values
.firstWhere((val) => val.id == transactionInfo.id,
orElse: () => null)
?.recipientAddress;
if (recipientAddress?.isNotEmpty ?? false) {
items.add(StandartListItem(
title: S.current.transaction_details_recipient_address,
value: recipientAddress));
}
}
if (tx.key?.isNotEmpty ?? null) {
// FIXME: add translation
items.add(StandartListItem(title: 'Transaction Key', value: tx.key));
}
@@ -87,11 +87,9 @@ class WalletListBodyState extends State<WalletListBody> {
final confirmed = await showPopUp<bool>(
context: context,
builder: (dialogContext) {
// FIXME:
return AlertWithTwoActions(
alertTitle: 'Change current wallet',
alertContent:
'Do you want to change current wallet to ${wallet.name} ?',
alertTitle: S.of(context).change_wallet_alert_title,
alertContent: S.of(context).change_wallet_alert_content(wallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () =>
@@ -242,12 +240,12 @@ class WalletListBodyState extends State<WalletListBody> {
Future<void> _generateNewWallet() async {
try {
changeProcessText('Creating new wallet'); // FIXME: Unnamed constant
changeProcessText(S.of(context).creating_new_wallet);
await widget.walletListViewModel.walletNewVM.create(options: 'English'); // FIXME: Unnamed constant
hideProgressText();
await Navigator.of(context).pushNamed(Routes.seed, arguments: true);
} catch(e) {
changeProcessText('Error: ${e.toString()}');
changeProcessText(S.of(context).creating_new_wallet_error(e.toString()));
}
}
@@ -89,7 +89,7 @@ class WalletMenuAlert extends StatelessWidget {
style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
decoration: TextDecoration.none
),
+2 -2
View File
@@ -220,9 +220,9 @@ class AddressTextField extends StatelessWidget {
Future<void> _pasteAddress(BuildContext context) async {
String address;
await Clipboard.getData('text/plain').then((value) => address = value.text);
await Clipboard.getData('text/plain').then((value) => address = value?.text);
if (address.isNotEmpty) {
if (address?.isNotEmpty ?? false) {
controller.text = address;
}
}
@@ -1,161 +0,0 @@
import 'package:flutter/material.dart';
class Annotation extends Comparable<Annotation> {
Annotation({@required this.range, this.style});
final TextRange range;
final TextStyle style;
@override
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
}
class TextAnnotation extends Comparable<TextAnnotation> {
TextAnnotation({@required this.text, this.style});
final TextStyle style;
final String text;
@override
int compareTo(TextAnnotation other) => text.compareTo(other.text);
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
Color backgroundCursorColor,
TextSelectionControls selectionControls,
@required this.words,
}) : textAnnotations = words
.map((word) => TextAnnotation(
text: word,
style: TextStyle(
color: Colors.black,
backgroundColor: Colors.transparent,
fontWeight: FontWeight.normal,
fontSize: 16)))
.toList(),
super(
maxLines: null,
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: false,
autofocus: false,
selectionColor: selectionColor,
selectionControls: selectionControls,
backgroundCursorColor: backgroundCursorColor,
onChanged: onChanged,
onSubmitted: onSubmitted,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: true,
paste: true,
selectAll: true,
),
enableSuggestions: false,
enableInteractiveSelection: true,
showSelectionHandles: true,
showCursor: true,
) {
textAnnotations.add(TextAnnotation(
text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
}
final List<String> words;
final List<TextAnnotation> textAnnotations;
@override
AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
@override
AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
List<Annotation> getRanges() {
final source = widget.textAnnotations
.map((item) => range(item.text, textEditingValue.text)
.map((range) => Annotation(style: item.style, range: range)))
.expand((e) => e)
.toList();
final result = List<Annotation>();
final text = textEditingValue.text;
source.sort();
Annotation prev;
for (var item in source) {
if (prev == null) {
if (item.range.start > 0) {
result.add(Annotation(
range: TextRange(start: 0, end: item.range.start),
style: TextStyle(
color: Colors.black, backgroundColor: Colors.transparent)));
}
result.add(item);
prev = item;
continue;
} else {
if (prev.range.end > item.range.start) {
// throw StateError('Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
style: TextStyle(
color: Colors.red, backgroundColor: Colors.transparent)));
}
result.add(item);
prev = item;
}
}
if (result.length > 0 && result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
style: TextStyle( backgroundColor: Colors.transparent)));
}
return result;
}
List<TextRange> range(String pattern, String source) {
final result = List<TextRange>();
for (int index = source.indexOf(pattern);
index >= 0;
index = source.indexOf(pattern, index + 1)) {
final start = index;
final end = start + pattern.length;
result.add(TextRange(start: start, end: end));
}
return result;
}
@override
TextSpan buildTextSpan() {
final text = textEditingValue.text;
final ranges = getRanges();
if (ranges.isNotEmpty) {
return TextSpan(
style: widget.style,
children: ranges
.map((item) => TextSpan(
style: item.style, text: item.range.textInside(text)))
.toList());
}
return TextSpan(style: widget.style, text: text);
}
}
+4 -4
View File
@@ -17,7 +17,7 @@ class BaseAlertDialog extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
@@ -32,7 +32,7 @@ class BaseAlertDialog extends StatelessWidget {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Poppins',
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color,
decoration: TextDecoration.none,
),
@@ -59,7 +59,7 @@ class BaseAlertDialog extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Colors.white,
decoration: TextDecoration.none,
@@ -84,7 +84,7 @@ class BaseAlertDialog extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Colors.white,
decoration: TextDecoration.none,
+23 -2
View File
@@ -6,10 +6,12 @@ import 'package:cake_wallet/monero/get_height_by_date.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class BlockchainHeightWidget extends StatefulWidget {
BlockchainHeightWidget({GlobalKey key, this.onHeightChange, this.focusNode})
BlockchainHeightWidget({GlobalKey key, this.onHeightChange, this.focusNode,
this.onHeightOrDateEntered})
: super(key: key);
final Function(int) onHeightChange;
final Function(bool) onHeightOrDateEntered;
final FocusNode focusNode;
@override
@@ -26,6 +28,13 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
@override
void initState() {
restoreHeightController.addListener(() {
if (restoreHeightController.text.isNotEmpty) {
widget.onHeightOrDateEntered?.call(true);
}
else {
widget.onHeightOrDateEntered?.call(false);
dateController.text = '';
}
try {
_changeHeight(restoreHeightController.text != null &&
restoreHeightController.text.isNotEmpty
@@ -83,6 +92,18 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
))
],
),
Padding(
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
child: Text(
S.of(context).restore_from_date_or_blockheight,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context).hintColor
),
),
)
],
);
}
@@ -92,7 +113,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
final date = await getDate(
context: context,
initialDate: now.subtract(Duration(days: 1)),
firstDate: DateTime(2014, DateTime.april),
firstDate: DateTime(2014, DateTime.may),
lastDate: now);
if (date != null) {
+1 -1
View File
@@ -68,7 +68,7 @@ class CheckboxWidgetState extends State<CheckboxWidget> {
style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
decoration: TextDecoration.none
),
+4 -3
View File
@@ -70,7 +70,7 @@ class PickerState<Item> extends State<Picker> {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white
@@ -90,6 +90,7 @@ class PickerState<Item> extends State<Picker> {
alignment: Alignment.center,
children: <Widget>[
ListView.separated(
padding: EdgeInsets.all(0),
controller: controller,
separatorBuilder: (context, index) => Divider(
color: Theme.of(context).accentTextTheme.title.backgroundColor,
@@ -134,7 +135,7 @@ class PickerState<Item> extends State<Picker> {
item.toString(),
style: TextStyle(
fontSize: 18,
fontFamily: 'Poppins',
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: textColor,
decoration: TextDecoration.none,
@@ -159,7 +160,7 @@ class PickerState<Item> extends State<Picker> {
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
fontFamily: 'Poppins',
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: Theme.of(context).primaryTextTheme
.title.color
+25 -14
View File
@@ -1,5 +1,5 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/src/widgets/annotated_editable_text.dart';
import 'package:cake_wallet/src/widgets/validable_annotated_editable_text.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -77,17 +77,28 @@ class SeedWidgetState extends State<SeedWidget> {
fontSize: 16.0, color: Theme.of(context).hintColor))),
Padding(
padding: EdgeInsets.only(right: 40, top: 10),
child: AnnotatedEditableText(
cursorColor: Colors.green,
backgroundCursorColor: Colors.blue,
style: TextStyle(
fontSize: 20,
color: Colors.red,
fontWeight: FontWeight.normal,
backgroundColor: Colors.transparent),
focusNode: focusNode,
controller: controller,
words: words)),
child: ValidatableAnnotatedEditableText(
cursorColor: Colors.blue,
backgroundCursorColor: Colors.blue,
validStyle: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
backgroundColor: Colors.transparent,
fontWeight: FontWeight.normal,
fontSize: 16),
invalidStyle: TextStyle(
fontSize: 16,
color: Colors.red,
fontWeight: FontWeight.normal,
backgroundColor: Colors.transparent),
focusNode: focusNode,
controller: controller,
words: words,
textStyle: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
backgroundColor: Colors.transparent,
fontWeight: FontWeight.normal,
fontSize: 16),
)),
Positioned(
top: 0,
right: 0,
@@ -95,7 +106,7 @@ class SeedWidgetState extends State<SeedWidget> {
width: 34,
height: 34,
child: InkWell(
onTap: () async => _pasteAddress(),
onTap: () async => _pasteText(),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
@@ -116,7 +127,7 @@ class SeedWidgetState extends State<SeedWidget> {
]));
}
Future<void> _pasteAddress() async {
Future<void> _pasteText() async {
final value = await Clipboard.getData('text/plain');
if (value?.text?.isNotEmpty ?? false) {
@@ -0,0 +1,170 @@
import 'package:cake_wallet/core/seed_validator.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:flutter/material.dart';
class Annotation extends Comparable<Annotation> {
Annotation({@required this.range, this.style});
final TextRange range;
final TextStyle style;
@override
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
}
class TextAnnotation extends Comparable<TextAnnotation> {
TextAnnotation({@required this.text, this.style});
final TextStyle style;
final String text;
@override
int compareTo(TextAnnotation other) => text.compareTo(other.text);
}
class ValidatableAnnotatedEditableText extends EditableText {
ValidatableAnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
List<String> wordList,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
Color backgroundCursorColor,
TextSelectionControls selectionControls,
this.validStyle,
this.invalidStyle,
TextStyle textStyle = const TextStyle(
color: Colors.black,
backgroundColor: Colors.transparent,
fontWeight: FontWeight.normal,
fontSize: 16),
@required this.words,
}) : super(
maxLines: null,
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: validStyle,
keyboardType: TextInputType.visiblePassword,
autocorrect: false,
autofocus: false,
selectionColor: selectionColor,
selectionControls: selectionControls,
backgroundCursorColor: backgroundCursorColor,
onChanged: onChanged,
onSubmitted: onSubmitted,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: true,
paste: true,
selectAll: true,
),
enableSuggestions: false,
enableInteractiveSelection: true,
showSelectionHandles: true,
showCursor: true);
final List<String> words;
final TextStyle validStyle;
final TextStyle invalidStyle;
@override
ValidatableAnnotatedEditableTextState createState() =>
ValidatableAnnotatedEditableTextState();
}
class ValidatableAnnotatedEditableTextState extends EditableTextState {
@override
ValidatableAnnotatedEditableText get widget =>
super.widget as ValidatableAnnotatedEditableText;
List<Annotation> getRanges() {
final result = List<Annotation>();
final text = textEditingValue.text;
final source = text
.split(' ')
.map((word) {
final ranges = range(word, text);
final isValid = validate(word);
return ranges.map((range) => Annotation(
style: isValid ? widget.validStyle : widget.invalidStyle,
range: range));
})
.expand((e) => e)
.toList();
source.sort();
Annotation prev;
for (var item in source) {
Annotation annotation;
if (prev == null) {
annotation = Annotation(
range: TextRange(start: 0, end: item.range.start),
style: TextStyle(
color: Colors.black, backgroundColor: Colors.transparent));
} else if (prev.range.end < item.range.start) {
annotation = Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
style: TextStyle(
color: Colors.red, backgroundColor: Colors.transparent));
}
if (annotation != null) {
result.add(annotation);
result.add(item);
prev = item;
}
}
if (result.length > 0 && result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
style: TextStyle(backgroundColor: Colors.transparent)));
}
return result;
}
bool validate(String source) => widget.words.indexOf(source) >= 0;
List<TextRange> range(String pattern, String source) {
final result = List<TextRange>();
if (pattern.isEmpty || source.isEmpty) {
return result;
}
for (int index = source.indexOf(pattern);
index >= 0;
index = source.indexOf(pattern, index + 1)) {
final start = index;
final end = start + pattern.length;
result.add(TextRange(start: start, end: end));
}
return result;
}
@override
TextSpan buildTextSpan() {
final text = textEditingValue.text;
final ranges = getRanges().toSet();
if (ranges.isNotEmpty) {
return TextSpan(
style: widget.style,
children: ranges
.map((item) => TextSpan(
style: item.style, text: item.range.textInside(text)))
.toList());
}
return TextSpan(style: widget.style, text: text);
}
}