Merge branch 'dev' into redesign

# Conflicts:
#	lib/generated/i18n.dart
#	lib/src/screens/dashboard/wallet_menu.dart
#	lib/src/screens/exchange/widgets/base_exchange_widget.dart
#	lib/src/screens/send/widgets/base_send_widget.dart
This commit is contained in:
OleksandrSobol
2020-09-14 21:33:44 +03:00
80 changed files with 3511 additions and 1520 deletions
+13 -7
View File
@@ -3,22 +3,28 @@ import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
class BiometricAuth {
final _localAuth = LocalAuthentication();
Future<bool> isAuthenticated() async {
final LocalAuthentication _localAuth = LocalAuthentication();
try {
return await _localAuth.authenticateWithBiometrics(
localizedReason: S.current.biometric_auth_reason,
useErrorDialogs: true,
stickyAuth: false
);
} on PlatformException
catch(e) {
stickyAuth: false);
} on PlatformException catch (e) {
print(e);
}
return false;
}
}
Future<bool> canCheckBiometrics() async {
try {
return await _localAuth.canCheckBiometrics;
} on PlatformException catch (e) {
print(e);
}
return false;
}
}
+5 -1
View File
@@ -1,11 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/utils/mobx.dart';
part 'contact.g.dart';
@HiveType(typeId: 0)
class Contact extends HiveObject {
class Contact extends HiveObject with Keyable {
Contact({@required this.name, @required this.address, CryptoCurrency type})
: raw = type?.raw;
@@ -22,6 +23,9 @@ class Contact extends HiveObject {
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
@override
dynamic get keyIndex => key;
@override
bool operator ==(Object o) => o is Contact && o.key == key;
+38
View File
@@ -0,0 +1,38 @@
// import 'package:hive/hive.dart';
// import 'package:mobx/mobx.dart';
// import 'package:cake_wallet/src/domain/common/contact.dart';
// import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
// part 'contact_model.g.dart';
// class ContactModel = ContactModelBase with _$ContactModel;
// abstract class ContactModelBase with Store {
// ContactModelBase(this._contacts, {Contact contact}) : _contact = contact {
// name = _contact?.name;
// address = _contact?.address;
// currency = _contact?.type;
// _contacts.watch(key: contact.key).listen((event) {
// });
// }
// @observable
// String name;
// @observable
// String address;
// @observable
// CryptoCurrency currency;
// // @computed
// // bool get isReady =>
// // (name?.isNotEmpty ?? false) &&
// // (currency?.toString()?.isNotEmpty ?? false) &&
// // (address?.isNotEmpty ?? false);
// final Box<ContactBase> _contacts;
// final Contact _contact;
// }
@@ -29,15 +29,19 @@ Future defaultSettingsMigration(
switch (version) {
case 1:
await sharedPreferences.setString(
SettingsStoreBase.currentFiatCurrencyKey, FiatCurrency.usd.toString());
SettingsStoreBase.currentFiatCurrencyKey,
FiatCurrency.usd.toString());
await sharedPreferences.setInt(
SettingsStoreBase.currentTransactionPriorityKey, TransactionPriority.standart.raw);
SettingsStoreBase.currentTransactionPriorityKey,
TransactionPriority.standart.raw);
await sharedPreferences.setInt(
SettingsStoreBase.currentBalanceDisplayModeKey,
BalanceDisplayMode.availableBalance.raw);
await sharedPreferences.setBool('save_recipient_address', true);
await resetToDefault(nodes);
await changeCurrentNodeToDefault(
await changeMoneroCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeBitcoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
@@ -50,6 +54,11 @@ Future defaultSettingsMigration(
case 3:
await updateNodeTypes(nodes: nodes);
await addBitcoinElectrumServerList(nodes: nodes);
break;
case 4:
await changeBitcoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
default:
break;
@@ -69,10 +78,11 @@ Future defaultSettingsMigration(
Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
final replaceNodes = <String, Node>{
'eu-node.cakewallet.io:18081':
Node(uri: 'xmr-node-eu.cakewallet.com:18081'),
'node.cakewallet.io:18081':
Node(uri: 'xmr-node-usa-east.cakewallet.com:18081'),
'node.xmr.ru:13666': Node(uri: 'node.monero.net:18081')
Node(uri: 'xmr-node-eu.cakewallet.com:18081', type: WalletType.monero),
'node.cakewallet.io:18081': Node(
uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
'node.xmr.ru:13666':
Node(uri: 'node.monero.net:18081', type: WalletType.monero)
};
nodes.values.forEach((Node node) async {
@@ -87,11 +97,27 @@ Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
});
}
Future<void> changeCurrentNodeToDefault(
Future<void> changeMoneroCurrentNodeToDefault(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
final node = getMoneroDefaultNode(nodes: nodes);
final nodeId = node?.key as int ?? 0; // 0 - England
await sharedPreferences.setInt('current_node_id', nodeId);
}
Node getBitcoinDefaultElectrumServer({@required Box<Node> nodes}) {
final uri = 'electrumx.cakewallet.com:50002';
return nodes.values
.firstWhere((Node node) => node.uri == uri, orElse: () => null) ??
nodes.values.firstWhere((node) => node.type == WalletType.bitcoin,
orElse: () => null);
}
Node getMoneroDefaultNode({@required Box<Node> nodes}) {
final timeZone = DateTime.now().timeZoneOffset.inHours;
String nodeUri = '';
var nodeUri = '';
if (timeZone >= 1) {
// Eurasia
@@ -101,11 +127,18 @@ Future<void> changeCurrentNodeToDefault(
nodeUri = 'xmr-node-usa-east.cakewallet.com:18081';
}
final node = nodes.values.firstWhere((Node node) => node.uri == nodeUri) ??
return nodes.values
.firstWhere((Node node) => node.uri == nodeUri, orElse: () => null) ??
nodes.values.first;
final nodeId = node != null ? node.key as int : 0; // 0 - England
}
await sharedPreferences.setInt('current_node_id', nodeId);
Future<void> changeBitcoinCurrentElectrumServerToDefault(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0;
await sharedPreferences.setInt('current_node_id_btc', serverId);
}
Future<void> replaceDefaultNode(
@@ -126,7 +159,7 @@ Future<void> replaceDefaultNode(
return;
}
await changeCurrentNodeToDefault(
await changeMoneroCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
}
+8 -3
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/utils/mobx.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
@@ -8,13 +9,17 @@ import 'package:cake_wallet/src/domain/common/digest_request.dart';
part 'node.g.dart';
@HiveType(typeId: 1)
class Node extends HiveObject {
Node({@required this.uri, @required WalletType type, this.login, this.password}) {
class Node extends HiveObject with Keyable {
Node(
{@required this.uri,
@required WalletType type,
this.login,
this.password}) {
this.type = type;
}
Node.fromMap(Map map)
: uri = (map['uri'] ?? '') as String,
: uri = map['uri'] as String ?? '',
login = map['login'] as String,
password = map['password'] as String,
typeRaw = map['typeRaw'] as int;
+5 -8
View File
@@ -10,7 +10,10 @@ Future<List<Node>> loadDefaultNodes() async {
return nodes.map((dynamic raw) {
if (raw is Map) {
return Node.fromMap(raw);
final node = Node.fromMap(raw);
node?.type = WalletType.monero;
return node;
}
return null;
@@ -38,13 +41,7 @@ Future resetToDefault(Box<Node> nodeSource) async {
final moneroNodes = await loadDefaultNodes();
final bitcoinElectrumServerList = await loadElectrumServerList();
final nodes = moneroNodes + bitcoinElectrumServerList;
final entities = <int, Node>{};
await nodeSource.clear();
for (var i = 0; i < nodes.length; i++) {
entities[i] = nodes[i];
}
await nodeSource.putAll(entities);
await nodeSource.addAll(nodes);
}
+8
View File
@@ -73,3 +73,11 @@ class ConnectedSyncStatus extends SyncStatus {
@override
String title() => S.current.sync_status_connected;
}
class LostConnectionSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_failed_connect;
}
@@ -1,11 +1,13 @@
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
abstract class TransactionInfo extends Object {
String id;
int amount;
TransactionDirection direction;
bool isPending;
DateTime date;
int height;
int confirmations;
String amountFormatted();
String fiatAmount();
void changeFiatAmount(String amount);
+25 -23
View File
@@ -5,19 +5,20 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/auth_state.dart';
import 'package:cake_wallet/view_model/auth_view_model.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
class AuthPage extends StatefulWidget {
AuthPage(
{this.onAuthenticationFinished,
{@required this.allowBiometricalAuthentication,
this.onAuthenticationFinished,
this.authViewModel,
this.closable = true});
final AuthViewModel authViewModel;
final OnAuthenticationFinished onAuthenticationFinished;
final bool allowBiometricalAuthentication;
final bool closable;
@override
@@ -95,6 +96,27 @@ class AuthPageState extends State<AuthPage> {
});
}
});
if (widget.allowBiometricalAuthentication) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
print('post');
await Future<void>.delayed(Duration(milliseconds: 100));
print('after timeout');
final biometricAuth = BiometricAuth();
final isAuth = await biometricAuth.isAuthenticated();
if (isAuth) {
widget.authViewModel.biometricAuth();
_key.currentState.showSnackBar(
SnackBar(
content: Text(S.of(context).authenticated),
backgroundColor: Colors.green,
),
);
}
});
}
super.initState();
}
@@ -111,27 +133,7 @@ class AuthPageState extends State<AuthPage> {
@override
Widget build(BuildContext context) {
// final authStore = Provider.of<AuthStore>(context);
// final settingsStore = Provider.of<SettingsStore>(context);
// if (settingsStore.allowBiometricalAuthentication) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// final biometricAuth = BiometricAuth();
// biometricAuth.isAuthenticated().then(
// (isAuth) {
// if (isAuth) {
// authStore.biometricAuth();
// _key.currentState.showSnackBar(
// SnackBar(
// content: Text(S.of(context).authenticated),
// backgroundColor: Colors.green,
// ),
// );
// }
// }
// );
// });
// }
print('start');
return Scaffold(
key: _key,
+55 -84
View File
@@ -27,25 +27,20 @@ class DashboardPage extends BasePage {
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) => Container(
(BuildContext context, Widget scaffold) => Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
Theme.of(context).accentColor,
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).primaryColor,
],
begin: Alignment.topRight,
end: Alignment.bottomLeft)),
Theme.of(context).accentColor,
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).primaryColor,
], begin: Alignment.topRight, end: Alignment.bottomLeft)),
child: scaffold);
@override
bool get resizeToAvoidBottomPadding => false;
@override
Widget get endDrawer => MenuWidget(
name: walletViewModel.name,
subname: walletViewModel.subname,
type: walletViewModel.type);
Widget get endDrawer => MenuWidget(walletViewModel);
@override
Widget middle(BuildContext context) {
@@ -54,20 +49,18 @@ class DashboardPage extends BasePage {
@override
Widget trailing(BuildContext context) {
final menuButton = Image.asset('assets/images/menu.png',
color: Colors.white);
final menuButton =
Image.asset('assets/images/menu.png', color: Colors.white);
return Container(
alignment: Alignment.centerRight,
width: 40,
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () => onOpenEndDrawer(),
child: menuButton
)
);
alignment: Alignment.centerRight,
width: 40,
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () => onOpenEndDrawer(),
child: menuButton));
}
final DashboardViewModel walletViewModel;
@@ -85,77 +78,55 @@ class DashboardPage extends BasePage {
@override
Widget body(BuildContext context) {
_setEffects();
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: PageView.builder(
controller: controller,
itemCount: pages.length,
itemBuilder: (context, index) {
return pages[index];
}
)
),
Padding(
padding: EdgeInsets.only(
bottom: 24
),
controller: controller,
itemCount: pages.length,
itemBuilder: (context, index) => pages[index])),
Padding(
padding: EdgeInsets.only(bottom: 24),
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
count: pages.length,
effect: ColorTransitionEffect(
spacing: 6.0,
radius: 6.0,
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).indicatorColor,
activeDotColor: Colors.white
),
)
),
Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 45,
right: 45,
bottom: 24
),
child: Row(
children: <Widget>[
Flexible(
child: ActionButton(
image: sendImage,
title: S.of(context).send,
route: Routes.send,
alignment: Alignment.centerLeft,
),
spacing: 6.0,
radius: 6.0,
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).indicatorColor,
activeDotColor: Colors.white),
)),
Container(
width: double.infinity,
padding: EdgeInsets.only(left: 44, right: 0, bottom: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: ActionButton(
image: sendImage,
title: S.of(context).send,
route: Routes.send,
alignment: Alignment.centerLeft,
),
Flexible(
child: ActionButton(
),
Flexible(
child: ActionButton(
image: exchangeImage,
title: S.of(context).exchange,
route: Routes.exchange
),
),
Flexible(
child: ActionButton(
image: receiveImage,
title: S.of(context).receive,
route: Routes.receive,
alignment: Alignment.centerRight,
),
)
],
),
)
],
)
);
route: Routes.exchange),
)
],
),
)
],
));
}
void _setEffects() {
+9 -9
View File
@@ -6,8 +6,10 @@ import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
// FIXME: terrible design
class WalletMenu {
WalletMenu(this.context);
WalletMenu(this.context, this.reconnect);
final List<String> items = [
S.current.reconnect,
@@ -30,6 +32,7 @@ class WalletMenu {
];
final BuildContext context;
final Future<void> Function() reconnect;
void action(int index) {
switch (index) {
@@ -70,22 +73,19 @@ class WalletMenu {
}
Future<void> _presentReconnectAlert(BuildContext context) async {
final walletStore = Provider.of<WalletStore>(context);
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).reconnection,
alertContent: S.of(context).reconnect_alert_text,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
walletStore.reconnect();
leftButtonText: S.of(context).ok,
rightButtonText: S.of(context).cancel,
actionLeftButton: () async {
await reconnect?.call();
Navigator.of(context).pop();
},
actionLeftButton: () => Navigator.of(context).pop()
);
actionRightButton: () => Navigator.of(context).pop());
});
}
}
@@ -1,12 +1,11 @@
import 'package:flutter/material.dart';
class ActionButton extends StatelessWidget{
ActionButton({
@required this.image,
@required this.title,
@required this.route,
this.alignment = Alignment.center
});
class ActionButton extends StatelessWidget {
ActionButton(
{@required this.image,
@required this.title,
@required this.route,
this.alignment = Alignment.center});
final Image image;
final String title;
@@ -35,20 +34,16 @@ class ActionButton extends StatelessWidget{
width: 60,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).buttonColor,
shape: BoxShape.circle),
color: Theme.of(context).buttonColor, shape: BoxShape.circle),
child: image,
),
),
Text(
title,
style: TextStyle(
fontSize: 14,
color: Colors.white
),
style: TextStyle(fontSize: 14, color: Colors.white),
)
],
),
);
}
}
}
+136 -125
View File
@@ -1,16 +1,17 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
import 'package:flutter/rendering.dart';
class MenuWidget extends StatefulWidget {
MenuWidget({this.type, this.name, this.subname});
// FIXME: terrible design.
final WalletType type;
final String name;
final String subname;
class MenuWidget extends StatefulWidget {
MenuWidget(this.dashboardViewModel);
final DashboardViewModel dashboardViewModel;
@override
MenuWidgetState createState() => MenuWidgetState();
@@ -64,17 +65,14 @@ class MenuWidgetState extends State<MenuWidget> {
@override
Widget build(BuildContext context) {
final walletMenu = WalletMenu(context);
final walletMenu =
WalletMenu(context, () async => widget.dashboardViewModel.reconnect());
final itemCount = walletMenu.items.length;
moneroIcon = Image.asset('assets/images/monero_menu.png',
color: Theme.of(context)
.accentTextTheme
.overline.decorationColor);
color: Theme.of(context).accentTextTheme.overline.decorationColor);
bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
color: Theme.of(context)
.accentTextTheme
.overline.decorationColor);
color: Theme.of(context).accentTextTheme.overline.decorationColor);
return Row(
mainAxisSize: MainAxisSize.max,
@@ -92,124 +90,137 @@ class MenuWidgetState extends State<MenuWidget> {
SizedBox(width: 12),
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
bottomLeft: Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme.body2.decorationColor,
child: ListView.separated(
padding: EdgeInsets.only(top: 0),
itemBuilder: (_, index) {
if (index == 0) {
return Container(
height: headerHeight,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
Theme.of(context).accentTextTheme.display1.color,
Theme.of(context).accentTextTheme.display1.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
padding: EdgeInsets.only(
left: 24,
top: fromTopEdge,
right: 24,
bottom: fromBottomEdge
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_iconFor(type: widget.type),
SizedBox(width: 12),
Expanded(
child: Container(
height: 42,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: widget.subname != null
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.center,
children: <Widget>[
Text(
widget.name,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
),
if (widget.subname != null)
Text(
widget.subname,
style: TextStyle(
color: Theme.of(context)
.accentTextTheme
.overline.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 12),
)
],
),
))
],
),
);
}
index--;
final item = walletMenu.items[index];
final image = walletMenu.images[index] ?? Offstage();
final isLastTile = index == itemCount - 1;
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
walletMenu.action(index);
},
child: Container(
color: Theme.of(context).textTheme.body2.decorationColor,
height: isLastTile
? headerHeight
: tileHeight,
padding: isLastTile
? EdgeInsets.only(
left: 24,
right: 24,
top: fromBottomEdge,
//bottom: fromTopEdge
)
: EdgeInsets.only(left: 24, right: 24),
alignment: isLastTile ? Alignment.topLeft : null,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
bottomLeft: Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme.body2.decorationColor,
child: ListView.separated(
padding: EdgeInsets.only(top: 0),
itemBuilder: (_, index) {
if (index == 0) {
return Container(
height: headerHeight,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context)
.accentTextTheme
.display1
.color,
Theme.of(context)
.accentTextTheme
.display1
.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
padding: EdgeInsets.only(
left: 24,
top: fromTopEdge,
right: 24,
bottom: fromBottomEdge),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
image,
SizedBox(width: 16),
_iconFor(type: widget.dashboardViewModel.type),
SizedBox(width: 12),
Expanded(
child: Text(
item,
style: TextStyle(
color: Theme.of(context).textTheme
.display2.color,
fontSize: 16,
fontWeight: FontWeight.bold),
))
child: Container(
height: 42,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
widget.dashboardViewModel.subname !=
null
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.center,
children: <Widget>[
Text(
widget.dashboardViewModel.name,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
),
if (widget.dashboardViewModel.subname !=
null)
Text(
widget.dashboardViewModel.subname,
style: TextStyle(
color: Theme.of(context)
.accentTextTheme
.overline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 12),
)
],
),
))
],
),
)
);
},
separatorBuilder: (_, index) => Container(
height: 1,
color: Theme.of(context).primaryTextTheme.caption.decorationColor,
),
itemCount: itemCount + 1),
)
)
)
);
}
index--;
final item = walletMenu.items[index];
final image = walletMenu.images[index] ?? Offstage();
final isLastTile = index == itemCount - 1;
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
walletMenu.action(index);
},
child: Container(
color: Theme.of(context)
.textTheme
.body2
.decorationColor,
height: isLastTile ? headerHeight : tileHeight,
padding: isLastTile
? EdgeInsets.only(
left: 24,
right: 24,
top: fromBottomEdge,
//bottom: fromTopEdge
)
: EdgeInsets.only(left: 24, right: 24),
alignment: isLastTile ? Alignment.topLeft : null,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
image,
SizedBox(width: 16),
Expanded(
child: Text(
item,
style: TextStyle(
color: Theme.of(context)
.textTheme
.display2
.color,
fontSize: 16,
fontWeight: FontWeight.bold),
))
],
),
));
},
separatorBuilder: (_, index) => Container(
height: 1,
color: Theme.of(context)
.primaryTextTheme
.caption
.decorationColor,
),
itemCount: itemCount + 1),
)))
],
);
}
@@ -24,7 +24,7 @@ import 'package:cake_wallet/core/amount_validator.dart';
class BaseExchangeWidget extends StatefulWidget {
BaseExchangeWidget({
@ required this.exchangeViewModel,
@required this.exchangeViewModel,
this.leading,
this.middle,
this.trailing,
@@ -50,11 +50,11 @@ class BaseExchangeWidget extends StatefulWidget {
class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
BaseExchangeWidgetState({
@ required this.exchangeViewModel,
@ required this.leading,
@ required this.middle,
@ required this.trailing,
@ required this.isTemplate,
@required this.exchangeViewModel,
@required this.leading,
@required this.middle,
@required this.trailing,
@required this.isTemplate,
});
final ExchangeViewModel exchangeViewModel;
@@ -134,131 +134,150 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
builder: (_) => ExchangeCard(
key: depositKey,
title: S.of(context).you_will_send,
initialCurrency: exchangeViewModel.depositCurrency,
initialCurrency:
exchangeViewModel.depositCurrency,
initialWalletName: depositWalletName,
initialAddress:
exchangeViewModel.depositCurrency == exchangeViewModel.wallet.currency
initialAddress: exchangeViewModel
.depositCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.depositAddress,
initialIsAmountEditable: true,
initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled,
initialIsAddressEditable: exchangeViewModel
.isDepositAddressEnabled,
isAmountEstimated: false,
currencies: CryptoCurrency.all,
onCurrencySelected: (currency) =>
exchangeViewModel.changeDepositCurrency(currency: currency),
exchangeViewModel.changeDepositCurrency(
currency: currency),
imageArrow: arrowBottomPurple,
currencyButtonColor: Colors.transparent,
addressButtonsColor: Theme.of(context).focusColor,
borderColor: Theme.of(context).primaryTextTheme.body2.color,
addressButtonsColor:
Theme.of(context).focusColor,
borderColor: Theme.of(context)
.primaryTextTheme
.body2
.color,
currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator(
type: exchangeViewModel.depositCurrency),
type:
exchangeViewModel.depositCurrency),
),
),
)
],
)
),
)),
Padding(
padding: EdgeInsets.only(top: 29, left: 24, right: 24),
child: Observer(
builder: (_) => ExchangeCard(
key: receiveKey,
title: S.of(context).you_will_get,
initialCurrency: exchangeViewModel.receiveCurrency,
initialWalletName: receiveWalletName,
initialAddress:
exchangeViewModel.receiveCurrency == exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.receiveAddress,
initialIsAmountEditable: false,
initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true,
currencies: CryptoCurrency.all,
onCurrencySelected: (currency) => exchangeViewModel
.changeReceiveCurrency(currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent,
addressButtonsColor: Theme.of(context).focusColor,
borderColor: Theme.of(context).primaryTextTheme.body2.decorationColor,
currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator(
type: exchangeViewModel.receiveCurrency),
)),
key: receiveKey,
title: S.of(context).you_will_get,
initialCurrency:
exchangeViewModel.receiveCurrency,
initialWalletName: receiveWalletName,
initialAddress:
exchangeViewModel.receiveCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.receiveAddress,
initialIsAmountEditable: false,
initialIsAddressEditable:
exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true,
currencies: CryptoCurrency.all,
onCurrencySelected: (currency) =>
exchangeViewModel.changeReceiveCurrency(
currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).focusColor,
borderColor: Theme.of(context)
.primaryTextTheme
.body2
.decorationColor,
currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator(
type: exchangeViewModel.receiveCurrency),
)),
)
],
)
),
)),
isTemplate
? Offstage()
: Padding(
padding: EdgeInsets.only(
top: 30,
left: 24,
bottom: 24
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).send_templates,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.display4.color
padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).send_templates,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.display4
.color),
)
],
),
)
],
),
),
),
isTemplate
? Offstage()
: Container(
height: 40,
width: double.infinity,
padding: EdgeInsets.only(left: 24),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () => Navigator.of(context)
.pushNamed(Routes.exchangeTemplate),
child: Container(
padding: EdgeInsets.only(left: 1, right: 10),
child: DottedBorder(
borderType: BorderType.RRect,
dashPattern: [6, 4],
color: Theme.of(context).primaryTextTheme.display2.decorationColor,
strokeWidth: 2,
radius: Radius.circular(20),
child: Container(
height: 34,
width: 75,
padding: EdgeInsets.only(left: 10, right: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.transparent,
),
child: Text(
S.of(context).send_new,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.display3.color
),
),
)
height: 40,
width: double.infinity,
padding: EdgeInsets.only(left: 24),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () => Navigator.of(context)
.pushNamed(Routes.exchangeTemplate),
child: Container(
padding: EdgeInsets.only(left: 1, right: 10),
child: DottedBorder(
borderType: BorderType.RRect,
dashPattern: [6, 4],
color: Theme.of(context)
.primaryTextTheme
.display2
.decorationColor,
strokeWidth: 2,
radius: Radius.circular(20),
child: Container(
height: 34,
width: 75,
padding: EdgeInsets.only(
left: 10, right: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20)),
color: Colors.transparent,
),
child: Text(
S.of(context).send_new,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.display3
.color),
),
)),
),
),
),
),
Observer(
builder: (_) {
Observer(builder: (_) {
final templates = exchangeViewModel.templates;
final itemCount = exchangeViewModel.templates.length;
final itemCount =
exchangeViewModel.templates.length;
return ListView.builder(
scrollDirection: Axis.horizontal,
@@ -274,7 +293,8 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
from: template.depositCurrency,
to: template.receiveCurrency,
onTap: () {
applyTemplate(exchangeViewModel, template);
applyTemplate(
exchangeViewModel, template);
},
onRemove: () {
showDialog<void>(
@@ -296,57 +316,56 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
);
},
);
}
);
}
),
],
)
)
)
});
}),
],
)))
],
),
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 15),
child: Observer(builder: (_) {
final description =
exchangeViewModel.provider is XMRTOExchangeProvider
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
exchangeViewModel.provider is XMRTOExchangeProvider
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
return Center(
child: Text(
description,
style: TextStyle(
color: Theme.of(context).primaryTextTheme.display4.decorationColor,
color: Theme.of(context)
.primaryTextTheme
.display4
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 12
),
fontSize: 12),
),
);
}),
),
isTemplate
? PrimaryButton(
onPressed: () {
if (_formKey.currentState.validate()) {
exchangeViewModel.exchangeTemplateStore.addTemplate(
amount: exchangeViewModel.depositAmount,
depositCurrency: exchangeViewModel.depositCurrency.toString(),
receiveCurrency: exchangeViewModel.receiveCurrency.toString(),
provider: exchangeViewModel.provider.toString(),
depositAddress: exchangeViewModel.depositAddress,
receiveAddress: exchangeViewModel.receiveAddress
);
exchangeViewModel.exchangeTemplateStore.update();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white
)
onPressed: () {
if (_formKey.currentState.validate()) {
exchangeViewModel.exchangeTemplateStore.addTemplate(
amount: exchangeViewModel.depositAmount,
depositCurrency:
exchangeViewModel.depositCurrency.toString(),
receiveCurrency:
exchangeViewModel.receiveCurrency.toString(),
provider: exchangeViewModel.provider.toString(),
depositAddress: exchangeViewModel.depositAddress,
receiveAddress: exchangeViewModel.receiveAddress);
exchangeViewModel.exchangeTemplateStore.update();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white)
: Observer(
builder: (_) => LoadingPrimaryButton(
text: S.of(context).exchange,
@@ -413,27 +432,29 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
key.currentState.changeLimits(min: min, max: max);
}
_onCurrencyChange(exchangeViewModel.receiveCurrency, exchangeViewModel, receiveKey);
_onCurrencyChange(exchangeViewModel.depositCurrency, exchangeViewModel, depositKey);
_onCurrencyChange(
exchangeViewModel.receiveCurrency, exchangeViewModel, receiveKey);
_onCurrencyChange(
exchangeViewModel.depositCurrency, exchangeViewModel, depositKey);
reaction(
(_) => exchangeViewModel.wallet.name,
(String _) => _onWalletNameChange(
(_) => exchangeViewModel.wallet.name,
(String _) => _onWalletNameChange(
exchangeViewModel, exchangeViewModel.receiveCurrency, receiveKey));
reaction(
(_) => exchangeViewModel.wallet.name,
(String _) => _onWalletNameChange(
exchangeViewModel, exchangeViewModel.depositCurrency, depositKey));
(_) => exchangeViewModel.wallet.name,
(String _) => _onWalletNameChange(
exchangeViewModel, exchangeViewModel.depositCurrency, depositKey));
reaction(
(_) => exchangeViewModel.receiveCurrency,
(CryptoCurrency currency) =>
(_) => exchangeViewModel.receiveCurrency,
(CryptoCurrency currency) =>
_onCurrencyChange(currency, exchangeViewModel, receiveKey));
reaction(
(_) => exchangeViewModel.depositCurrency,
(CryptoCurrency currency) =>
(_) => exchangeViewModel.depositCurrency,
(CryptoCurrency currency) =>
_onCurrencyChange(currency, exchangeViewModel, depositKey));
reaction((_) => exchangeViewModel.depositAmount, (String amount) {
@@ -448,7 +469,8 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
}
});
reaction((_) => exchangeViewModel.isDepositAddressEnabled, (bool isEnabled) {
reaction((_) => exchangeViewModel.isDepositAddressEnabled,
(bool isEnabled) {
depositKey.currentState.isAddressEditable(isEditable: isEnabled);
});
@@ -464,7 +486,8 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
}
});
reaction((_) => exchangeViewModel.isReceiveAddressEnabled, (bool isEnabled) {
reaction((_) => exchangeViewModel.isReceiveAddressEnabled,
(bool isEnabled) {
receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
});
@@ -478,14 +501,12 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
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 TradeIsCreatedSuccessfully) {
Navigator.of(context)
.pushNamed(Routes.exchangeConfirm);
Navigator.of(context).pushNamed(Routes.exchangeConfirm);
}
});
@@ -513,20 +534,22 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
});
depositAddressController.addListener(
() => exchangeViewModel.depositAddress = depositAddressController.text);
() => exchangeViewModel.depositAddress = depositAddressController.text);
depositAmountController.addListener(() {
if (depositAmountController.text != exchangeViewModel.depositAmount) {
exchangeViewModel.changeDepositAmount(amount: depositAmountController.text);
exchangeViewModel.changeDepositAmount(
amount: depositAmountController.text);
}
});
receiveAddressController.addListener(
() => exchangeViewModel.receiveAddress = receiveAddressController.text);
() => exchangeViewModel.receiveAddress = receiveAddressController.text);
receiveAmountController.addListener(() {
if (receiveAmountController.text != exchangeViewModel.receiveAmount) {
exchangeViewModel.changeReceiveAmount(amount: receiveAmountController.text);
exchangeViewModel.changeReceiveAmount(
amount: receiveAmountController.text);
}
});
@@ -544,34 +567,31 @@ class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
}
void _onCurrencyChange(CryptoCurrency currency,
ExchangeViewModel exchangeViewModel,
GlobalKey<ExchangeCardState> key) {
ExchangeViewModel exchangeViewModel, GlobalKey<ExchangeCardState> key) {
final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency;
key.currentState.changeSelectedCurrency(currency);
key.currentState
.changeWalletName(isCurrentTypeWallet
? exchangeViewModel.wallet.name : null);
key.currentState.changeWalletName(
isCurrentTypeWallet ? exchangeViewModel.wallet.name : null);
key.currentState
.changeAddress(address: isCurrentTypeWallet
? exchangeViewModel.wallet.address : '');
key.currentState.changeAddress(
address: isCurrentTypeWallet ? exchangeViewModel.wallet.address : '');
key.currentState.changeAmount(amount: '');
}
void _onWalletNameChange(ExchangeViewModel exchangeViewModel,
CryptoCurrency currency,
GlobalKey<ExchangeCardState> key) {
CryptoCurrency currency, GlobalKey<ExchangeCardState> key) {
final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency;
if (isCurrentTypeWallet) {
key.currentState.changeWalletName(exchangeViewModel.wallet.name);
key.currentState.addressController.text = exchangeViewModel.wallet.address;
key.currentState.addressController.text =
exchangeViewModel.wallet.address;
} else if (key.currentState.addressController.text ==
exchangeViewModel.wallet.address) {
key.currentState.changeWalletName(null);
key.currentState.addressController.text = null;
}
}
}
}
+34 -8
View File
@@ -74,15 +74,41 @@ class NodeListPage extends BasePage {
}
final node = nodeListViewModel.nodes[index];
final isSelected = index == 1; // FIXME: hardcoded value.
final nodeListRow = NodeListRow(
title: node.uri,
isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) {});
title: node.value.uri,
isSelected: node.isSelected,
isAlive: node.value.requestNode(),
onTap: (_) async {
if (node.isSelected) {
return;
}
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text(
S.of(context).change_current_node(node.value.uri),
textAlign: TextAlign.center,
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text(S.of(context).cancel)),
FlatButton(
onPressed: () async {
Navigator.of(context).pop();
await nodeListViewModel
.setAsCurrent(node.value);
},
child: Text(S.of(context).change)),
],
);
});
});
final dismissibleRow = Dismissible(
key: Key('${node.key}'),
key: Key('${node.keyIndex}'),
confirmDismiss: (direction) async {
return await showDialog(
context: context,
@@ -99,7 +125,7 @@ class NodeListPage extends BasePage {
});
},
onDismissed: (direction) async =>
nodeListViewModel.delete(node),
nodeListViewModel.delete(node.value),
direction: DismissDirection.endToStart,
background: Container(
padding: EdgeInsets.only(right: 10.0),
@@ -120,7 +146,7 @@ class NodeListPage extends BasePage {
)),
child: nodeListRow);
return isSelected ? nodeListRow : dismissibleRow;
return node.isSelected ? nodeListRow : dismissibleRow;
},
itemCounter: (int sectionIndex) {
if (sectionIndex == 0) {
+9 -2
View File
@@ -126,7 +126,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
shape: BoxShape.circle,
color: isFilled
? Theme.of(context).primaryTextTheme.title.color
: Theme.of(context).accentTextTheme.body1.color,
: Theme.of(context)
.accentTextTheme
.body1
.color
.withOpacity(0.25),
));
}),
),
@@ -144,7 +148,10 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).accentTextTheme.body1.decorationColor),
color: Theme.of(context)
.accentTextTheme
.body1
.decorationColor),
))
],
Spacer(flex: 1),
+611 -13
View File
@@ -1,16 +1,40 @@
import 'package:cake_wallet/view_model/send_view_model.dart';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/address_text_field.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/view_model/send/send_view_model.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/top_panel.dart';
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/screens/send/widgets/confirm_sending_alert.dart';
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
import 'package:cake_wallet/src/widgets/trail_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/base_send_widget.dart';
// FIXME: Refactor this screen.
class SendPage extends BasePage {
SendPage({@required this.sendViewModel});
final SendViewModel sendViewModel;
// ???
@override
String get title => sendViewModel.pageTitle;
String get title => 'SEND';
@override
Color get titleColor => Colors.white;
@@ -18,15 +42,66 @@ class SendPage extends BasePage {
@override
Color get backgroundLightColor => Colors.transparent;
@override
Color get backgroundDarkColor => Colors.transparent;
@override
bool get resizeToAvoidBottomPadding => false;
@override
Widget body(BuildContext context) =>
BaseSendWidget(
Widget trailing(context) => TrailButton(
caption: S.of(context).clear, onPressed: () => sendViewModel.reset());
Color get backgroundDarkColor => Colors.transparent;
// @override
// State<StatefulWidget> createState() => SendFormState();
final _addressController = TextEditingController();
final _cryptoAmountController = TextEditingController();
final _fiatAmountController = TextEditingController();
final _focusNode = FocusNode();
bool _effectsInstalled = false;
final _formKey = GlobalKey<FormState>();
// @override
// void initState() {
// _focusNode.addListener(() {
// if (!_focusNode.hasFocus && _addressController.text.isNotEmpty) {
// getOpenaliasRecord(context);
// }
// });
// super.initState();
// }
Future<void> getOpenaliasRecord(BuildContext context) async {
// final sendStore = Provider.of<SendStore>(context);
// final isOpenalias =
// await sendStore.isOpenaliasRecord(_addressController.text);
//
// if (isOpenalias) {
// _addressController.text = sendStore.recordAddress;
//
// await showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithOneAction(
// alertTitle: S.of(context).openalias_alert_title,
// alertContent:
// S.of(context).openalias_alert_content(sendStore.recordName),
// buttonText: S.of(context).ok,
// buttonAction: () => Navigator.of(context).pop());
// });
// }
}
// @override
// Widget body(BuildContext context) {
// return super.build(context);
// }
@override
Widget body(BuildContext context) => BaseSendWidget(
sendViewModel: sendViewModel,
leading: leading(context),
middle: middle(context),
@@ -35,11 +110,534 @@ class SendPage extends BasePage {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
body: Container(
color: Theme.of(context).backgroundColor,
child: body(context)
)
);
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
body: Container(
color: Theme.of(context).backgroundColor, child: body(context)));
}
// @override
// Widget build(BuildContext context) {
// _setEffects(context);
// return Container(
// color: Theme.of(context).backgroundColor,
// child: ScrollableWithBottomSection(
// contentPadding: EdgeInsets.only(bottom: 24),
// content: Column(
// children: <Widget>[
// TopPanel(
// color: Theme.of(context).accentTextTheme.title.backgroundColor,
// widget: Form(
// key: _formKey,
// child: Column(children: <Widget>[
// AddressTextField(
// controller: _addressController,
// placeholder: 'Address',
// //S.of(context).send_monero_address, FIXME: placeholder for btc and xmr address text field.
// focusNode: _focusNode,
// onURIScanned: (uri) {
// var address = '';
// var amount = '';
// if (uri != null) {
// address = uri.path;
// amount = uri.queryParameters['tx_amount'];
// } else {
// address = uri.toString();
// }
// _addressController.text = address;
// _cryptoAmountController.text = amount;
// },
// options: [
// AddressTextFieldOption.qrCode,
// AddressTextFieldOption.addressBook
// ],
// buttonColor: Theme.of(context).accentTextTheme.title.color,
// validator: widget.sendViewModel.addressValidator,
// ),
// Padding(
// padding: const EdgeInsets.only(top: 20),
// child: TextFormField(
// onChanged: (value) =>
// widget.sendViewModel.setCryptoAmount(value),
// style: TextStyle(
// fontSize: 16.0,
// color:
// Theme.of(context).primaryTextTheme.title.color),
// controller: _cryptoAmountController,
// keyboardType: TextInputType.numberWithOptions(
// signed: false, decimal: true),
// // inputFormatters: [
// // BlacklistingTextInputFormatter(
// // RegExp('[\\-|\\ |\\,]'))
// // ],
// decoration: InputDecoration(
// prefixIcon: Padding(
// padding: EdgeInsets.only(top: 12),
// child: Text(
// '${widget.sendViewModel.currency.toString()}:',
// style: TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
// )),
// ),
// suffixIcon: Padding(
// padding: EdgeInsets.only(bottom: 5),
// child: Container(
// height: 32,
// width: 32,
// margin: EdgeInsets.only(
// left: 12, bottom: 7, top: 4),
// decoration: BoxDecoration(
// color: Theme.of(context)
// .accentTextTheme
// .title
// .color,
// borderRadius:
// BorderRadius.all(Radius.circular(6))),
// child: InkWell(
// onTap: () => widget.sendViewModel.setAll(),
// child: Center(
// child: Text(S.of(context).all,
// textAlign: TextAlign.center,
// style: TextStyle(
// fontSize: 9,
// fontWeight: FontWeight.bold,
// color: Theme.of(context)
// .primaryTextTheme
// .caption
// .color)),
// ),
// ),
// )),
// hintStyle: TextStyle(
// fontSize: 16.0,
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color),
// hintText: '0.0000',
// focusedBorder: UnderlineInputBorder(
// borderSide: BorderSide(
// color: Theme.of(context).dividerColor,
// width: 1.0)),
// enabledBorder: UnderlineInputBorder(
// borderSide: BorderSide(
// color: Theme.of(context).dividerColor,
// width: 1.0))),
// validator: (String value) {
// if (widget.sendViewModel.all) {
// return null;
// }
// return widget.sendViewModel.amountValidator
// .call(value);
// }),
// ),
// Padding(
// padding: const EdgeInsets.only(top: 20),
// child: TextFormField(
// onChanged: (value) =>
// widget.sendViewModel.setFiatAmount(value),
// style: TextStyle(
// fontSize: 16.0,
// color:
// Theme.of(context).primaryTextTheme.title.color),
// controller: _fiatAmountController,
// keyboardType: TextInputType.numberWithOptions(
// signed: false, decimal: true),
// // inputFormatters: [
// // BlacklistingTextInputFormatter(
// // RegExp('[\\-|\\ |\\,]'))
// // ],
// decoration: InputDecoration(
// prefixIcon: Padding(
// padding: EdgeInsets.only(top: 12),
// child: Text(
// '${widget.sendViewModel.fiat.toString()}:',
// style: TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
// )),
// ),
// hintStyle: TextStyle(
// fontSize: 16.0,
// color: Theme.of(context)
// .primaryTextTheme
// .caption
// .color),
// hintText: '0.00',
// focusedBorder: UnderlineInputBorder(
// borderSide: BorderSide(
// color: Theme.of(context).dividerColor,
// width: 1.0)),
// enabledBorder: UnderlineInputBorder(
// borderSide: BorderSide(
// color: Theme.of(context).dividerColor,
// width: 1.0)))),
// ),
// Padding(
// padding: const EdgeInsets.only(top: 20),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: <Widget>[
// Text(S.of(context).send_estimated_fee,
// style: TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
// )),
// Text(
// '${widget.sendViewModel.estimatedFee} ${widget.sendViewModel.currency.toString()}',
// style: TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
// ))
// ],
// ),
// )
// ]),
// ),
// ),
// // Padding(
// // padding: EdgeInsets.only(top: 32, left: 24, bottom: 24),
// // child: Row(
// // mainAxisAlignment: MainAxisAlignment.start,
// // children: <Widget>[
// // Text(
// // S.of(context).send_templates,
// // style: TextStyle(
// // fontSize: 18,
// // fontWeight: FontWeight.w600,
// // color:
// // Theme.of(context).primaryTextTheme.caption.color),
// // )
// // ],
// // ),
// // ),
// // Container(
// // height: 40,
// // width: double.infinity,
// // padding: EdgeInsets.only(left: 24),
// // child: Observer(builder: (_) {
// // final itemCount = sendTemplateStore.templates.length + 1;
// //
// // return ListView.builder(
// // scrollDirection: Axis.horizontal,
// // itemCount: itemCount,
// // itemBuilder: (context, index) {
// // if (index == 0) {
// // return GestureDetector(
// // onTap: () => Navigator.of(context)
// // .pushNamed(Routes.sendTemplate),
// // child: Container(
// // padding: EdgeInsets.only(right: 10),
// // child: DottedBorder(
// // borderType: BorderType.RRect,
// // dashPattern: [8, 4],
// // color: Theme.of(context)
// // .accentTextTheme
// // .title
// // .backgroundColor,
// // strokeWidth: 2,
// // radius: Radius.circular(20),
// // child: Container(
// // height: 40,
// // width: 75,
// // padding: EdgeInsets.only(left: 10, right: 10),
// // alignment: Alignment.center,
// // decoration: BoxDecoration(
// // borderRadius:
// // BorderRadius.all(Radius.circular(20)),
// // color: Colors.transparent,
// // ),
// // child: Text(
// // S.of(context).send_new,
// // style: TextStyle(
// // fontSize: 14,
// // fontWeight: FontWeight.w600,
// // color: Theme.of(context)
// // .primaryTextTheme
// // .caption
// // .color),
// // ),
// // )),
// // ),
// // );
// // }
// //
// // index -= 1;
// //
// // final template = sendTemplateStore.templates[index];
// //
// // return TemplateTile(
// // to: template.name,
// // amount: template.amount,
// // from: template.cryptoCurrency,
// // onTap: () {
// // _addressController.text = template.address;
// // _cryptoAmountController.text = template.amount;
// // getOpenaliasRecord(context);
// // });
// // });
// // }),
// // )
// ],
// ),
// bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
// bottomSection: Observer(builder: (_) {
// return LoadingPrimaryButton(
// onPressed: () async {
// FocusScope.of(context).requestFocus(FocusNode());
// if (!_formKey.currentState.validate()) {
// return;
// }
// await showDialog<void>(
// context: context,
// builder: (dialogContext) {
// return AlertWithTwoActions(
// alertTitle: S.of(context).send_creating_transaction,
// alertContent: S.of(context).confirm_sending,
// leftButtonText: S.of(context).send,
// rightButtonText: S.of(context).cancel,
// actionLeftButton: () async {
// await Navigator.of(dialogContext)
// .popAndPushNamed(Routes.auth, arguments:
// (bool isAuthenticatedSuccessfully,
// AuthPageState auth) {
// if (!isAuthenticatedSuccessfully) {
// return;
// }
// Navigator.of(auth.context).pop();
// widget.sendViewModel.createTransaction();
// });
// },
// actionRightButton: () => Navigator.of(context).pop());
// });
// },
// text: S.of(context).send,
// color: Colors.blue,
// textColor: Colors.white,
// isLoading: widget.sendViewModel.state is TransactionIsCreating ||
// widget.sendViewModel.state is TransactionCommitting,
// isDisabled: !widget.sendViewModel.isReadyForSend);
// }),
// ),
// );
// }
// void _setEffects(BuildContext context) {
// if (_effectsInstalled) {
// return;
// }
// reaction((_) => widget.sendViewModel.all, (bool all) {
// if (all) {
// _cryptoAmountController.text = S.current.all;
// _fiatAmountController.text = null;
// }
// });
// reaction((_) => widget.sendViewModel.fiatAmount, (String amount) {
// if (amount != _fiatAmountController.text) {
// _fiatAmountController.text = amount;
// }
// });
// reaction((_) => widget.sendViewModel.cryptoAmount, (String amount) {
// if (widget.sendViewModel.all && amount != S.current.all) {
// widget.sendViewModel.all = false;
// }
// if (amount != _cryptoAmountController.text) {
// _cryptoAmountController.text = amount;
// }
// });
// reaction((_) => widget.sendViewModel.address, (String address) {
// if (address != _addressController.text) {
// _addressController.text = address;
// }
// });
// _addressController.addListener(() {
// final address = _addressController.text;
// if (widget.sendViewModel.address != address) {
// widget.sendViewModel.address = address;
// }
// });
// reaction((_) => widget.sendViewModel.state, (SendViewModelState state) {
// if (state is SendingFailed) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithOneAction(
// alertTitle: S.of(context).error,
// alertContent: state.error,
// buttonText: S.of(context).ok,
// buttonAction: () => Navigator.of(context).pop());
// });
// });
// }
// if (state is TransactionCreatedSuccessfully) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return ConfirmSendingAlert(
// alertTitle: S.of(context).confirm_sending,
// amount: S.of(context).send_amount,
// amountValue:
// widget.sendViewModel.pendingTransaction.amountFormatted,
// fee: S.of(context).send_fee,
// feeValue:
// widget.sendViewModel.pendingTransaction.feeFormatted,
// leftButtonText: S.of(context).ok,
// rightButtonText: S.of(context).cancel,
// actionLeftButton: () {
// Navigator.of(context).pop();
// widget.sendViewModel.commitTransaction();
// showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return Observer(builder: (_) {
// final state = widget.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: Colors.blue,
// 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());
// });
// });
// }
// if (state is TransactionCommitted) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// _addressController.text = '';
// _cryptoAmountController.text = '';
// });
// }
// });
// _effectsInstalled = true;
// }
// Widget body(BuildContext context) => BaseSendWidget(
// sendViewModel: sendViewModel,
// leading: leading(context),
// middle: middle(context),
// );
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
// body: Container(
// color: Theme.of(context).backgroundColor, child: body(context)));
// }
}
+10 -15
View File
@@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/send_view_model.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart';
import 'package:cake_wallet/src/screens/send/widgets/base_send_widget.dart';
class SendTemplatePage extends BasePage {
@@ -26,22 +26,17 @@ class SendTemplatePage extends BasePage {
bool get resizeToAvoidBottomPadding => false;
@override
Widget body(BuildContext context) =>
BaseSendWidget(
sendViewModel: sendViewModel,
leading: leading(context),
middle: middle(context),
isTemplate: true
);
Widget body(BuildContext context) => BaseSendWidget(
sendViewModel: sendViewModel,
leading: leading(context),
middle: middle(context),
isTemplate: true);
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
body: Container(
color: Theme.of(context).backgroundColor,
child: body(context)
)
);
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
body: Container(
color: Theme.of(context).backgroundColor, child: body(context)));
}
}
}
+442 -312
View File
@@ -1,8 +1,12 @@
import 'dart:ui';
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
import 'package:cake_wallet/src/widgets/picker.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/view_model/send/send_view_model_state.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/send_view_model.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';
@@ -19,12 +23,11 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/routes.dart';
class BaseSendWidget extends StatelessWidget {
BaseSendWidget({
@required this.sendViewModel,
@required this.leading,
@required this.middle,
this.isTemplate = false
});
BaseSendWidget(
{@required this.sendViewModel,
@required this.leading,
@required this.middle,
this.isTemplate = false});
final SendViewModel sendViewModel;
final bool isTemplate;
@@ -42,7 +45,6 @@ class BaseSendWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
_setEffects(context);
return ScrollableWithBottomSection(
@@ -54,9 +56,7 @@ class BaseSendWidget extends StatelessWidget {
gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context).primaryTextTheme.subhead.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
], begin: Alignment.topLeft, end: Alignment.bottomRight),
widget: Form(
key: _formKey,
child: Column(children: <Widget>[
@@ -71,22 +71,27 @@ class BaseSendWidget extends StatelessWidget {
child: Column(
children: <Widget>[
isTemplate
? 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,
)
: Offstage(),
? 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,
)
: Offstage(),
Padding(
padding: EdgeInsets.only(top: isTemplate ? 20 : 0),
child: AddressTextField(
@@ -113,104 +118,127 @@ class BaseSendWidget extends StatelessWidget {
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
buttonColor: Theme.of(context).primaryTextTheme.display1.color,
borderColor: Theme.of(context).primaryTextTheme.headline.color,
buttonColor:
Theme.of(context).primaryTextTheme.display1.color,
borderColor:
Theme.of(context).primaryTextTheme.headline.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white
),
color: Colors.white),
hintStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.headline.decorationColor
),
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor),
validator: sendViewModel.addressValidator,
),
),
Observer(
builder: (_) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
controller: _cryptoAmountController,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
BlacklistingTextInputFormatter(
RegExp('[\\-|\\ |\\,]'))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(sendViewModel.currency.title + ':',
Observer(builder: (_) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
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,
)),
),
suffixIcon: isTemplate
),
suffixIcon: isTemplate
? Offstage()
: Padding(
padding: EdgeInsets.only(bottom: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width/2,
alignment: Alignment.centerLeft,
child: Text(
' / ' + sendViewModel.balance,
maxLines: 1,
overflow: TextOverflow.ellipsis,
: 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: 14,
color: Theme.of(context).primaryTextTheme.headline.decorationColor
)
),
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.display1
.decorationColor)),
),
Container(
height: 34,
width: 34,
margin: EdgeInsets.only(left: 12, bottom: 8),
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
.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));
}),
isTemplate
? Offstage()
: Observer(
builder: (_) => Padding(
padding: EdgeInsets.only(top: 10),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Text(
S.of(context).available_balance + ':',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor),
)),
Text(
sendViewModel.balance,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor),
)
],
),
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(
@@ -223,8 +251,7 @@ class BaseSendWidget extends StatelessWidget {
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendViewModel.fiat.title + ':',
child: Text(sendViewModel.fiat.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
@@ -232,60 +259,71 @@ class BaseSendWidget extends StatelessWidget {
)),
),
hintText: '0.00',
borderColor: Theme.of(context).primaryTextTheme.headline.color,
borderColor: Theme.of(context)
.primaryTextTheme
.headline
.color,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white
),
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context).primaryTextTheme.headline.decorationColor,
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
)
),
)),
isTemplate
? Offstage()
: GestureDetector(
onTap: () {},
child: Container(
padding: EdgeInsets.only(top: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(S.of(context).send_estimated_fee,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
//color: Theme.of(context).primaryTextTheme.display2.color,
color: Colors.white
)),
Container(
child: Row(
children: <Widget>[
Text(
sendViewModel.estimatedFee.toString() + ' '
+ sendViewModel.currency.title,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
//color: Theme.of(context).primaryTextTheme.display2.color,
color: Colors.white
)),
Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_forward_ios,
size: 12,
color: Colors.white,),
)
],
),
)
],
),
),
)
? Offstage()
: Observer(
builder: (_) => GestureDetector(
onTap: () =>
_setTransactionPriority(context),
child: Container(
padding: EdgeInsets.only(top: 24),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(S.of(context).send_estimated_fee,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
//color: Theme.of(context).primaryTextTheme.display2.color,
color: Colors.white)),
Container(
child: Row(
children: <Widget>[
Text(
sendViewModel.estimatedFee
.toString() +
' ' +
sendViewModel
.currency.title,
style: TextStyle(
fontSize: 12,
fontWeight:
FontWeight.w600,
//color: Theme.of(context).primaryTextTheme.display2.color,
color: Colors.white)),
Padding(
padding:
EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_forward_ios,
size: 12,
color: Colors.white,
),
)
],
),
)
],
),
),
))
],
),
)
@@ -293,81 +331,84 @@ class BaseSendWidget extends StatelessWidget {
),
),
isTemplate
? Offstage()
: Padding(
padding: EdgeInsets.only(
top: 30,
left: 24,
bottom: 24
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).send_templates,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.display4.color
? Offstage()
: Padding(
padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).send_templates,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.display4
.color),
)
],
),
)
],
),
),
),
isTemplate
? Offstage()
: Container(
height: 40,
width: double.infinity,
padding: EdgeInsets.only(left: 24),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () => Navigator.of(context)
.pushNamed(Routes.sendTemplate),
child: Container(
padding: EdgeInsets.only(left: 1, right: 10),
child: DottedBorder(
borderType: BorderType.RRect,
dashPattern: [6, 4],
color: Theme.of(context).primaryTextTheme.display2.decorationColor,
strokeWidth: 2,
radius: Radius.circular(20),
? Offstage()
: Container(
height: 40,
width: double.infinity,
padding: EdgeInsets.only(left: 24),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () => Navigator.of(context)
.pushNamed(Routes.sendTemplate),
child: Container(
height: 34,
width: 75,
padding: EdgeInsets.only(left: 10, right: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.transparent,
),
child: Text(
S.of(context).send_new,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.display3.color
),
),
)
),
),
),
Observer(
builder: (_) {
final templates = sendViewModel.templates;
final itemCount = templates.length;
padding: EdgeInsets.only(left: 1, right: 10),
child: DottedBorder(
borderType: BorderType.RRect,
dashPattern: [6, 4],
color: Theme.of(context)
.primaryTextTheme
.display2
.decorationColor,
strokeWidth: 2,
radius: Radius.circular(20),
child: Container(
height: 34,
width: 75,
padding: EdgeInsets.only(left: 10, right: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(20)),
color: Colors.transparent,
),
child: Text(
S.of(context).send_new,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.display3
.color),
),
)),
),
),
// 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(),
@@ -412,21 +453,20 @@ class BaseSendWidget extends StatelessWidget {
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: isTemplate
? PrimaryButton(
onPressed: () {
if (_formKey.currentState.validate()) {
sendViewModel.sendTemplateStore.addTemplate(
name: _nameController.text,
address: _addressController.text,
cryptoCurrency: sendViewModel.currency.title,
amount: _cryptoAmountController.text
);
sendViewModel.sendTemplateStore.update();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white)
onPressed: () {
if (_formKey.currentState.validate()) {
// sendViewModel.sendTemplateStore.addTemplate(
// name: _nameController.text,
// address: _addressController.text,
// cryptoCurrency: sendViewModel.currency.title,
// amount: _cryptoAmountController.text);
// sendViewModel.sendTemplateStore.update();
Navigator.of(context).pop();
}
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white)
: Observer(builder: (_) {
return LoadingPrimaryButton(
onPressed: () {
@@ -451,6 +491,13 @@ class BaseSendWidget extends StatelessWidget {
return;
}
reaction((_) => sendViewModel.sendAll, (bool all) {
if (all) {
_cryptoAmountController.text = S.current.all;
_fiatAmountController.text = null;
}
});
reaction((_) => sendViewModel.fiatAmount, (String amount) {
if (amount != _fiatAmountController.text) {
_fiatAmountController.text = amount;
@@ -458,6 +505,10 @@ class BaseSendWidget extends StatelessWidget {
});
reaction((_) => sendViewModel.cryptoAmount, (String amount) {
if (sendViewModel.sendAll && amount != S.current.all) {
sendViewModel.sendAll = false;
}
if (amount != _cryptoAmountController.text) {
_cryptoAmountController.text = amount;
}
@@ -473,29 +524,7 @@ class BaseSendWidget extends StatelessWidget {
final address = _addressController.text;
if (sendViewModel.address != address) {
sendViewModel.changeAddress(address);
}
});
_fiatAmountController.addListener(() {
final fiatAmount = _fiatAmountController.text;
if (sendViewModel.fiatAmount != fiatAmount) {
sendViewModel.changeFiatAmount(fiatAmount);
}
});
_cryptoAmountController.addListener(() {
final cryptoAmount = _cryptoAmountController.text;
if (sendViewModel.cryptoAmount != cryptoAmount) {
sendViewModel.changeCryptoAmount(cryptoAmount);
}
});
_focusNode.addListener(() {
if (!_focusNode.hasFocus && _addressController.text.isNotEmpty) {
getOpenaliasRecord(context);
sendViewModel.address = address;
}
});
@@ -505,44 +534,126 @@ class BaseSendWidget extends StatelessWidget {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(S.of(context).error),
content: Text(state.error),
actions: <Widget>[
FlatButton(
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop())
],
);
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: state.error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
});
}
if (state is TransactionCreatedSuccessfully) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return ConfirmSendingAlert(
// alertTitle: S.of(context).confirm_sending,
// amount: S.of(context).send_amount,
// amountValue: sendStore.pendingTransaction.amount,
// fee: S.of(context).send_fee,
// feeValue: sendStore.pendingTransaction.fee,
// leftButtonText: S.of(context).ok,
// rightButtonText: S.of(context).cancel,
// actionLeftButton: () {
// Navigator.of(context).pop();
// sendStore.commitTransaction();
// showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return SendingAlert(sendStore: sendStore);
// });
// },
// actionRightButton: () => Navigator.of(context).pop());
// });
// });
WidgetsBinding.instance.addPostFrameCallback((_) {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending,
amount: S.of(context).send_amount,
amountValue:
sendViewModel.pendingTransaction.amountFormatted,
fee: S.of(context).send_fee,
feeValue: sendViewModel.pendingTransaction.feeFormatted,
leftButtonText: S.of(context).ok,
rightButtonText: S.of(context).cancel,
actionLeftButton: () {
Navigator.of(context).pop();
sendViewModel.commitTransaction();
showDialog<void>(
context: context,
builder: (BuildContext context) {
return Observer(builder: (_) {
final state = 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: Colors.blue,
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());
});
});
}
if (state is TransactionCommitted) {
@@ -557,21 +668,40 @@ class BaseSendWidget extends StatelessWidget {
}
Future<void> getOpenaliasRecord(BuildContext context) async {
final isOpenalias = await sendViewModel.isOpenaliasRecord(_addressController.text);
// final isOpenalias =
// await sendViewModel.isOpenaliasRecord(_addressController.text);
if (isOpenalias) {
_addressController.text = sendViewModel.recordAddress;
// if (isOpenalias) {
// _addressController.text = sendViewModel.recordAddress;
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).openalias_alert_title,
alertContent: S.of(context).openalias_alert_content(sendViewModel.recordName),
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()
);
});
}
// await showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithOneAction(
// alertTitle: S.of(context).openalias_alert_title,
// alertContent: S
// .of(context)
// .openalias_alert_content(sendViewModel.recordName),
// buttonText: S.of(context).ok,
// buttonAction: () => Navigator.of(context).pop());
// });
// }
}
}
Future<void> _setTransactionPriority(BuildContext context) async {
final items = TransactionPriority.all;
final selectedItem = items.indexOf(sendViewModel.transactionPriority);
await showDialog<void>(
builder: (_) => Picker(
items: items,
selectedAtIndex: selectedItem,
title: S.of(context).please_select,
mainAxisAlignment: MainAxisAlignment.center,
onItemSelected: (TransactionPriority priority) => null,
// sendViewModel.setTransactionPriority(priority),
isAlwaysShowScrollThumb: true,
),
context: context);
}
}
@@ -1,6 +1,6 @@
import 'dart:ui';
import 'package:cake_wallet/src/stores/send/sending_state.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/stores/send/sending_state.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/stores/send/send_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
+10 -7
View File
@@ -41,11 +41,12 @@ class SettingsPage extends BasePage {
if (item is PickerListItem) {
return Observer(builder: (_) {
return SettingsPickerCell<dynamic>(
title: item.title,
selectedItem: item.selectedItem(),
setItem: (dynamic value) => item.setItem(value),
isAlwaysShowScrollThumb: item.isAlwaysShowScrollThumb,
items: item.items);
title: item.title,
selectedItem: item.selectedItem(),
isAlwaysShowScrollThumb: item.isAlwaysShowScrollThumb,
items: item.items,
onItemSelected: (dynamic value) => item.onItemSelected(value),
);
});
}
@@ -59,7 +60,8 @@ class SettingsPage extends BasePage {
}
if (item is RegularListItem) {
return SettingsCellWithArrow(title: item.title, handler: item.handler);
return SettingsCellWithArrow(
title: item.title, handler: item.handler);
}
if (item is LinkListItem) {
@@ -73,7 +75,8 @@ class SettingsPage extends BasePage {
if (item is VersionListItem) {
return Observer(builder: (_) {
return SettingsVersionCell(
title: S.of(context).version(settingsViewModel.currentVersion));
title:
S.of(context).version(settingsViewModel.currentVersion));
});
}
@@ -4,28 +4,33 @@ import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/generated/i18n.dart';
class SettingsPickerCell<ItemType> extends StandardListRow {
SettingsPickerCell({@required String title, this.selectedItem, this.items,
this.setItem, this.isAlwaysShowScrollThumb})
SettingsPickerCell(
{@required String title,
this.selectedItem,
this.items,
this.onItemSelected,
this.isAlwaysShowScrollThumb})
: super(
title: title,
isSelected: false,
onTap: (BuildContext context) async {
final selectedAtIndex = items.indexOf(selectedItem);
title: title,
isSelected: false,
onTap: (BuildContext context) async {
final selectedAtIndex = items.indexOf(selectedItem);
await showDialog<void>(
context: context,
builder: (_) => Picker(
items: items,
selectedAtIndex: selectedAtIndex,
title: S.current.please_select,
mainAxisAlignment: MainAxisAlignment.center,
isAlwaysShowScrollThumb: isAlwaysShowScrollThumb,
onItemSelected: (ItemType value) => setItem(value)));
});
await showDialog<void>(
context: context,
builder: (_) => Picker(
items: items,
selectedAtIndex: selectedAtIndex,
title: S.current.please_select,
mainAxisAlignment: MainAxisAlignment.center,
isAlwaysShowScrollThumb: isAlwaysShowScrollThumb,
onItemSelected: (ItemType item) =>
onItemSelected?.call(item)));
});
final ItemType selectedItem;
final List<ItemType> items;
final Function(ItemType) setItem;
final void Function(ItemType item) onItemSelected;
final bool isAlwaysShowScrollThumb;
@override
@@ -39,4 +44,4 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
color: Theme.of(context).primaryTextTheme.overline.color),
);
}
}
}
@@ -8,9 +8,9 @@ class SettingsSwitcherCell extends StandardListRow {
: super(title: title, isSelected: false);
final bool value;
final void Function(bool value) onValueChange;
final void Function(BuildContext context, bool value) onValueChange;
@override
Widget buildTrailing(BuildContext context) =>
StandartSwitch(value: value, onTaped: () => onValueChange(!value));
Widget buildTrailing(BuildContext context) => StandartSwitch(
value: value, onTaped: () => onValueChange(context, !value));
}
@@ -1,3 +1,4 @@
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -48,6 +49,9 @@ class TransactionDetailsPage extends BasePage {
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: 'Confirmations',
value: tx.confirmations?.toString()),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
@@ -66,14 +66,6 @@ class WalletListBodyState extends State<WalletListBody> {
itemBuilder: (__, index) {
final wallet = widget.walletListViewModel.wallets[index];
final screenWidth = MediaQuery.of(context).size.width;
// String shortAddress = '';
// if (wallet.isCurrent) {
// shortAddress = wallet.address;
// shortAddress = shortAddress.replaceRange(
// 4, shortAddress.length - 4, '...');
// }
final walletMenu = WalletMenu(context, widget.walletListViewModel);
final items =
walletMenu.generateItemsForWalletMenu(wallet.isCurrent);
+32 -10
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
@@ -36,10 +37,14 @@ class WalletMenu {
];
final List<Image> listImages = [
Image.asset('assets/images/load.png', height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/eye_action.png', height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/trash.png', height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/scanner.png', height: 24, width: 24, color: Colors.white)
Image.asset('assets/images/load.png',
height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/eye_action.png',
height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/trash.png',
height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/scanner.png',
height: 24, width: 24, color: Colors.white)
];
List<String> generateItemsForWalletMenu(bool isCurrentWallet) {
@@ -87,10 +92,11 @@ class WalletMenu {
return images;
}
void action(int index, WalletListItem wallet, bool isCurrentWallet) {
Future<void> action(
int index, WalletListItem wallet, bool isCurrentWallet) async {
switch (index) {
case 0:
Navigator.of(context).pushNamed(Routes.auth, arguments:
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
@@ -110,7 +116,7 @@ class WalletMenu {
});
break;
case 1:
Navigator.of(context).pushNamed(Routes.auth, arguments:
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
@@ -120,7 +126,23 @@ class WalletMenu {
});
break;
case 2:
Navigator.of(context).pushNamed(Routes.auth, arguments:
final isComfirmed = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: 'Remove wallet',
alertContent: S.of(context).confirm_delete_wallet,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).remove,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () => Navigator.of(context).pop(true));
});
if (isComfirmed == null || !isComfirmed) {
return;
}
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
@@ -129,7 +151,7 @@ class WalletMenu {
try {
auth.changeProcessText(
S.of(context).wallet_list_removing_wallet(wallet.name));
// await _walletListStore.remove(wallet);
await walletListViewModel.remove(wallet);
auth.close();
} catch (e) {
auth.changeProcessText(S
@@ -139,7 +161,7 @@ class WalletMenu {
});
break;
case 3:
Navigator.of(context).pushNamed(Routes.rescan);
await Navigator.of(context).pushNamed(Routes.rescan);
break;
default:
break;
+3 -3
View File
@@ -42,7 +42,7 @@ abstract class SettingsStoreBase with Store {
_sharedPreferences = sharedPreferences;
_nodes = nodes;
allowBiometricalAuthentication = initialAllowBiometricalAuthentication;
isDarkTheme = initialDarkTheme;
isDarkTheme = true;
defaultPinLength = initialPinLength;
languageCode = initialLanguageCode;
currentLocale = initialCurrentLocale;
@@ -143,7 +143,7 @@ abstract class SettingsStoreBase with Store {
bool allowBiometricalAuthentication;
@observable
bool isDarkTheme;
bool isDarkTheme = true;
@observable
int defaultPinLength;
@@ -285,7 +285,7 @@ abstract class SettingsStoreBase with Store {
}
Future setCurrentNodeToDefault() async {
await changeCurrentNodeToDefault(sharedPreferences: _sharedPreferences, nodes: _nodes);
// await changeCurrentNodeToDefault(sharedPreferences: _sharedPreferences, nodes: _nodes);
await loadSettings();
}
+83 -78
View File
@@ -206,85 +206,84 @@ class SeedWidgetState extends State<SeedWidget> {
fit: FlexFit.tight,
flex: 2,
child: Container(
width: double.infinity,
height: double.infinity,
padding: EdgeInsets.all(0),
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: Column(
children: <Widget>[
CupertinoNavigationBar(
leading: widget.leading,
middle: widget.middle,
backgroundColor: Colors.transparent,
border: null,
),
Expanded(
child: Container(
padding: EdgeInsets.all(24),
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).restore_active_seed,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color:
Theme.of(context).textTheme.overline.backgroundColor),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Wrap(
children: items.map((item) {
final isValid = widget.validator.isValid(item);
final isSelected = selectedItem == item;
width: double.infinity,
height: double.infinity,
padding: EdgeInsets.all(0),
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: Column(
children: <Widget>[
CupertinoNavigationBar(
leading: widget.leading,
middle: widget.middle,
backgroundColor: Colors.transparent,
border: null,
),
Expanded(
child: Container(
padding: EdgeInsets.all(24),
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
S.of(context).restore_active_seed,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.textTheme
.overline
.backgroundColor),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Wrap(
children: items.map((item) {
final isValid =
widget.validator.isValid(item);
final isSelected = selectedItem == item;
return InkWell(
onTap: () => onMnemonicTap(item),
child: Container(
decoration: BoxDecoration(
return InkWell(
onTap: () => onMnemonicTap(item),
child: Container(
decoration: BoxDecoration(
color: isValid
? Colors.transparent
: Palette.red),
margin: EdgeInsets.only(
right: 7, bottom: 8),
child: Text(
item.toString(),
style: TextStyle(
color: isValid
? Colors.transparent
: Palette.red),
margin: EdgeInsets.only(right: 7, bottom: 8),
child: Text(
item.toString(),
style: TextStyle(
color: isValid
? Colors.white
: Colors.grey,
fontSize: 16,
fontWeight: isSelected
? FontWeight.w900
: FontWeight.w600,
decoration: isSelected
? TextDecoration.underline
: TextDecoration.none),
)),
);
}).toList(),
))
],
),
? Colors.white
: Colors.grey,
fontSize: 16,
fontWeight: isSelected
? FontWeight.w900
: FontWeight.w600,
decoration: isSelected
? TextDecoration.underline
: TextDecoration.none),
)),
);
}).toList(),
))
],
),
)
)
],
)
),
),
))
],
)),
),
Flexible(
fit: FlexFit.tight,
@@ -372,11 +371,17 @@ class SeedWidgetState extends State<SeedWidget> {
errorText: _errorMessage,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).accentTextTheme.subtitle.backgroundColor,
color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
width: 1.0)),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).accentTextTheme.subtitle.backgroundColor,
color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
width: 1.0))),
enableInteractiveSelection: false,
),