mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-21 06:18:42 +02:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)));
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user