mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-19 05:58:50 +02:00
TMP 2
This commit is contained in:
+651
-99
File diff suppressed because it is too large
Load Diff
+13
-1
@@ -21,6 +21,8 @@ import 'package:cake_wallet/src/stores/login/login_store.dart';
|
||||
import 'package:cake_wallet/src/stores/balance/balance_store.dart';
|
||||
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/stores/send_template/send_template_store.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/src/screens/root/root.dart';
|
||||
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
@@ -32,6 +34,8 @@ import 'package:cake_wallet/src/domain/common/default_settings_migration.dart';
|
||||
import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/domain/common/template.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/language.dart';
|
||||
@@ -49,6 +53,8 @@ void main() async {
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
Hive.registerAdapter(TemplateAdapter());
|
||||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
||||
@@ -66,6 +72,8 @@ void main() async {
|
||||
final trades =
|
||||
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
final walletService = WalletService();
|
||||
@@ -102,6 +110,8 @@ void main() async {
|
||||
final loginStore = LoginStore(
|
||||
sharedPreferences: sharedPreferences, walletsService: walletListService);
|
||||
final seedLanguageStore = SeedLanguageStore();
|
||||
final sendTemplateStore = SendTemplateStore(templateSource: templates);
|
||||
final exchangeTemplateStore = ExchangeTemplateStore(templateSource: exchangeTemplates);
|
||||
|
||||
setReactions(
|
||||
settingsStore: settingsStore,
|
||||
@@ -127,7 +137,9 @@ void main() async {
|
||||
Provider(create: (_) => nodes),
|
||||
Provider(create: (_) => transactionDescriptions),
|
||||
Provider(create: (_) => trades),
|
||||
Provider(create: (_) => seedLanguageStore)
|
||||
Provider(create: (_) => seedLanguageStore),
|
||||
Provider(create: (_) => sendTemplateStore),
|
||||
Provider(create: (_) => exchangeTemplateStore),
|
||||
], child: CakeWalletApp()));
|
||||
}
|
||||
|
||||
|
||||
+21
-63
@@ -1,72 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Palette {
|
||||
static const Color lightBlue = Color.fromRGBO(126, 147, 177, 1.0);
|
||||
static const Color lightBlueWithOpacity = Color.fromRGBO(126, 147, 177, 0.4);
|
||||
static const Color lightGrey = Color.fromRGBO(224, 233, 246, 1.0);
|
||||
static const Color purple = Color.fromRGBO(243, 229, 245, 1.0);
|
||||
static const Color deepPink = Color.fromRGBO(225, 190, 231, 1.0);
|
||||
static const Color indigo = Color.fromRGBO(232, 234, 246, 1.0);
|
||||
static const Color deepIndigo = Color.fromRGBO(197, 202, 233, 1.0);
|
||||
static const Color creamyGrey = Color.fromRGBO(245, 246, 249, 1.0);
|
||||
static const Color deepPurple = Color.fromRGBO(124, 83, 240, 1.0);
|
||||
static const Color wildDarkBlue = Color.fromRGBO(155, 172, 197, 1.0);
|
||||
static const Color wildDarkBlueWithOpacity = Color.fromRGBO(155, 172, 197, 0.1);
|
||||
static const Color lightGreen = Color.fromRGBO(52, 186, 204, 1.0);
|
||||
static const Color darkPurple = Color.fromRGBO(124, 83, 240, 1.0);
|
||||
static const Color brightBlue = Color.fromRGBO(151, 226, 255, 0.6);
|
||||
static const Color cloudySky = Color.fromRGBO(121, 201, 233, 0.8);
|
||||
static const Color darkGrey = Color.fromRGBO(136, 155, 183, 0.21);
|
||||
static const Color shadowGrey = Color.fromRGBO(132, 141, 198, 0.14);
|
||||
static const Color shadowGreyWithOpacity = Color.fromRGBO(132, 141, 198, 0.05);
|
||||
static const Color blueGrey = Color.fromRGBO(103, 107, 141, 1.0);
|
||||
static const Color lightGrey2 = Color.fromRGBO(249, 249, 249, 1.0);
|
||||
static const Color violet = Color.fromRGBO(138, 80, 255, 1.0);
|
||||
static const Color lightViolet = Color.fromRGBO(131, 87, 255, 1);
|
||||
static const Color cakeGreen = Color.fromRGBO(41, 187, 244, 1.0);
|
||||
static const Color cakeGreenWithOpacity = Color.fromRGBO(41, 187, 244, 0.2);
|
||||
static const Color switchBackground = Color.fromRGBO(228, 231, 240, 1.0);
|
||||
static const Color switchBorder = Color.fromRGBO(211, 222, 238, 1.0);
|
||||
static const Color green = Color.fromRGBO(39, 206, 80, 1.0);
|
||||
static const Color red = Color.fromRGBO(255, 51, 51, 1.0);
|
||||
static const Color nightBlue = Color.fromRGBO(34, 40, 75, 1.0);
|
||||
static const Color lavender = Color.fromRGBO(249, 250, 253, 1);
|
||||
static const Color lightLavender = Color.fromRGBO(242, 244, 247, 1);
|
||||
static const Color cadetBlue = Color.fromRGBO(191, 201, 215, 1);
|
||||
static const Color manatee = Color.fromRGBO(138, 153, 175, 1);
|
||||
static const Color separator = Color.fromRGBO(240, 241, 244, 1);
|
||||
static const Color containerLavender = Color.fromRGBO(226, 235, 238, 0.4);
|
||||
static const Color purpleBlue = Color.fromRGBO(84, 92, 139, 1);
|
||||
static const Color floatingActionButton = Color.fromRGBO(213, 56, 99, 1);
|
||||
static const Color failure = Color.fromRGBO(226, 35, 35, 1);
|
||||
static const Color powered = Color.fromRGBO(191, 201, 215, 1);
|
||||
static const Color buttonShadow = Color.fromRGBO(23, 46, 77, 0.129207);
|
||||
static const Color blueAlice = Color.fromRGBO(231, 240, 253, 1.0);
|
||||
static const Color lightBlue = Color.fromRGBO(172, 203, 238, 1.0);
|
||||
static const Color lavender = Color.fromRGBO(237, 245, 252, 1.0);
|
||||
static const Color oceanBlue = Color.fromRGBO(30, 52, 78, 1.0);
|
||||
static const Color lightBlueGrey = Color.fromRGBO(118, 131, 169, 1.0);
|
||||
static const Color periwinkle = Color.fromRGBO(197, 208, 230, 1.0);
|
||||
static const Color blue = Color.fromRGBO(88, 143, 252, 1.0);
|
||||
static const Color darkLavender = Color.fromRGBO(225, 238, 250, 1.0);
|
||||
static const Color nightBlue = Color.fromRGBO(46, 57, 96, 1.0);
|
||||
}
|
||||
|
||||
class PaletteDark {
|
||||
static const Color darkThemeTitle = Color.fromRGBO(132, 154, 186, 1.0);
|
||||
static const Color darkThemeTitleViolet = Color.fromRGBO(121, 92, 190, 1.0);
|
||||
static const Color darkThemeGrey = Color.fromRGBO(100, 115, 137, 1.0);
|
||||
static const Color darkThemeGreyWithOpacity = Color.fromRGBO(100, 115, 137, 0.5);
|
||||
static const Color darkThemeMidGrey = Color.fromRGBO(20, 26, 38, 1.0);
|
||||
static const Color darkThemePurpleButton = Color.fromRGBO(182, 143, 255, 0.1);
|
||||
static const Color darkThemePurpleButtonBorder = Color.fromRGBO(161, 120, 255, 0.7);
|
||||
static const Color darkThemeBackground = Color.fromRGBO(39, 41, 50, 1.0);
|
||||
static const Color darkThemeBackgroundDark = Color.fromRGBO(9, 12, 18, 1.0);
|
||||
static const Color darkThemeDarkGrey = Color.fromRGBO(218, 228, 243, 0.06);
|
||||
static const Color darkGrey = Color.fromRGBO(218, 228, 243, 0.4);
|
||||
static const Color darkThemeBlackWithOpacity = Color.fromRGBO(0, 0, 0, 0.2);
|
||||
static const Color darkThemeBlack = Color.fromRGBO(7, 10, 14, 1.0);
|
||||
static const Color darkThemeAppBarBlack = Color.fromRGBO(4, 5, 7, 1.0);
|
||||
static const Color darkThemeViolet = Color.fromRGBO(131, 87, 255, 0.2);
|
||||
static const Color darkThemeIndigoButton = Color.fromRGBO(216, 223, 246, 0.1);
|
||||
static const Color darkThemeIndigoButtonBorder = Color.fromRGBO(196, 206, 237, 0.4);
|
||||
static const Color darkThemeBlueButton = Color.fromRGBO(151, 226, 255, 0.1);
|
||||
static const Color darkThemeBlueButtonBorder = Color.fromRGBO(62, 190, 240, 0.6);
|
||||
static const Color darkThemeCloseButton = Color.fromRGBO(34, 40, 74, 1.0);
|
||||
static const Color darkThemePinButton = Color.fromRGBO(136, 155, 183, 0.1);
|
||||
static const Color darkThemePinDigitButton = Color.fromRGBO(100, 115, 137, 0.34);
|
||||
static const Color switchBackground = Color.fromRGBO(100, 115, 137, 0.4);
|
||||
static const Color wildDarkBlueWithOpacity = Color.fromRGBO(155, 172, 197, 0.4);
|
||||
static const Color wildDarkBlue = Color.fromRGBO(155, 172, 197, 0.8);
|
||||
static const Color distantBlue = Color.fromRGBO(70, 85, 133, 1.0); // mainBackgroundColor
|
||||
static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0); // borderCardColor
|
||||
static const Color nightBlue = Color.fromRGBO(45, 56, 95, 1.0); // walletCardBottomEndSync
|
||||
static const Color gray = Color.fromRGBO(140, 153, 201, 1.0); // walletCardText
|
||||
static const Color violetBlue = Color.fromRGBO(51, 63, 104, 1.0); // walletCardAddressField
|
||||
static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField
|
||||
static const Color darkNightBlue = Color.fromRGBO(33, 43, 73, 1.0); // historyPanel
|
||||
static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0); // historyPanelText
|
||||
static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0); // historyPanelButton
|
||||
static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0); // menuHeader
|
||||
static const Color lightNightBlue = Color.fromRGBO(48, 59, 95, 1.0); // menuList
|
||||
static const Color moderatePurpleBlue = Color.fromRGBO(57, 74, 95, 1.0); // selectButtonText
|
||||
}
|
||||
+40
-25
@@ -1,4 +1,3 @@
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
@@ -25,6 +24,7 @@ import 'package:cake_wallet/src/domain/monero/account.dart';
|
||||
import 'package:cake_wallet/src/domain/common/mnemotic_item.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
|
||||
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
|
||||
// MARK: Import stores
|
||||
|
||||
@@ -69,7 +69,6 @@ import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/seed_language_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/accounts/account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/accounts/account_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/address_book/address_book_page.dart';
|
||||
import 'package:cake_wallet/src/screens/address_book/contact_page.dart';
|
||||
import 'package:cake_wallet/src/screens/show_keys/show_keys_page.dart';
|
||||
@@ -88,6 +87,9 @@ import 'package:cake_wallet/src/screens/auth/create_login_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/create_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/create_dashboard_page.dart';
|
||||
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
||||
|
||||
class Router {
|
||||
static Route<dynamic> generateRoute(
|
||||
@@ -120,9 +122,8 @@ class Router {
|
||||
secureStorage: FlutterSecureStorage(),
|
||||
sharedPreferences: sharedPreferences)),
|
||||
child: SetupPinCodePage(
|
||||
onPinCodeSetup: (context, _) => Navigator.pushNamed(
|
||||
context, Routes.newWallet,
|
||||
arguments: type))));
|
||||
onPinCodeSetup: (context, _) =>
|
||||
Navigator.pushNamed(context, Routes.newWallet))));
|
||||
|
||||
case Routes.newWallet:
|
||||
final type = settings.arguments as WalletType;
|
||||
@@ -250,18 +251,24 @@ class Router {
|
||||
transactionDescriptions: transactionDescriptions)),
|
||||
], child: SendPage()));
|
||||
|
||||
case Routes.sendTemplate:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => Provider(
|
||||
create: (_) => SendStore(
|
||||
walletService: walletService,
|
||||
priceStore: priceStore,
|
||||
transactionDescriptions: transactionDescriptions),
|
||||
child: SendTemplatePage())
|
||||
);
|
||||
|
||||
case Routes.receive:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => MultiProvider(
|
||||
providers: walletService.getType() == WalletType.monero
|
||||
? [
|
||||
Provider(
|
||||
create: (_) => SubaddressListStore(
|
||||
walletService: walletService))
|
||||
]
|
||||
: [],
|
||||
child: ReceivePage()));
|
||||
builder: (_) => MultiProvider(providers: [
|
||||
Provider(
|
||||
create: (_) =>
|
||||
SubaddressListStore(walletService: walletService))
|
||||
], child: ReceivePage()));
|
||||
|
||||
case Routes.transactionDetails:
|
||||
return CupertinoPageRoute<void>(
|
||||
@@ -343,17 +350,6 @@ class Router {
|
||||
authenticationStore: authenticationStore);
|
||||
});
|
||||
|
||||
case Routes.accountList:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (context) {
|
||||
return MultiProvider(providers: [
|
||||
Provider(
|
||||
create: (_) =>
|
||||
AccountListStore(walletService: walletService)),
|
||||
], child: AccountListPage());
|
||||
},
|
||||
fullscreenDialog: true);
|
||||
|
||||
case Routes.accountCreation:
|
||||
return CupertinoPageRoute<String>(builder: (context) {
|
||||
return Provider(
|
||||
@@ -486,6 +482,25 @@ class Router {
|
||||
}),
|
||||
], child: ExchangePage()));
|
||||
|
||||
case Routes.exchangeTemplate:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Provider(create: (_) {
|
||||
final xmrtoprovider = XMRTOExchangeProvider();
|
||||
|
||||
return ExchangeStore(
|
||||
initialProvider: xmrtoprovider,
|
||||
initialDepositCurrency: CryptoCurrency.xmr,
|
||||
initialReceiveCurrency: CryptoCurrency.btc,
|
||||
trades: trades,
|
||||
providerList: [
|
||||
xmrtoprovider,
|
||||
ChangeNowExchangeProvider(),
|
||||
MorphTokenExchangeProvider(trades: trades)
|
||||
],
|
||||
walletStore: walletStore);
|
||||
}, child: ExchangeTemplatePage(),)
|
||||
);
|
||||
|
||||
case Routes.settings:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Provider(
|
||||
|
||||
+3
-1
@@ -25,7 +25,6 @@ class Routes {
|
||||
static const newNode = '/new_node_list';
|
||||
static const login = '/login';
|
||||
static const splash = '/splash';
|
||||
static const accountList = '/account_list';
|
||||
static const accountCreation = '/account_new';
|
||||
static const addressBook = '/address_book';
|
||||
static const pickerAddressBook = '/picker_address_book';
|
||||
@@ -44,4 +43,7 @@ class Routes {
|
||||
static const rescan = '/rescan';
|
||||
static const faq = '/faq';
|
||||
static const changeLanguage = '/change_language';
|
||||
static const newWalletType = '/new_wallet_type';
|
||||
static const sendTemplate = '/send_template';
|
||||
static const exchangeTemplate = '/exchange_template';
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'template.g.dart';
|
||||
|
||||
@HiveType(typeId: 6)
|
||||
class Template extends HiveObject {
|
||||
Template({this.name, this.address, this.cryptoCurrency, this.amount});
|
||||
|
||||
static const boxName = 'Template';
|
||||
|
||||
@HiveField(0)
|
||||
String name;
|
||||
|
||||
@HiveField(1)
|
||||
String address;
|
||||
|
||||
@HiveField(2)
|
||||
String cryptoCurrency;
|
||||
|
||||
@HiveField(3)
|
||||
String amount;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'exchange_template.g.dart';
|
||||
|
||||
@HiveType(typeId: 7)
|
||||
class ExchangeTemplate extends HiveObject {
|
||||
ExchangeTemplate({
|
||||
this.amount,
|
||||
this.depositCurrency,
|
||||
this.receiveCurrency,
|
||||
this.provider,
|
||||
this.depositAddress,
|
||||
this.receiveAddress
|
||||
});
|
||||
|
||||
static const boxName = 'ExchangeTemplate';
|
||||
|
||||
@HiveField(0)
|
||||
String amount;
|
||||
|
||||
@HiveField(1)
|
||||
String depositCurrency;
|
||||
|
||||
@HiveField(2)
|
||||
String receiveCurrency;
|
||||
|
||||
@HiveField(3)
|
||||
String provider;
|
||||
|
||||
@HiveField(4)
|
||||
String depositAddress;
|
||||
|
||||
@HiveField(5)
|
||||
String receiveAddress;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class SubaddressList {
|
||||
{int accountIndex, int addressIndex, String label}) async {
|
||||
await subaddress_list.setLabelForSubaddress(
|
||||
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
await update();
|
||||
await update(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
void refresh({int accountIndex}) {
|
||||
|
||||
@@ -1,120 +1,153 @@
|
||||
import 'dart:ui';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/account_list/account_list_store.dart';
|
||||
import 'package:cake_wallet/src/screens/accounts/widgets/account_tile.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class AccountListPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.accounts;
|
||||
class AccountListPage extends StatefulWidget {
|
||||
AccountListPage({@required this.accountListStore});
|
||||
|
||||
final AccountListStore accountListStore;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
final accountListStore = Provider.of<AccountListStore>(context);
|
||||
AccountListPageForm createState() => AccountListPageForm(accountListStore);
|
||||
}
|
||||
|
||||
return Container(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add, color: Palette.violet, size: 22.0),
|
||||
ButtonTheme(
|
||||
minWidth: 28.0,
|
||||
height: 28.0,
|
||||
child: FlatButton(
|
||||
shape: CircleBorder(),
|
||||
onPressed: () async {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.accountCreation);
|
||||
accountListStore.updateAccountList();
|
||||
},
|
||||
child: Offstage()),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
class AccountListPageForm extends State<AccountListPage> {
|
||||
AccountListPageForm(this.accountListStore);
|
||||
|
||||
final AccountListStore accountListStore;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final accountListStore = Provider.of<AccountListStore>(context);
|
||||
Widget build(BuildContext context) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
|
||||
final currentColor = Theme.of(context).selectedRowColor;
|
||||
final notCurrentColor = Theme.of(context).backgroundColor;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10, bottom: 20),
|
||||
child: Observer(builder: (_) {
|
||||
final accounts = accountListStore.accounts;
|
||||
return ListView.builder(
|
||||
itemCount: accounts == null ? 0 : accounts.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final account = accounts[index];
|
||||
|
||||
return Observer(builder: (_) {
|
||||
final isCurrent = walletStore.account.id == account.id;
|
||||
|
||||
return Slidable(
|
||||
key: Key(account.id.toString()),
|
||||
actionPane: SlidableDrawerActionPane(),
|
||||
child: Container(
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Text(
|
||||
account.label,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color),
|
||||
),
|
||||
onTap: () {
|
||||
if (isCurrent) {
|
||||
return;
|
||||
}
|
||||
|
||||
walletStore.setAccount(account);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0,
|
||||
)
|
||||
],
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).choose_account,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
),
|
||||
secondaryActions: <Widget>[
|
||||
IconSlideAction(
|
||||
caption: S.of(context).edit,
|
||||
color: Colors.blue,
|
||||
icon: Icons.edit,
|
||||
onTap: () async {
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.accountCreation,
|
||||
arguments: account);
|
||||
// await accountListStore.updateAccountList().then((_) {
|
||||
// if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]);
|
||||
// });
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
height: 296,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
final accounts = accountListStore.accounts;
|
||||
|
||||
return ListView.separated(
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
color: Theme.of(context).dividerColor,
|
||||
height: 1,
|
||||
),
|
||||
itemCount: accounts == null ? 0 : accounts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final account = accounts[index];
|
||||
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
final isCurrent = walletStore.account.id == account.id;
|
||||
|
||||
return AccountTile(
|
||||
isCurrent: isCurrent,
|
||||
accountName: account.label,
|
||||
onTap: () {
|
||||
if (isCurrent) {
|
||||
return;
|
||||
}
|
||||
|
||||
walletStore.setAccount(account);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.accountCreation);
|
||||
accountListStore.updateAccountList();
|
||||
},
|
||||
child: Container(
|
||||
height: 62,
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.add,
|
||||
color: PaletteDark.darkNightBlue,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 5),
|
||||
child: Text(
|
||||
S.of(context).create_new_account,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: PaletteDark.darkNightBlue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/domain/monero/account.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
|
||||
class AccountPage extends BasePage {
|
||||
AccountPage({this.account});
|
||||
@@ -15,7 +16,7 @@ class AccountPage extends BasePage {
|
||||
final Account account;
|
||||
|
||||
@override
|
||||
String get title => 'Account';
|
||||
String get title => S.current.account;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => AccountForm(account);
|
||||
@@ -50,30 +51,31 @@ class AccountFormState extends State<AccountForm> {
|
||||
Widget build(BuildContext context) {
|
||||
final accountListStore = Provider.of<AccountListStore>(context);
|
||||
|
||||
_textController.addListener(() {
|
||||
if (_textController.text.isNotEmpty) {
|
||||
accountListStore.setDisabledStatus(false);
|
||||
} else {
|
||||
accountListStore.setDisabledStatus(true);
|
||||
}
|
||||
});
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
padding: EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||
child: BaseTextFormField(
|
||||
controller: _textController,
|
||||
hintText: S.of(context).account,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor, width: 1.0))),
|
||||
controller: _textController,
|
||||
validator: (value) {
|
||||
accountListStore.validateAccountName(value);
|
||||
return accountListStore.errorMessage;
|
||||
},
|
||||
),
|
||||
validator: (value) {
|
||||
accountListStore.validateAccountName(value);
|
||||
return accountListStore.errorMessage;
|
||||
},
|
||||
)
|
||||
)),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
@@ -93,16 +95,11 @@ class AccountFormState extends State<AccountForm> {
|
||||
Navigator.of(context).pop(_textController.text);
|
||||
},
|
||||
text:
|
||||
widget.account != null ? 'Rename' : S.of(context).add,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
widget.account != null ? S.of(context).rename : S.of(context).add,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading: accountListStore.isAccountCreating,
|
||||
isDisabled: accountListStore.isDisabledStatus,
|
||||
))
|
||||
],
|
||||
),
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AccountTile extends StatelessWidget {
|
||||
AccountTile({
|
||||
@required this.isCurrent,
|
||||
@required this.accountName,
|
||||
@required this.onTap
|
||||
});
|
||||
|
||||
final bool isCurrent;
|
||||
final String accountName;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = isCurrent ? Theme.of(context).accentTextTheme.subtitle.decorationColor : Colors.transparent;
|
||||
final textColor = isCurrent ? Colors.blue : Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 77,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
alignment: Alignment.centerLeft,
|
||||
color: color,
|
||||
child: Text(
|
||||
accountName,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,20 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/stores/address_book/address_book_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
|
||||
class AddressBookPage extends BasePage {
|
||||
AddressBookPage({this.isEditable = true});
|
||||
|
||||
final bool isEditable;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
String get title => S.current.address_book;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.withShadow;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
if (!isEditable) {
|
||||
@@ -34,17 +28,21 @@ class AddressBookPage extends BasePage {
|
||||
final addressBookStore = Provider.of<AddressBookStore>(context);
|
||||
|
||||
return Container(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add, color: Palette.violet, size: 22.0),
|
||||
Icon(Icons.add,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
size: 22.0),
|
||||
ButtonTheme(
|
||||
minWidth: 28.0,
|
||||
height: 28.0,
|
||||
minWidth: 32.0,
|
||||
height: 32.0,
|
||||
child: FlatButton(
|
||||
shape: CircleBorder(),
|
||||
onPressed: () async {
|
||||
@@ -63,20 +61,30 @@ class AddressBookPage extends BasePage {
|
||||
final addressBookStore = Provider.of<AddressBookStore>(context);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
child: Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
separatorBuilder: (_, __) => Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0,
|
||||
),
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
itemCount: addressBookStore.contactList == null
|
||||
? 0
|
||||
: addressBookStore.contactList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final contact = addressBookStore.contactList[index];
|
||||
final image = _getCurrencyImage(contact.type);
|
||||
|
||||
final content = ListTile(
|
||||
final isDrawTop = index == 0 ? true : false;
|
||||
final isDrawBottom = index == addressBookStore.contactList.length - 1 ? true : false;
|
||||
|
||||
final content = GestureDetector(
|
||||
onTap: () async {
|
||||
if (!isEditable) {
|
||||
Navigator.of(context).pop(contact);
|
||||
@@ -86,39 +94,69 @@ class AddressBookPage extends BasePage {
|
||||
final isCopied = await showNameAndAddressDialog(
|
||||
context, contact.name, contact.address);
|
||||
|
||||
if (isCopied) {
|
||||
if (isCopied != null && isCopied) {
|
||||
await Clipboard.setData(
|
||||
ClipboardData(text: contact.address));
|
||||
Scaffold.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Copied to Clipboard'),
|
||||
content: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
style: TextStyle(
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 1500),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
leading: Container(
|
||||
height: 25.0,
|
||||
width: 48.0,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: _getCurrencyBackgroundColor(contact.type),
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
),
|
||||
child: Text(
|
||||
contact.type.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 11.0,
|
||||
color: _getCurrencyTextColor(contact.type),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
isDrawTop
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
)
|
||||
: Offstage(),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? image
|
||||
: Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 12)
|
||||
: EdgeInsets.only(left: 0),
|
||||
child: Text(
|
||||
contact.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
contact.name,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
isDrawBottom
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -130,7 +168,7 @@ class AddressBookPage extends BasePage {
|
||||
child: content,
|
||||
secondaryActions: <Widget>[
|
||||
IconSlideAction(
|
||||
caption: 'Edit',
|
||||
caption: S.of(context).edit,
|
||||
color: Colors.blue,
|
||||
icon: Icons.edit,
|
||||
onTap: () async {
|
||||
@@ -141,7 +179,7 @@ class AddressBookPage extends BasePage {
|
||||
},
|
||||
),
|
||||
IconSlideAction(
|
||||
caption: 'Delete',
|
||||
caption: S.of(context).delete,
|
||||
color: Colors.red,
|
||||
icon: CupertinoIcons.delete,
|
||||
onTap: () async {
|
||||
@@ -171,95 +209,68 @@ class AddressBookPage extends BasePage {
|
||||
));
|
||||
}
|
||||
|
||||
Color _getCurrencyBackgroundColor(CryptoCurrency currency) {
|
||||
Color color;
|
||||
Image _getCurrencyImage(CryptoCurrency currency) {
|
||||
Image image;
|
||||
switch (currency) {
|
||||
case CryptoCurrency.xmr:
|
||||
color = Palette.cakeGreenWithOpacity;
|
||||
image = Image.asset('assets/images/monero.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.ada:
|
||||
color = Colors.blue[200];
|
||||
image = Image.asset('assets/images/ada.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.bch:
|
||||
color = Colors.orangeAccent;
|
||||
image = Image.asset('assets/images/bch.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.bnb:
|
||||
color = Colors.blue;
|
||||
image = Image.asset('assets/images/bnb.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.btc:
|
||||
color = Colors.orange;
|
||||
image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.dash:
|
||||
color = Colors.blue;
|
||||
image = Image.asset('assets/images/dash.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.eos:
|
||||
color = Colors.orangeAccent;
|
||||
image = Image.asset('assets/images/eos.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.eth:
|
||||
color = Colors.black;
|
||||
image = Image.asset('assets/images/eth.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.ltc:
|
||||
color = Colors.blue[200];
|
||||
image = Image.asset('assets/images/litecoin.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.nano:
|
||||
color = Colors.orange;
|
||||
image = Image.asset('assets/images/nano.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.trx:
|
||||
color = Colors.black;
|
||||
image = Image.asset('assets/images/trx.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.usdt:
|
||||
color = Colors.blue[200];
|
||||
image = Image.asset('assets/images/usdt.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.xlm:
|
||||
color = color = Colors.blue;
|
||||
image = Image.asset('assets/images/xlm.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.xrp:
|
||||
color = Colors.orangeAccent;
|
||||
image = Image.asset('assets/images/xrp.png', height: 24, width: 24);
|
||||
break;
|
||||
default:
|
||||
color = Colors.white;
|
||||
image = null;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
Color _getCurrencyTextColor(CryptoCurrency currency) {
|
||||
Color color;
|
||||
switch (currency) {
|
||||
case CryptoCurrency.xmr:
|
||||
color = Palette.cakeGreen;
|
||||
break;
|
||||
case CryptoCurrency.ltc:
|
||||
case CryptoCurrency.ada:
|
||||
case CryptoCurrency.usdt:
|
||||
color = Palette.lightBlue;
|
||||
break;
|
||||
default:
|
||||
color = Colors.white;
|
||||
}
|
||||
return color;
|
||||
return image;
|
||||
}
|
||||
|
||||
Future<bool> showAlertDialog(BuildContext context) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
'Remove contact',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: const Text(
|
||||
'Are you sure that you want to remove selected contact?',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop( false),
|
||||
child: const Text('Cancel')),
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('Remove')),
|
||||
],
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).address_remove_contact,
|
||||
alertContent: S.of(context).address_remove_content,
|
||||
leftButtonText: S.of(context).remove,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () => Navigator.of(context).pop(true),
|
||||
actionRightButton: () => Navigator.of(context).pop(false)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -269,24 +280,13 @@ class AddressBookPage extends BasePage {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
name,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
content: Text(
|
||||
address,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: Text('Cancel')),
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: Text('Copy'))
|
||||
],
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: name,
|
||||
alertContent: address,
|
||||
leftButtonText: S.of(context).copy,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () => Navigator.of(context).pop(true),
|
||||
actionRightButton: () => Navigator.of(context).pop(false)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
@@ -9,7 +10,9 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class ContactPage extends BasePage {
|
||||
ContactPage({this.contact});
|
||||
@@ -37,22 +40,27 @@ class ContactFormState extends State<ContactForm> {
|
||||
final _contactNameController = TextEditingController();
|
||||
final _currencyTypeController = TextEditingController();
|
||||
final _addressController = TextEditingController();
|
||||
final currencies = CryptoCurrency.all;
|
||||
|
||||
CryptoCurrency _selectectCrypto = CryptoCurrency.xmr;
|
||||
CryptoCurrency _selectectCrypto;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.contact == null) {
|
||||
_currencyTypeController.text = _selectectCrypto.toString();
|
||||
} else {
|
||||
if (widget.contact != null) {
|
||||
_selectectCrypto = widget.contact.type;
|
||||
_contactNameController.text = widget.contact.name;
|
||||
_currencyTypeController.text = _selectectCrypto.toString();
|
||||
_addressController.text = widget.contact.address;
|
||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void afterLayout(dynamic _) {
|
||||
final addressBookStore = Provider.of<AddressBookStore>(context);
|
||||
addressBookStore.setDisabledStatus(false);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_contactNameController.dispose();
|
||||
@@ -61,198 +69,166 @@ class ContactFormState extends State<ContactForm> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _setCurrencyType(BuildContext context) async {
|
||||
var currencyType = CryptoCurrency.all[0].toString();
|
||||
var selectedCurrency = CryptoCurrency.all[0];
|
||||
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).please_select),
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
content: Container(
|
||||
height: 150.0,
|
||||
child: CupertinoPicker(
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
itemExtent: 45.0,
|
||||
onSelectedItemChanged: (int index) {
|
||||
selectedCurrency = CryptoCurrency.all[index];
|
||||
currencyType = CryptoCurrency.all[index].toString();
|
||||
},
|
||||
children:
|
||||
List.generate(CryptoCurrency.all.length, (int index) {
|
||||
return Center(
|
||||
child: Text(
|
||||
CryptoCurrency.all[index].toString(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color),
|
||||
),
|
||||
);
|
||||
})),
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
_selectectCrypto = selectedCurrency;
|
||||
_currencyTypeController.text = currencyType;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(S.of(context).ok))
|
||||
],
|
||||
);
|
||||
});
|
||||
void onHandleControllers(AddressBookStore addressBookStore) {
|
||||
if (_contactNameController.text.isNotEmpty &&
|
||||
_addressController.text.isNotEmpty &&
|
||||
_currencyTypeController.text.isNotEmpty) {
|
||||
addressBookStore.setDisabledStatus(false);
|
||||
} else {
|
||||
addressBookStore.setDisabledStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addressBookStore = Provider.of<AddressBookStore>(context);
|
||||
final downArrow = Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
color: Theme.of(context).dividerColor,
|
||||
height: 8);
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.headline.color),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).contact_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor, width: 1.0))),
|
||||
controller: _contactNameController,
|
||||
validator: (value) {
|
||||
addressBookStore.validateContactName(value);
|
||||
return addressBookStore.errorMessage;
|
||||
},
|
||||
),
|
||||
SizedBox(height: 14.0),
|
||||
Container(
|
||||
child: InkWell(
|
||||
onTap: () => _setCurrencyType(context),
|
||||
child: IgnorePointer(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color),
|
||||
decoration: InputDecoration(
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
controller: _currencyTypeController,
|
||||
_contactNameController.addListener(() {onHandleControllers(addressBookStore);});
|
||||
_currencyTypeController.addListener(() {onHandleControllers(addressBookStore);});
|
||||
_addressController.addListener(() {onHandleControllers(addressBookStore);});
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.all(24),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
BaseTextFormField(
|
||||
controller: _contactNameController,
|
||||
hintText: S.of(context).contact_name,
|
||||
validator: (value) {
|
||||
addressBookStore.validateContactName(value);
|
||||
return addressBookStore.errorMessage;
|
||||
}
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Container(
|
||||
child: InkWell(
|
||||
onTap: () => _presentPicker(context),
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: _currencyTypeController,
|
||||
hintText: S.of(context).settings_currency,
|
||||
suffixIcon: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
downArrow
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
controller: _addressController,
|
||||
options: [AddressTextFieldOption.qrCode],
|
||||
validator: (value) {
|
||||
addressBookStore.validateAddress(value,
|
||||
cryptoCurrency: _selectectCrypto);
|
||||
return addressBookStore.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 24
|
||||
),
|
||||
bottomSection: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectectCrypto = null;
|
||||
_contactNameController.text = '';
|
||||
_currencyTypeController.text = '';
|
||||
_addressController.text = '';
|
||||
});
|
||||
},
|
||||
text: S.of(context).reset,
|
||||
color: Colors.red,
|
||||
textColor: Colors.white
|
||||
),
|
||||
),
|
||||
SizedBox(height: 14.0),
|
||||
AddressTextField(
|
||||
controller: _addressController,
|
||||
options: [AddressTextFieldOption.qrCode],
|
||||
validator: (value) {
|
||||
addressBookStore.validateAddress(value,
|
||||
cryptoCurrency: _selectectCrypto);
|
||||
return addressBookStore.errorMessage;
|
||||
},
|
||||
SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) => PrimaryButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (widget.contact == null) {
|
||||
final newContact = Contact(
|
||||
name: _contactNameController.text,
|
||||
address: _addressController.text,
|
||||
type: _selectectCrypto);
|
||||
|
||||
await addressBookStore.add(contact: newContact);
|
||||
} else {
|
||||
widget.contact.name = _contactNameController.text;
|
||||
widget.contact.address = _addressController.text;
|
||||
widget.contact
|
||||
.updateCryptoCurrency(currency: _selectectCrypto);
|
||||
|
||||
await addressBookStore.update(
|
||||
contact: widget.contact);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.contact,
|
||||
alertContent: e.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isDisabled: addressBookStore.isDisabledStatus,
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
void _presentPicker(BuildContext context) {
|
||||
showDialog<void>(
|
||||
builder: (_) => CurrencyPicker(
|
||||
selectedAtIndex: currencies.indexOf(_selectectCrypto),
|
||||
items: currencies,
|
||||
title: S.of(context).please_select,
|
||||
onItemSelected: (CryptoCurrency item) {
|
||||
_selectectCrypto = item;
|
||||
_currencyTypeController.text = _selectectCrypto.toString();
|
||||
}
|
||||
),
|
||||
bottomSection: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectectCrypto = CryptoCurrency.xmr;
|
||||
_contactNameController.text = '';
|
||||
_currencyTypeController.text =
|
||||
_selectectCrypto.toString();
|
||||
_addressController.text = '';
|
||||
});
|
||||
},
|
||||
text: S.of(context).reset,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).accentTextTheme.button.decorationColor),
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (widget.contact == null) {
|
||||
final newContact = Contact(
|
||||
name: _contactNameController.text,
|
||||
address: _addressController.text,
|
||||
type: _selectectCrypto);
|
||||
|
||||
await addressBookStore.add(contact: newContact);
|
||||
} else {
|
||||
widget.contact.name = _contactNameController.text;
|
||||
widget.contact.address = _addressController.text;
|
||||
widget.contact
|
||||
.updateCryptoCurrency(currency: _selectectCrypto);
|
||||
|
||||
await addressBookStore.update(
|
||||
contact: widget.contact);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
e.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(),
|
||||
child: Text(S.of(context).ok))
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor))
|
||||
],
|
||||
));
|
||||
context: context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ class AuthPage extends StatefulWidget {
|
||||
class AuthPageState extends State<AuthPage> {
|
||||
final _key = GlobalKey<ScaffoldState>();
|
||||
final _pinCodeKey = GlobalKey<PinCodeState>();
|
||||
final _backArrowImageDarkTheme =
|
||||
Image.asset('assets/images/back_arrow_dark_theme.png');
|
||||
|
||||
void changeProcessText(String text) {
|
||||
_key.currentState.showSnackBar(
|
||||
@@ -121,7 +123,21 @@ class AuthPageState extends State<AuthPage> {
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
appBar: CupertinoNavigationBar(
|
||||
leading: widget.closable ? CloseButton() : Container(),
|
||||
leading: widget.closable
|
||||
? SizedBox(
|
||||
height: 37,
|
||||
width: 20,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: _backArrowImageDarkTheme),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
border: null,
|
||||
),
|
||||
|
||||
@@ -4,13 +4,15 @@ import 'package:cake_wallet/src/widgets/nav_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
enum AppBarStyle { regular, withShadow }
|
||||
|
||||
abstract class BasePage extends StatelessWidget {
|
||||
String get title => null;
|
||||
bool get isModalBackButton => false;
|
||||
Color get backgroundColor => Colors.white;
|
||||
Color get backgroundLightColor => Colors.white;
|
||||
Color get backgroundDarkColor => PaletteDark.darkNightBlue;
|
||||
bool get resizeToAvoidBottomPadding => true;
|
||||
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
||||
|
||||
@@ -60,8 +62,8 @@ abstract class BasePage extends StatelessWidget {
|
||||
: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
);
|
||||
}
|
||||
@@ -82,8 +84,8 @@ abstract class BasePage extends StatelessWidget {
|
||||
middle: middle(context),
|
||||
trailing: trailing(context),
|
||||
backgroundColor: _isDarkTheme
|
||||
? Theme.of(context).backgroundColor
|
||||
: backgroundColor);
|
||||
? backgroundDarkColor
|
||||
: backgroundLightColor);
|
||||
|
||||
case AppBarStyle.withShadow:
|
||||
return NavBar.withShadow(
|
||||
@@ -92,8 +94,8 @@ abstract class BasePage extends StatelessWidget {
|
||||
middle: middle(context),
|
||||
trailing: trailing(context),
|
||||
backgroundColor: _isDarkTheme
|
||||
? Theme.of(context).backgroundColor
|
||||
: backgroundColor);
|
||||
? backgroundDarkColor
|
||||
: backgroundLightColor);
|
||||
|
||||
default:
|
||||
return NavBar(
|
||||
@@ -102,8 +104,8 @@ abstract class BasePage extends StatelessWidget {
|
||||
middle: middle(context),
|
||||
trailing: trailing(context),
|
||||
backgroundColor: _isDarkTheme
|
||||
? Theme.of(context).backgroundColor
|
||||
: backgroundColor);
|
||||
? backgroundDarkColor
|
||||
: backgroundLightColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +117,9 @@ abstract class BasePage extends StatelessWidget {
|
||||
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor:
|
||||
_isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor,
|
||||
backgroundColor: _isDarkTheme
|
||||
? backgroundDarkColor
|
||||
: backgroundLightColor,
|
||||
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||
appBar: appBar(context),
|
||||
body: SafeArea(child: body(context)),
|
||||
|
||||
@@ -1,106 +1,14 @@
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
|
||||
import 'package:cake_wallet/src/stores/balance/balance_store.dart';
|
||||
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/date_section_item.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/date_section_raw.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/trade_row.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/transaction_raw.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/wallet_card.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/trade_history_panel.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
|
||||
|
||||
class DashboardPage extends BasePage {
|
||||
class DashboardPage extends StatelessWidget {
|
||||
final _bodyKey = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 30,
|
||||
child: FlatButton(
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => _presentWalletMenu(context),
|
||||
child: Image.asset('assets/images/more.png',
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
width: 30)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
|
||||
return Observer(builder: (_) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
walletStore.name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
walletStore.account != null ? '${walletStore.account.label}' : '',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 20,
|
||||
child: FlatButton(
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => Navigator.of(context).pushNamed(Routes.settings),
|
||||
child: Image.asset('assets/images/settings_icon.png',
|
||||
color: Colors.grey, height: 20)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => DashboardPageBody(key: _bodyKey);
|
||||
|
||||
@override
|
||||
Widget floatingActionButton(BuildContext context) => FloatingActionButton(
|
||||
child: Image.asset('assets/images/exchange_icon.png',
|
||||
color: Colors.white, height: 26, width: 22),
|
||||
backgroundColor: Palette.floatingActionButton,
|
||||
onPressed: () async => await Navigator.of(context, rootNavigator: true)
|
||||
.pushNamed(Routes.exchange));
|
||||
|
||||
void _presentWalletMenu(BuildContext bodyContext) {
|
||||
final walletMenu = WalletMenu(bodyContext);
|
||||
|
||||
showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: walletMenu.items,
|
||||
selectedAtIndex: -1,
|
||||
title: S.of(bodyContext).wallet_menu,
|
||||
pickerHeight: 510,
|
||||
onItemSelected: (String item) =>
|
||||
walletMenu.action(walletMenu.items.indexOf(item))),
|
||||
context: bodyContext);
|
||||
}
|
||||
Widget build(BuildContext context) => DashboardPageBody(key: _bodyKey);
|
||||
}
|
||||
|
||||
class DashboardPageBody extends StatefulWidget {
|
||||
@@ -111,488 +19,62 @@ class DashboardPageBody extends StatefulWidget {
|
||||
}
|
||||
|
||||
class DashboardPageBodyState extends State<DashboardPageBody> {
|
||||
final _connectionStatusObserverKey = GlobalKey();
|
||||
final _balanceObserverKey = GlobalKey();
|
||||
final _balanceTitleObserverKey = GlobalKey();
|
||||
final _syncingObserverKey = GlobalKey();
|
||||
final _listObserverKey = GlobalKey();
|
||||
final _listKey = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final balanceStore = Provider.of<BalanceStore>(context);
|
||||
final actionListStore = Provider.of<ActionListStore>(context);
|
||||
final syncStore = Provider.of<SyncStore>(context);
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final transactionDateFormat = settingsStore.getCurrentDateFormat(
|
||||
formatUSA: "MMMM d, yyyy, HH:mm",
|
||||
formatDefault: "d MMMM yyyy, HH:mm");
|
||||
final menuButton = Image.asset('assets/images/header.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
|
||||
return Observer(
|
||||
key: _listObserverKey,
|
||||
builder: (_) {
|
||||
final items = actionListStore.items == null
|
||||
? <String>[]
|
||||
: actionListStore.items;
|
||||
final itemsCount = items.length + 2;
|
||||
|
||||
return ListView.builder(
|
||||
key: _listKey,
|
||||
padding: EdgeInsets.only(bottom: 15),
|
||||
itemCount: itemsCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Palette.shadowGreyWithOpacity,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 12))
|
||||
]),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Observer(
|
||||
key: _syncingObserverKey,
|
||||
builder: (_) {
|
||||
final status = syncStore.status;
|
||||
final statusText = status.title();
|
||||
final progress = syncStore.status.progress();
|
||||
final isFialure = status is FailedSyncStatus;
|
||||
|
||||
var descriptionText = '';
|
||||
|
||||
if (status is SyncingSyncStatus) {
|
||||
descriptionText = S
|
||||
.of(context)
|
||||
.Blocks_remaining(
|
||||
syncStore.status.toString());
|
||||
}
|
||||
|
||||
if (status is FailedSyncStatus) {
|
||||
descriptionText = S
|
||||
.of(context)
|
||||
.please_try_to_connect_to_another_node;
|
||||
}
|
||||
|
||||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 3,
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: Palette.separator,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(
|
||||
Palette.cakeGreen),
|
||||
value: progress,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(statusText,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isFialure
|
||||
? Palette.failure
|
||||
: Palette.cakeGreen)),
|
||||
Text(descriptionText,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Palette.wildDarkBlue,
|
||||
height: 2.0))
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
GestureDetector(
|
||||
onTapUp: (_) => balanceStore.isReversing = false,
|
||||
onTapDown: (_) => balanceStore.isReversing = true,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 40, bottom: 40),
|
||||
color: Colors.transparent,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(width: double.infinity),
|
||||
Observer(
|
||||
key: _balanceTitleObserverKey,
|
||||
builder: (_) {
|
||||
final savedDisplayMode =
|
||||
settingsStore.balanceDisplayMode;
|
||||
final displayMode = balanceStore
|
||||
.isReversing
|
||||
? (savedDisplayMode ==
|
||||
BalanceDisplayMode
|
||||
.availableBalance
|
||||
? BalanceDisplayMode.fullBalance
|
||||
: BalanceDisplayMode
|
||||
.availableBalance)
|
||||
: savedDisplayMode;
|
||||
|
||||
return Text(displayMode.toString(),
|
||||
style: TextStyle(
|
||||
color: Palette.violet,
|
||||
fontSize: 16));
|
||||
}),
|
||||
Observer(
|
||||
key: _connectionStatusObserverKey,
|
||||
builder: (_) {
|
||||
final savedDisplayMode =
|
||||
settingsStore.balanceDisplayMode;
|
||||
var balance = '---';
|
||||
final displayMode = balanceStore
|
||||
.isReversing
|
||||
? (savedDisplayMode ==
|
||||
BalanceDisplayMode
|
||||
.availableBalance
|
||||
? BalanceDisplayMode.fullBalance
|
||||
: BalanceDisplayMode
|
||||
.availableBalance)
|
||||
: savedDisplayMode;
|
||||
|
||||
if (displayMode ==
|
||||
BalanceDisplayMode.availableBalance) {
|
||||
balance =
|
||||
balanceStore.unlockedBalance ??
|
||||
'0.0';
|
||||
}
|
||||
|
||||
if (displayMode ==
|
||||
BalanceDisplayMode.fullBalance) {
|
||||
balance =
|
||||
balanceStore.fullBalance ?? '0.0';
|
||||
}
|
||||
|
||||
return Text(
|
||||
balance,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
fontSize: 42),
|
||||
);
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 7),
|
||||
child: Observer(
|
||||
key: _balanceObserverKey,
|
||||
builder: (_) {
|
||||
final savedDisplayMode =
|
||||
settingsStore.balanceDisplayMode;
|
||||
final displayMode =
|
||||
balanceStore.isReversing
|
||||
? (savedDisplayMode ==
|
||||
BalanceDisplayMode
|
||||
.availableBalance
|
||||
? BalanceDisplayMode
|
||||
.fullBalance
|
||||
: BalanceDisplayMode
|
||||
.availableBalance)
|
||||
: savedDisplayMode;
|
||||
final symbol = settingsStore
|
||||
.fiatCurrency
|
||||
.toString();
|
||||
var balance = '---';
|
||||
|
||||
if (displayMode ==
|
||||
BalanceDisplayMode
|
||||
.availableBalance) {
|
||||
balance =
|
||||
'${balanceStore.fiatUnlockedBalance} $symbol';
|
||||
}
|
||||
|
||||
if (displayMode ==
|
||||
BalanceDisplayMode.fullBalance) {
|
||||
balance =
|
||||
'${balanceStore.fiatFullBalance} $symbol';
|
||||
}
|
||||
|
||||
return Text(balance,
|
||||
style: TextStyle(
|
||||
color: Palette.wildDarkBlue,
|
||||
fontSize: 16));
|
||||
}))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, right: 20, bottom: 30),
|
||||
child: Container(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: PrimaryImageButton(
|
||||
image: Image.asset(
|
||||
'assets/images/send_icon.png',
|
||||
height: 25,
|
||||
width: 25),
|
||||
text: S.of(context).send,
|
||||
onPressed: () => Navigator.of(context,
|
||||
rootNavigator: true)
|
||||
.pushNamed(Routes.send),
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
)),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: PrimaryImageButton(
|
||||
image: Image.asset(
|
||||
'assets/images/receive_icon.png',
|
||||
height: 25,
|
||||
width: 25),
|
||||
text: S.of(context).receive,
|
||||
onPressed: () => Navigator.of(context,
|
||||
rootNavigator: true)
|
||||
.pushNamed(Routes.receive),
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.decorationColor,
|
||||
))
|
||||
],
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (index == 1 && actionListStore.totalCount > 0) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: 20, top: 10, bottom: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
PopupMenuButton<int>(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
enabled: false,
|
||||
value: -1,
|
||||
child: Text(S.of(context).transactions,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color))),
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).incoming),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.transactionFilterStore
|
||||
.displayIncoming,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.transactionFilterStore
|
||||
.toggleIncoming(),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).outgoing),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.transactionFilterStore
|
||||
.displayOutgoing,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.transactionFilterStore
|
||||
.toggleOutgoing(),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child:
|
||||
Text(S.of(context).transactions_by_date)),
|
||||
PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
enabled: false,
|
||||
value: -1,
|
||||
child: Text(S.of(context).trades,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color))),
|
||||
PopupMenuItem(
|
||||
value: 3,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('XMR.TO'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayXMRTO,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.xmrto),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 4,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('Change.NOW'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayChangeNow,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.changeNow),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 5,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('MorphToken'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayMorphToken,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.morphToken),
|
||||
)
|
||||
])))
|
||||
],
|
||||
child: Text(S.of(context).filters,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color)),
|
||||
onSelected: (item) async {
|
||||
if (item == 2) {
|
||||
final List<DateTime> picked =
|
||||
await date_rage_picker.showDatePicker(
|
||||
context: context,
|
||||
initialFirstDate: DateTime.now()
|
||||
.subtract(Duration(days: 1)),
|
||||
initialLastDate: (DateTime.now()),
|
||||
firstDate: DateTime(2015),
|
||||
lastDate: DateTime.now()
|
||||
.add(Duration(days: 1)));
|
||||
|
||||
if (picked != null && picked.length == 2) {
|
||||
actionListStore.transactionFilterStore
|
||||
.changeStartDate(picked.first);
|
||||
actionListStore.transactionFilterStore
|
||||
.changeEndDate(picked.last);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
index -= 2;
|
||||
|
||||
if (index < 0 || index >= items.length) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final item = items[index];
|
||||
|
||||
if (item is DateSectionItem) {
|
||||
return DateSectionRaw(date: item.date);
|
||||
}
|
||||
|
||||
if (item is TransactionListItem) {
|
||||
final transaction = item.transaction;
|
||||
final savedDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final formattedAmount =
|
||||
savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: transaction.amountFormatted();
|
||||
final formattedFiatAmount =
|
||||
savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: transaction.fiatAmount();
|
||||
|
||||
return TransactionRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.transactionDetails,
|
||||
arguments: transaction),
|
||||
direction: transaction.direction,
|
||||
formattedDate:
|
||||
transactionDateFormat.format(transaction.date),
|
||||
formattedAmount: formattedAmount,
|
||||
formattedFiatAmount: formattedFiatAmount,
|
||||
isPending: transaction.isPending);
|
||||
}
|
||||
|
||||
if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
final savedDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final formattedAmount = trade.amount != null
|
||||
? savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: trade.amountFormatted()
|
||||
: trade.amount;
|
||||
|
||||
return TradeRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate:
|
||||
transactionDateFormat.format(trade.createdAt),
|
||||
formattedAmount: formattedAmount);
|
||||
}
|
||||
|
||||
return Container();
|
||||
});
|
||||
});
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
Theme.of(context).primaryColor
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight
|
||||
)
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 10, right: 10),
|
||||
alignment: Alignment.centerRight,
|
||||
child: SizedBox(
|
||||
height: 44,
|
||||
width: 44,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () async {
|
||||
await showDialog<void>(
|
||||
builder: (_) => MenuWidget(),
|
||||
context: context
|
||||
);
|
||||
},
|
||||
child: menuButton),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, top: 20),
|
||||
child: WalletCard(),
|
||||
),
|
||||
SizedBox(
|
||||
height: 28,
|
||||
),
|
||||
Expanded(child: TradeHistoryPanel())
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TransactionRow extends StatelessWidget {
|
||||
TransactionRow(
|
||||
{this.direction,
|
||||
this.formattedDate,
|
||||
this.formattedAmount,
|
||||
this.formattedFiatAmount,
|
||||
this.isPending,
|
||||
@required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final TransactionDirection direction;
|
||||
final String formattedDate;
|
||||
final String formattedAmount;
|
||||
final String formattedFiatAmount;
|
||||
final bool isPending;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 14, bottom: 14, left: 20, right: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: PaletteDark.darkGrey,
|
||||
width: 0.5,
|
||||
style: BorderStyle.solid))),
|
||||
child: Row(children: <Widget>[
|
||||
Image.asset(
|
||||
direction == TransactionDirection.incoming
|
||||
? 'assets/images/transaction_incoming.png'
|
||||
: 'assets/images/transaction_outgoing.png',
|
||||
height: 25,
|
||||
width: 25),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(direction == TransactionDirection.incoming
|
||||
? S.of(context).received
|
||||
: S.of(context).sent) +
|
||||
(isPending ? S.of(context).pending : ''),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subhead
|
||||
.color)),
|
||||
Text(formattedAmount,
|
||||
style: const TextStyle(
|
||||
fontSize: 16, color: Palette.purpleBlue))
|
||||
]),
|
||||
SizedBox(height: 6),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(formattedDate,
|
||||
style: const TextStyle(
|
||||
fontSize: 13, color: Palette.blueGrey)),
|
||||
Text(formattedFiatAmount,
|
||||
style: const TextStyle(
|
||||
fontSize: 14, color: Palette.blueGrey))
|
||||
]),
|
||||
],
|
||||
),
|
||||
))
|
||||
]),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,29 @@ import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
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';
|
||||
|
||||
class WalletMenu {
|
||||
WalletMenu(this.context);
|
||||
|
||||
final List<String> items = [
|
||||
S.current.reconnect,
|
||||
S.current.rescan,
|
||||
S.current.wallets,
|
||||
S.current.nodes,
|
||||
S.current.show_seed,
|
||||
S.current.show_keys,
|
||||
S.current.accounts,
|
||||
S.current.address_book_menu
|
||||
S.current.address_book_menu,
|
||||
S.current.settings_title
|
||||
];
|
||||
|
||||
final List<Image> images = [
|
||||
Image.asset('assets/images/reconnect.png'),
|
||||
Image.asset('assets/images/wallet.png'),
|
||||
Image.asset('assets/images/nodes.png'),
|
||||
Image.asset('assets/images/eye.png'),
|
||||
Image.asset('assets/images/key.png'),
|
||||
Image.asset('assets/images/open_book.png'),
|
||||
Image.asset('assets/images/settings.png'),
|
||||
];
|
||||
|
||||
final BuildContext context;
|
||||
@@ -26,11 +37,10 @@ class WalletMenu {
|
||||
_presentReconnectAlert(context);
|
||||
break;
|
||||
case 1:
|
||||
Navigator.of(context).pushNamed(Routes.rescan);
|
||||
Navigator.of(context).pushNamed(Routes.walletList);
|
||||
break;
|
||||
case 2:
|
||||
Navigator.of(context).pushNamed(Routes.walletList);
|
||||
|
||||
Navigator.of(context).pushNamed(Routes.nodeList);
|
||||
break;
|
||||
case 3:
|
||||
Navigator.of(context).pushNamed(Routes.auth,
|
||||
@@ -49,10 +59,10 @@ class WalletMenu {
|
||||
: null);
|
||||
break;
|
||||
case 5:
|
||||
Navigator.of(context).pushNamed(Routes.accountList);
|
||||
Navigator.of(context).pushNamed(Routes.addressBook);
|
||||
break;
|
||||
case 6:
|
||||
Navigator.of(context).pushNamed(Routes.addressBook);
|
||||
Navigator.of(context).pushNamed(Routes.settings);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -65,23 +75,16 @@ class WalletMenu {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
S.of(context).reconnection,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: Text(S.of(context).reconnect_alert_text),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
walletStore.reconnect();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(S.of(context).ok))
|
||||
],
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).reconnection,
|
||||
alertContent: S.of(context).reconnect_alert_text,
|
||||
leftButtonText: S.of(context).ok,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
walletStore.reconnect();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
|
||||
class ButtonHeader extends SliverPersistentHeaderDelegate {
|
||||
final sendImage = Image.asset('assets/images/send.png');
|
||||
final exchangeImage = Image.asset('assets/images/exchange.png');
|
||||
final buyImage = Image.asset('assets/images/coins.png');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
final actionListStore = Provider.of<ActionListStore>(context);
|
||||
final historyPanelWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
Image filterButton;
|
||||
|
||||
if (_themeChanger.getTheme() == Themes.darkTheme) {
|
||||
filterButton = Image.asset('assets/images/filter_button.png');
|
||||
} else {
|
||||
filterButton = Image.asset('assets/images/filter_light_button.png');
|
||||
}
|
||||
|
||||
double buttonsOpacity = 1 - shrinkOffset / (maxExtent - minExtent);
|
||||
double buttonsHeight = maxExtent - minExtent - shrinkOffset;
|
||||
|
||||
buttonsOpacity = buttonsOpacity >= 0 ? buttonsOpacity : 0;
|
||||
buttonsHeight = buttonsHeight >= 0 ? buttonsHeight : 0;
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
overflow: Overflow.visible,
|
||||
children: <Widget>[
|
||||
Opacity(
|
||||
opacity: buttonsOpacity,
|
||||
child: Container(
|
||||
height: buttonsHeight,
|
||||
padding: EdgeInsets.only(left: 44, right: 44),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: actionButton(
|
||||
context: context,
|
||||
image: sendImage,
|
||||
title: S.of(context).send,
|
||||
route: Routes.send
|
||||
)
|
||||
),
|
||||
Flexible(
|
||||
child: actionButton(
|
||||
context: context,
|
||||
image: exchangeImage,
|
||||
title: S.of(context).exchange,
|
||||
route: Routes.exchange
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: buttonsHeight,
|
||||
left: 0,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
|
||||
child: Container(
|
||||
width: historyPanelWidth,
|
||||
height: 66,
|
||||
padding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 10),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).transactions,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
child: PopupMenuButton<int>(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
enabled: false,
|
||||
value: -1,
|
||||
child: Text(S.of(context).transactions,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color))),
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).incoming),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.transactionFilterStore
|
||||
.displayIncoming,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.transactionFilterStore
|
||||
.toggleIncoming(),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).outgoing),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.transactionFilterStore
|
||||
.displayOutgoing,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.transactionFilterStore
|
||||
.toggleOutgoing(),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child:
|
||||
Text(S.of(context).transactions_by_date)),
|
||||
PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
enabled: false,
|
||||
value: -1,
|
||||
child: Text(S.of(context).trades,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color))),
|
||||
PopupMenuItem(
|
||||
value: 3,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('XMR.TO'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayXMRTO,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.xmrto),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 4,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('Change.NOW'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayChangeNow,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.changeNow),
|
||||
)
|
||||
]))),
|
||||
PopupMenuItem(
|
||||
value: 5,
|
||||
child: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text('MorphToken'),
|
||||
Checkbox(
|
||||
value: actionListStore
|
||||
.tradeFilterStore
|
||||
.displayMorphToken,
|
||||
onChanged: (value) =>
|
||||
actionListStore
|
||||
.tradeFilterStore
|
||||
.toggleDisplayExchange(
|
||||
ExchangeProviderDescription
|
||||
.morphToken),
|
||||
)
|
||||
])))
|
||||
],
|
||||
child: filterButton,
|
||||
onSelected: (item) async {
|
||||
if (item == 2) {
|
||||
final List<DateTime> picked =
|
||||
await date_rage_picker.showDatePicker(
|
||||
context: context,
|
||||
initialFirstDate: DateTime.now()
|
||||
.subtract(Duration(days: 1)),
|
||||
initialLastDate: (DateTime.now()),
|
||||
firstDate: DateTime(2015),
|
||||
lastDate: DateTime.now()
|
||||
.add(Duration(days: 1)));
|
||||
|
||||
if (picked != null && picked.length == 2) {
|
||||
actionListStore.transactionFilterStore
|
||||
.changeStartDate(picked.first);
|
||||
actionListStore.transactionFilterStore
|
||||
.changeEndDate(picked.last);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => 174;
|
||||
|
||||
@override
|
||||
double get minExtent => 66;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
|
||||
|
||||
Widget actionButton({
|
||||
BuildContext context,
|
||||
@required Image image,
|
||||
@required String title,
|
||||
@required String route}) {
|
||||
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (route.isNotEmpty) {
|
||||
Navigator.of(context, rootNavigator: true).pushNamed(route);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
height: 48,
|
||||
width: 48,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryTextTheme.subhead.color,
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
child: image,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+18
-8
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -20,8 +19,8 @@ class DateSectionRaw extends StatelessWidget {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final currentLanguage = settingsStore.languageCode;
|
||||
final dateSectionDateFormat = settingsStore.getCurrentDateFormat(
|
||||
formatUSA: "MMM d",
|
||||
formatDefault: "d MMM");
|
||||
formatUSA: "yyyy MMM d",
|
||||
formatDefault: "d MMM yyyy");
|
||||
var title = "";
|
||||
|
||||
if (isToday) {
|
||||
@@ -35,11 +34,22 @@ class DateSectionRaw extends StatelessWidget {
|
||||
title = dateSectionDateFormat.format(date);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Center(
|
||||
child: Text(title,
|
||||
style: TextStyle(fontSize: 16, color: Palette.wildDarkBlue))),
|
||||
return Container(
|
||||
height: 36,
|
||||
padding: EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: Theme.of(context).backgroundColor
|
||||
),
|
||||
),
|
||||
child: Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.headline.color
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MenuWidget extends StatefulWidget {
|
||||
@override
|
||||
MenuWidgetState createState() => MenuWidgetState();
|
||||
}
|
||||
|
||||
class MenuWidgetState extends State<MenuWidget> {
|
||||
final moneroIcon = Image.asset('assets/images/monero.png');
|
||||
final largeScreen = 731;
|
||||
|
||||
double menuWidth;
|
||||
double screenWidth;
|
||||
double screenHeight;
|
||||
double opacity;
|
||||
bool isDraw;
|
||||
|
||||
double headerHeight;
|
||||
double tileHeight;
|
||||
double fromTopEdge;
|
||||
double fromBottomEdge;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
menuWidth = 0;
|
||||
screenWidth = 0;
|
||||
screenHeight = 0;
|
||||
opacity = 0;
|
||||
isDraw = false;
|
||||
|
||||
headerHeight = 120;
|
||||
tileHeight = 75;
|
||||
fromTopEdge = 50;
|
||||
fromBottomEdge = 30;
|
||||
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||
}
|
||||
|
||||
void afterLayout(dynamic _) {
|
||||
screenWidth = MediaQuery.of(context).size.width;
|
||||
screenHeight = MediaQuery.of(context).size.height;
|
||||
|
||||
setState(() {
|
||||
menuWidth = screenWidth;
|
||||
opacity = 1;
|
||||
|
||||
if (screenHeight > largeScreen) {
|
||||
final scale = screenHeight / largeScreen;
|
||||
tileHeight *= scale;
|
||||
headerHeight *= scale;
|
||||
fromTopEdge *= scale;
|
||||
fromBottomEdge *= scale;
|
||||
}
|
||||
});
|
||||
|
||||
Timer(Duration(milliseconds: 350), () =>
|
||||
setState(() => isDraw = true)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletMenu = WalletMenu(context);
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final itemCount = walletMenu.items.length;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
child: isDraw
|
||||
? Container(
|
||||
height: 60,
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(2)),
|
||||
color: Theme.of(context).hintColor //
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: 60,
|
||||
width: 4,
|
||||
)
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
alignment: Alignment.centerRight,
|
||||
child: AnimatedContainer(
|
||||
alignment: Alignment.centerLeft,
|
||||
width: menuWidth,
|
||||
height: double.infinity,
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.fastOutSlowIn,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)),
|
||||
color: Theme.of(context).primaryTextTheme.display1.color.withOpacity(opacity)
|
||||
),
|
||||
child: isDraw
|
||||
? ListView.separated(
|
||||
itemBuilder: (_, index) {
|
||||
|
||||
if (index == 0) {
|
||||
return Container(
|
||||
height: headerHeight,
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
top: fromTopEdge,
|
||||
right: 24,
|
||||
bottom: fromBottomEdge),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(24)),
|
||||
color: Theme.of(context).primaryTextTheme.display2.color
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
moneroIcon,
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
walletStore.name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
fontFamily: 'Lato',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
),
|
||||
Text(
|
||||
walletStore.account.label,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
decoration: TextDecoration.none,
|
||||
fontFamily: 'Lato',
|
||||
fontSize: 12
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
index -= 1;
|
||||
final item = walletMenu.items[index];
|
||||
final image = walletMenu.images[index] ?? Offstage();
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
walletMenu.action(index);
|
||||
},
|
||||
child: index == itemCount - 1
|
||||
? Container(
|
||||
height: headerHeight,
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: fromBottomEdge,
|
||||
bottom: fromTopEdge),
|
||||
alignment: Alignment.topLeft,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)),
|
||||
color: Theme.of(context).primaryTextTheme.display1.color,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
decoration: TextDecoration.none,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
fontFamily: 'Lato',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: tileHeight,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
color: Theme.of(context).primaryTextTheme.display1.color,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
decoration: TextDecoration.none,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
fontFamily: 'Lato',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) =>
|
||||
Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
itemCount: itemCount + 1)
|
||||
: Offstage()
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/date_section_item.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart';
|
||||
import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'date_section_raw.dart';
|
||||
import 'trade_row.dart';
|
||||
import 'transaction_raw.dart';
|
||||
import 'button_header.dart';
|
||||
|
||||
class TradeHistoryPanel extends StatefulWidget {
|
||||
@override
|
||||
TradeHistoryPanelState createState() => TradeHistoryPanelState();
|
||||
}
|
||||
|
||||
class TradeHistoryPanelState extends State<TradeHistoryPanel> {
|
||||
final _listObserverKey = GlobalKey();
|
||||
final _listKey = GlobalKey();
|
||||
|
||||
double panelHeight;
|
||||
double screenHeight;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
panelHeight = 0;
|
||||
screenHeight = 0;
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||
}
|
||||
|
||||
void afterLayout(dynamic _) {
|
||||
screenHeight = MediaQuery.of(context).size.height;
|
||||
setState(() {
|
||||
panelHeight = screenHeight;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final actionListStore = Provider.of<ActionListStore>(context);
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final transactionDateFormat = DateFormat("HH:mm");
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: AnimatedContainer(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: panelHeight,
|
||||
duration: Duration(milliseconds: 1000),
|
||||
curve: Curves.fastOutSlowIn,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverPersistentHeader(
|
||||
delegate: ButtonHeader(),
|
||||
pinned: true,
|
||||
floating: false,
|
||||
),
|
||||
Observer(
|
||||
key: _listObserverKey,
|
||||
builder: (_) {
|
||||
final items = actionListStore.items == null
|
||||
? <String>[]
|
||||
: actionListStore.items;
|
||||
final itemsCount = items.length + 1;
|
||||
final symbol = settingsStore.fiatCurrency.toString();
|
||||
double freeSpaceHeight = MediaQuery.of(context).size.height - 496;
|
||||
|
||||
return SliverList(
|
||||
key: _listKey,
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
|
||||
if (index == itemsCount - 1) {
|
||||
freeSpaceHeight = freeSpaceHeight >= 0 ? freeSpaceHeight : 0;
|
||||
|
||||
return Container(
|
||||
height: freeSpaceHeight,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
final item = items[index];
|
||||
|
||||
if (item is DateSectionItem) {
|
||||
freeSpaceHeight -= 38;
|
||||
return DateSectionRaw(date: item.date);
|
||||
}
|
||||
|
||||
if (item is TransactionListItem) {
|
||||
freeSpaceHeight -= 62;
|
||||
final transaction = item.transaction;
|
||||
final savedDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final formattedAmount =
|
||||
savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: transaction.amountFormatted();
|
||||
final formattedFiatAmount =
|
||||
savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: transaction.fiatAmount(); // symbol ???
|
||||
|
||||
return TransactionRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.transactionDetails,
|
||||
arguments: transaction),
|
||||
direction: transaction.direction,
|
||||
formattedDate:
|
||||
transactionDateFormat.format(transaction.date),
|
||||
formattedAmount: formattedAmount,
|
||||
formattedFiatAmount: formattedFiatAmount,
|
||||
isPending: transaction.isPending);
|
||||
}
|
||||
|
||||
if (item is TradeListItem) {
|
||||
freeSpaceHeight -= 62;
|
||||
final trade = item.trade;
|
||||
final savedDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final formattedAmount = trade.amount != null
|
||||
? savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: trade.amountFormatted()
|
||||
: trade.amount;
|
||||
|
||||
return TradeRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate:
|
||||
transactionDateFormat.format(trade.createdAt),
|
||||
formattedAmount: formattedAmount);
|
||||
}
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor
|
||||
);
|
||||
},
|
||||
|
||||
childCount: itemsCount
|
||||
)
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+28
-21
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||
|
||||
@@ -21,25 +20,33 @@ class TradeRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final amountCrypto = provider == ExchangeProviderDescription.xmrto
|
||||
? to.toString()
|
||||
: from.toString();
|
||||
final amountCrypto = from.toString();
|
||||
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 14, bottom: 14, left: 20, right: 20),
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: PaletteDark.darkGrey,
|
||||
width: 0.5,
|
||||
style: BorderStyle.solid))),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: Theme.of(context).backgroundColor
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20),
|
||||
child: Row(children: <Widget>[
|
||||
_getPoweredImage(provider),
|
||||
Container(
|
||||
height: 36,
|
||||
width: 36,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).backgroundColor
|
||||
),
|
||||
child: _getPoweredImage(provider),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
@@ -48,23 +55,23 @@ class TradeRow extends StatelessWidget {
|
||||
Text('${from.toString()} → ${to.toString()}',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subhead
|
||||
.color)),
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
)),
|
||||
formattedAmount != null
|
||||
? Text(formattedAmount + ' ' + amountCrypto,
|
||||
style: const TextStyle(
|
||||
fontSize: 16, color: Palette.purpleBlue))
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
))
|
||||
: Container()
|
||||
]),
|
||||
SizedBox(height: 6),
|
||||
SizedBox(height: 5),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(createdAtFormattedDate,
|
||||
style: const TextStyle(
|
||||
fontSize: 13, color: Palette.blueGrey))
|
||||
style: TextStyle(
|
||||
fontSize: 14, color: Theme.of(context).primaryTextTheme.headline.color))
|
||||
]),
|
||||
],
|
||||
),
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TransactionRow extends StatelessWidget {
|
||||
TransactionRow(
|
||||
{this.direction,
|
||||
this.formattedDate,
|
||||
this.formattedAmount,
|
||||
this.formattedFiatAmount,
|
||||
this.isPending,
|
||||
@required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final TransactionDirection direction;
|
||||
final String formattedDate;
|
||||
final String formattedAmount;
|
||||
final String formattedFiatAmount;
|
||||
final bool isPending;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: Theme.of(context).backgroundColor
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20),
|
||||
child: Row(children: <Widget>[
|
||||
Container(
|
||||
height: 36,
|
||||
width: 36,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).primaryTextTheme.display3.color
|
||||
),
|
||||
child: Image.asset(
|
||||
direction == TransactionDirection.incoming
|
||||
? 'assets/images/down_arrow.png'
|
||||
: 'assets/images/up_arrow.png'),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(direction == TransactionDirection.incoming
|
||||
? S.of(context).received
|
||||
: S.of(context).sent) +
|
||||
(isPending ? S.of(context).pending : ''),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
)),
|
||||
Text(direction == TransactionDirection.incoming
|
||||
? formattedAmount
|
||||
: '- ' + formattedAmount,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
))
|
||||
]),
|
||||
SizedBox(height: 5,),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(formattedDate,
|
||||
style: TextStyle(
|
||||
fontSize: 14, color: Theme.of(context).primaryTextTheme.headline.color)),
|
||||
Text(direction == TransactionDirection.incoming
|
||||
? formattedFiatAmount
|
||||
: '- ' + formattedFiatAmount,
|
||||
style: TextStyle(
|
||||
fontSize: 14, color: Theme.of(context).primaryTextTheme.headline.color))
|
||||
]),
|
||||
],
|
||||
),
|
||||
))
|
||||
]),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
import 'dart:async';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/src/stores/balance/balance_store.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
||||
class WalletCard extends StatefulWidget {
|
||||
@override
|
||||
WalletCardState createState() => WalletCardState();
|
||||
}
|
||||
|
||||
class WalletCardState extends State<WalletCard> {
|
||||
final _syncingObserverKey = GlobalKey();
|
||||
final _balanceObserverKey = GlobalKey();
|
||||
final _addressObserverKey = GlobalKey();
|
||||
|
||||
double cardWidth;
|
||||
double cardHeight;
|
||||
double screenWidth;
|
||||
double opacity;
|
||||
bool isDraw;
|
||||
bool isFrontSide;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
cardWidth = 0;
|
||||
cardHeight = 220;
|
||||
screenWidth = 0;
|
||||
opacity = 0;
|
||||
isDraw = false;
|
||||
isFrontSide = true;
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||
}
|
||||
|
||||
void afterLayout(dynamic _) {
|
||||
screenWidth = MediaQuery.of(context).size.width - 20;
|
||||
setState(() {
|
||||
cardWidth = screenWidth;
|
||||
opacity = 1;
|
||||
});
|
||||
Timer(Duration(milliseconds: 500), () =>
|
||||
setState(() => isDraw = true)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Color> colorsSync = [
|
||||
Theme.of(context).cardTheme.color,
|
||||
Theme.of(context).hoverColor
|
||||
];
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: cardHeight,
|
||||
alignment: Alignment.centerRight,
|
||||
child: AnimatedContainer(
|
||||
alignment: Alignment.centerLeft,
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.fastOutSlowIn,
|
||||
padding: EdgeInsets.only(
|
||||
top: 1,
|
||||
left: 1,
|
||||
bottom: 1
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
|
||||
color: Theme.of(context).focusColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: PaletteDark.darkNightBlue.withOpacity(0.5),
|
||||
blurRadius: 8,
|
||||
offset: Offset(5, 5))
|
||||
]
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
|
||||
child: Container(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
color: Theme.of(context).cardColor,
|
||||
child: InkWell(
|
||||
onTap: () => setState(() => isFrontSide = !isFrontSide),
|
||||
child: isFrontSide
|
||||
? frontSide(colorsSync)
|
||||
: backSide(colorsSync)
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget frontSide(List<Color> colorsSync) {
|
||||
final syncStore = Provider.of<SyncStore>(context);
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final balanceStore = Provider.of<BalanceStore>(context);
|
||||
final triangleButton = Image.asset('assets/images/triangle.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
|
||||
return Observer(
|
||||
key: _syncingObserverKey,
|
||||
builder: (_) {
|
||||
final status = syncStore.status;
|
||||
final statusText = status.title();
|
||||
final progress = syncStore.status.progress();
|
||||
final indicatorWidth = progress * cardWidth;
|
||||
|
||||
String shortAddress = walletStore.subaddress.address;
|
||||
shortAddress = shortAddress.replaceRange(4, shortAddress.length - 4, '...');
|
||||
|
||||
var descriptionText = '';
|
||||
|
||||
if (status is SyncingSyncStatus) {
|
||||
descriptionText = S
|
||||
.of(context)
|
||||
.Blocks_remaining(
|
||||
syncStore.status.toString());
|
||||
}
|
||||
|
||||
if (status is FailedSyncStatus) {
|
||||
descriptionText = S
|
||||
.of(context)
|
||||
.please_try_to_connect_to_another_node;
|
||||
}
|
||||
|
||||
return Container(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: cardHeight,
|
||||
width: indicatorWidth,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
|
||||
gradient: LinearGradient(
|
||||
colors: colorsSync,
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter
|
||||
)
|
||||
),
|
||||
),
|
||||
progress != 1
|
||||
? Positioned(
|
||||
left: indicatorWidth,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
width: 1,
|
||||
height: cardHeight,
|
||||
color: Theme.of(context).focusColor,
|
||||
)
|
||||
)
|
||||
: Offstage(),
|
||||
isDraw ? Positioned(
|
||||
left: 20,
|
||||
right: 20,
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
walletStore.name,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
triangleButton
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Text(
|
||||
walletStore.account.label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: 98,
|
||||
height: 32,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).accentTextTheme.subtitle.backgroundColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(16))
|
||||
),
|
||||
child: Text(
|
||||
shortAddress,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
status is SyncedSyncStatus
|
||||
? Observer(
|
||||
key: _balanceObserverKey,
|
||||
builder: (_) {
|
||||
final balanceDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final symbol = settingsStore
|
||||
.fiatCurrency
|
||||
.toString();
|
||||
var balance = '---';
|
||||
var fiatBalance = '---';
|
||||
|
||||
if (balanceDisplayMode ==
|
||||
BalanceDisplayMode.availableBalance) {
|
||||
balance =
|
||||
balanceStore.unlockedBalance ??
|
||||
'0.0';
|
||||
fiatBalance =
|
||||
'$symbol ${balanceStore.fiatUnlockedBalance}';
|
||||
}
|
||||
|
||||
if (balanceDisplayMode ==
|
||||
BalanceDisplayMode.fullBalance) {
|
||||
balance =
|
||||
balanceStore.fullBalance ?? '0.0';
|
||||
fiatBalance =
|
||||
'$symbol ${balanceStore.fiatFullBalance}';
|
||||
}
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
balanceDisplayMode.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
balance,
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
fiatBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
)
|
||||
: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
descriptionText,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget backSide(List<Color> colorsSync) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final rightArrow = Image.asset('assets/images/right_arrow.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
double messageBoxHeight = 0;
|
||||
double messageBoxWidth = cardWidth - 10;
|
||||
|
||||
return Observer(
|
||||
key: _addressObserverKey,
|
||||
builder: (_) {
|
||||
return Container(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
alignment: Alignment.topCenter,
|
||||
child: Stack(
|
||||
alignment: Alignment.topRight,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
padding: EdgeInsets.only(left: 20, right: 20, top: 30, bottom: 30),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
|
||||
gradient: LinearGradient(
|
||||
colors: colorsSync,
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter
|
||||
)
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 90,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.current.card_address,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: walletStore.subaddress.address));
|
||||
_addressObserverKey.currentState.setState(() {
|
||||
messageBoxHeight = 20;
|
||||
messageBoxWidth = cardWidth;
|
||||
});
|
||||
Timer(Duration(milliseconds: 1000), () {
|
||||
try {
|
||||
_addressObserverKey.currentState.setState(() {
|
||||
messageBoxHeight = 0;
|
||||
messageBoxWidth = cardWidth - 10;
|
||||
});
|
||||
} catch(e) {
|
||||
print('${e.toString()}');
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
walletStore.subaddress.address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Container(
|
||||
width: 90,
|
||||
height: 90,
|
||||
child: QrImage(
|
||||
data: walletStore.subaddress.address,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 44,
|
||||
padding: EdgeInsets.only(left: 20, right: 20),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(22)),
|
||||
color: Theme.of(context).primaryTextTheme.overline.color
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () => Navigator.of(context,
|
||||
rootNavigator: true)
|
||||
.pushNamed(Routes.receive),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).accounts_subaddresses,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
rightArrow
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
AnimatedContainer(
|
||||
width: messageBoxWidth,
|
||||
height: messageBoxHeight,
|
||||
alignment: Alignment.center,
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.fastOutSlowIn,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10)),
|
||||
color: Colors.green
|
||||
),
|
||||
child: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,17 @@ import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class DisclaimerPage extends BasePage {
|
||||
DisclaimerPage({this.isReadOnly = false});
|
||||
|
||||
final bool isReadOnly;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => false;
|
||||
|
||||
@override
|
||||
String get title => 'Terms of Use';
|
||||
|
||||
@@ -34,7 +32,7 @@ class DisclaimerPageBody extends StatefulWidget {
|
||||
class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
DisclaimerBodyState(this._isAccepted);
|
||||
|
||||
static const xmrtoUrl = 'https://xmr.to/app_static/html/tos.html';
|
||||
static const xmrtoUrl = 'https://xmr.to/terms-of-service';
|
||||
static const changenowUrl = 'https://changenow.io/terms-of-use';
|
||||
static const morphUrl = 'http://morphtoken.com/terms';
|
||||
|
||||
@@ -55,22 +53,11 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
'Terms and conditions',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: Text(
|
||||
'By using this app, you agree to the Terms of Agreement set forth to below',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('OK')),
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: 'Terms and conditions',
|
||||
alertContent: 'By using this app, you agree to the Terms of Agreement set forth to below',
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -86,245 +73,255 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
SizedBox(height: 10.0),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.only(left: 25.0, right: 25.0),
|
||||
child: Column(
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
SizedBox(height: 10.0),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Terms and conditions',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0,
|
||||
fontWeight: FontWeight.bold),
|
||||
fontSize: 20.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? SizedBox(
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? SizedBox(
|
||||
height: 20.0,
|
||||
)
|
||||
: Offstage(),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Legal Disclaimer\nAnd\nTerms of Use',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
_fileText,
|
||||
style: TextStyle(fontSize: 12.0),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Other Terms and Conditions',
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(xmrtoUrl),
|
||||
child: Text(
|
||||
xmrtoUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(changenowUrl),
|
||||
child: Text(
|
||||
changenowUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(morphUrl),
|
||||
child: Text(
|
||||
morphUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
height: 12.0,
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).backgroundColor.withOpacity(0.0),
|
||||
Theme.of(context).backgroundColor,
|
||||
: Offstage(),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Legal Disclaimer\nAnd\nTerms of Use',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
begin: FractionalOffset.topCenter,
|
||||
end: FractionalOffset.bottomCenter,
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
_fileText,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Other Terms and Conditions',
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(xmrtoUrl),
|
||||
child: Text(
|
||||
xmrtoUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(changenowUrl),
|
||||
child: Text(
|
||||
changenowUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => launchUrl(morphUrl),
|
||||
child: Text(
|
||||
morphUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
height: 12.0,
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).backgroundColor.withOpacity(0.0),
|
||||
Theme.of(context).backgroundColor,
|
||||
],
|
||||
begin: FractionalOffset.topCenter,
|
||||
end: FractionalOffset.bottomCenter,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
if (!widget.isReadOnly) ...[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_checked = !_checked;
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 24.0,
|
||||
width: 24.0,
|
||||
margin: EdgeInsets.only(
|
||||
right: 10.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color, width: 1.0),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0)),
|
||||
color: Theme.of(context).backgroundColor),
|
||||
child: _checked
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: Colors.blue,
|
||||
size: 20.0,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
Text(
|
||||
'I agree to Terms of Use',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: _checked ? () {} : null,
|
||||
text: 'Accept',
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
_isAccepted
|
||||
? SizedBox(
|
||||
height: 24.0,
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
)),
|
||||
if (!widget.isReadOnly) ...[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 25.0, top: 10.0, right: 25.0, bottom: 10.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_checked = !_checked;
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 25.0,
|
||||
width: 25.0,
|
||||
margin: EdgeInsets.only(
|
||||
right: 10.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Palette.lightGrey, width: 1.0),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0)),
|
||||
color: Theme.of(context).backgroundColor),
|
||||
child: _checked
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: Colors.blue,
|
||||
size: 20.0,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
Text(
|
||||
'I agree to Terms of Use',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 25.0, right: 25.0, bottom: 25.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: _checked ? () {} : null,
|
||||
text: 'Accept',
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
_isAccepted
|
||||
? SizedBox(
|
||||
height: 20.0,
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,31 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/base_exchange_widget.dart';
|
||||
|
||||
class ExchangePage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.exchange;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
Color get backgroundLightColor => Palette.darkLavender;
|
||||
|
||||
final Image arrowBottomPurple =
|
||||
Image.asset('assets/images/arrow_bottom_purple_icon.png', height: 8);
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.moderateBlue;
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
final exchangeStore = Provider.of<ExchangeStore>(context);
|
||||
|
||||
return FlatButton(
|
||||
onPressed: () => _presentProviderPicker(context),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(S.of(context).exchange,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
SizedBox(width: 5),
|
||||
arrowBottomPurple
|
||||
]),
|
||||
Observer(
|
||||
builder: (_) => Text('${exchangeStore.provider.title}',
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.headline.color)))
|
||||
],
|
||||
),
|
||||
);
|
||||
return PresentProviderPicker(exchangeStore: exchangeStore);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -72,14 +34,16 @@ class ExchangePage extends BasePage {
|
||||
|
||||
return ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: FlatButton(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: Text(
|
||||
S.of(context).clear,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentTextTheme.caption.color,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16),
|
||||
fontSize: 14),
|
||||
),
|
||||
onPressed: () => exchangeStore.reset()),
|
||||
);
|
||||
@@ -87,21 +51,6 @@ class ExchangePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => ExchangeForm();
|
||||
|
||||
void _presentProviderPicker(BuildContext context) {
|
||||
final exchangeStore = Provider.of<ExchangeStore>(context);
|
||||
final items = exchangeStore.providersForCurrentPair();
|
||||
final selectedItem = items.indexOf(exchangeStore.provider);
|
||||
|
||||
showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).change_exchange_provider,
|
||||
onItemSelected: (ExchangeProvider provider) =>
|
||||
exchangeStore.changeProvider(provider: provider)),
|
||||
context: context);
|
||||
}
|
||||
}
|
||||
|
||||
class ExchangeForm extends StatefulWidget {
|
||||
@@ -110,362 +59,18 @@ class ExchangeForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class ExchangeFormState extends State<ExchangeForm> {
|
||||
final depositKey = GlobalKey<ExchangeCardState>();
|
||||
final receiveKey = GlobalKey<ExchangeCardState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
var _isReactionsSet = false;
|
||||
|
||||
final Image arrowBottomPurple = Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
height: 8,
|
||||
);
|
||||
final Image arrowBottomCakeGreen = Image.asset(
|
||||
'assets/images/arrow_bottom_cake_green.png',
|
||||
height: 8,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final exchangeStore = Provider.of<ExchangeStore>(context);
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final exchangeTemplateStore = Provider.of<ExchangeTemplateStore>(context);
|
||||
|
||||
final depositWalletName =
|
||||
exchangeStore.depositCurrency == CryptoCurrency.xmr
|
||||
? walletStore.name
|
||||
: null;
|
||||
final receiveWalletName =
|
||||
exchangeStore.receiveCurrency == CryptoCurrency.xmr
|
||||
? walletStore.name
|
||||
: null;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => _setReactions(context, exchangeStore, walletStore));
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 20, right: 20),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10, bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).you_will_send,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
height: 1.1,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
ExchangeCard(
|
||||
key: depositKey,
|
||||
initialCurrency: exchangeStore.depositCurrency,
|
||||
initialWalletName: depositWalletName,
|
||||
initialAddress:
|
||||
exchangeStore.depositCurrency == walletStore.type
|
||||
? walletStore.address
|
||||
: null,
|
||||
initialIsAmountEditable: true,
|
||||
initialIsAddressEditable: true,
|
||||
isAmountEstimated: false,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) =>
|
||||
exchangeStore.changeDepositCurrency(currency: currency),
|
||||
imageArrow: arrowBottomPurple,
|
||||
currencyValueValidator: (value) {
|
||||
exchangeStore.validateCryptoCurrency(value);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
addressTextFieldValidator: (value) {
|
||||
exchangeStore.validateAddress(value,
|
||||
cryptoCurrency: exchangeStore.depositCurrency);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
),
|
||||
SizedBox(height: 35),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).you_will_get,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
height: 1.1,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.title.color),
|
||||
)),
|
||||
Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
key: receiveKey,
|
||||
initialCurrency: exchangeStore.receiveCurrency,
|
||||
initialWalletName: receiveWalletName,
|
||||
initialAddress:
|
||||
exchangeStore.receiveCurrency == walletStore.type
|
||||
? walletStore.address
|
||||
: null,
|
||||
initialIsAmountEditable: false,
|
||||
initialIsAddressEditable: true,
|
||||
isAmountEstimated: true,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) => exchangeStore
|
||||
.changeReceiveCurrency(currency: currency),
|
||||
imageArrow: arrowBottomCakeGreen,
|
||||
currencyValueValidator: (value) {
|
||||
exchangeStore.validateCryptoCurrency(value);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
addressTextFieldValidator: (value) {
|
||||
exchangeStore.validateAddress(value,
|
||||
cryptoCurrency: exchangeStore.receiveCurrency);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(top: 35, left: 20, right: 20),
|
||||
bottomSection: Column(children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 15),
|
||||
child: Observer(builder: (_) {
|
||||
final description =
|
||||
exchangeStore.provider is XMRTOExchangeProvider
|
||||
? S.of(context).amount_is_guaranteed
|
||||
: S.of(context).amount_is_estimate;
|
||||
return Center(
|
||||
child: Text(
|
||||
description,
|
||||
style: TextStyle(color: Palette.blueGrey, fontSize: 12),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
exchangeStore.createTrade();
|
||||
}
|
||||
},
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
isLoading: exchangeStore.tradeState is TradeIsCreating,
|
||||
)),
|
||||
Observer(builder: (_) {
|
||||
final title = exchangeStore.provider.description.title;
|
||||
var imageSrc = '';
|
||||
|
||||
switch (exchangeStore.provider.description) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
imageSrc = 'assets/images/xmr_btc.png';
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
imageSrc = 'assets/images/change_now.png';
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
imageSrc = 'assets/images/morph_icon.png';
|
||||
break;
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Image.asset(imageSrc),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
S.of(context).powered_by(title),
|
||||
style: TextStyle(fontSize: 14, color: Palette.powered),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
]),
|
||||
));
|
||||
}
|
||||
|
||||
void _setReactions(
|
||||
BuildContext context, ExchangeStore store, WalletStore walletStore) {
|
||||
if (_isReactionsSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
final depositAddressController = depositKey.currentState.addressController;
|
||||
final depositAmountController = depositKey.currentState.amountController;
|
||||
final receiveAddressController = receiveKey.currentState.addressController;
|
||||
final receiveAmountController = receiveKey.currentState.amountController;
|
||||
final limitsState = store.limitsState;
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
final min = limitsState.limits.min != null
|
||||
? limitsState.limits.min.toString()
|
||||
: null;
|
||||
final max = limitsState.limits.max != null
|
||||
? limitsState.limits.max.toString()
|
||||
: null;
|
||||
final key = depositKey;
|
||||
key.currentState.changeLimits(min: min, max: max);
|
||||
}
|
||||
|
||||
_onCurrencyChange(store.receiveCurrency, walletStore, receiveKey);
|
||||
_onCurrencyChange(store.depositCurrency, walletStore, depositKey);
|
||||
|
||||
reaction(
|
||||
(_) => walletStore.name,
|
||||
(String _) => _onWalletNameChange(
|
||||
walletStore, store.receiveCurrency, receiveKey));
|
||||
|
||||
reaction(
|
||||
(_) => walletStore.name,
|
||||
(String _) => _onWalletNameChange(
|
||||
walletStore, store.depositCurrency, depositKey));
|
||||
|
||||
reaction(
|
||||
(_) => store.receiveCurrency,
|
||||
(CryptoCurrency currency) =>
|
||||
_onCurrencyChange(currency, walletStore, receiveKey));
|
||||
|
||||
reaction(
|
||||
(_) => store.depositCurrency,
|
||||
(CryptoCurrency currency) =>
|
||||
_onCurrencyChange(currency, walletStore, depositKey));
|
||||
|
||||
reaction((_) => store.depositAmount, (String amount) {
|
||||
if (depositKey.currentState.amountController.text != amount) {
|
||||
depositKey.currentState.amountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.receiveAmount, (String amount) {
|
||||
if (receiveKey.currentState.amountController.text !=
|
||||
store.receiveAmount) {
|
||||
receiveKey.currentState.amountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.provider, (ExchangeProvider provider) {
|
||||
receiveKey.currentState.isAddressEditable(isEditable: true);
|
||||
receiveKey.currentState.isAmountEditable(isEditable: false);
|
||||
depositKey.currentState.isAddressEditable(isEditable: true);
|
||||
depositKey.currentState.isAmountEditable(isEditable: true);
|
||||
|
||||
receiveKey.currentState.changeIsAmountEstimated(true);
|
||||
});
|
||||
|
||||
reaction((_) => store.tradeState, (ExchangeTradeState state) {
|
||||
if (state is TradeIsCreatedFailure) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
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())
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (state is TradeIsCreatedSuccessfully) {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.exchangeConfirm, arguments: state.trade);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.limitsState, (LimitsState state) {
|
||||
String min;
|
||||
String max;
|
||||
|
||||
if (state is LimitsLoadedSuccessfully) {
|
||||
min = state.limits.min != null ? state.limits.min.toString() : null;
|
||||
max = state.limits.max != null ? state.limits.max.toString() : null;
|
||||
}
|
||||
|
||||
if (state is LimitsLoadedFailure) {
|
||||
min = '0';
|
||||
max = '0';
|
||||
}
|
||||
|
||||
if (state is LimitsIsLoading) {
|
||||
min = '...';
|
||||
max = '...';
|
||||
}
|
||||
|
||||
depositKey.currentState.changeLimits(min: min, max: max);
|
||||
receiveKey.currentState.changeLimits(min: null, max: null);
|
||||
});
|
||||
|
||||
depositAddressController.addListener(
|
||||
() => store.depositAddress = depositAddressController.text);
|
||||
|
||||
depositAmountController.addListener(() {
|
||||
if (depositAmountController.text != store.depositAmount) {
|
||||
store.changeDepositAmount(amount: depositAmountController.text);
|
||||
}
|
||||
});
|
||||
|
||||
receiveAddressController.addListener(
|
||||
() => store.receiveAddress = receiveAddressController.text);
|
||||
|
||||
receiveAmountController.addListener(() {
|
||||
if (receiveAmountController.text != store.receiveAmount) {
|
||||
store.changeReceiveAmount(amount: receiveAmountController.text);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletStore.address, (String address) {
|
||||
if (store.depositCurrency == CryptoCurrency.xmr) {
|
||||
depositKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
|
||||
if (store.receiveCurrency == CryptoCurrency.xmr) {
|
||||
receiveKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
});
|
||||
|
||||
_isReactionsSet = true;
|
||||
}
|
||||
|
||||
void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore,
|
||||
GlobalKey<ExchangeCardState> key) {
|
||||
final isCurrentTypeWallet = currency == walletStore.type;
|
||||
|
||||
key.currentState.changeSelectedCurrency(currency);
|
||||
key.currentState
|
||||
.changeWalletName(isCurrentTypeWallet ? walletStore.name : null);
|
||||
|
||||
key.currentState
|
||||
.changeAddress(address: isCurrentTypeWallet ? walletStore.address : '');
|
||||
|
||||
key.currentState.changeAmount(amount: '');
|
||||
}
|
||||
|
||||
void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency,
|
||||
GlobalKey<ExchangeCardState> key) {
|
||||
final isCurrentTypeWallet = currency == walletStore.type;
|
||||
|
||||
if (isCurrentTypeWallet) {
|
||||
key.currentState.changeWalletName(walletStore.name);
|
||||
key.currentState.addressController.text = walletStore.address;
|
||||
} else if (key.currentState.addressController.text == walletStore.address) {
|
||||
key.currentState.changeWalletName(null);
|
||||
key.currentState.addressController.text = null;
|
||||
}
|
||||
return BaseExchangeWidget(
|
||||
exchangeStore: exchangeStore,
|
||||
walletStore: walletStore,
|
||||
exchangeTemplateStore: exchangeTemplateStore,
|
||||
isTemplate: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/base_exchange_widget.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class ExchangeTemplatePage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.exchange_new_template;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => Palette.darkLavender;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.moderateBlue;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
final exchangeStore = Provider.of<ExchangeStore>(context);
|
||||
|
||||
return PresentProviderPicker(exchangeStore: exchangeStore);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => ExchangeTemplateForm();
|
||||
}
|
||||
|
||||
class ExchangeTemplateForm extends StatefulWidget{
|
||||
@override
|
||||
ExchangeTemplateFormState createState() => ExchangeTemplateFormState();
|
||||
}
|
||||
|
||||
class ExchangeTemplateFormState extends State<ExchangeTemplateForm> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final exchangeStore = Provider.of<ExchangeStore>(context);
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final exchangeTemplateStore = Provider.of<ExchangeTemplateStore>(context);
|
||||
|
||||
return BaseExchangeWidget(
|
||||
exchangeStore: exchangeStore,
|
||||
walletStore: walletStore,
|
||||
exchangeTemplateStore: exchangeTemplateStore,
|
||||
isTemplate: true
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
import 'dart:ui';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_store.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/top_panel.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class BaseExchangeWidget extends StatefulWidget {
|
||||
BaseExchangeWidget({
|
||||
@ required this.exchangeStore,
|
||||
@ required this.walletStore,
|
||||
@ required this.exchangeTemplateStore,
|
||||
@ required this.isTemplate,
|
||||
});
|
||||
|
||||
final ExchangeStore exchangeStore;
|
||||
final WalletStore walletStore;
|
||||
final ExchangeTemplateStore exchangeTemplateStore;
|
||||
final bool isTemplate;
|
||||
|
||||
@override
|
||||
BaseExchangeWidgetState createState() =>
|
||||
BaseExchangeWidgetState(
|
||||
exchangeStore: exchangeStore,
|
||||
walletStore: walletStore,
|
||||
exchangeTemplateStore: exchangeTemplateStore,
|
||||
isTemplate: isTemplate
|
||||
);
|
||||
}
|
||||
|
||||
class BaseExchangeWidgetState extends State<BaseExchangeWidget> {
|
||||
BaseExchangeWidgetState({
|
||||
@ required this.exchangeStore,
|
||||
@ required this.walletStore,
|
||||
@ required this.exchangeTemplateStore,
|
||||
@ required this.isTemplate,
|
||||
});
|
||||
|
||||
final ExchangeStore exchangeStore;
|
||||
final WalletStore walletStore;
|
||||
final ExchangeTemplateStore exchangeTemplateStore;
|
||||
final bool isTemplate;
|
||||
|
||||
final depositKey = GlobalKey<ExchangeCardState>();
|
||||
final receiveKey = GlobalKey<ExchangeCardState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
var _isReactionsSet = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Image arrowBottomPurple = Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
height: 8,
|
||||
);
|
||||
final Image arrowBottomCakeGreen = Image.asset(
|
||||
'assets/images/arrow_bottom_cake_green.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
height: 8,
|
||||
);
|
||||
|
||||
final depositWalletName =
|
||||
exchangeStore.depositCurrency == CryptoCurrency.xmr
|
||||
? walletStore.name
|
||||
: null;
|
||||
final receiveWalletName =
|
||||
exchangeStore.receiveCurrency == CryptoCurrency.xmr
|
||||
? walletStore.name
|
||||
: null;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => _setReactions(context, exchangeStore, walletStore));
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Column(
|
||||
children: <Widget>[
|
||||
TopPanel(
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
edgeInsets: EdgeInsets.only(bottom: 24),
|
||||
widget: Column(
|
||||
children: <Widget>[
|
||||
TopPanel(
|
||||
color: Theme.of(context).accentTextTheme.title.color,
|
||||
widget: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
key: depositKey,
|
||||
title: S.of(context).you_will_send,
|
||||
initialCurrency: exchangeStore.depositCurrency,
|
||||
initialWalletName: depositWalletName,
|
||||
initialAddress:
|
||||
exchangeStore.depositCurrency == walletStore.type
|
||||
? walletStore.address
|
||||
: exchangeStore.depositAddress,
|
||||
initialIsAmountEditable: true,
|
||||
initialIsAddressEditable: exchangeStore.isDepositAddressEnabled,
|
||||
isAmountEstimated: false,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) =>
|
||||
exchangeStore.changeDepositCurrency(currency: currency),
|
||||
imageArrow: arrowBottomPurple,
|
||||
currencyButtonColor: Theme.of(context).accentTextTheme.title.color,
|
||||
addressButtonsColor: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
currencyValueValidator: (value) {
|
||||
exchangeStore.validateCryptoCurrency(value);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
addressTextFieldValidator: (value) {
|
||||
exchangeStore.validateAddress(value,
|
||||
cryptoCurrency: exchangeStore.depositCurrency);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 32, left: 24, right: 24),
|
||||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
key: receiveKey,
|
||||
title: S.of(context).you_will_get,
|
||||
initialCurrency: exchangeStore.receiveCurrency,
|
||||
initialWalletName: receiveWalletName,
|
||||
initialAddress:
|
||||
exchangeStore.receiveCurrency == walletStore.type
|
||||
? walletStore.address
|
||||
: exchangeStore.receiveAddress,
|
||||
initialIsAmountEditable: false,
|
||||
initialIsAddressEditable: exchangeStore.isReceiveAddressEnabled,
|
||||
isAmountEstimated: true,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) => exchangeStore
|
||||
.changeReceiveCurrency(currency: currency),
|
||||
imageArrow: arrowBottomCakeGreen,
|
||||
currencyButtonColor: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
addressButtonsColor: Theme.of(context).accentTextTheme.title.color,
|
||||
currencyValueValidator: (value) {
|
||||
exchangeStore.validateCryptoCurrency(value);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
addressTextFieldValidator: (value) {
|
||||
exchangeStore.validateAddress(value,
|
||||
cryptoCurrency: exchangeStore.receiveCurrency);
|
||||
return exchangeStore.errorMessage;
|
||||
},
|
||||
)),
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
isTemplate
|
||||
? Offstage()
|
||||
: 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
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
isTemplate
|
||||
? Offstage()
|
||||
: Container(
|
||||
height: 40,
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
final itemCount = exchangeTemplateStore.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.exchangeTemplate),
|
||||
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 = exchangeTemplateStore.templates[index];
|
||||
|
||||
return TemplateTile(
|
||||
amount: template.amount,
|
||||
from: template.depositCurrency,
|
||||
to: template.receiveCurrency,
|
||||
onTap: () {
|
||||
applyTemplate(exchangeStore, template);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Column(children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 15),
|
||||
child: Observer(builder: (_) {
|
||||
final description =
|
||||
exchangeStore.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.caption.color,
|
||||
fontSize: 12
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
isTemplate
|
||||
? PrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
exchangeTemplateStore.addTemplate(
|
||||
amount: exchangeStore.depositAmount,
|
||||
depositCurrency: exchangeStore.depositCurrency.toString(),
|
||||
receiveCurrency: exchangeStore.receiveCurrency.toString(),
|
||||
provider: exchangeStore.provider.toString(),
|
||||
depositAddress: exchangeStore.depositAddress,
|
||||
receiveAddress: exchangeStore.receiveAddress
|
||||
);
|
||||
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,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
exchangeStore.createTrade();
|
||||
}
|
||||
},
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white,
|
||||
isLoading: exchangeStore.tradeState is TradeIsCreating,
|
||||
)),
|
||||
]),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
void applyTemplate(ExchangeStore store, ExchangeTemplate template) {
|
||||
store.changeDepositCurrency(currency: CryptoCurrency.fromString(template.depositCurrency));
|
||||
store.changeReceiveCurrency(currency: CryptoCurrency.fromString(template.receiveCurrency));
|
||||
|
||||
switch (template.provider) {
|
||||
case 'XMR.TO':
|
||||
store.changeProvider(provider: store.providerList[0]);
|
||||
break;
|
||||
case 'ChangeNOW':
|
||||
store.changeProvider(provider: store.providerList[1]);
|
||||
break;
|
||||
case 'MorphToken':
|
||||
store.changeProvider(provider: store.providerList[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
store.changeDepositAmount(amount: template.amount);
|
||||
store.depositAddress = template.depositAddress;
|
||||
store.receiveAddress = template.receiveAddress;
|
||||
}
|
||||
|
||||
void _setReactions(
|
||||
BuildContext context, ExchangeStore store, WalletStore walletStore) {
|
||||
if (_isReactionsSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
final depositAddressController = depositKey.currentState.addressController;
|
||||
final depositAmountController = depositKey.currentState.amountController;
|
||||
final receiveAddressController = receiveKey.currentState.addressController;
|
||||
final receiveAmountController = receiveKey.currentState.amountController;
|
||||
final limitsState = store.limitsState;
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
final min = limitsState.limits.min != null
|
||||
? limitsState.limits.min.toString()
|
||||
: null;
|
||||
final max = limitsState.limits.max != null
|
||||
? limitsState.limits.max.toString()
|
||||
: null;
|
||||
final key = depositKey;
|
||||
key.currentState.changeLimits(min: min, max: max);
|
||||
}
|
||||
|
||||
_onCurrencyChange(store.receiveCurrency, walletStore, receiveKey);
|
||||
_onCurrencyChange(store.depositCurrency, walletStore, depositKey);
|
||||
|
||||
reaction(
|
||||
(_) => walletStore.name,
|
||||
(String _) => _onWalletNameChange(
|
||||
walletStore, store.receiveCurrency, receiveKey));
|
||||
|
||||
reaction(
|
||||
(_) => walletStore.name,
|
||||
(String _) => _onWalletNameChange(
|
||||
walletStore, store.depositCurrency, depositKey));
|
||||
|
||||
reaction(
|
||||
(_) => store.receiveCurrency,
|
||||
(CryptoCurrency currency) =>
|
||||
_onCurrencyChange(currency, walletStore, receiveKey));
|
||||
|
||||
reaction(
|
||||
(_) => store.depositCurrency,
|
||||
(CryptoCurrency currency) =>
|
||||
_onCurrencyChange(currency, walletStore, depositKey));
|
||||
|
||||
reaction((_) => store.depositAmount, (String amount) {
|
||||
if (depositKey.currentState.amountController.text != amount) {
|
||||
depositKey.currentState.amountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.depositAddress, (String address) {
|
||||
if (depositKey.currentState.addressController.text != address) {
|
||||
depositKey.currentState.addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.isDepositAddressEnabled, (bool isEnabled) {
|
||||
depositKey.currentState.isAddressEditable(isEditable: isEnabled);
|
||||
});
|
||||
|
||||
reaction((_) => store.receiveAmount, (String amount) {
|
||||
if (receiveKey.currentState.amountController.text !=
|
||||
store.receiveAmount) {
|
||||
receiveKey.currentState.amountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.receiveAddress, (String address) {
|
||||
if (receiveKey.currentState.addressController.text != address) {
|
||||
receiveKey.currentState.addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.isReceiveAddressEnabled, (bool isEnabled) {
|
||||
receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
|
||||
});
|
||||
|
||||
reaction((_) => store.tradeState, (ExchangeTradeState state) {
|
||||
if (state is TradeIsCreatedFailure) {
|
||||
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 TradeIsCreatedSuccessfully) {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.exchangeConfirm, arguments: state.trade);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => store.limitsState, (LimitsState state) {
|
||||
String min;
|
||||
String max;
|
||||
|
||||
if (state is LimitsLoadedSuccessfully) {
|
||||
min = state.limits.min != null ? state.limits.min.toString() : null;
|
||||
max = state.limits.max != null ? state.limits.max.toString() : null;
|
||||
}
|
||||
|
||||
if (state is LimitsLoadedFailure) {
|
||||
min = '0';
|
||||
max = '0';
|
||||
}
|
||||
|
||||
if (state is LimitsIsLoading) {
|
||||
min = '...';
|
||||
max = '...';
|
||||
}
|
||||
|
||||
depositKey.currentState.changeLimits(min: min, max: max);
|
||||
receiveKey.currentState.changeLimits(min: null, max: null);
|
||||
});
|
||||
|
||||
depositAddressController.addListener(
|
||||
() => store.depositAddress = depositAddressController.text);
|
||||
|
||||
depositAmountController.addListener(() {
|
||||
if (depositAmountController.text != store.depositAmount) {
|
||||
store.changeDepositAmount(amount: depositAmountController.text);
|
||||
}
|
||||
});
|
||||
|
||||
receiveAddressController.addListener(
|
||||
() => store.receiveAddress = receiveAddressController.text);
|
||||
|
||||
receiveAmountController.addListener(() {
|
||||
if (receiveAmountController.text != store.receiveAmount) {
|
||||
store.changeReceiveAmount(amount: receiveAmountController.text);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletStore.address, (String address) {
|
||||
if (store.depositCurrency == CryptoCurrency.xmr) {
|
||||
depositKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
|
||||
if (store.receiveCurrency == CryptoCurrency.xmr) {
|
||||
receiveKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
});
|
||||
|
||||
_isReactionsSet = true;
|
||||
}
|
||||
|
||||
void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore,
|
||||
GlobalKey<ExchangeCardState> key) {
|
||||
final isCurrentTypeWallet = currency == walletStore.type;
|
||||
|
||||
key.currentState.changeSelectedCurrency(currency);
|
||||
key.currentState
|
||||
.changeWalletName(isCurrentTypeWallet ? walletStore.name : null);
|
||||
|
||||
key.currentState
|
||||
.changeAddress(address: isCurrentTypeWallet ? walletStore.address : '');
|
||||
|
||||
key.currentState.changeAmount(amount: '');
|
||||
}
|
||||
|
||||
void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency,
|
||||
GlobalKey<ExchangeCardState> key) {
|
||||
final isCurrentTypeWallet = currency == walletStore.type;
|
||||
|
||||
if (isCurrentTypeWallet) {
|
||||
key.currentState.changeWalletName(walletStore.name);
|
||||
key.currentState.addressController.text = walletStore.address;
|
||||
} else if (key.currentState.addressController.text == walletStore.address) {
|
||||
key.currentState.changeWalletName(null);
|
||||
key.currentState.addressController.text = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
|
||||
class CurrencyPicker extends StatelessWidget {
|
||||
CurrencyPicker({
|
||||
@required this.selectedAtIndex,
|
||||
@required this.items,
|
||||
@required this.title,
|
||||
@required this.onItemSelected,
|
||||
});
|
||||
|
||||
final int selectedAtIndex;
|
||||
final List<CryptoCurrency> items;
|
||||
final String title;
|
||||
final Function(CryptoCurrency) onItemSelected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
height: 400,
|
||||
width: 300,
|
||||
color: Theme.of(context).dividerColor,
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.25,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisSpacing: 1,
|
||||
mainAxisSpacing: 1,
|
||||
children: List.generate(15, (index) {
|
||||
|
||||
if (index == 14) {
|
||||
return Container(
|
||||
color: Theme.of(context).primaryTextTheme.display1.color,
|
||||
);
|
||||
}
|
||||
|
||||
final item = items[index];
|
||||
final isItemSelected = index == selectedAtIndex;
|
||||
|
||||
final color = isItemSelected
|
||||
? Theme.of(context).accentTextTheme.subtitle.decorationColor
|
||||
: Theme.of(context).primaryTextTheme.display1.color;
|
||||
final textColor = isItemSelected
|
||||
? Colors.blue
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (onItemSelected == null) {
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
onItemSelected(item);
|
||||
},
|
||||
child: Container(
|
||||
color: color,
|
||||
child: Center(
|
||||
child: Text(
|
||||
item.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: textColor
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
})
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
|
||||
class ExchangeCard extends StatefulWidget {
|
||||
ExchangeCard(
|
||||
{Key key,
|
||||
this.title = '',
|
||||
this.initialCurrency,
|
||||
this.initialAddress,
|
||||
this.initialWalletName,
|
||||
@@ -18,12 +19,15 @@ class ExchangeCard extends StatefulWidget {
|
||||
this.currencies,
|
||||
this.onCurrencySelected,
|
||||
this.imageArrow,
|
||||
this.currencyButtonColor = Colors.transparent,
|
||||
this.addressButtonsColor = Colors.transparent,
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator})
|
||||
: super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
final Function(CryptoCurrency) onCurrencySelected;
|
||||
final String title;
|
||||
final CryptoCurrency initialCurrency;
|
||||
final String initialWalletName;
|
||||
final String initialAddress;
|
||||
@@ -31,6 +35,8 @@ class ExchangeCard extends StatefulWidget {
|
||||
final bool initialIsAddressEditable;
|
||||
final bool isAmountEstimated;
|
||||
final Image imageArrow;
|
||||
final Color currencyButtonColor;
|
||||
final Color addressButtonsColor;
|
||||
final FormFieldValidator<String> currencyValueValidator;
|
||||
final FormFieldValidator<String> addressTextFieldValidator;
|
||||
|
||||
@@ -42,6 +48,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
final addressController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
|
||||
String _title;
|
||||
String _min;
|
||||
String _max;
|
||||
CryptoCurrency _selectedCurrency;
|
||||
@@ -52,6 +59,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_title = widget.title;
|
||||
_isAmountEditable = widget.initialIsAmountEditable;
|
||||
_isAddressEditable = widget.initialIsAddressEditable;
|
||||
_walletName = widget.initialWalletName;
|
||||
@@ -103,157 +111,114 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.fromLTRB(22, 15, 22, 30),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(12))),
|
||||
child: Column(children: <Widget>[
|
||||
_isAmountEstimated != null && _isAmountEstimated
|
||||
? Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
|
||||
SizedBox(
|
||||
height: 30,
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Palette.lightGrey,
|
||||
borderRadius: BorderRadius.circular(10.0)),
|
||||
child: Text(
|
||||
S.of(context).estimated,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Palette.wildDarkBlue,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
])
|
||||
: Container(),
|
||||
Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 52,
|
||||
width: 90,
|
||||
color: Colors.transparent,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_title,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
BaseTextFormField(
|
||||
controller: amountController,
|
||||
enabled: _isAmountEditable,
|
||||
textAlign: TextAlign.left,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
],
|
||||
hintText: '0.0000',
|
||||
validator: widget.currencyValueValidator
|
||||
),
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 32,
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
color: widget.currencyButtonColor,
|
||||
child: InkWell(
|
||||
onTap: () => _presentPicker(context),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(_selectedCurrency.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color)),
|
||||
widget.imageArrow
|
||||
]),
|
||||
_walletName != null
|
||||
? Text(_walletName,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Palette.wildDarkBlue))
|
||||
: SizedBox(),
|
||||
Text(
|
||||
_selectedCurrency.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 5),
|
||||
child: widget.imageArrow,
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
style: TextStyle(fontSize: 23, height: 1.21),
|
||||
controller: amountController,
|
||||
enabled: _isAmountEditable,
|
||||
textAlign: TextAlign.right,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
fontSize: 23,
|
||||
height: 1.21),
|
||||
hintText: '0.00000000',
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: _isAmountEditable
|
||||
? Palette.deepPurple
|
||||
: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: widget.currencyValueValidator),
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
width: double.infinity,
|
||||
child: Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
_min != null
|
||||
? Text(
|
||||
S.of(context).min_value(
|
||||
_min, _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color),
|
||||
)
|
||||
: SizedBox(),
|
||||
_min != null ? SizedBox(width: 10) : SizedBox(),
|
||||
_max != null
|
||||
? Text(
|
||||
S.of(context).max_value(
|
||||
_max, _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color))
|
||||
: SizedBox(),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_min != null
|
||||
? Text(
|
||||
S.of(context).min_value(
|
||||
_min, _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)
|
||||
: Offstage(),
|
||||
_min != null ? SizedBox(width: 10) : Offstage(),
|
||||
_max != null
|
||||
? Text(
|
||||
S.of(context).max_value(
|
||||
_max, _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color))
|
||||
: Offstage(),
|
||||
]),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
AddressTextField(
|
||||
controller: addressController,
|
||||
isActive: _isAddressEditable,
|
||||
options: _isAddressEditable
|
||||
? _walletName != null
|
||||
? [
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
AddressTextFieldOption.subaddressList
|
||||
]
|
||||
: [
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
]
|
||||
: [],
|
||||
validator: widget.addressTextFieldValidator,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: AddressTextField(
|
||||
controller: addressController,
|
||||
isActive: _isAddressEditable,
|
||||
options: _isAddressEditable
|
||||
? _walletName != null
|
||||
? []
|
||||
: [
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
]
|
||||
: [],
|
||||
isBorderExist: false,
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
),
|
||||
)
|
||||
]),
|
||||
);
|
||||
@@ -261,14 +226,14 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
|
||||
void _presentPicker(BuildContext context) {
|
||||
showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: widget.currencies,
|
||||
builder: (_) => CurrencyPicker(
|
||||
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
|
||||
items: widget.currencies,
|
||||
title: S.of(context).change_currency,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
widget.onCurrencySelected != null
|
||||
? widget.onCurrencySelected(item)
|
||||
: null),
|
||||
widget.onCurrencySelected != null
|
||||
? widget.onCurrencySelected(item)
|
||||
: null),
|
||||
context: context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange/exchange_store.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
|
||||
class PresentProviderPicker extends StatelessWidget {
|
||||
PresentProviderPicker({@required this.exchangeStore});
|
||||
|
||||
final ExchangeStore exchangeStore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Image arrowBottom =
|
||||
Image.asset('assets/images/arrow_bottom_purple_icon.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
height: 6);
|
||||
|
||||
return FlatButton(
|
||||
onPressed: () => _presentProviderPicker(context),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(S.of(context).exchange,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
Observer(
|
||||
builder: (_) => Text('${exchangeStore.provider.title}',
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color)))
|
||||
],
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: arrowBottom,
|
||||
)
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void _presentProviderPicker(BuildContext context) {
|
||||
final items = exchangeStore.providersForCurrentPair();
|
||||
final selectedItem = items.indexOf(exchangeStore.provider);
|
||||
final images = List<Image>();
|
||||
|
||||
for (ExchangeProvider provider in items) {
|
||||
switch (provider.description) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
images.add(Image.asset('assets/images/xmr_btc.png'));
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
images.add(Image.asset('assets/images/change_now.png'));
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
images.add(Image.asset('assets/images/morph_icon.png'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
images: images,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).change_exchange_provider,
|
||||
onItemSelected: (ExchangeProvider provider) =>
|
||||
exchangeStore.changeProvider(provider: provider)),
|
||||
context: context);
|
||||
}
|
||||
}
|
||||
@@ -17,43 +17,42 @@ class ExchangeConfirmPage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 80.0, right: 80.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).exchange_result_write_down_trade_id,
|
||||
final copyImage = Image.asset('assets/images/copy_content.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).exchange_result_write_down_trade_id,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 60),
|
||||
child: Text(
|
||||
S.of(context).trade_id,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
SizedBox(
|
||||
height: 70.0,
|
||||
),
|
||||
Text(
|
||||
S.of(context).trade_id(trade.id),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
SizedBox(
|
||||
height: 70.0,
|
||||
),
|
||||
PrimaryButton(
|
||||
onPressed: () {
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Builder(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: trade.id));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
@@ -62,31 +61,52 @@ class ExchangeConfirmPage extends BasePage {
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 1500),
|
||||
));
|
||||
},
|
||||
text: S.of(context).copy_id,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.decorationColor)
|
||||
],
|
||||
),
|
||||
))),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 40.0),
|
||||
child: PrimaryButton(
|
||||
child: Container(
|
||||
height: 60,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
trade.id,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
PrimaryButton(
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pushReplacementNamed(Routes.exchangeTrade, arguments: trade),
|
||||
text: S.of(context).saved_the_trade_id,
|
||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor),
|
||||
)
|
||||
],
|
||||
color: Colors.green,
|
||||
textColor: Colors.white)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,18 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/exchange_trade/exchange_trade_store.dart';
|
||||
import 'package:cake_wallet/src/stores/send/send_store.dart';
|
||||
import 'package:cake_wallet/src/stores/send/sending_state.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/widgets/copy_button.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/qr_image.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/widgets/timer_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
|
||||
class ExchangeTradePage extends BasePage {
|
||||
@override
|
||||
@@ -46,281 +46,274 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
|
||||
_setEffects(context);
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 20, right: 20, top: 20),
|
||||
content: Observer(builder: (_) {
|
||||
final trade = tradeStore.trade;
|
||||
final walletName = walletStore.name;
|
||||
return Container(
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
content: Observer(builder: (_) {
|
||||
final trade = tradeStore.trade;
|
||||
final walletName = walletStore.name;
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).id,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.id ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color),
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).amount,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.amount ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color),
|
||||
)
|
||||
],
|
||||
),
|
||||
trade.extraId != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).payment_id,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.extraId ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color),
|
||||
)
|
||||
],
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).id,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.id ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)
|
||||
: Container(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).status,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color,
|
||||
height: 2),
|
||||
),
|
||||
Text(
|
||||
'${trade.state ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color),
|
||||
)
|
||||
],
|
||||
),
|
||||
trade.expiredAt != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).offer_expires_in,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
TimerWidget(trade.expiredAt,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color)
|
||||
],
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).amount,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.amount ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
color: Colors.white,
|
||||
constraints: BoxConstraints(minWidth: 65, maxWidth: 105),
|
||||
child: QrImage(
|
||||
data: trade.inputAddress ?? fetchingLabel,
|
||||
backgroundColor: Colors.white))
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
S.of(context).trade_is_powered_by(trade.provider != null
|
||||
? trade.provider.title
|
||||
: fetchingLabel),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.headline.color),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Center(
|
||||
child: Text(
|
||||
trade.inputAddress ?? fetchingLabel,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 14.0, color: Palette.lightViolet),
|
||||
],
|
||||
),
|
||||
trade.extraId != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).payment_id,
|
||||
style: TextStyle(
|
||||
height: 2,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
Text(
|
||||
'${trade.extraId ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Container(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).status,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
height: 2),
|
||||
),
|
||||
Text(
|
||||
'${trade.state ?? fetchingLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
height: 2,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)
|
||||
],
|
||||
),
|
||||
trade.expiredAt != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).offer_expires_in,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
TimerWidget(trade.expiredAt,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color)
|
||||
],
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 50.0, right: 50.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 5.0),
|
||||
child: CopyButton(
|
||||
onPressed: () => Clipboard.setData(
|
||||
ClipboardData(text: trade.inputAddress)),
|
||||
text: S.of(context).copy_address,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.decorationColor),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: CopyButton(
|
||||
onPressed: () =>
|
||||
Clipboard.setData(ClipboardData(text: trade.id)),
|
||||
text: S.of(context).copy_id,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.decorationColor),
|
||||
))
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: QrImage(
|
||||
data: trade.inputAddress ?? fetchingLabel,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Theme.of(context).primaryTextTheme.display4.color,
|
||||
),
|
||||
),
|
||||
)),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
tradeStore.isSendable
|
||||
? S.of(context).exchange_result_confirm(
|
||||
trade.amount ?? fetchingLabel,
|
||||
trade.from.toString(),
|
||||
walletName)
|
||||
: S.of(context).exchange_result_description(
|
||||
trade.amount ?? fetchingLabel, trade.from.toString()),
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
S.of(context).trade_is_powered_by(trade.provider != null
|
||||
? trade.provider.title
|
||||
: fetchingLabel),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Center(
|
||||
child: Text(
|
||||
trade.inputAddress ?? fetchingLabel,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 5.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: trade.inputAddress));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 1500),
|
||||
));
|
||||
},
|
||||
text: S.of(context).copy_address,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color)
|
||||
),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: trade.id));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 1500),
|
||||
));
|
||||
},
|
||||
text: S.of(context).copy_id,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color)
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
tradeStore.isSendable
|
||||
? S.of(context).exchange_result_confirm(
|
||||
trade.amount ?? fetchingLabel,
|
||||
trade.from.toString(),
|
||||
walletName)
|
||||
: S.of(context).exchange_result_description(
|
||||
trade.amount ?? fetchingLabel, trade.from.toString()),
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
S.of(context).exchange_result_write_down_ID,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
S.of(context).exchange_result_write_down_ID,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Theme.of(context).accentTextTheme.title.color),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => tradeStore.trade.from == CryptoCurrency.xmr &&
|
||||
!(sendStore.state is TransactionCommitted)
|
||||
? Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
child: LoadingPrimaryButton(
|
||||
isDisabled: tradeStore.trade.inputAddress == null ||
|
||||
tradeStore.trade.inputAddress.isEmpty,
|
||||
isLoading: sendStore.state is CreatingTransaction ||
|
||||
sendStore.state is TransactionCommitted,
|
||||
onPressed: () => sendStore.createTransaction(
|
||||
address: tradeStore.trade.inputAddress,
|
||||
amount: tradeStore.trade.amount),
|
||||
text: tradeStore.trade.provider ==
|
||||
ExchangeProviderDescription.xmrto
|
||||
? S.of(context).confirm
|
||||
: S.of(context).send_xmr,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor),
|
||||
)
|
||||
: Offstage()),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
bottomSectionPadding: EdgeInsets.all(24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => tradeStore.trade.from == CryptoCurrency.xmr &&
|
||||
!(sendStore.state is TransactionCommitted)
|
||||
? LoadingPrimaryButton(
|
||||
isDisabled: tradeStore.trade.inputAddress == null ||
|
||||
tradeStore.trade.inputAddress.isEmpty,
|
||||
isLoading: sendStore.state is CreatingTransaction ||
|
||||
sendStore.state is TransactionCommitted,
|
||||
onPressed: () => sendStore.createTransaction(
|
||||
address: tradeStore.trade.inputAddress,
|
||||
amount: tradeStore.trade.amount),
|
||||
text: tradeStore.trade.provider ==
|
||||
ExchangeProviderDescription.xmrto
|
||||
? S.of(context).confirm
|
||||
: S.of(context).send_xmr,
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white)
|
||||
: Offstage()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -337,14 +330,11 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
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()
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -355,23 +345,18 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).confirm_sending),
|
||||
content: Text(S.of(context).commit_transaction_amount_fee(
|
||||
sendStore.pendingTransaction.amount,
|
||||
sendStore.pendingTransaction.fee)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
sendStore.commitTransaction();
|
||||
}),
|
||||
FlatButton(
|
||||
child: Text(S.of(context).cancel),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
)
|
||||
],
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).confirm_sending,
|
||||
alertContent: S.of(context).commit_transaction_amount_fee(
|
||||
sendStore.pendingTransaction.amount,
|
||||
sendStore.pendingTransaction.fee),
|
||||
leftButtonText: S.of(context).ok,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
Navigator.of(context).pop();
|
||||
sendStore.commitTransaction();
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -382,14 +367,11 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).sending),
|
||||
content: Text(S.of(context).transaction_sent),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop())
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).sending,
|
||||
alertContent: S.of(context).transaction_sent,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CopyButton extends StatelessWidget {
|
||||
const CopyButton(
|
||||
{@required this.onPressed,
|
||||
@required this.text,
|
||||
@required this.color,
|
||||
@required this.borderColor});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Color color;
|
||||
final Color borderColor;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ButtonTheme(
|
||||
minWidth: double.infinity,
|
||||
height: 44.0,
|
||||
child: FlatButton(
|
||||
onPressed: onPressed,
|
||||
color: color,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: borderColor),
|
||||
borderRadius: BorderRadius.circular(10.0)),
|
||||
child: Text(text, style: TextStyle(fontSize: 14.0)),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -11,43 +11,124 @@ class FaqPage extends BasePage {
|
||||
String get title => S.current.faq;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
builder: (context, snapshot) {
|
||||
final faqItems = jsonDecode(snapshot.data.toString()) as List;
|
||||
Widget body(BuildContext context) => FaqForm();
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final itemTitle = faqItems[index]["question"].toString();
|
||||
final itemChild = faqItems[index]["answer"].toString();
|
||||
class FaqForm extends StatefulWidget {
|
||||
@override
|
||||
FaqFormState createState() => FaqFormState();
|
||||
}
|
||||
|
||||
return ExpansionTile(
|
||||
title: Text(itemTitle),
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 15.0, right: 15.0),
|
||||
class FaqFormState extends State<FaqForm> {
|
||||
List<Icon> icons;
|
||||
List<Color> colors;
|
||||
bool isLoaded = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addIcon = Icon(Icons.add, color: Theme.of(context).primaryTextTheme.title.color);
|
||||
final removeIcon = Icon(Icons.remove, color: Colors.green);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.color,
|
||||
child: FutureBuilder(
|
||||
builder: (context, snapshot) {
|
||||
final faqItems = jsonDecode(snapshot.data.toString()) as List;
|
||||
|
||||
if (snapshot.hasData) {
|
||||
setIconsAndColors(context, faqItems.length, addIcon);
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final itemTitle = faqItems[index]["question"].toString();
|
||||
final itemChild = faqItems[index]["answer"].toString();
|
||||
|
||||
return ExpansionTile(
|
||||
title: Padding(
|
||||
padding: EdgeInsets.only(left: 8, top: 12, bottom: 12),
|
||||
child: Text(
|
||||
itemChild,
|
||||
itemTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colors[index]
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
trailing: Padding(
|
||||
padding: EdgeInsets.only(right: 24),
|
||||
child: Container(
|
||||
width: double.minPositive,
|
||||
child: Center(
|
||||
child: icons[index]
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
onExpansionChanged: (value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
icons[index] = removeIcon;
|
||||
colors[index] = Colors.green;
|
||||
} else {
|
||||
icons[index] = addIcon;
|
||||
colors[index] = Theme.of(context).primaryTextTheme.title.color;
|
||||
}
|
||||
});
|
||||
},
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
bottom: 8
|
||||
),
|
||||
child: Text(
|
||||
itemChild,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) =>
|
||||
Container(color: Theme.of(context).dividerColor, height: 1.0),
|
||||
itemCount: faqItems == null ? 0 : faqItems.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) =>
|
||||
Divider(color: Theme.of(context).dividerTheme.color, height: 1.0),
|
||||
itemCount: faqItems == null ? 0 : faqItems.length,
|
||||
);
|
||||
},
|
||||
future: rootBundle.loadString(getFaqPath(context)),
|
||||
future: rootBundle.loadString(getFaqPath(context)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setIconsAndColors(BuildContext context, int index, Icon icon) {
|
||||
if (isLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
icons = List.generate(index, (int i) => icon);
|
||||
colors = List.generate(index, (int i) => Theme.of(context).primaryTextTheme.title.color);
|
||||
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
String getFaqPath(BuildContext context) {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
|
||||
@@ -80,4 +161,4 @@ class FaqPage extends BasePage {
|
||||
return 'assets/faq/faq_en.json';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,10 @@ import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class NewWalletPage extends BasePage {
|
||||
NewWalletPage(
|
||||
@@ -39,14 +40,42 @@ class WalletNameForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _WalletNameFormState extends State<WalletNameForm> {
|
||||
static const aspectRatioImage = 1.22;
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final nameController = TextEditingController();
|
||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletCreationStore = Provider.of<WalletCreationStore>(context);
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
|
||||
final List<String> seedLocales = [
|
||||
S.current.seed_language_english,
|
||||
S.current.seed_language_chinese,
|
||||
S.current.seed_language_dutch,
|
||||
S.current.seed_language_german,
|
||||
S.current.seed_language_japanese,
|
||||
S.current.seed_language_portuguese,
|
||||
S.current.seed_language_russian,
|
||||
S.current.seed_language_spanish
|
||||
];
|
||||
|
||||
nameController.addListener(() {
|
||||
if (nameController.text.isNotEmpty) {
|
||||
walletCreationStore.setDisabledStatus(false);
|
||||
} else {
|
||||
walletCreationStore.setDisabledStatus(true);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletCreationStore.state, (WalletCreationState state) {
|
||||
if (state is WalletCreatedSuccessfully) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
@@ -56,81 +85,106 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(state.error),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.new_wallet,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
content: Column(children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 10),
|
||||
child: Image.asset('assets/images/bitmap.png',
|
||||
height: 224, width: 400),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 24.0,
|
||||
color: Theme.of(context).accentTextTheme.subtitle.color),
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 24.0, color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletCreationStore.validateWalletName(value);
|
||||
return walletCreationStore.errorMessage;
|
||||
},
|
||||
)),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).seed_language_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16.0),
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletNameImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: TextFormField(
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
hintText: S.of(context).wallet_name,
|
||||
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: (value) {
|
||||
walletCreationStore.validateWalletName(value);
|
||||
return walletCreationStore.errorMessage;
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: SeedLanguagePicker(),
|
||||
)
|
||||
]),
|
||||
bottomSection: Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
walletCreationStore.create(name: nameController.text,
|
||||
language: seedLanguageStore.selectedSeedLanguage);
|
||||
}
|
||||
},
|
||||
text: S.of(context).continue_text,
|
||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor,
|
||||
isLoading: walletCreationStore.state is WalletIsCreating,
|
||||
);
|
||||
},
|
||||
));
|
||||
Padding(padding: EdgeInsets.only(top: 40),
|
||||
child: Text(
|
||||
S.of(context).seed_language_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(top: 24),
|
||||
child: Observer(
|
||||
builder: (_) => SelectButton(
|
||||
image: null,
|
||||
text: seedLocales[seedLanguages.indexOf(seedLanguageStore.selectedSeedLanguage)],
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color,
|
||||
onTap: () async => await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => SeedLanguagePicker()
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
]),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
walletCreationStore.create(name: nameController.text,
|
||||
language: seedLanguageStore.selectedSeedLanguage);
|
||||
}
|
||||
},
|
||||
text: S.of(context).continue_text,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading: walletCreationStore.state is WalletIsCreating,
|
||||
isDisabled: walletCreationStore.isDisabledStatus,
|
||||
);
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
||||
class NewWalletTypePage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.new_wallet;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => WalletTypeForm();
|
||||
}
|
||||
|
||||
class WalletTypeForm extends StatefulWidget {
|
||||
@override
|
||||
WalletTypeFormState createState() => WalletTypeFormState();
|
||||
}
|
||||
|
||||
class WalletTypeFormState extends State<WalletTypeForm> {
|
||||
static const aspectRatioImage = 1.22;
|
||||
|
||||
final moneroIcon = Image.asset('assets/images/monero.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final walletTypeImage = Image.asset('assets/images/wallet_type.png');
|
||||
|
||||
bool isDisabledButton;
|
||||
bool isMoneroSelected;
|
||||
bool isBitcoinSelected;
|
||||
|
||||
Color moneroBackgroundColor = Colors.transparent;
|
||||
Color moneroTextColor = Colors.transparent;
|
||||
Color bitcoinBackgroundColor = Colors.transparent;
|
||||
Color bitcoinTextColor = Colors.transparent;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
isDisabledButton = true;
|
||||
isMoneroSelected = false;
|
||||
isBitcoinSelected = false;
|
||||
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||
}
|
||||
|
||||
void afterLayout(dynamic _) {
|
||||
moneroBackgroundColor = Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
moneroTextColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
bitcoinBackgroundColor = Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
bitcoinTextColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletTypeImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 48),
|
||||
child: Text(
|
||||
S.of(context).choose_wallet_currency,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: SelectButton(
|
||||
image: bitcoinIcon,
|
||||
text: 'Bitcoin',
|
||||
color: bitcoinBackgroundColor,
|
||||
textColor: bitcoinTextColor,
|
||||
onTap: () {}),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: SelectButton(
|
||||
image: moneroIcon,
|
||||
text: 'Monero',
|
||||
color: moneroBackgroundColor,
|
||||
textColor: moneroTextColor,
|
||||
onTap: () => onSelectMoneroButton(context)),
|
||||
)
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 24
|
||||
),
|
||||
bottomSection: PrimaryButton(
|
||||
onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet),
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isDisabled: isDisabledButton,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onSelectMoneroButton(BuildContext context) {
|
||||
isMoneroSelected = true;
|
||||
isBitcoinSelected = false;
|
||||
isDisabledButton = false;
|
||||
|
||||
moneroBackgroundColor = Theme.of(context).accentTextTheme.title.decorationColor;
|
||||
moneroTextColor = Theme.of(context).primaryTextTheme.title.backgroundColor;
|
||||
bitcoinBackgroundColor = Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
bitcoinTextColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
void onSelectBitcoinButton(BuildContext context) {
|
||||
isMoneroSelected = false;
|
||||
isBitcoinSelected = true;
|
||||
isDisabledButton = false;
|
||||
|
||||
moneroBackgroundColor = Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
moneroTextColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
bitcoinBackgroundColor = moneroBackgroundColor = Theme.of(context).accentTextTheme.title.decorationColor;
|
||||
bitcoinTextColor = Theme.of(context).primaryTextTheme.title.backgroundColor;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SelectButton extends StatelessWidget {
|
||||
SelectButton({
|
||||
@required this.image,
|
||||
@required this.text,
|
||||
@required this.color,
|
||||
@required this.textColor,
|
||||
@required this.onTap,
|
||||
});
|
||||
|
||||
final Image image;
|
||||
final String text;
|
||||
final Color color;
|
||||
final Color textColor;
|
||||
final VoidCallback onTap;
|
||||
|
||||
final selectArrowImage = Image.asset('assets/images/select_arrow.png');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: EdgeInsets.only(left: 30, right: 30),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
color: color
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? image
|
||||
: Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 15)
|
||||
: EdgeInsets.only(left: 0),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: textColor
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
selectArrowImage
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/node_list/node_list_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
||||
class NewNodePage extends BasePage {
|
||||
@override
|
||||
@@ -36,130 +37,166 @@ class NewNodeFormState extends State<NewNodePageForm> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onHandleControllers(NodeListStore nodeListStore) {
|
||||
if (_nodeAddressController.text.isNotEmpty &&
|
||||
_nodePortController.text.isNotEmpty) {
|
||||
nodeListStore.setDisabledState(false);
|
||||
} else {
|
||||
nodeListStore.setDisabledState(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final nodeList = Provider.of<NodeListStore>(context);
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 38.0, right: 38.0, top: 0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Palette.wildDarkBlue),
|
||||
hintText: S.of(context).node_address,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
controller: _nodeAddressController,
|
||||
validator: (value) {
|
||||
nodeList.validateNodeAddress(value);
|
||||
return nodeList.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Palette.wildDarkBlue),
|
||||
hintText: S.of(context).node_port,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
controller: _nodePortController,
|
||||
validator: (value) {
|
||||
nodeList.validateNodePort(value);
|
||||
return nodeList.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Palette.wildDarkBlue),
|
||||
hintText: S.of(context).login,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
controller: _loginController,
|
||||
validator: (value) => null,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Palette.wildDarkBlue),
|
||||
hintText: S.of(context).password,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
controller: _passwordController,
|
||||
validator: (value) => null,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(bottom: 20.0, left: 20.0, right: 20.0),
|
||||
child: Row(
|
||||
_nodeAddressController.addListener(() {onHandleControllers(nodeList);});
|
||||
_nodePortController.addListener(() {onHandleControllers(nodeList);});
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).node_address,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
controller: _nodeAddressController,
|
||||
validator: (value) {
|
||||
nodeList.validateNodeAddress(value);
|
||||
return nodeList.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).node_port,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
controller: _nodePortController,
|
||||
validator: (value) {
|
||||
nodeList.validateNodePort(value);
|
||||
return nodeList.errorMessage;
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).login,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
controller: _loginController,
|
||||
validator: (value) => null,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).password,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
controller: _passwordController,
|
||||
validator: (value) => null,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
@@ -169,17 +206,11 @@ class NewNodeFormState extends State<NewNodePageForm> {
|
||||
_passwordController.text = '';
|
||||
},
|
||||
text: S.of(context).reset,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.decorationColor),
|
||||
color: Colors.red,
|
||||
textColor: Colors.white),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () async {
|
||||
@@ -196,20 +227,15 @@ class NewNodeFormState extends State<NewNodePageForm> {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isDisabled: nodeList.disabledState,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
],
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_indicator.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart';
|
||||
import 'package:cake_wallet/src/stores/node_list/node_list_store.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
|
||||
class NodeListPage extends BasePage {
|
||||
NodeListPage();
|
||||
@@ -21,71 +23,42 @@ class NodeListPage extends BasePage {
|
||||
final nodeList = Provider.of<NodeListStore>(context);
|
||||
final settings = Provider.of<SettingsStore>(context);
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
onPressed: () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
S.of(context).node_reset_settings_title,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: Text(
|
||||
S.of(context).nodes_list_reset_to_default_message,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
await nodeList.reset();
|
||||
await settings.setCurrentNodeToDefault();
|
||||
},
|
||||
child: Text(S.of(context).reset))
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
S.of(context).reset,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.subtitle.color),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).selectedRowColor),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add, color: Palette.violet, size: 22.0),
|
||||
ButtonTheme(
|
||||
minWidth: 28.0,
|
||||
height: 28.0,
|
||||
child: FlatButton(
|
||||
shape: CircleBorder(),
|
||||
onPressed: () async =>
|
||||
await Navigator.of(context).pushNamed(Routes.newNode),
|
||||
child: Offstage()),
|
||||
)
|
||||
],
|
||||
return Container(
|
||||
height: 32,
|
||||
width: 72,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor
|
||||
),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
onPressed: () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).node_reset_settings_title,
|
||||
alertContent: S.of(context).nodes_list_reset_to_default_message,
|
||||
leftButtonText: S.of(context).reset,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await nodeList.reset();
|
||||
await settings.setCurrentNodeToDefault();
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
S.of(context).reset,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
color: Colors.blue),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,137 +77,142 @@ class NodeListPageBodyState extends State<NodeListPageBody> {
|
||||
final nodeList = Provider.of<NodeListStore>(context);
|
||||
final settings = Provider.of<SettingsStore>(context);
|
||||
|
||||
final currentColor = Theme.of(context).selectedRowColor;
|
||||
final notCurrentColor = Theme.of(context).backgroundColor;
|
||||
final trashImage = Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white);
|
||||
|
||||
final currentColor = Theme.of(context).accentTextTheme.subtitle.decorationColor;
|
||||
final notCurrentColor = Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
|
||||
final currentTextColor = Colors.blue;
|
||||
final notCurrentTextColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(bottom: 20.0),
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Expanded(child: Observer(builder: (context) {
|
||||
return ListView.separated(
|
||||
separatorBuilder: (_, __) => Divider(
|
||||
color: Theme.of(context).dividerTheme.color, height: 1),
|
||||
itemCount: nodeList.nodes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final node = nodeList.nodes[index];
|
||||
NodeListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
trailing: Icon(Icons.add,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
size: 24.0),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color,
|
||||
onTap: () async =>
|
||||
await Navigator.of(context).pushNamed(Routes.newNode),
|
||||
isDrawTop: true,
|
||||
isDrawBottom: true),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 32),
|
||||
child: Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
itemCount: nodeList.nodes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final node = nodeList.nodes[index];
|
||||
|
||||
return Observer(builder: (_) {
|
||||
final isCurrent = settings.node == null
|
||||
? false
|
||||
: node.key == settings.node.key;
|
||||
final isDrawTop = index == 0 ? true : false;
|
||||
final isDrawBottom = index == nodeList.nodes.length - 1 ? true : false;
|
||||
|
||||
final content = Container(
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
node.uri,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
),
|
||||
trailing: FutureBuilder(
|
||||
future: nodeList.isNodeOnline(node),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.done:
|
||||
return NodeIndicator(
|
||||
color: snapshot.data as bool
|
||||
? Palette.green
|
||||
: Palette.red);
|
||||
default:
|
||||
return NodeIndicator();
|
||||
}
|
||||
}),
|
||||
onTap: () async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(
|
||||
S
|
||||
.of(context)
|
||||
.change_current_node(node.uri),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () =>
|
||||
Navigator.pop(context),
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () async {
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
final isCurrent = settings.node == null
|
||||
? false
|
||||
: node.key == settings.node.key;
|
||||
|
||||
final content = NodeListRow(
|
||||
title: node.uri,
|
||||
trailing: FutureBuilder(
|
||||
future: nodeList.isNodeOnline(node),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.done:
|
||||
return NodeIndicator(
|
||||
color: snapshot.data as bool
|
||||
? Palette.green
|
||||
: Palette.red);
|
||||
default:
|
||||
return NodeIndicator();
|
||||
}
|
||||
}),
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
textColor: isCurrent ? currentTextColor : notCurrentTextColor,
|
||||
onTap: () async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.current.nodes,
|
||||
alertContent: S.of(context)
|
||||
.change_current_node(node.uri),
|
||||
leftButtonText: S.of(context).change,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await settings.setCurrentNode(
|
||||
node: node);
|
||||
},
|
||||
child: Text(S.of(context).change)),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
));
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
isDrawTop: isDrawTop,
|
||||
isDrawBottom: isDrawBottom);
|
||||
|
||||
return isCurrent
|
||||
? content
|
||||
: Dismissible(
|
||||
key: Key('${node.key}'),
|
||||
confirmDismiss: (direction) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
S.of(context).remove_node,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: Text(
|
||||
S.of(context).remove_node_message,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () =>
|
||||
Navigator.pop(context, false),
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () =>
|
||||
Navigator.pop(context, true),
|
||||
child: Text(S.of(context).remove)),
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
onDismissed: (direction) async =>
|
||||
await nodeList.remove(node: node),
|
||||
direction: DismissDirection.endToStart,
|
||||
background: Container(
|
||||
padding: EdgeInsets.only(right: 10.0),
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
color: Palette.red,
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
CupertinoIcons.delete,
|
||||
color: Colors.white,
|
||||
),
|
||||
Text(
|
||||
S.of(context).delete,
|
||||
style: TextStyle(color: Colors.white),
|
||||
)
|
||||
],
|
||||
)),
|
||||
child: content);
|
||||
});
|
||||
});
|
||||
}))
|
||||
return isCurrent
|
||||
? content
|
||||
: Dismissible(
|
||||
key: Key('${node.key}'),
|
||||
confirmDismiss: (direction) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
leftButtonText: S.of(context).remove,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () =>
|
||||
Navigator.pop(context, true),
|
||||
actionRightButton: () =>
|
||||
Navigator.pop(context, false)
|
||||
);
|
||||
});
|
||||
},
|
||||
onDismissed: (direction) async =>
|
||||
await nodeList.remove(node: node),
|
||||
direction: DismissDirection.endToStart,
|
||||
background: Container(
|
||||
padding: EdgeInsets.only(right: 10.0, top: 2),
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
color: Palette.red,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
trashImage,
|
||||
Text(
|
||||
S.of(context).delete,
|
||||
style: TextStyle(color: Colors.white),
|
||||
)
|
||||
],
|
||||
)),
|
||||
child: content);
|
||||
},
|
||||
);
|
||||
})
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ class NodeIndicator extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
width: 8.0,
|
||||
height: 8.0,
|
||||
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NodeListRow extends StatelessWidget {
|
||||
NodeListRow({
|
||||
@required this.title,
|
||||
@required this.trailing,
|
||||
@required this.color,
|
||||
@required this.textColor,
|
||||
@required this.onTap,
|
||||
@required this.isDrawTop,
|
||||
@required this.isDrawBottom});
|
||||
|
||||
final String title;
|
||||
final Widget trailing;
|
||||
final Color color;
|
||||
final Color textColor;
|
||||
final VoidCallback onTap;
|
||||
final bool isDrawTop;
|
||||
final bool isDrawBottom;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
isDrawTop
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
)
|
||||
: Offstage(),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
color: color,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: textColor
|
||||
),
|
||||
textAlign: TextAlign.left),
|
||||
trailing: trailing,
|
||||
onTap: onTap,
|
||||
)
|
||||
),
|
||||
isDrawBottom
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
@@ -29,8 +28,6 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
static const defaultPinLength = 4;
|
||||
static const sixPinLength = 6;
|
||||
static const fourPinLength = 4;
|
||||
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
||||
static final backArrowImage = Image.asset('assets/images/back_arrow.png');
|
||||
final _gridViewKey = GlobalKey();
|
||||
|
||||
int pinLength = defaultPinLength;
|
||||
@@ -89,6 +86,15 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
Widget build(BuildContext context) => Scaffold(body: body(context));
|
||||
|
||||
Widget body(BuildContext context) {
|
||||
final deleteIconImage = Image.asset(
|
||||
'assets/images/delete_icon.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
final faceImage = Image.asset(
|
||||
'assets/images/face.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
@@ -96,7 +102,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
child: Column(children: <Widget>[
|
||||
Spacer(flex: 2),
|
||||
Text(title,
|
||||
style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
)),
|
||||
Spacer(flex: 3),
|
||||
Container(
|
||||
width: 180,
|
||||
@@ -111,8 +121,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: isFilled ? Palette.deepPurple : Colors.transparent,
|
||||
border: Border.all(color: Palette.wildDarkBlue),
|
||||
color: isFilled
|
||||
? Theme.of(context).primaryTextTheme.title.color
|
||||
: Theme.of(context).primaryTextTheme.caption.color,
|
||||
));
|
||||
}),
|
||||
),
|
||||
@@ -127,7 +138,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
},
|
||||
child: Text(
|
||||
_changePinLengthText(),
|
||||
style: TextStyle(fontSize: 16.0, color: Palette.wildDarkBlue),
|
||||
style: TextStyle(fontSize: 14.0, color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
))
|
||||
],
|
||||
Spacer(flex: 1),
|
||||
@@ -149,9 +160,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(
|
||||
left: marginLeft, right: marginRight),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).buttonColor,
|
||||
child: FlatButton(
|
||||
onPressed: () {},
|
||||
color: Theme.of(context).backgroundColor,
|
||||
shape: CircleBorder(),
|
||||
child: faceImage,
|
||||
),
|
||||
);
|
||||
} else if (index == 10) {
|
||||
@@ -162,7 +175,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
left: marginLeft, right: marginRight),
|
||||
child: FlatButton(
|
||||
onPressed: () => _pop(),
|
||||
color: Theme.of(context).buttonColor,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
shape: CircleBorder(),
|
||||
child: deleteIconImage,
|
||||
),
|
||||
@@ -176,14 +189,13 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
left: marginLeft, right: marginRight),
|
||||
child: FlatButton(
|
||||
onPressed: () => _push(index),
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.title
|
||||
.backgroundColor,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
shape: CircleBorder(),
|
||||
child: Text('$index',
|
||||
style: TextStyle(
|
||||
fontSize: 23.0, color: Palette.blueGrey)),
|
||||
fontSize: 30.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -3,58 +3,31 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/subaddress_list/subaddress_list_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/qr_image.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/screens/accounts/account_list_page.dart';
|
||||
import 'package:cake_wallet/src/stores/account_list/account_list_store.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
|
||||
class ReceivePage extends BasePage {
|
||||
class ReceivePage extends StatefulWidget {
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
String get title => S.current.receive;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
|
||||
return SizedBox(
|
||||
height: 37.0,
|
||||
width: 37.0,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => Share.text(
|
||||
'Share address', walletStore.getAddress, 'text/plain'),
|
||||
child: Icon(
|
||||
Icons.share,
|
||||
size: 30.0,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
SingleChildScrollView(child: ReceiveBody());
|
||||
ReceivePageState createState() => ReceivePageState();
|
||||
}
|
||||
|
||||
class ReceiveBody extends StatefulWidget {
|
||||
@override
|
||||
ReceiveBodyState createState() => ReceiveBodyState();
|
||||
}
|
||||
|
||||
class ReceiveBodyState extends State<ReceiveBody> {
|
||||
class ReceivePageState extends State<ReceivePage> {
|
||||
final amountController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _backArrowImage = Image.asset('assets/images/back_arrow.png');
|
||||
final _backArrowImageDarkTheme =
|
||||
Image.asset('assets/images/back_arrow_dark_theme.png');
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -65,14 +38,30 @@ class ReceiveBodyState extends State<ReceiveBody> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
SubaddressListStore subaddressListStore;
|
||||
final subaddressListStore = Provider.of<SubaddressListStore>(context);
|
||||
final accountListStore = Provider.of<AccountListStore>(context);
|
||||
|
||||
try {
|
||||
subaddressListStore = Provider.of<SubaddressListStore>(context);
|
||||
} catch (_) {}
|
||||
final shareImage = Image.asset('assets/images/share.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
final copyImage = Image.asset('assets/images/copy_content.png',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
);
|
||||
|
||||
final currentColor = Theme.of(context).selectedRowColor;
|
||||
final notCurrentColor = Theme.of(context).scaffoldBackgroundColor;
|
||||
final currentColor = Theme.of(context).accentTextTheme.subtitle.decorationColor;
|
||||
final notCurrentColor = Theme.of(context).backgroundColor;
|
||||
|
||||
final currentTextColor = Colors.blue;
|
||||
final notCurrentTextColor = Theme.of(context).primaryTextTheme.caption.color;
|
||||
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
Image _backButton;
|
||||
|
||||
if (_themeChanger.getTheme() == Themes.darkTheme) {
|
||||
_backButton = _backArrowImageDarkTheme;
|
||||
} else {
|
||||
_backButton = _backArrowImage;
|
||||
}
|
||||
|
||||
amountController.addListener(() {
|
||||
if (_formKey.currentState.validate()) {
|
||||
@@ -82,207 +71,292 @@ class ReceiveBodyState extends State<ReceiveBody> {
|
||||
}
|
||||
});
|
||||
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(35.0),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomPadding: false,
|
||||
body: Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
Theme.of(context).primaryColor
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight
|
||||
)
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Observer(builder: (_) {
|
||||
return Row(
|
||||
Container(
|
||||
padding: EdgeInsets.only(
|
||||
top: 10,
|
||||
bottom: 20,
|
||||
left: 5,
|
||||
right: 10
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Spacer(
|
||||
flex: 1,
|
||||
SizedBox(
|
||||
height: 44,
|
||||
width: 44,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: _backButton),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
color: Colors.white,
|
||||
child: QrImage(
|
||||
data: walletStore.getAddress +
|
||||
walletStore.amountValue,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
)),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
Text(
|
||||
S.of(context).receive,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
SizedBox(
|
||||
height: 44.0,
|
||||
width: 44.0,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => Share.text(
|
||||
S.current.share_address, walletStore.subaddress.address, 'text/plain'),
|
||||
child: shareImage),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
Observer(builder: (_) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
child: Center(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: walletStore.getAddress));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
));
|
||||
},
|
||||
child: Text(
|
||||
walletStore.getAddress,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Observer(builder: (_) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: QrImage(
|
||||
data: walletStore.subaddress.address +
|
||||
walletStore.amountValue,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Theme.of(context).primaryTextTheme.display4.color,
|
||||
),
|
||||
),
|
||||
)),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: BaseTextFormField(
|
||||
controller: amountController,
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
],
|
||||
textAlign: TextAlign.center,
|
||||
hintText: S.of(context).receive_amount,
|
||||
borderColor: Theme.of(context).primaryTextTheme.caption.color,
|
||||
validator: (value) {
|
||||
walletStore.validateAmount(value);
|
||||
return walletStore.errorMessage;
|
||||
},
|
||||
autovalidate: true,
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
);
|
||||
}),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: TextFormField(
|
||||
keyboardType:
|
||||
TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
],
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).amount,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletStore.validateAmount(value);
|
||||
return walletStore.errorMessage;
|
||||
},
|
||||
autovalidate: true,
|
||||
controller: amountController,
|
||||
)))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
subaddressListStore != null
|
||||
? Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.color,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Text(
|
||||
S.of(context).subaddresses,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color),
|
||||
),
|
||||
trailing: Container(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).selectedRowColor,
|
||||
shape: BoxShape.circle),
|
||||
child: InkWell(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress),
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(14.0)),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Palette.violet,
|
||||
size: 22.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0,
|
||||
)
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
)
|
||||
: Container(),
|
||||
subaddressListStore != null
|
||||
? Observer(builder: (_) {
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: subaddressListStore.subaddresses.length,
|
||||
separatorBuilder: (context, i) {
|
||||
return Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0,
|
||||
);
|
||||
},
|
||||
itemBuilder: (context, i) {
|
||||
return Observer(builder: (_) {
|
||||
final subaddress = subaddressListStore.subaddresses[i];
|
||||
final isCurrent =
|
||||
walletStore.getAddress == subaddress.address;
|
||||
final label = subaddress.label.isNotEmpty
|
||||
? subaddress.label
|
||||
: subaddress.address;
|
||||
|
||||
return InkWell(
|
||||
onTap: () => walletStore.setSubaddress(subaddress),
|
||||
child: Container(
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
child: Column(children: <Widget>[
|
||||
ListTile(
|
||||
title: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
child: Builder(
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: walletStore.subaddress.address));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_to_clipboard,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 500),
|
||||
));
|
||||
},
|
||||
child: Container(
|
||||
height: 48,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
color: Theme.of(context).primaryTextTheme.overline.color
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
walletStore.subaddress.address,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
: Container()
|
||||
],
|
||||
)));
|
||||
)
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: subaddressListStore.subaddresses.length + 2,
|
||||
itemBuilder: (context, index) {
|
||||
|
||||
if (index == 0) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24)
|
||||
),
|
||||
child: HeaderTile(
|
||||
onTap: () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AccountListPage(accountListStore: accountListStore);
|
||||
}
|
||||
);
|
||||
},
|
||||
title: walletStore.account.label,
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (index == 1) {
|
||||
return HeaderTile(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress),
|
||||
title: S.of(context).subaddresses,
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
size: 20,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
index -= 2;
|
||||
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
final subaddress = subaddressListStore.subaddresses[index];
|
||||
final isCurrent =
|
||||
walletStore.subaddress.address == subaddress.address;
|
||||
|
||||
final label = subaddress.label.isNotEmpty
|
||||
? subaddress.label
|
||||
: subaddress.address;
|
||||
|
||||
final content = InkWell(
|
||||
onTap: () => walletStore.setSubaddress(subaddress),
|
||||
child: Container(
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: 28,
|
||||
bottom: 28
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: subaddress.label.isNotEmpty
|
||||
? 18 : 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isCurrent
|
||||
? currentTextColor
|
||||
: notCurrentTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return isCurrent
|
||||
? content
|
||||
: Slidable(
|
||||
key: Key(subaddress.address),
|
||||
actionPane: SlidableDrawerActionPane(),
|
||||
child: content,
|
||||
secondaryActions: <Widget>[
|
||||
IconSlideAction(
|
||||
caption: S.of(context).edit,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color,
|
||||
icon: Icons.edit,
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress, arguments: subaddress),
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class HeaderTile extends StatelessWidget {
|
||||
HeaderTile({
|
||||
@required this.onTap,
|
||||
@required this.title,
|
||||
@required this.icon
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final String title;
|
||||
final Icon icon;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: 24,
|
||||
bottom: 24
|
||||
),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 32,
|
||||
width: 32,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color
|
||||
),
|
||||
child: icon,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qr/qr.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/qr_painter.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_painter.dart';
|
||||
|
||||
class QrImage extends StatelessWidget {
|
||||
QrImage({
|
||||
@@ -17,7 +17,7 @@ class RescanPage extends BasePage {
|
||||
final rescanWalletStore = Provider.of<RescanWalletStore>(context);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
child:
|
||||
Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
BlockchainHeightWidget(key: blockchainKey),
|
||||
@@ -31,10 +31,8 @@ class RescanPage extends BasePage {
|
||||
restoreHeight: blockchainKey.currentState.height);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor))
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white,))
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/restore_button.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/image_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/base_restore_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
@@ -18,46 +16,38 @@ class RestoreOptionsPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.restore_restore_wallet;
|
||||
|
||||
@override
|
||||
Color get backgroundColor => Palette.creamyGrey;
|
||||
|
||||
final _imageSeedKeys = Image.asset('assets/images/seedKeys.png');
|
||||
final _imageRestoreSeed = Image.asset('assets/images/restoreSeed.png');
|
||||
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png');
|
||||
final imageBackup = Image.asset('assets/images/backup.png');
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final isLargeScreen = MediaQuery.of(context).size.height > largeHeight;
|
||||
|
||||
return BaseRestoreWidget(
|
||||
firstRestoreButton: RestoreButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(
|
||||
context, Routes.restoreWalletOptionsFromWelcome),
|
||||
imageWidget: ImageWidget(
|
||||
image: _imageSeedKeys,
|
||||
aspectRatioImage: _aspectRatioImage,
|
||||
isLargeScreen: isLargeScreen,
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
RestoreButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(
|
||||
context, Routes.restoreWalletOptionsFromWelcome),
|
||||
image: imageSeedKeys,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description: S.of(context).restore_description_from_seed_keys
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
onPressed: () {},
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
titleColor: Palette.lightViolet,
|
||||
color: Palette.lightViolet,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description: S.of(context).restore_description_from_seed_keys,
|
||||
textButton: S.of(context).restore_next,
|
||||
),
|
||||
secondRestoreButton: RestoreButton(
|
||||
onPressed: () {},
|
||||
imageWidget: ImageWidget(
|
||||
image: _imageRestoreSeed,
|
||||
aspectRatioImage: _aspectRatioImage,
|
||||
isLargeScreen: isLargeScreen,
|
||||
),
|
||||
titleColor: Palette.cakeGreen,
|
||||
color: Palette.cakeGreen,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup,
|
||||
textButton: S.of(context).restore_next,
|
||||
),
|
||||
isLargeScreen: isLargeScreen,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class RestoreWalletFromKeysPage extends BasePage {
|
||||
RestoreWalletFromKeysPage(
|
||||
@@ -47,11 +47,36 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
final _viewKeyController = TextEditingController();
|
||||
final _spendKeyController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_addressController.dispose();
|
||||
_viewKeyController.dispose();
|
||||
_spendKeyController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onHandleControllers(WalletRestorationStore walletRestorationStore) {
|
||||
if (_nameController.text.isNotEmpty &&
|
||||
_addressController.text.isNotEmpty &&
|
||||
_viewKeyController.text.isNotEmpty &&
|
||||
_spendKeyController.text.isNotEmpty) {
|
||||
walletRestorationStore.setDisabledState(false);
|
||||
} else {
|
||||
walletRestorationStore.setDisabledState(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
|
||||
_nameController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_addressController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_viewKeyController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_spendKeyController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
|
||||
reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||
if (state is WalletRestoredSuccessfully) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
@@ -62,48 +87,48 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(state.error),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.restore_title_from_keys,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 20.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 13, right: 13),
|
||||
child: Column(children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateWalletName(value);
|
||||
@@ -111,28 +136,34 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
controller: _addressController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_address,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateAddress(value);
|
||||
@@ -140,26 +171,32 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
controller: _viewKeyController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_view_key_private,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateKeys(value);
|
||||
@@ -167,26 +204,32 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
controller: _spendKeyController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_spend_key_private,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateKeys(value);
|
||||
@@ -194,16 +237,14 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
BlockchainHeightWidget(key: _blockchainHeightKey),
|
||||
]),
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
BlockchainHeightWidget(key: _blockchainHeightKey),
|
||||
]),
|
||||
),
|
||||
),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
walletRestorationStore.restoreFromKeys(
|
||||
@@ -216,10 +257,12 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||
}
|
||||
},
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor);
|
||||
}),
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isDisabled: walletRestorationStore.disabledState,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class RestoreWalletFromSeedDetailsPage extends BasePage {
|
||||
@override
|
||||
@@ -32,10 +32,24 @@ class _RestoreFromSeedDetailsFormState
|
||||
final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
|
||||
final _nameController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
||||
|
||||
_nameController.addListener(() {
|
||||
if (_nameController.text.isNotEmpty) {
|
||||
walletRestorationStore.setDisabledState(false);
|
||||
} else {
|
||||
walletRestorationStore.setDisabledState(true);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||
if (state is WalletRestoredSuccessfully) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
@@ -46,68 +60,65 @@ class _RestoreFromSeedDetailsFormState
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(state.error),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.restore_title_from_seed,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 20.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 13, right: 13),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen,
|
||||
width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore
|
||||
.validateWalletName(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
BlockchainHeightWidget(key: _blockchainHeightKey),
|
||||
]))
|
||||
],
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
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: (value) {
|
||||
walletRestorationStore
|
||||
.validateWalletName(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
BlockchainHeightWidget(key: _blockchainHeightKey),
|
||||
]),
|
||||
),
|
||||
),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
walletRestorationStore.restoreFromSeed(
|
||||
@@ -117,10 +128,12 @@ class _RestoreFromSeedDetailsFormState
|
||||
},
|
||||
isLoading: walletRestorationStore.state is WalletIsRestoring,
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor);
|
||||
}),
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isDisabled: walletRestorationStore.disabledState,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet_restoration/wallet_restoration_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class RestoreWalletFromSeedPage extends BasePage {
|
||||
RestoreWalletFromSeedPage(
|
||||
@@ -27,13 +28,10 @@ class RestoreWalletFromSeedPage extends BasePage {
|
||||
String get title => S.current.restore_title_from_seed;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => SizedBox(
|
||||
width: 80,
|
||||
height: 20,
|
||||
child: FlatButton(
|
||||
child: Text(S.of(context).clear),
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => formKey?.currentState?.clear()));
|
||||
Color get backgroundLightColor => Palette.lavender;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.lightNightBlue;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => RestoreFromSeedForm(key: formKey);
|
||||
@@ -59,7 +57,7 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
||||
onTap: () =>
|
||||
SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: SeedWidget(
|
||||
key: _seedKey,
|
||||
onMnemoticChange: (seed) => walletRestorationStore.setSeed(seed),
|
||||
|
||||
@@ -3,8 +3,6 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/restore_button.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/image_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/base_restore_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
@@ -20,49 +18,43 @@ class RestoreWalletOptionsPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.restore_seed_keys_restore;
|
||||
|
||||
@override
|
||||
Color get backgroundColor => Palette.creamyGrey;
|
||||
|
||||
final _imageSeed = Image.asset('assets/images/seedIco.png');
|
||||
final _imageKeys = Image.asset('assets/images/keysIco.png');
|
||||
final imageSeed = Image.asset('assets/images/restore_seed.png');
|
||||
final imageKeys = Image.asset('assets/images/restore_keys.png');
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
final isLargeScreen = MediaQuery.of(context).size.height > largeHeight;
|
||||
|
||||
return BaseRestoreWidget(
|
||||
firstRestoreButton: RestoreButton(
|
||||
onPressed: () {
|
||||
seedLanguageStore.setCurrentRoute(Routes.restoreWalletFromSeed);
|
||||
Navigator.pushNamed(context, Routes.seedLanguage, arguments: type);
|
||||
},
|
||||
imageWidget: ImageWidget(
|
||||
image: _imageSeed,
|
||||
aspectRatioImage: _aspectRatioImage,
|
||||
isLargeScreen: isLargeScreen),
|
||||
titleColor: Palette.lightViolet,
|
||||
color: Palette.lightViolet,
|
||||
title: S.of(context).restore_title_from_seed,
|
||||
description: S.of(context).restore_description_from_seed,
|
||||
textButton: S.of(context).restore_next,
|
||||
),
|
||||
secondRestoreButton: RestoreButton(
|
||||
onPressed: () {
|
||||
seedLanguageStore.setCurrentRoute(Routes.restoreWalletFromKeys);
|
||||
Navigator.pushNamed(context, Routes.seedLanguage, arguments: type);
|
||||
},
|
||||
imageWidget: ImageWidget(
|
||||
image: _imageKeys,
|
||||
aspectRatioImage: _aspectRatioImage,
|
||||
isLargeScreen: isLargeScreen),
|
||||
titleColor: Palette.cakeGreen,
|
||||
color: Palette.cakeGreen,
|
||||
title: S.of(context).restore_title_from_keys,
|
||||
description: S.of(context).restore_description_from_keys,
|
||||
textButton: S.of(context).restore_next,
|
||||
),
|
||||
isLargeScreen: isLargeScreen,
|
||||
);
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
RestoreButton(
|
||||
onPressed: () {
|
||||
seedLanguageStore
|
||||
.setCurrentRoute(Routes.restoreWalletFromSeed);
|
||||
Navigator.pushNamed(context, Routes.seedLanguage);
|
||||
},
|
||||
image: imageSeed,
|
||||
title: S.of(context).restore_title_from_seed,
|
||||
description: S.of(context).restore_description_from_seed),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
onPressed: () {
|
||||
seedLanguageStore
|
||||
.setCurrentRoute(Routes.restoreWalletFromKeys);
|
||||
Navigator.pushNamed(context, Routes.seedLanguage);
|
||||
},
|
||||
image: imageKeys,
|
||||
title: S.of(context).restore_title_from_keys,
|
||||
description: S.of(context).restore_description_from_keys),
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const largeHeight = 700;
|
||||
|
||||
class BaseRestoreWidget extends StatelessWidget {
|
||||
BaseRestoreWidget({
|
||||
@required this.firstRestoreButton,
|
||||
@required this.secondRestoreButton,
|
||||
this.isLargeScreen = false
|
||||
});
|
||||
|
||||
final Widget firstRestoreButton;
|
||||
final Widget secondRestoreButton;
|
||||
final bool isLargeScreen;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 20.0,
|
||||
right: 20.0,
|
||||
),
|
||||
child: isLargeScreen
|
||||
? Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: firstRestoreButton
|
||||
),
|
||||
Flexible(
|
||||
child: secondRestoreButton
|
||||
)
|
||||
],
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
firstRestoreButton,
|
||||
secondRestoreButton
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ImageWidget extends StatelessWidget {
|
||||
ImageWidget({
|
||||
@required this.image,
|
||||
@required this.aspectRatioImage,
|
||||
this.isLargeScreen = false});
|
||||
|
||||
final Image image;
|
||||
final double aspectRatioImage;
|
||||
final bool isLargeScreen;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return isLargeScreen
|
||||
? Flexible(
|
||||
child: Container(
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: image,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: image;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +1,70 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
|
||||
class RestoreButton extends StatelessWidget {
|
||||
const RestoreButton(
|
||||
{@required this.onPressed,
|
||||
@required this.imageWidget,
|
||||
@required this.color,
|
||||
@required this.titleColor,
|
||||
this.title = '',
|
||||
this.description = '',
|
||||
this.textButton = ''});
|
||||
const RestoreButton({
|
||||
@required this.onPressed,
|
||||
@required this.image,
|
||||
@required this.title,
|
||||
@required this.description});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Widget imageWidget;
|
||||
final Color color;
|
||||
final Color titleColor;
|
||||
final Image image;
|
||||
final String title;
|
||||
final String description;
|
||||
final String textButton;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Palette.buttonShadow,
|
||||
blurRadius: 10,
|
||||
offset: Offset(
|
||||
0,
|
||||
12,
|
||||
return GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 150,
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.topLeft,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
image,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
]),
|
||||
child: InkWell(
|
||||
onTap: onPressed,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
imageWidget,
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20),
|
||||
child: AutoSizeText(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: titleColor,
|
||||
fontWeight: FontWeight.bold),
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, top: 10),
|
||||
child: AutoSizeText(
|
||||
description,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentTextTheme.subhead.color,
|
||||
),
|
||||
maxLines: 2,
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Container(
|
||||
height: 56.0,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.headline
|
||||
.decorationColor,
|
||||
width: 1.15)),
|
||||
color: Colors.transparent,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
textButton,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
))
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+120
-126
@@ -4,19 +4,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet_seed/wallet_seed_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
||||
class SeedPage extends BasePage {
|
||||
SeedPage({this.onCloseCallback});
|
||||
|
||||
static final image = Image.asset('assets/images/seed_image.png');
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
static final image = Image.asset('assets/images/crypto_lock.png');
|
||||
|
||||
@override
|
||||
String get title => S.current.seed_title;
|
||||
@@ -32,135 +29,132 @@ class SeedPage extends BasePage {
|
||||
return onCloseCallback != null ? Offstage() : super.leading(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
return onCloseCallback != null
|
||||
? GestureDetector(
|
||||
onTap: () => onClose(context),
|
||||
child: Container(
|
||||
width: 70,
|
||||
height: 32,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
color: Theme.of(context).accentTextTheme.title.color
|
||||
),
|
||||
child: Text(
|
||||
S.of(context).seed_language_next,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.blue
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Offstage();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final walletSeedStore = Provider.of<WalletSeedStore>(context);
|
||||
String _seed;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(30.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
image,
|
||||
Container(
|
||||
margin: EdgeInsets.only(left: 30.0, top: 10.0, right: 30.0),
|
||||
child: Observer(builder: (_) {
|
||||
_seed = walletSeedStore.seed;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
width: 1.0,
|
||||
color: Theme.of(context)
|
||||
.dividerColor))),
|
||||
padding: EdgeInsets.only(bottom: 20.0),
|
||||
margin: EdgeInsets.only(bottom: 10.0),
|
||||
child: Text(
|
||||
walletSeedStore.name,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.color),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.0,
|
||||
),
|
||||
Text(
|
||||
walletSeedStore.seed,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 30.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () => Share.text(
|
||||
S.of(context).seed_share,
|
||||
_seed,
|
||||
'text/plain'),
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
text: S.of(context).save),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: _seed));
|
||||
Scaffold.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(S
|
||||
.of(context)
|
||||
.copied_to_clipboard),
|
||||
backgroundColor: Colors.green,
|
||||
duration:
|
||||
Duration(milliseconds: 1500),
|
||||
),
|
||||
);
|
||||
},
|
||||
text: S.of(context).copy,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.decorationColor),
|
||||
)))
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 40, right: 40, bottom: 20),
|
||||
content: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 33),
|
||||
child: image,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 33),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
_seed = walletSeedStore.seed;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
walletSeedStore.name,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
_seed,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 52
|
||||
),
|
||||
bottomSection: Container(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () => Share.text(
|
||||
S.of(context).seed_share,
|
||||
_seed,
|
||||
'text/plain'),
|
||||
text: S.of(context).save,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white),
|
||||
)
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: _seed));
|
||||
Scaffold.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(S
|
||||
.of(context)
|
||||
.copied_to_clipboard),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(milliseconds: 1500),
|
||||
),
|
||||
);
|
||||
},
|
||||
text: S.of(context).copy,
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white)
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
onCloseCallback != null
|
||||
? PrimaryButton(
|
||||
onPressed: () => onClose(context),
|
||||
text: S.of(context).restore_next,
|
||||
color: Palette.darkGrey,
|
||||
borderColor: Palette.darkGrey)
|
||||
: Offstage()
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,52 +1,94 @@
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
|
||||
class SeedLanguage extends BasePage {
|
||||
final imageSeed = Image.asset('assets/images/seedIco.png');
|
||||
@override
|
||||
Widget body(BuildContext context) => SeedLanguageForm();
|
||||
}
|
||||
|
||||
class SeedLanguageForm extends StatefulWidget {
|
||||
@override
|
||||
SeedLanguageFormState createState() => SeedLanguageFormState();
|
||||
}
|
||||
|
||||
class SeedLanguageFormState extends State<SeedLanguageForm> {
|
||||
static const aspectRatioImage = 1.22;
|
||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
Widget build(BuildContext context) {
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
|
||||
final List<String> seedLocales = [
|
||||
S.current.seed_language_english,
|
||||
S.current.seed_language_chinese,
|
||||
S.current.seed_language_dutch,
|
||||
S.current.seed_language_german,
|
||||
S.current.seed_language_japanese,
|
||||
S.current.seed_language_portuguese,
|
||||
S.current.seed_language_russian,
|
||||
S.current.seed_language_spanish
|
||||
];
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
imageSeed,
|
||||
Text(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletNameImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(top: 40),
|
||||
child: Text(
|
||||
S.of(context).seed_language_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(top: 24),
|
||||
child: Observer(
|
||||
builder: (_) => SelectButton(
|
||||
image: null,
|
||||
text: seedLocales[seedLanguages.indexOf(seedLanguageStore.selectedSeedLanguage)],
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color,
|
||||
onTap: () async => await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => SeedLanguagePicker()
|
||||
)
|
||||
)
|
||||
),
|
||||
SeedLanguagePicker(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PrimaryButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).popAndPushNamed(seedLanguageStore.currentRoute),
|
||||
text: S.of(context).seed_language_next,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor),
|
||||
],
|
||||
),
|
||||
)
|
||||
]),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (context) {
|
||||
return PrimaryButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).popAndPushNamed(seedLanguageStore.currentRoute),
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white);
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,238 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/present_picker.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class SeedLanguagePicker extends StatelessWidget {
|
||||
List<String> seedLocales = [
|
||||
S.current.seed_language_english,
|
||||
S.current.seed_language_chinese,
|
||||
S.current.seed_language_dutch,
|
||||
S.current.seed_language_german,
|
||||
S.current.seed_language_japanese,
|
||||
S.current.seed_language_portuguese,
|
||||
S.current.seed_language_russian,
|
||||
S.current.seed_language_spanish
|
||||
];
|
||||
List<Image> flagImages = [
|
||||
Image.asset('assets/images/usa.png'),
|
||||
Image.asset('assets/images/china.png'),
|
||||
Image.asset('assets/images/holland.png'),
|
||||
Image.asset('assets/images/germany.png'),
|
||||
Image.asset('assets/images/japan.png'),
|
||||
Image.asset('assets/images/portugal.png'),
|
||||
Image.asset('assets/images/russia.png'),
|
||||
Image.asset('assets/images/spain.png'),
|
||||
];
|
||||
|
||||
List<String> languageCodes = [
|
||||
'Eng',
|
||||
'Chi',
|
||||
'Ned',
|
||||
'Ger',
|
||||
'Jap',
|
||||
'Por',
|
||||
'Rus',
|
||||
'Esp',
|
||||
];
|
||||
|
||||
enum Places {topLeft, topRight, bottomLeft, bottomRight, inside}
|
||||
|
||||
class SeedLanguagePicker extends StatefulWidget {
|
||||
@override
|
||||
SeedLanguagePickerState createState() => SeedLanguagePickerState();
|
||||
}
|
||||
|
||||
class SeedLanguagePickerState extends State<SeedLanguagePicker> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
|
||||
return Observer(
|
||||
builder: (_) => InkWell(
|
||||
onTap: () => _setSeedLanguage(context),
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
//width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).dividerTheme.color
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0)
|
||||
),
|
||||
child: Text(seedLocales[seedLanguages.indexOf(seedLanguageStore.selectedSeedLanguage)],
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16.0, color: Palette.lightBlue),
|
||||
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).seed_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: Container(
|
||||
height: 300,
|
||||
width: 300,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
color: Theme.of(context).dividerColor
|
||||
),
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisSpacing: 1,
|
||||
mainAxisSpacing: 1,
|
||||
children: List.generate(9, (index) {
|
||||
|
||||
if (index == 8) {
|
||||
|
||||
return gridTile(
|
||||
isCurrent: false,
|
||||
place: Places.bottomRight,
|
||||
image: null,
|
||||
text: '',
|
||||
onTap: null);
|
||||
|
||||
} else {
|
||||
|
||||
final code = languageCodes[index];
|
||||
final flag = flagImages[index];
|
||||
final isCurrent = index == seedLanguages.indexOf(seedLanguageStore.selectedSeedLanguage);
|
||||
|
||||
if (index == 0) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.topLeft,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
seedLanguageStore.setSelectedSeedLanguage(seedLanguages[index]);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (index == 2) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.topRight,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
seedLanguageStore.setSelectedSeedLanguage(seedLanguages[index]);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (index == 6) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.bottomLeft,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
seedLanguageStore.setSelectedSeedLanguage(seedLanguages[index]);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.inside,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
seedLanguageStore.setSelectedSeedLanguage(seedLanguages[index]);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
);
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _setSeedLanguage(BuildContext context) async {
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
String selectedSeedLanguage =
|
||||
await presentPicker(context, seedLocales);
|
||||
Widget gridTile({
|
||||
@required bool isCurrent,
|
||||
@required Places place,
|
||||
@required Image image,
|
||||
@required String text,
|
||||
@required VoidCallback onTap}) {
|
||||
|
||||
if (selectedSeedLanguage != null) {
|
||||
selectedSeedLanguage = seedLanguages[seedLocales.indexOf(selectedSeedLanguage)];
|
||||
seedLanguageStore.setSelectedSeedLanguage(selectedSeedLanguage);
|
||||
BorderRadius borderRadius;
|
||||
final color = isCurrent
|
||||
? Theme.of(context).accentTextTheme.subtitle.decorationColor
|
||||
: Theme.of(context).primaryTextTheme.display1.color;
|
||||
final textColor = isCurrent
|
||||
? Colors.blue
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
switch (place) {
|
||||
case Places.topLeft:
|
||||
borderRadius = BorderRadius.only(topLeft: Radius.circular(14));
|
||||
break;
|
||||
case Places.topRight:
|
||||
borderRadius = BorderRadius.only(topRight: Radius.circular(14));
|
||||
break;
|
||||
case Places.bottomLeft:
|
||||
borderRadius = BorderRadius.only(bottomLeft: Radius.circular(14));
|
||||
break;
|
||||
case Places.bottomRight:
|
||||
borderRadius = BorderRadius.only(bottomRight: Radius.circular(14));
|
||||
break;
|
||||
case Places.inside:
|
||||
borderRadius = BorderRadius.all(Radius.circular(0));
|
||||
break;
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: borderRadius,
|
||||
color: color
|
||||
),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? image
|
||||
: Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 10)
|
||||
: EdgeInsets.only(left: 0),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: textColor
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+332
-310
@@ -17,22 +17,58 @@ import 'package:cake_wallet/src/stores/send/send_store.dart';
|
||||
import 'package:cake_wallet/src/stores/send/sending_state.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/src/domain/common/calculate_estimated_fee.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/top_panel.dart';
|
||||
import 'package:dotted_border/dotted_border.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/src/screens/send/widgets/sending_alert.dart';
|
||||
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||
import 'package:cake_wallet/src/stores/send_template/send_template_store.dart';
|
||||
|
||||
class SendPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.send_title;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
Color get backgroundLightColor => Palette.lavender;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.lightNightBlue;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
|
||||
@override
|
||||
Widget trailing(context) {
|
||||
final sendStore = Provider.of<SendStore>(context);
|
||||
|
||||
return Container(
|
||||
height: 32,
|
||||
width: 82,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
color: Theme.of(context).accentTextTheme.title.color
|
||||
),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
onPressed: () => sendStore.clear(),
|
||||
child: Text(
|
||||
S.of(context).clear,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
color: Colors.blue),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => SendForm();
|
||||
}
|
||||
@@ -44,7 +80,6 @@ class SendForm extends StatefulWidget {
|
||||
|
||||
class SendFormState extends State<SendForm> {
|
||||
final _addressController = TextEditingController();
|
||||
final _paymentIdController = TextEditingController();
|
||||
final _cryptoAmountController = TextEditingController();
|
||||
final _fiatAmountController = TextEditingController();
|
||||
|
||||
@@ -75,14 +110,11 @@ class SendFormState extends State<SendForm> {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).openalias_alert_title),
|
||||
content: Text(S.of(context).openalias_alert_content(sendStore.recordName)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop())
|
||||
],
|
||||
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()
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -96,92 +128,20 @@ class SendFormState extends State<SendForm> {
|
||||
final balanceStore = Provider.of<BalanceStore>(context);
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
final syncStore = Provider.of<SyncStore>(context);
|
||||
final sendTemplateStore = Provider.of<SendTemplateStore>(context);
|
||||
|
||||
_setEffects(context);
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.all(0),
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 38, right: 30),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Palette.shadowGrey,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 12),
|
||||
)
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
width: 1,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.subtitle
|
||||
.backgroundColor))),
|
||||
child: SizedBox(
|
||||
height: 56,
|
||||
width: double.infinity,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Observer(builder: (_) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(S.of(context).send_your_wallet,
|
||||
style: TextStyle(
|
||||
fontSize: 12, color: Palette.lightViolet)),
|
||||
Text(walletStore.name,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color,
|
||||
height: 1.25)),
|
||||
]);
|
||||
}),
|
||||
Observer(builder: (context) {
|
||||
final savedDisplayMode = settingsStore.balanceDisplayMode;
|
||||
final availableBalance =
|
||||
savedDisplayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: balanceStore.unlockedBalance;
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(S.of(context).xmr_available_balance,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.backgroundColor,
|
||||
)),
|
||||
Text(availableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color,
|
||||
height: 1.1)),
|
||||
]);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 38, right: 33, top: 10, bottom: 30),
|
||||
children: <Widget>[
|
||||
TopPanel(
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
widget: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: <Widget>[
|
||||
AddressTextField(
|
||||
controller: _addressController,
|
||||
@@ -190,126 +150,126 @@ class SendFormState extends State<SendForm> {
|
||||
onURIScanned: (uri) {
|
||||
var address = '';
|
||||
var amount = '';
|
||||
var paymentId = '';
|
||||
|
||||
if (uri != null) {
|
||||
address = uri.path;
|
||||
amount = uri.queryParameters['tx_amount'];
|
||||
paymentId = uri.queryParameters['tx_payment_id'];
|
||||
} else {
|
||||
address = uri.toString();
|
||||
}
|
||||
|
||||
_addressController.text = address;
|
||||
_cryptoAmountController.text = amount;
|
||||
_paymentIdController.text = paymentId;
|
||||
},
|
||||
options: [
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook
|
||||
],
|
||||
buttonColor: Theme.of(context).accentTextTheme.title.color,
|
||||
validator: (value) {
|
||||
sendStore.validateAddress(value,
|
||||
cryptoCurrency: CryptoCurrency.xmr);
|
||||
return sendStore.errorMessage;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.backgroundColor),
|
||||
controller: _paymentIdController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).send_payment_id,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
sendStore.validatePaymentID(value);
|
||||
return sendStore.errorMessage;
|
||||
}),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
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('XMR:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
)),
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 5
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width/2,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
' / ' + balanceStore.unlockedBalance,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
)
|
||||
),
|
||||
),
|
||||
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: () => sendStore.setSendAll(),
|
||||
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: (value) {
|
||||
sendStore.validateXMR(
|
||||
value, balanceStore.unlockedBalance);
|
||||
return sendStore.errorMessage;
|
||||
}),
|
||||
);
|
||||
}
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color),
|
||||
controller: _cryptoAmountController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: Text('XMR:',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color,
|
||||
)),
|
||||
),
|
||||
suffixIcon: Container(
|
||||
width: 1,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Center(
|
||||
child: InkWell(
|
||||
onTap: () => sendStore.setSendAll(),
|
||||
child: Text(S.of(context).all,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.decorationColor))),
|
||||
),
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context).hintColor),
|
||||
hintText: '0.0000',
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
sendStore.validateXMR(
|
||||
value, balanceStore.unlockedBalance);
|
||||
return sendStore.errorMessage;
|
||||
}),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color),
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
controller: _fiatAmountController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
@@ -323,124 +283,188 @@ class SendFormState extends State<SendForm> {
|
||||
child: Text(
|
||||
'${settingsStore.fiatCurrency.toString()}:',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.color,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
)),
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context).hintColor),
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
hintText: '0.00',
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)))),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0, bottom: 10),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(S.of(context).send_estimated_fee,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.overline
|
||||
.backgroundColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
)),
|
||||
Text(
|
||||
'${calculateEstimatedFee(priority: settingsStore.transactionPriority)} XMR',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.overline
|
||||
.backgroundColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
S.of(context).send_priority(
|
||||
settingsStore.transactionPriority.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color,
|
||||
height: 1.3)),
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
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: syncStore.status is SyncedSyncStatus
|
||||
? () async {
|
||||
// Hack. Don't ask me.
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
// Hack. Don't ask me.
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
|
||||
if (_formKey.currentState.validate()) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
S.of(context).send_creating_transaction),
|
||||
content: Text(S.of(context).confirm_sending),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).send),
|
||||
onPressed: () async {
|
||||
await Navigator.of(dialogContext)
|
||||
.popAndPushNamed(Routes.auth,
|
||||
arguments: (bool
|
||||
isAuthenticatedSuccessfully,
|
||||
AuthPageState auth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (_formKey.currentState.validate()) {
|
||||
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();
|
||||
Navigator.of(auth.context).pop();
|
||||
|
||||
sendStore.createTransaction(
|
||||
address: _addressController.text,
|
||||
paymentId:
|
||||
_paymentIdController.text);
|
||||
});
|
||||
}),
|
||||
FlatButton(
|
||||
child: Text(S.of(context).cancel),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop())
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
: null,
|
||||
sendStore.createTransaction(
|
||||
address: _addressController.text,
|
||||
paymentId: '');
|
||||
});
|
||||
},
|
||||
actionRightButton: () =>
|
||||
Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
: null,
|
||||
text: S.of(context).send,
|
||||
color: Theme.of(context).accentTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).accentTextTheme.button.decorationColor,
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white,
|
||||
isLoading: sendStore.state is CreatingTransaction ||
|
||||
sendStore.state is TransactionCommiting);
|
||||
}));
|
||||
sendStore.state is TransactionCommiting,
|
||||
isDisabled: !(syncStore.status is SyncedSyncStatus),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
@@ -462,6 +486,20 @@ class SendFormState extends State<SendForm> {
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendStore.address, (String address) {
|
||||
if (address != _addressController.text) {
|
||||
_addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
_addressController.addListener(() {
|
||||
final address = _addressController.text;
|
||||
|
||||
if (sendStore.address != address) {
|
||||
sendStore.changeAddress(address);
|
||||
}
|
||||
});
|
||||
|
||||
_fiatAmountController.addListener(() {
|
||||
final fiatAmount = _fiatAmountController.text;
|
||||
|
||||
@@ -484,14 +522,11 @@ class SendFormState extends State<SendForm> {
|
||||
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()
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -502,23 +537,25 @@ class SendFormState extends State<SendForm> {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).confirm_sending),
|
||||
content: Text(S.of(context).commit_transaction_amount_fee(
|
||||
sendStore.pendingTransaction.amount,
|
||||
sendStore.pendingTransaction.fee)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
sendStore.commitTransaction();
|
||||
}),
|
||||
FlatButton(
|
||||
child: Text(S.of(context).cancel),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
)
|
||||
],
|
||||
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()
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -526,23 +563,8 @@ class SendFormState extends State<SendForm> {
|
||||
|
||||
if (state is TransactionCommitted) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(S.of(context).sending),
|
||||
content: Text(S.of(context).transaction_sent),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
_addressController.text = '';
|
||||
_cryptoAmountController.text = '';
|
||||
Navigator.of(context)..pop()..pop();
|
||||
})
|
||||
],
|
||||
);
|
||||
});
|
||||
_addressController.text = '';
|
||||
_cryptoAmountController.text = '';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/palette.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/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/stores/balance/balance_store.dart';
|
||||
import 'package:cake_wallet/src/stores/send/send_store.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/stores/send_template/send_template_store.dart';
|
||||
|
||||
class SendTemplatePage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.send_title;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => Palette.lavender;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.lightNightBlue;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => SendTemplateForm();
|
||||
}
|
||||
|
||||
class SendTemplateForm extends StatefulWidget {
|
||||
@override
|
||||
SendTemplateFormState createState() => SendTemplateFormState();
|
||||
}
|
||||
|
||||
class SendTemplateFormState extends State<SendTemplateForm> {
|
||||
final _nameController = TextEditingController();
|
||||
final _addressController = TextEditingController();
|
||||
final _cryptoAmountController = TextEditingController();
|
||||
final _fiatAmountController = TextEditingController();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
bool _effectsInstalled = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_addressController.dispose();
|
||||
_cryptoAmountController.dispose();
|
||||
_fiatAmountController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final balanceStore = Provider.of<BalanceStore>(context);
|
||||
final sendStore = Provider.of<SendStore>(context);
|
||||
sendStore.settingsStore = settingsStore;
|
||||
final sendTemplateStore = Provider.of<SendTemplateStore>(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>[
|
||||
TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
hintText: S.of(context).send_name,
|
||||
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: (value) {
|
||||
sendTemplateStore.validateTemplate(value);
|
||||
return sendTemplateStore.errorMessage;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
controller: _addressController,
|
||||
placeholder: S.of(context).send_monero_address,
|
||||
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: (value) {
|
||||
sendTemplateStore.validateTemplate(value);
|
||||
return sendTemplateStore.errorMessage;
|
||||
},
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
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('XMR:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.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))),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: TextFormField(
|
||||
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(
|
||||
'${settingsStore.fiatCurrency.toString()}:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
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)))),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: PrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
sendTemplateStore.addTemplate(
|
||||
name: _nameController.text,
|
||||
address: _addressController.text,
|
||||
cryptoCurrency: 'XMR',
|
||||
amount: _cryptoAmountController.text
|
||||
);
|
||||
sendTemplateStore.update();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Colors.blue,
|
||||
textColor: Colors.white
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
if (_effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
final sendStore = Provider.of<SendStore>(context);
|
||||
|
||||
reaction((_) => sendStore.fiatAmount, (String amount) {
|
||||
if (amount != _fiatAmountController.text) {
|
||||
_fiatAmountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendStore.cryptoAmount, (String amount) {
|
||||
if (amount != _cryptoAmountController.text) {
|
||||
_cryptoAmountController.text = amount;
|
||||
}
|
||||
});
|
||||
|
||||
_fiatAmountController.addListener(() {
|
||||
final fiatAmount = _fiatAmountController.text;
|
||||
|
||||
if (sendStore.fiatAmount != fiatAmount) {
|
||||
sendStore.changeFiatAmount(fiatAmount);
|
||||
}
|
||||
});
|
||||
|
||||
_cryptoAmountController.addListener(() {
|
||||
final cryptoAmount = _cryptoAmountController.text;
|
||||
|
||||
if (sendStore.cryptoAmount != cryptoAmount) {
|
||||
sendStore.changeCryptoAmount(cryptoAmount);
|
||||
}
|
||||
});
|
||||
|
||||
_effectsInstalled = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||
|
||||
class ConfirmSendingAlert extends BaseAlertDialog {
|
||||
ConfirmSendingAlert({
|
||||
@required this.alertTitle,
|
||||
@required this.amount,
|
||||
@required this.amountValue,
|
||||
@required this.fee,
|
||||
@required this.feeValue,
|
||||
@required this.leftButtonText,
|
||||
@required this.rightButtonText,
|
||||
@required this.actionLeftButton,
|
||||
@required this.actionRightButton,
|
||||
this.alertBarrierDismissible = true
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
final String amount;
|
||||
final String amountValue;
|
||||
final String fee;
|
||||
final String feeValue;
|
||||
final String leftButtonText;
|
||||
final String rightButtonText;
|
||||
final VoidCallback actionLeftButton;
|
||||
final VoidCallback actionRightButton;
|
||||
final bool alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
|
||||
@override
|
||||
String get leftActionButtonText => leftButtonText;
|
||||
@override
|
||||
String get rightActionButtonText => rightButtonText;
|
||||
@override
|
||||
VoidCallback get actionLeft => actionLeftButton;
|
||||
@override
|
||||
VoidCallback get actionRight => actionRightButton;
|
||||
@override
|
||||
bool get barrierDismissible => alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
Widget content(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
amount,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
amountValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
fee,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
feeValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import 'dart:ui';
|
||||
import 'package:cake_wallet/src/stores/send/sending_state.dart';
|
||||
import 'package:flutter/material.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';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class SendingAlert extends StatefulWidget {
|
||||
SendingAlert({@required this.sendStore});
|
||||
|
||||
final SendStore sendStore;
|
||||
|
||||
@override
|
||||
SendingAlertState createState() => SendingAlertState(sendStore);
|
||||
}
|
||||
|
||||
class SendingAlertState extends State<SendingAlert> {
|
||||
SendingAlertState(this.sendStore);
|
||||
|
||||
final SendStore sendStore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
final state = sendStore.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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/language.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
|
||||
class ChangeLanguage extends BasePage {
|
||||
@override
|
||||
@@ -15,66 +16,85 @@ class ChangeLanguage extends BasePage {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final currentLanguage = Provider.of<Language>(context);
|
||||
|
||||
final currentColor = Theme.of(context).selectedRowColor;
|
||||
final notCurrentColor = Theme.of(context).accentTextTheme.subhead.backgroundColor;
|
||||
final currentColor = Colors.green;
|
||||
final notCurrentColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
final shortDivider = Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
);
|
||||
|
||||
final longDivider = Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10.0, bottom: 10.0),
|
||||
padding: EdgeInsets.only(top: 10.0),
|
||||
child: ListView.builder(
|
||||
itemCount: languages.values.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final item = languages.values.elementAt(index);
|
||||
final code = languages.keys.elementAt(index);
|
||||
|
||||
final isCurrent = settingsStore.languageCode == null
|
||||
? false
|
||||
: languages.keys.elementAt(index) ==
|
||||
settingsStore.languageCode;
|
||||
: code == settingsStore.languageCode;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(top: 10.0, bottom: 10.0),
|
||||
color: isCurrent ? currentColor : notCurrentColor,
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
languages.values.elementAt(index),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
onTap: () async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
S.of(context).change_language,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: Text(
|
||||
S.of(context).change_language_to(
|
||||
languages.values.elementAt(index)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(S.of(context).cancel)),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
index == 0 ? longDivider : Offstage(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 4, bottom: 4),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24),
|
||||
title: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isCurrent ? currentColor : notCurrentColor
|
||||
),
|
||||
),
|
||||
trailing: isCurrent
|
||||
? Icon(Icons.done, color: currentColor)
|
||||
: Offstage(),
|
||||
onTap: () async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_language,
|
||||
alertContent: S.of(context).change_language_to(item),
|
||||
leftButtonText: S.of(context).change,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
settingsStore.saveLanguageCode(
|
||||
languageCode:
|
||||
languages.keys.elementAt(index));
|
||||
currentLanguage.setCurrentLanguage(
|
||||
languages.keys.elementAt(index));
|
||||
languageCode: code);
|
||||
currentLanguage.setCurrentLanguage(code);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(S.of(context).change)),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
item == languages.values.last
|
||||
? longDivider
|
||||
: shortDivider
|
||||
],
|
||||
);
|
||||
},
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class EnterPinCode extends StatefulWidget {
|
||||
const EnterPinCode(this.currentPinLength, this.currentPin);
|
||||
|
||||
final int currentPinLength;
|
||||
final List<int> currentPin;
|
||||
|
||||
@override
|
||||
EnterPinCodeState createState() =>
|
||||
EnterPinCodeState(currentPinLength, currentPin);
|
||||
}
|
||||
|
||||
class EnterPinCodeState extends State<EnterPinCode> {
|
||||
EnterPinCodeState(this.pinLength, this.currentPin);
|
||||
|
||||
final _gridViewKey = GlobalKey();
|
||||
final _closeButtonImage = Image.asset('assets/images/close_button.png');
|
||||
final _closeButtonImageDarkTheme =
|
||||
Image.asset('assets/images/close_button_dark_theme.png');
|
||||
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
||||
final int pinLength;
|
||||
final List<int> currentPin;
|
||||
List<int> pin;
|
||||
double _aspectRatio = 0;
|
||||
|
||||
void _calcualteCurrentAspectRatio() {
|
||||
final renderBox =
|
||||
_gridViewKey.currentContext.findRenderObject() as RenderBox;
|
||||
final cellWidth = renderBox.size.width / 3;
|
||||
final cellHeight = renderBox.size.height / 4;
|
||||
|
||||
if (cellWidth > 0 && cellHeight > 0) {
|
||||
_aspectRatio = cellWidth / cellHeight;
|
||||
}
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
pin = List<int>.filled(pinLength, null);
|
||||
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
|
||||
}
|
||||
|
||||
void _afterLayout(dynamic _) => _calcualteCurrentAspectRatio();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
appBar: CupertinoNavigationBar(
|
||||
leading: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, false);
|
||||
},
|
||||
child: _isDarkTheme
|
||||
? _closeButtonImageDarkTheme
|
||||
: _closeButtonImage),
|
||||
),
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
border: null),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 2),
|
||||
Text(S.of(context).enter_your_pin,
|
||||
style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)),
|
||||
Spacer(flex: 3),
|
||||
Container(
|
||||
width: 180,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: List.generate(pinLength, (index) {
|
||||
const size = 10.0;
|
||||
final isFilled = pin[index] != null;
|
||||
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color:
|
||||
isFilled ? Palette.deepPurple : Colors.transparent,
|
||||
border: Border.all(color: Palette.wildDarkBlue),
|
||||
));
|
||||
}),
|
||||
),
|
||||
),
|
||||
Spacer(flex: 3),
|
||||
Flexible(
|
||||
flex: 24,
|
||||
child: Container(
|
||||
key: _gridViewKey,
|
||||
child: _aspectRatio > 0
|
||||
? GridView.count(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: _aspectRatio,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: List.generate(12, (index) {
|
||||
if (index == 9) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _isDarkTheme
|
||||
? PaletteDark.darkThemePinButton
|
||||
: Palette.darkGrey,
|
||||
),
|
||||
);
|
||||
} else if (index == 10) {
|
||||
index = 0;
|
||||
} else if (index == 11) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5.0),
|
||||
child: FlatButton(
|
||||
onPressed: () {
|
||||
_pop();
|
||||
},
|
||||
color: _isDarkTheme
|
||||
? PaletteDark.darkThemePinButton
|
||||
: Palette.darkGrey,
|
||||
shape: CircleBorder(),
|
||||
child: deleteIconImage,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5.0),
|
||||
child: FlatButton(
|
||||
onPressed: () {
|
||||
_push(index);
|
||||
},
|
||||
color: _isDarkTheme
|
||||
? PaletteDark.darkThemePinDigitButton
|
||||
: Palette.creamyGrey,
|
||||
shape: CircleBorder(),
|
||||
child: Text('$index',
|
||||
style: TextStyle(
|
||||
fontSize: 23.0,
|
||||
color: Palette.blueGrey)),
|
||||
),
|
||||
);
|
||||
}),
|
||||
)
|
||||
: null))
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
void _showIncorrectPinDialog(BuildContext context) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(S.of(context).pin_is_incorrect),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _push(int num) {
|
||||
if (_pinLength() >= pinLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < pin.length; i++) {
|
||||
if (pin[i] == null) {
|
||||
setState(() => pin[i] = num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final currentPinLength = _pinLength();
|
||||
|
||||
if (currentPinLength == pinLength) {
|
||||
if (listEquals<int>(pin, currentPin)) {
|
||||
Navigator.pop(context, true);
|
||||
} else {
|
||||
Navigator.pop(context, false);
|
||||
|
||||
_showIncorrectPinDialog(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _pop() {
|
||||
if (_pinLength() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = pin.length - 1; i >= 0; i--) {
|
||||
if (pin[i] != null) {
|
||||
setState(() => pin[i] = null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _pinLength() {
|
||||
return pin.fold(0, (v, e) {
|
||||
if (e != null) {
|
||||
return v + 1;
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -17,7 +16,7 @@ import 'package:cake_wallet/src/screens/settings/attributes.dart';
|
||||
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/items/settings_item.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/items/item_headers.dart';
|
||||
import 'package:cake_wallet/src/widgets/present_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
// Settings widgets
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_arrow_list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_header_list_row.dart';
|
||||
@@ -30,12 +29,6 @@ class SettingsPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.settings_title;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
Color get backgroundColor => Palette.lightGrey2;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SettingsForm();
|
||||
@@ -73,21 +66,6 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
settingsStore.setItemHeaders();
|
||||
|
||||
_items.addAll([
|
||||
SettingsItem(title: ItemHeaders.nodes, attribute: Attributes.header),
|
||||
SettingsItem(
|
||||
onTaped: () => Navigator.of(context).pushNamed(Routes.nodeList),
|
||||
title: ItemHeaders.currentNode,
|
||||
widget: Observer(
|
||||
builder: (_) => Text(
|
||||
settingsStore.node == null ? '' : settingsStore.node.uri,
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.subtitle.color),
|
||||
)),
|
||||
attribute: Attributes.widget),
|
||||
SettingsItem(title: ItemHeaders.wallets, attribute: Attributes.header),
|
||||
SettingsItem(
|
||||
onTaped: () => _setBalance(context),
|
||||
title: ItemHeaders.displayBalanceAs,
|
||||
@@ -96,9 +74,8 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
settingsStore.balanceDisplayMode.toString(),
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.subtitle.color),
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)),
|
||||
attribute: Attributes.widget),
|
||||
SettingsItem(
|
||||
@@ -109,9 +86,8 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
settingsStore.fiatCurrency.toString(),
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.subtitle.color),
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)),
|
||||
attribute: Attributes.widget),
|
||||
SettingsItem(
|
||||
@@ -122,15 +98,14 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
settingsStore.transactionPriority.toString(),
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.subtitle.color),
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
)),
|
||||
attribute: Attributes.widget),
|
||||
SettingsItem(
|
||||
title: ItemHeaders.saveRecipientAddress,
|
||||
attribute: Attributes.switcher),
|
||||
SettingsItem(title: ItemHeaders.personal, attribute: Attributes.header),
|
||||
SettingsItem(title: '', attribute: Attributes.header),
|
||||
SettingsItem(
|
||||
onTaped: () {
|
||||
Navigator.of(context).pushNamed(Routes.auth,
|
||||
@@ -166,7 +141,11 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
children: [
|
||||
Text(S
|
||||
.of(context)
|
||||
.settings_transactions),
|
||||
.settings_transactions,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Checkbox(
|
||||
value: settingsStore
|
||||
.actionlistDisplayMode
|
||||
@@ -183,7 +162,12 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).settings_trades),
|
||||
Text(
|
||||
S.of(context).settings_trades,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
Checkbox(
|
||||
value: settingsStore
|
||||
.actionlistDisplayMode
|
||||
@@ -196,17 +180,14 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
],
|
||||
child: Container(
|
||||
height: 56,
|
||||
padding: EdgeInsets.only(left: 20, right: 20),
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(S.of(context).settings_display_on_dashboard_list,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color)),
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
Observer(builder: (_) {
|
||||
var title = '';
|
||||
|
||||
@@ -233,17 +214,14 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
|
||||
return Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.subtitle
|
||||
.color));
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color));
|
||||
})
|
||||
]),
|
||||
));
|
||||
},
|
||||
attribute: Attributes.rawWidget),
|
||||
SettingsItem(title: ItemHeaders.support, attribute: Attributes.header),
|
||||
SettingsItem(title: '', attribute: Attributes.header),
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_emailUrl),
|
||||
title: 'Email',
|
||||
@@ -253,13 +231,13 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_telegramUrl),
|
||||
title: 'Telegram',
|
||||
link: 't.me/cakewallet_bot',
|
||||
link: 'Cake_Wallet',
|
||||
image: _telegramImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_twitterUrl),
|
||||
title: 'Twitter',
|
||||
link: 'twitter.com/CakewalletXMR',
|
||||
link: '@CakeWalletXMR',
|
||||
image: _twitterImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
@@ -268,18 +246,18 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
link: 'support@changenow.io',
|
||||
image: _changeNowImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_morphUrl),
|
||||
title: 'Morph',
|
||||
link: 'support@morphtoken.com',
|
||||
image: _morphImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_xmrToUrl),
|
||||
title: 'XMR.to',
|
||||
link: 'support@xmr.to',
|
||||
image: _xmrBtcImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
onTaped: () => _launchUrl(_morphUrl),
|
||||
title: 'MorphToken',
|
||||
link: 'support@morphtoken.com',
|
||||
image: _morphImage,
|
||||
attribute: Attributes.link),
|
||||
SettingsItem(
|
||||
onTaped: () {
|
||||
Navigator.push(
|
||||
@@ -345,87 +323,116 @@ class SettingsFormState extends State<SettingsForm> {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
settingsStore.setItemHeaders();
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _items[index];
|
||||
bool _isDrawDivider = true;
|
||||
final shortDivider = Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
);
|
||||
|
||||
if (item.attribute == Attributes.header || item == _items.last) {
|
||||
_isDrawDivider = false;
|
||||
} else {
|
||||
if (_items[index + 1].attribute == Attributes.header) {
|
||||
_isDrawDivider = false;
|
||||
}
|
||||
}
|
||||
final longDivider = Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
_getWidget(item),
|
||||
_isDrawDivider
|
||||
? Container(
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.headline
|
||||
.backgroundColor,
|
||||
padding: EdgeInsets.only(
|
||||
left: 20.0,
|
||||
right: 20.0,
|
||||
),
|
||||
child: Divider(
|
||||
color: Theme.of(context).dividerColor,
|
||||
height: 1.0,
|
||||
),
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
);
|
||||
}),
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 20.0),
|
||||
title: Text(
|
||||
settingsStore.itemHeaders[ItemHeaders.version],
|
||||
style: TextStyle(
|
||||
fontSize: 14.0, color: Palette.wildDarkBlue)
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
longDivider,
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _items[index];
|
||||
|
||||
Widget divider;
|
||||
|
||||
if (item.attribute == Attributes.header || item == _items.last) {
|
||||
divider = longDivider;
|
||||
} else if (_items[index + 1].attribute == Attributes.header){
|
||||
divider = longDivider;
|
||||
} else {
|
||||
divider = shortDivider;
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
_getWidget(item),
|
||||
divider
|
||||
],
|
||||
);
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: ListTile(
|
||||
title: Center(
|
||||
child: Text(
|
||||
settingsStore.itemHeaders[ItemHeaders.version],
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color)
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _setBalance(BuildContext context) async {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final selectedDisplayMode =
|
||||
await presentPicker(context, BalanceDisplayMode.all);
|
||||
final items = BalanceDisplayMode.all;
|
||||
final selectedItem = items.indexOf(settingsStore.balanceDisplayMode);
|
||||
|
||||
if (selectedDisplayMode != null) {
|
||||
await settingsStore.setCurrentBalanceDisplayMode(
|
||||
balanceDisplayMode: selectedDisplayMode);
|
||||
}
|
||||
await showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).please_select,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onItemSelected: (BalanceDisplayMode mode) async =>
|
||||
await settingsStore.setCurrentBalanceDisplayMode(
|
||||
balanceDisplayMode: mode)),
|
||||
context: context);
|
||||
}
|
||||
|
||||
Future<void> _setCurrency(BuildContext context) async {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final selectedCurrency = await presentPicker(context, FiatCurrency.all);
|
||||
final items = FiatCurrency.all;
|
||||
final selectedItem = items.indexOf(settingsStore.fiatCurrency);
|
||||
|
||||
if (selectedCurrency != null) {
|
||||
await settingsStore.setCurrentFiatCurrency(currency: selectedCurrency);
|
||||
}
|
||||
await showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).please_select,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onItemSelected: (FiatCurrency currency) async =>
|
||||
await settingsStore.setCurrentFiatCurrency(currency: currency)),
|
||||
context: context);
|
||||
}
|
||||
|
||||
Future<void> _setTransactionPriority(BuildContext context) async {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final selectedPriority =
|
||||
await presentPicker(context, TransactionPriority.all);
|
||||
final items = TransactionPriority.all;
|
||||
final selectedItem = items.indexOf(settingsStore.transactionPriority);
|
||||
|
||||
if (selectedPriority != null) {
|
||||
await settingsStore.setCurrentTransactionPriority(
|
||||
priority: selectedPriority);
|
||||
}
|
||||
await showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).please_select,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onItemSelected: (TransactionPriority priority) async =>
|
||||
await settingsStore.setCurrentTransactionPriority(
|
||||
priority: priority)),
|
||||
context: context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,21 +8,22 @@ class SettingsArrowListRow extends StatelessWidget {
|
||||
|
||||
final VoidCallback onTaped;
|
||||
final String title;
|
||||
final _cakeArrowImage = Image.asset('assets/images/cake_arrow.png');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final _cakeArrowImage = Image.asset('assets/images/select_arrow.png',
|
||||
color: Theme.of(context).primaryTextTheme.caption.color);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
contentPadding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
title: Observer(
|
||||
builder: (_) => Text(
|
||||
settingsStore.itemHeaders[title],
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
)),
|
||||
trailing: _cakeArrowImage,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class SettingsHeaderListRow extends StatelessWidget {
|
||||
@@ -16,7 +15,7 @@ class SettingsHeaderListRow extends StatelessWidget {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: 28.0,
|
||||
height: 20.0,
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20.0),
|
||||
@@ -25,9 +24,12 @@ class SettingsHeaderListRow extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Observer(
|
||||
builder: (_) => Text(
|
||||
settingsStore.itemHeaders[title],
|
||||
title.isNotEmpty
|
||||
? settingsStore.itemHeaders[title]
|
||||
: '',
|
||||
style: TextStyle(
|
||||
fontSize: 15.0, color: Palette.wildDarkBlue),
|
||||
fontSize: 15.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
))
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class SettingsLinktListRow extends StatelessWidget {
|
||||
SettingsLinktListRow(
|
||||
@@ -13,9 +12,9 @@ class SettingsLinktListRow extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
contentPadding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -26,8 +25,7 @@ class SettingsLinktListRow extends StatelessWidget {
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
)
|
||||
@@ -35,7 +33,7 @@ class SettingsLinktListRow extends StatelessWidget {
|
||||
),
|
||||
trailing: Text(
|
||||
link,
|
||||
style: TextStyle(fontSize: 14.0, color: Palette.cakeGreen),
|
||||
style: TextStyle(fontSize: 14.0, color: Colors.blue),
|
||||
),
|
||||
onTap: onTaped,
|
||||
),
|
||||
|
||||
@@ -8,7 +8,7 @@ class SettingRawWidgetListRow extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: widgetBuilder(context) ?? Container(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ class SettingsSwitchListRow extends StatelessWidget {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
contentPadding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
title: Observer(
|
||||
builder: (_) => Text(settingsStore.itemHeaders[title],
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
),
|
||||
trailing: _getSwitch(context)),
|
||||
|
||||
@@ -15,9 +15,9 @@ class SettingsTextListRow extends StatelessWidget {
|
||||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
contentPadding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
@@ -26,7 +26,7 @@ class SettingsTextListRow extends StatelessWidget {
|
||||
builder: (_) => Text(
|
||||
settingsStore.itemHeaders[title],
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
)),
|
||||
),
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
||||
class SetupPinCodePage extends BasePage {
|
||||
SetupPinCodePage({this.onPinCodeSetup});
|
||||
@@ -58,36 +59,28 @@ class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
|
||||
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(S.of(context).setup_successful),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
widget.onPinCodeSetup(context, pin);
|
||||
reset();
|
||||
},
|
||||
),
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.setup_pin,
|
||||
alertContent: S.of(context).setup_successful,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () {
|
||||
Navigator.of(context).pop();
|
||||
widget.onPinCodeSetup(context, pin);
|
||||
reset();
|
||||
},
|
||||
alertBarrierDismissible: false,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(S.of(context).pin_is_incorrect),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.setup_pin,
|
||||
alertContent: S.of(context).pin_is_incorrect,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,15 +3,12 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_keys_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
|
||||
class ShowKeysPage extends BasePage {
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
String get title => S.current.wallet_keys;
|
||||
|
||||
@@ -20,7 +17,7 @@ class ShowKeysPage extends BasePage {
|
||||
final walletKeysStore = Provider.of<WalletKeysStore>(context);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0, left: 20, right: 20),
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
final keysMap = {
|
||||
@@ -39,39 +36,43 @@ class ShowKeysPage extends BasePage {
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
separatorBuilder: (_, __) => Container(
|
||||
padding: EdgeInsets.only(left: 30.0, right: 20.0),
|
||||
child: Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0)),
|
||||
separatorBuilder: (context, index) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
itemCount: keysMap.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final key = keysMap.keys.elementAt(index);
|
||||
final value = keysMap.values.elementAt(index);
|
||||
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.only(
|
||||
top: 10, bottom: 10, left: 30, right: 20),
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: keysMap.values.elementAt(index)));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_key_to_clipboard(key),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(seconds: 1),
|
||||
));
|
||||
},
|
||||
title: Text(key + ':', style: TextStyle(fontSize: 16.0)),
|
||||
subtitle: Container(
|
||||
padding: EdgeInsets.only(top: 5.0),
|
||||
child: Text(value,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0, color: Palette.wildDarkBlue)),
|
||||
final isDrawTop = index == 0 ? true : false;
|
||||
final isDrawBottom = index == keysMap.length - 1 ? true : false;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: value));
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
S.of(context).copied_key_to_clipboard(key),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(seconds: 1),
|
||||
));
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: key + ':',
|
||||
value: value,
|
||||
isDrawTop: isDrawTop,
|
||||
isDrawBottom: isDrawBottom,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@@ -8,14 +9,18 @@ import 'package:cake_wallet/src/stores/subaddress_creation/subaddress_creation_s
|
||||
import 'package:cake_wallet/src/stores/subaddress_creation/subaddress_creation_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
|
||||
class NewSubaddressPage extends BasePage {
|
||||
NewSubaddressPage({this.subaddress});
|
||||
|
||||
final Subaddress subaddress;
|
||||
|
||||
@override
|
||||
String get title => S.current.new_subaddress_title;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => NewSubaddressForm();
|
||||
Widget body(BuildContext context) => NewSubaddressForm(subaddress);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -34,68 +39,92 @@ class NewSubaddressPage extends BasePage {
|
||||
}
|
||||
|
||||
class NewSubaddressForm extends StatefulWidget {
|
||||
NewSubaddressForm(this.subaddress);
|
||||
|
||||
final Subaddress subaddress;
|
||||
|
||||
@override
|
||||
NewSubaddressFormState createState() => NewSubaddressFormState();
|
||||
NewSubaddressFormState createState() => NewSubaddressFormState(subaddress);
|
||||
}
|
||||
|
||||
class NewSubaddressFormState extends State<NewSubaddressForm> {
|
||||
NewSubaddressFormState(this.subaddress);
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _labelController = TextEditingController();
|
||||
final Subaddress subaddress;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (subaddress != null) _labelController.text = subaddress.label;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_labelController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final subaddressCreationStore =
|
||||
Provider.of<SubadrressCreationStore>(context);
|
||||
|
||||
_labelController.addListener(() {
|
||||
if (_labelController.text.isNotEmpty) {
|
||||
subaddressCreationStore.setDisabledStatus(false);
|
||||
} else {
|
||||
subaddressCreationStore.setDisabledStatus(true);
|
||||
}
|
||||
});
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Stack(children: <Widget>[
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 35, right: 35),
|
||||
child: TextFormField(
|
||||
controller: _labelController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||
hintText: S.of(context).new_subaddress_label_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
subaddressCreationStore.validateSubaddressName(value);
|
||||
return subaddressCreationStore.errorMessage;
|
||||
}),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 20,
|
||||
left: 20,
|
||||
right: 20,
|
||||
child: Observer(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: BaseTextFormField(
|
||||
controller: _labelController,
|
||||
hintText: S.of(context).new_subaddress_label_name,
|
||||
validator: (value) {
|
||||
subaddressCreationStore.validateSubaddressName(value);
|
||||
return subaddressCreationStore.errorMessage;
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState.validate()) {
|
||||
await subaddressCreationStore.add(
|
||||
label: _labelController.text);
|
||||
Navigator.of(context).pop();
|
||||
if (subaddress != null) {
|
||||
await subaddressCreationStore.setLabel(
|
||||
addressIndex: subaddress.id,
|
||||
label: _labelController.text
|
||||
);
|
||||
} else {
|
||||
await subaddressCreationStore.add(
|
||||
label: _labelController.text);
|
||||
}
|
||||
}
|
||||
},
|
||||
text: S.of(context).new_subaddress_create,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.button
|
||||
.decorationColor,
|
||||
text: subaddress != null
|
||||
? S.of(context).rename
|
||||
: S.of(context).new_subaddress_create,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading:
|
||||
subaddressCreationStore.state is SubaddressIsCreating),
|
||||
))
|
||||
]));
|
||||
subaddressCreationStore.state is SubaddressIsCreating,
|
||||
isDisabled: subaddressCreationStore.isDisabledStatus,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,12 @@ import 'package:cake_wallet/src/stores/exchange_trade/exchange_trade_store.dart'
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
|
||||
class TradeDetailsPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.trade_details_title;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
String get title => S.current.trade_details_title;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
@@ -26,7 +24,7 @@ class TradeDetailsPage extends BasePage {
|
||||
formatDefault: "dd.MM.yyyy, HH:mm");
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10.0, bottom: 10.0, left: 20, right: 15),
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Observer(builder: (_) {
|
||||
final trade = exchangeStore.trade;
|
||||
final items = [
|
||||
@@ -58,15 +56,22 @@ class TradeDetailsPage extends BasePage {
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
separatorBuilder: (_, __) => Divider(
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
height: 1.0,
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.only(left: 25, top: 10, right: 25, bottom: 15),
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
itemCount: items.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final item = items[index];
|
||||
|
||||
final isDrawTop = index == 0 ? true : false;
|
||||
final isDrawBottom = index == items.length - 1 ? true : false;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: '${item.value}'));
|
||||
@@ -80,7 +85,11 @@ class TradeDetailsPage extends BasePage {
|
||||
);
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}', value: '${item.value}'));
|
||||
title: '${item.title}',
|
||||
value: '${item.value}',
|
||||
isDrawTop: isDrawTop,
|
||||
isDrawBottom: isDrawBottom,
|
||||
));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class StandartListRow extends StatelessWidget {
|
||||
StandartListRow({this.title, this.value});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color),
|
||||
textAlign: TextAlign.left),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text(value,
|
||||
style: TextStyle(fontSize: 14, color: Palette.wildDarkBlue)),
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,15 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class TransactionDetailsPage extends BasePage {
|
||||
TransactionDetailsPage({this.transactionInfo});
|
||||
|
||||
final TransactionInfo transactionInfo;
|
||||
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
String get title => S.current.transaction_details_title;
|
||||
|
||||
@@ -80,17 +78,24 @@ class TransactionDetailsFormState extends State<TransactionDetailsForm> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 15, top: 10, bottom: 10),
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (context, index) => Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerTheme.color,
|
||||
),
|
||||
padding: EdgeInsets.only(left: 25, top: 10, right: 25, bottom: 15),
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _items[index];
|
||||
|
||||
final isDrawTop = index == 0 ? true : false;
|
||||
final isDrawBottom = index == _items.length - 1 ? true : false;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
@@ -104,7 +109,11 @@ class TransactionDetailsFormState extends State<TransactionDetailsForm> {
|
||||
);
|
||||
},
|
||||
child:
|
||||
StandartListRow(title: '${item.title}:', value: item.value),
|
||||
StandartListRow(
|
||||
title: '${item.title}:',
|
||||
value: item.value,
|
||||
isDrawTop: isDrawTop,
|
||||
isDrawBottom: isDrawBottom),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -6,23 +6,14 @@ import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_description.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet_list/wallet_list_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_menu.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_list/widgets/wallet_tile.dart';
|
||||
|
||||
class WalletListPage extends BasePage {
|
||||
@override
|
||||
bool get isModalBackButton => true;
|
||||
|
||||
@override
|
||||
String get title => S.current.wallet_list_title;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.withShadow;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => WalletListBody();
|
||||
}
|
||||
@@ -33,92 +24,154 @@ class WalletListBody extends StatefulWidget {
|
||||
}
|
||||
|
||||
class WalletListBodyState extends State<WalletListBody> {
|
||||
final moneroIcon = Image.asset('assets/images/monero.png', height: 24, width: 24);
|
||||
WalletListStore _walletListStore;
|
||||
|
||||
void presetMenuForWallet(WalletDescription wallet, bool isCurrentWallet,
|
||||
BuildContext bodyContext) {
|
||||
final walletMenu = WalletMenu(bodyContext);
|
||||
final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet);
|
||||
|
||||
showDialog<void>(
|
||||
context: bodyContext,
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: -1,
|
||||
title: S.of(context).wallet_menu,
|
||||
onItemSelected: (String item) => walletMenu.action(
|
||||
walletMenu.listItems.indexOf(item), wallet, isCurrentWallet)),
|
||||
);
|
||||
}
|
||||
ScrollController scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletStore = Provider.of<WalletStore>(context);
|
||||
_walletListStore = Provider.of<WalletListStore>(context);
|
||||
|
||||
return ScrollableWithBottomSection(
|
||||
content: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (_, index) => Divider(
|
||||
color: Theme.of(context).dividerTheme.color, height: 1.0),
|
||||
itemCount: _walletListStore.wallets.length,
|
||||
itemBuilder: (__, index) {
|
||||
final wallet = _walletListStore.wallets[index];
|
||||
final isCurrentWallet =
|
||||
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Palette.oceanBlue);
|
||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Theme.of(context).primaryTextTheme.title.color);
|
||||
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 20),
|
||||
content: Container(
|
||||
child: Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (_, index) => Divider(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
height: 16),
|
||||
itemCount: _walletListStore.wallets.length,
|
||||
itemBuilder: (__, index) {
|
||||
final wallet = _walletListStore.wallets[index];
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
final isCurrentWallet =
|
||||
_walletListStore.isCurrentWallet(wallet);
|
||||
|
||||
return InkWell(
|
||||
onTap: () =>
|
||||
presetMenuForWallet(wallet, isCurrentWallet, context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10.0, right: 10.0),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
wallet.name,
|
||||
style: TextStyle(
|
||||
color: isCurrentWallet
|
||||
? Palette.cakeGreen
|
||||
: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color,
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w600),
|
||||
String shortAddress = '';
|
||||
|
||||
if (isCurrentWallet) {
|
||||
shortAddress = walletStore.subaddress.address;
|
||||
shortAddress = shortAddress.replaceRange(4, shortAddress.length - 4, '...');
|
||||
}
|
||||
|
||||
final walletMenu = WalletMenu(context);
|
||||
final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet);
|
||||
final colors = walletMenu.generateColorsForWalletMenu(isCurrentWallet);
|
||||
final images = walletMenu.generateImagesForWalletMenu(isCurrentWallet);
|
||||
|
||||
return Container(
|
||||
height: 108,
|
||||
width: double.infinity,
|
||||
child: CustomScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
controller: scrollController,
|
||||
slivers: <Widget>[
|
||||
SliverPersistentHeader(
|
||||
pinned: false,
|
||||
floating: true,
|
||||
delegate: WalletTile(
|
||||
min: screenWidth - 228,
|
||||
max: screenWidth,
|
||||
image: moneroIcon,
|
||||
walletName: wallet.name,
|
||||
walletAddress: shortAddress,
|
||||
isCurrent: isCurrentWallet
|
||||
),
|
||||
trailing: isCurrentWallet
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: Palette.cakeGreen,
|
||||
size: 20.0,
|
||||
)
|
||||
: null)));
|
||||
}),
|
||||
),
|
||||
),
|
||||
bottomSection: Column(children: <Widget>[
|
||||
PrimaryIconButton(
|
||||
onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet),
|
||||
iconData: Icons.add,
|
||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor,
|
||||
iconColor: Palette.violet,
|
||||
iconBackgroundColor: Theme.of(context).primaryIconTheme.color,
|
||||
text: S.of(context).wallet_list_create_new_wallet),
|
||||
SizedBox(height: 10.0),
|
||||
PrimaryIconButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pushNamed(Routes.restoreWalletOptions),
|
||||
iconData: Icons.refresh,
|
||||
text: S.of(context).wallet_list_restore_wallet,
|
||||
color: Theme.of(context).accentTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).accentTextTheme.button.decorationColor,
|
||||
iconColor: Theme.of(context).primaryTextTheme.caption.color,
|
||||
iconBackgroundColor: Theme.of(context).accentIconTheme.color)
|
||||
]));
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
|
||||
final item = items[index];
|
||||
final color = colors[index];
|
||||
final image = images[index];
|
||||
|
||||
final radius = index == 0 ? 12.0 : 0.0;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
scrollController.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
|
||||
walletMenu.action(
|
||||
walletMenu.listItems.indexOf(item), wallet, isCurrentWallet);
|
||||
},
|
||||
child: Container(
|
||||
height: 108,
|
||||
width: 108,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 5, right: 5),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(radius),
|
||||
bottomLeft: Radius.circular(radius)
|
||||
),
|
||||
color: color
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
item,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: items.length
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
bottomSection: Column(children: <Widget>[
|
||||
PrimaryImageButton(
|
||||
onPressed: () => Navigator.of(context).pushNamed(Routes.newWalletType),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).wallet_list_create_new_wallet,
|
||||
color: Colors.white,
|
||||
textColor: Palette.oceanBlue,
|
||||
borderColor: Palette.oceanBlue,
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
PrimaryImageButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pushNamed(Routes.restoreWalletOptions),
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).wallet_list_restore_wallet,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color)
|
||||
])),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,20 @@ class WalletMenu {
|
||||
S.current.rescan
|
||||
];
|
||||
|
||||
final List<Color> listColors = [
|
||||
Colors.blue,
|
||||
Colors.orange,
|
||||
Colors.red,
|
||||
Colors.green
|
||||
];
|
||||
|
||||
final List<Image> listImages = [
|
||||
Image.asset('assets/images/load.png', height: 32, width: 32, color: Colors.white),
|
||||
Image.asset('assets/images/eye_action.png', height: 32, width: 32, color: Colors.white),
|
||||
Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white),
|
||||
Image.asset('assets/images/scanner.png', height: 32, width: 32, color: Colors.white)
|
||||
];
|
||||
|
||||
List<String> generateItemsForWalletMenu(bool isCurrentWallet) {
|
||||
final items = List<String>();
|
||||
|
||||
@@ -29,6 +43,28 @@ class WalletMenu {
|
||||
return items;
|
||||
}
|
||||
|
||||
List<Color> generateColorsForWalletMenu(bool isCurrentWallet) {
|
||||
final colors = List<Color>();
|
||||
|
||||
if (!isCurrentWallet) colors.add(listColors[0]);
|
||||
if (isCurrentWallet) colors.add(listColors[1]);
|
||||
if (!isCurrentWallet) colors.add(listColors[2]);
|
||||
if (isCurrentWallet) colors.add(listColors[3]);
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
List<Image> generateImagesForWalletMenu(bool isCurrentWallet) {
|
||||
final images = List<Image>();
|
||||
|
||||
if (!isCurrentWallet) images.add(listImages[0]);
|
||||
if (isCurrentWallet) images.add(listImages[1]);
|
||||
if (!isCurrentWallet) images.add(listImages[2]);
|
||||
if (isCurrentWallet) images.add(listImages[3]);
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
void action(int index, WalletDescription wallet, bool isCurrentWallet) {
|
||||
final _walletListStore = Provider.of<WalletListStore>(context);
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class WalletTile extends SliverPersistentHeaderDelegate {
|
||||
WalletTile({
|
||||
@required this.min,
|
||||
@required this.max,
|
||||
@required this.image,
|
||||
@required this.walletName,
|
||||
@required this.walletAddress,
|
||||
@required this.isCurrent
|
||||
});
|
||||
|
||||
final double min;
|
||||
final double max;
|
||||
final Image image;
|
||||
final String walletName;
|
||||
final String walletAddress;
|
||||
final bool isCurrent;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
|
||||
double opacity = 1 - shrinkOffset / (max - min);
|
||||
opacity = opacity >= 0 ? opacity : 0;
|
||||
|
||||
double panelWidth = 12 * opacity;
|
||||
panelWidth = panelWidth < 12 ? 0 : 12;
|
||||
|
||||
final currentColor = isCurrent
|
||||
? Theme.of(context).accentTextTheme.caption.color
|
||||
: Theme.of(context).backgroundColor;
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
overflow: Overflow.visible,
|
||||
children: <Widget>[
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: max - 4,
|
||||
child: Container(
|
||||
height: 108,
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topRight: Radius.circular(4), bottomRight: Radius.circular(4)),
|
||||
color: currentColor
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 12,
|
||||
child: Container(
|
||||
height: 108,
|
||||
width: max - 16,
|
||||
padding: EdgeInsets.only(left: 20, right: 20),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
walletName,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
isCurrent ? SizedBox(height: 5) : Offstage(),
|
||||
isCurrent
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
SizedBox(width: 34),
|
||||
Text(
|
||||
walletAddress,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Opacity(
|
||||
opacity: opacity,
|
||||
child: Container(
|
||||
height: 108,
|
||||
width: panelWidth,
|
||||
padding: EdgeInsets.only(
|
||||
top: 1,
|
||||
left: 1,
|
||||
bottom: 1
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(12), bottomLeft: Radius.circular(12)),
|
||||
color: Theme.of(context).accentTextTheme.subtitle.color
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(12), bottomLeft: Radius.circular(12)),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Theme.of(context).accentTextTheme.caption.backgroundColor,
|
||||
Theme.of(context).accentTextTheme.caption.decorationColor
|
||||
]
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => max;
|
||||
|
||||
@override
|
||||
double get minExtent => min;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
|
||||
|
||||
}
|
||||
@@ -1,44 +1,17 @@
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
WalletType _selectedType;
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
||||
class WelcomePage extends BasePage {
|
||||
static const _aspectRatioImage = 1.26;
|
||||
static const _baseWidth = 411.43;
|
||||
final _image = Image.asset('assets/images/welcomeImg.png');
|
||||
final _cakeLogo = Image.asset('assets/images/cake_logo.png');
|
||||
final Map<String, WalletType> _picker =
|
||||
walletTypes.fold(Map<String, WalletType>(), (acc, item) {
|
||||
acc[walletTypeToString(item)] = item;
|
||||
return acc;
|
||||
});
|
||||
static const aspectRatioImage = 1.25;
|
||||
final welcomeImage = Image.asset('assets/images/welcome.png');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _selectedType == null
|
||||
? showDialog<void>(
|
||||
builder: (_) => Picker(
|
||||
items: walletTypes
|
||||
.map((item) => walletTypeToString(item))
|
||||
.toList(),
|
||||
selectedAtIndex: -1,
|
||||
title: 'Select wallet type',
|
||||
pickerHeight: 510,
|
||||
onItemSelected: (String item) {
|
||||
print('before $_selectedType');
|
||||
_selectedType = _picker[item];
|
||||
print('after $_selectedType');
|
||||
}),
|
||||
context: context)
|
||||
: null);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
resizeToAvoidBottomPadding: false,
|
||||
@@ -47,77 +20,99 @@ class WelcomePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final _screenWidth = MediaQuery.of(context).size.width;
|
||||
final textScaleFactor = _screenWidth < _baseWidth ? 0.76 : 1.0;
|
||||
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Palette.oceanBlue);
|
||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Theme.of(context).primaryTextTheme.title.color);
|
||||
|
||||
return Column(children: <Widget>[
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
AspectRatio(
|
||||
aspectRatio: _aspectRatioImage,
|
||||
child: FittedBox(child: _image, fit: BoxFit.fill)),
|
||||
Positioned(bottom: 0.0, child: _cakeLogo)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 30.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textScaleFactor: textScaleFactor,
|
||||
textAlign: TextAlign.center,
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 20),
|
||||
content: Column(
|
||||
children: <Widget>[
|
||||
AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: welcomeImage, fit: BoxFit.fill)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Text(
|
||||
S.of(context).cake_wallet,
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 14),
|
||||
child: Text(
|
||||
S.of(context).first_wallet_text,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
S.of(context).first_wallet_text,
|
||||
style: TextStyle(
|
||||
fontSize: 22.0,
|
||||
color: Palette.lightBlue,
|
||||
),
|
||||
textScaleFactor: textScaleFactor,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Palette.lightBlue,
|
||||
),
|
||||
textScaleFactor: textScaleFactor,
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
]),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 20.0),
|
||||
child: Column(children: <Widget>[
|
||||
PrimaryButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routes.newWalletFromWelcome,
|
||||
arguments: _selectedType);
|
||||
},
|
||||
text: S.of(context).create_new,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.button.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme.button.decorationColor),
|
||||
SizedBox(height: 10),
|
||||
PrimaryButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routes.restoreOptions,
|
||||
arguments: _selectedType);
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.caption.backgroundColor,
|
||||
borderColor:
|
||||
Theme.of(context).accentTextTheme.caption.decorationColor,
|
||||
text: S.of(context).restore_wallet,
|
||||
)
|
||||
]))
|
||||
]);
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 20),
|
||||
bottomSection: Column(children: <Widget>[
|
||||
Text(
|
||||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).create_new,
|
||||
color: Colors.white,
|
||||
textColor: Palette.oceanBlue,
|
||||
borderColor: Palette.oceanBlue,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreOptions),
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).restore_wallet,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ abstract class AcountListStoreBase with Store {
|
||||
AcountListStoreBase({@required WalletService walletService}) {
|
||||
accounts = [];
|
||||
isAccountCreating = false;
|
||||
isDisabledStatus = true;
|
||||
|
||||
if (walletService.currentWallet != null) {
|
||||
_onWalletChanged(walletService.currentWallet);
|
||||
@@ -37,10 +38,18 @@ abstract class AcountListStoreBase with Store {
|
||||
@observable
|
||||
bool isAccountCreating;
|
||||
|
||||
@observable
|
||||
bool isDisabledStatus;
|
||||
|
||||
AccountList _accountList;
|
||||
StreamSubscription<Wallet> _onWalletChangeSubscription;
|
||||
StreamSubscription<List<Account>> _onAccountsChangeSubscription;
|
||||
|
||||
@action
|
||||
void setDisabledStatus(bool isDisabled) {
|
||||
isDisabledStatus = isDisabled;
|
||||
}
|
||||
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _onWalletChangeSubscription.cancel();
|
||||
|
||||
@@ -12,11 +12,15 @@ class AddressBookStore = AddressBookStoreBase with _$AddressBookStore;
|
||||
abstract class AddressBookStoreBase with Store {
|
||||
AddressBookStoreBase({@required this.contacts}) {
|
||||
updateContactList();
|
||||
isDisabledStatus = true;
|
||||
}
|
||||
|
||||
@observable
|
||||
List<Contact> contactList;
|
||||
|
||||
@observable
|
||||
bool isDisabledStatus;
|
||||
|
||||
@observable
|
||||
bool isValid;
|
||||
|
||||
@@ -37,6 +41,11 @@ abstract class AddressBookStoreBase with Store {
|
||||
@action
|
||||
Future delete({Contact contact}) async => await contact.delete();
|
||||
|
||||
@action
|
||||
void setDisabledStatus(bool isDisabled) {
|
||||
isDisabledStatus = isDisabled;
|
||||
}
|
||||
|
||||
void validateContactName(String value) {
|
||||
const pattern = '''^[^`,'"]{1,32}\$''';
|
||||
final regExp = RegExp(pattern);
|
||||
|
||||
@@ -33,6 +33,14 @@ abstract class ExchangeStoreBase with Store {
|
||||
provider = initialProvider;
|
||||
depositCurrency = initialDepositCurrency;
|
||||
receiveCurrency = initialReceiveCurrency;
|
||||
/*isDepositAddressEnabled = !(depositCurrency == walletStore.type);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == walletStore.type);*/
|
||||
isDepositAddressEnabled = true;
|
||||
isReceiveAddressEnabled = true;
|
||||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
depositAddress = '';
|
||||
receiveAddress = '';
|
||||
limitsState = LimitsInitialState();
|
||||
tradeState = ExchangeTradeStateInitial();
|
||||
_cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
|
||||
@@ -63,6 +71,18 @@ abstract class ExchangeStoreBase with Store {
|
||||
@observable
|
||||
String receiveAmount;
|
||||
|
||||
@observable
|
||||
String depositAddress;
|
||||
|
||||
@observable
|
||||
String receiveAddress;
|
||||
|
||||
@observable
|
||||
bool isDepositAddressEnabled;
|
||||
|
||||
@observable
|
||||
bool isReceiveAddressEnabled;
|
||||
|
||||
@observable
|
||||
bool isValid;
|
||||
|
||||
@@ -71,10 +91,6 @@ abstract class ExchangeStoreBase with Store {
|
||||
|
||||
Box<Trade> trades;
|
||||
|
||||
String depositAddress;
|
||||
|
||||
String receiveAddress;
|
||||
|
||||
WalletStore walletStore;
|
||||
|
||||
Limits limits;
|
||||
@@ -93,12 +109,16 @@ abstract class ExchangeStoreBase with Store {
|
||||
void changeDepositCurrency({CryptoCurrency currency}) {
|
||||
depositCurrency = currency;
|
||||
_onPairChange();
|
||||
/*isDepositAddressEnabled = !(depositCurrency == walletStore.type);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == walletStore.type);*/
|
||||
}
|
||||
|
||||
@action
|
||||
void changeReceiveCurrency({CryptoCurrency currency}) {
|
||||
receiveCurrency = currency;
|
||||
_onPairChange();
|
||||
/*isDepositAddressEnabled = !(depositCurrency == walletStore.type);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == walletStore.type);*/
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -218,12 +238,13 @@ abstract class ExchangeStoreBase with Store {
|
||||
void reset() {
|
||||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
depositAddress = '';
|
||||
receiveAddress = '';
|
||||
provider = XMRTOExchangeProvider();
|
||||
depositCurrency = CryptoCurrency.xmr;
|
||||
receiveCurrency = CryptoCurrency.btc;
|
||||
loadLimits();
|
||||
depositAddress = depositCurrency == walletStore.type ? walletStore.address : '';
|
||||
receiveAddress = receiveCurrency == walletStore.type ? walletStore.address : '';
|
||||
/*isDepositAddressEnabled = !(depositCurrency == walletStore.type);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == walletStore.type);*/
|
||||
_onPairChange();
|
||||
}
|
||||
|
||||
List<ExchangeProvider> providersForCurrentPair() {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import 'dart:async';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/src/domain/exchange/exchange_template.dart';
|
||||
|
||||
part 'exchange_template_store.g.dart';
|
||||
|
||||
class ExchangeTemplateStore = ExchangeTemplateBase with _$ExchangeTemplateStore;
|
||||
|
||||
abstract class ExchangeTemplateBase with Store {
|
||||
ExchangeTemplateBase({this.templateSource}) {
|
||||
templates = ObservableList<ExchangeTemplate>();
|
||||
update();
|
||||
}
|
||||
|
||||
@observable
|
||||
ObservableList<ExchangeTemplate> templates;
|
||||
|
||||
Box<ExchangeTemplate> templateSource;
|
||||
|
||||
@action
|
||||
void update() =>
|
||||
templates.replaceRange(0, templates.length, templateSource.values.toList());
|
||||
|
||||
@action
|
||||
Future addTemplate({String amount, String depositCurrency, String receiveCurrency,
|
||||
String provider, String depositAddress, String receiveAddress}) async {
|
||||
final template = ExchangeTemplate(
|
||||
amount: amount,
|
||||
depositCurrency: depositCurrency,
|
||||
receiveCurrency: receiveCurrency,
|
||||
provider: provider,
|
||||
depositAddress: depositAddress,
|
||||
receiveAddress: receiveAddress);
|
||||
await templateSource.add(template);
|
||||
}
|
||||
|
||||
@action
|
||||
Future remove({ExchangeTemplate template}) async => await template.delete();
|
||||
}
|
||||
@@ -12,6 +12,7 @@ class NodeListStore = NodeListBase with _$NodeListStore;
|
||||
abstract class NodeListBase with Store {
|
||||
NodeListBase({this.nodesSource}) {
|
||||
nodes = ObservableList<Node>();
|
||||
disabledState = true;
|
||||
_onNodesChangeSubscription = nodesSource.watch().listen((e) => update());
|
||||
update();
|
||||
}
|
||||
@@ -25,6 +26,9 @@ abstract class NodeListBase with Store {
|
||||
@observable
|
||||
String errorMessage;
|
||||
|
||||
@observable
|
||||
bool disabledState;
|
||||
|
||||
Box<Node> nodesSource;
|
||||
|
||||
StreamSubscription<BoxEvent> _onNodesChangeSubscription;
|
||||
@@ -61,6 +65,11 @@ abstract class NodeListBase with Store {
|
||||
@action
|
||||
Future reset() async => await resetToDefault(nodesSource);
|
||||
|
||||
@action
|
||||
void setDisabledState(bool isDisable) {
|
||||
disabledState = isDisable;
|
||||
}
|
||||
|
||||
Future<bool> isNodeOnline(Node node) async {
|
||||
try {
|
||||
return await node.requestNode(node.uri,
|
||||
|
||||
@@ -45,6 +45,9 @@ abstract class SendStoreBase with Store {
|
||||
@observable
|
||||
String cryptoAmount;
|
||||
|
||||
@observable
|
||||
String address;
|
||||
|
||||
@observable
|
||||
bool isValid;
|
||||
|
||||
@@ -157,6 +160,18 @@ abstract class SendStoreBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void changeAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@action
|
||||
void clear() {
|
||||
address = '';
|
||||
cryptoAmount = '';
|
||||
fiatAmount = '';
|
||||
}
|
||||
|
||||
Future<bool> isOpenaliasRecord(String name) async {
|
||||
final _openaliasRecord = await OpenaliasRecord
|
||||
.fetchAddressAndName(OpenaliasRecord.formatDomainName(name));
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'dart:async';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/src/domain/common/template.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'send_template_store.g.dart';
|
||||
|
||||
class SendTemplateStore = SendTemplateBase with _$SendTemplateStore;
|
||||
|
||||
abstract class SendTemplateBase with Store {
|
||||
SendTemplateBase({this.templateSource}) {
|
||||
templates = ObservableList<Template>();
|
||||
update();
|
||||
}
|
||||
|
||||
@observable
|
||||
ObservableList<Template> templates;
|
||||
|
||||
@observable
|
||||
bool isValid;
|
||||
|
||||
@observable
|
||||
String errorMessage;
|
||||
|
||||
Box<Template> templateSource;
|
||||
|
||||
@action
|
||||
void update() =>
|
||||
templates.replaceRange(0, templates.length, templateSource.values.toList());
|
||||
|
||||
@action
|
||||
Future addTemplate({String name, String address, String cryptoCurrency, String amount}) async {
|
||||
final template = Template(name: name, address: address,
|
||||
cryptoCurrency: cryptoCurrency, amount: amount);
|
||||
await templateSource.add(template);
|
||||
}
|
||||
|
||||
@action
|
||||
Future remove({Template template}) async => await template.delete();
|
||||
|
||||
void validateTemplate(String value) {
|
||||
const pattern = '''^[^`,'"]{1,106}\$''';
|
||||
final regExp = RegExp(pattern);
|
||||
isValid = regExp.hasMatch(value);
|
||||
errorMessage = isValid ? null : S.current.error_text_template;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ class SubadrressCreationStore = SubadrressCreationStoreBase
|
||||
abstract class SubadrressCreationStoreBase with Store {
|
||||
SubadrressCreationStoreBase({@required WalletService walletService}) {
|
||||
state = SubaddressCreationStateInitial();
|
||||
isDisabledStatus = true;
|
||||
|
||||
if (walletService.currentWallet != null) {
|
||||
_onWalletChanged(walletService.currentWallet);
|
||||
@@ -26,6 +27,7 @@ abstract class SubadrressCreationStoreBase with Store {
|
||||
walletService.onWalletChange.listen(_onWalletChanged);
|
||||
}
|
||||
|
||||
@observable
|
||||
SubaddressCreationState state;
|
||||
|
||||
@observable
|
||||
@@ -34,11 +36,19 @@ abstract class SubadrressCreationStoreBase with Store {
|
||||
@observable
|
||||
String errorMessage;
|
||||
|
||||
@observable
|
||||
bool isDisabledStatus;
|
||||
|
||||
SubaddressList _subaddressList;
|
||||
StreamSubscription<Wallet> _onWalletChangeSubscription;
|
||||
StreamSubscription<Account> _onAccountChangeSubscription;
|
||||
Account _account;
|
||||
|
||||
@action
|
||||
void setDisabledStatus(bool isDisabled) {
|
||||
isDisabledStatus = isDisabled;
|
||||
}
|
||||
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _onWalletChangeSubscription.cancel();
|
||||
@@ -61,6 +71,20 @@ abstract class SubadrressCreationStoreBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setLabel({int addressIndex, String label}) async {
|
||||
try {
|
||||
state = SubaddressIsCreating();
|
||||
await _subaddressList.setLabelSubaddress(
|
||||
accountIndex: _account.id,
|
||||
addressIndex: addressIndex,
|
||||
label: label
|
||||
);
|
||||
state = SubaddressCreatedSuccessfully();
|
||||
} catch (e) {
|
||||
state = SubaddressCreationFailure(error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onWalletChanged(Wallet wallet) async {
|
||||
if (wallet is MoneroWallet) {
|
||||
_account = wallet.account;
|
||||
|
||||
@@ -16,6 +16,7 @@ abstract class WalletCreationStoreBase with Store {
|
||||
@required this.walletListService,
|
||||
@required this.sharedPreferences}) {
|
||||
state = WalletCreationStateInitial();
|
||||
isDisabledStatus = true;
|
||||
}
|
||||
|
||||
final AuthenticationStore authStore;
|
||||
@@ -31,6 +32,9 @@ abstract class WalletCreationStoreBase with Store {
|
||||
@observable
|
||||
bool isValid;
|
||||
|
||||
@observable
|
||||
bool isDisabledStatus;
|
||||
|
||||
@action
|
||||
Future create({String name, String language}) async {
|
||||
state = WalletCreationStateInitial();
|
||||
@@ -45,6 +49,11 @@ abstract class WalletCreationStoreBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void setDisabledStatus(bool isDisabled) {
|
||||
isDisabledStatus = isDisabled;
|
||||
}
|
||||
|
||||
void validateWalletName(String value) {
|
||||
const pattern = '^[a-zA-Z0-9_]{1,15}\$';
|
||||
final regExp = RegExp(pattern);
|
||||
|
||||
@@ -20,6 +20,7 @@ abstract class WalleRestorationStoreBase with Store {
|
||||
@required this.walletListService,
|
||||
@required this.sharedPreferences}) {
|
||||
state = WalletRestorationStateInitial();
|
||||
disabledState = true;
|
||||
}
|
||||
|
||||
final AuthenticationStore authStore;
|
||||
@@ -38,6 +39,9 @@ abstract class WalleRestorationStoreBase with Store {
|
||||
@observable
|
||||
List<MnemoticItem> seed;
|
||||
|
||||
@observable
|
||||
bool disabledState;
|
||||
|
||||
@action
|
||||
Future restoreFromSeed({String name, String seed, int restoreHeight}) async {
|
||||
state = WalletRestorationStateInitial();
|
||||
@@ -109,6 +113,11 @@ abstract class WalleRestorationStoreBase with Store {
|
||||
return seed.fold('', (acc, item) => acc + ' ' + item.toString());
|
||||
}
|
||||
|
||||
@action
|
||||
void setDisabledState(bool isDisable) {
|
||||
disabledState = isDisable;
|
||||
}
|
||||
|
||||
void validateWalletName(String value) {
|
||||
const pattern = '^[a-zA-Z0-9_]{1,15}\$';
|
||||
final regExp = RegExp(pattern);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/common/contact.dart';
|
||||
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||
@@ -19,6 +18,8 @@ class AddressTextField extends StatelessWidget {
|
||||
],
|
||||
this.onURIScanned,
|
||||
this.focusNode,
|
||||
this.isBorderExist = true,
|
||||
this.buttonColor,
|
||||
this.validator});
|
||||
|
||||
static const prefixIconWidth = 34.0;
|
||||
@@ -31,6 +32,8 @@ class AddressTextField extends StatelessWidget {
|
||||
final Function(Uri) onURIScanned;
|
||||
final List<AddressTextFieldOption> options;
|
||||
final FormFieldValidator<String> validator;
|
||||
final bool isBorderExist;
|
||||
final Color buttonColor;
|
||||
FocusNode focusNode;
|
||||
|
||||
@override
|
||||
@@ -40,6 +43,10 @@ class AddressTextField extends StatelessWidget {
|
||||
enabled: isActive,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: SizedBox(
|
||||
width: prefixIconWidth * options.length +
|
||||
@@ -58,9 +65,9 @@ class AddressTextField extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Palette.wildDarkBlueWithOpacity,
|
||||
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(8))),
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset('assets/images/qr_code_icon.png')),
|
||||
))
|
||||
],
|
||||
@@ -76,11 +83,11 @@ class AddressTextField extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Palette.wildDarkBlueWithOpacity,
|
||||
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(8))),
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/address_book_icon.png')),
|
||||
'assets/images/open_book.png')),
|
||||
))
|
||||
],
|
||||
if (this
|
||||
@@ -95,9 +102,9 @@ class AddressTextField extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Palette.wildDarkBlueWithOpacity,
|
||||
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(8))),
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/receive_icon_raw.png')),
|
||||
))
|
||||
@@ -105,13 +112,27 @@ class AddressTextField extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
),
|
||||
hintText: placeholder ?? S.current.widgets_address,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
focusedBorder: isBorderExist
|
||||
? UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))
|
||||
: InputBorder.none,
|
||||
disabledBorder: isBorderExist
|
||||
? UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Theme.of(context).focusColor, width: 1.0)),
|
||||
BorderSide(color: Theme.of(context).dividerColor, width: 1.0))
|
||||
: InputBorder.none,
|
||||
enabledBorder: isBorderExist
|
||||
? UnderlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Theme.of(context).dividerColor, width: 1.0))
|
||||
: InputBorder.none,
|
||||
),
|
||||
validator: validator,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||
|
||||
class AlertWithOneAction extends BaseAlertDialog {
|
||||
AlertWithOneAction({
|
||||
@required this.alertTitle,
|
||||
@required this.alertContent,
|
||||
@required this.buttonText,
|
||||
@required this.buttonAction,
|
||||
this.alertBarrierDismissible = true
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
final String alertContent;
|
||||
final String buttonText;
|
||||
final VoidCallback buttonAction;
|
||||
final bool alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
|
||||
@override
|
||||
String get contentText => alertContent;
|
||||
|
||||
@override
|
||||
bool get barrierDismissible => alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
Widget actionButtons(BuildContext context) {
|
||||
return Container(
|
||||
width: 300,
|
||||
height: 52,
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)
|
||||
),
|
||||
color: Colors.white
|
||||
),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.infinity,
|
||||
child: FlatButton(
|
||||
onPressed: buttonAction,
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Text(
|
||||
buttonText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'dart:ui';
|
||||
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class AlertWithTwoActions extends BaseAlertDialog {
|
||||
AlertWithTwoActions({
|
||||
@required this.alertTitle,
|
||||
@required this.alertContent,
|
||||
@required this.leftButtonText,
|
||||
@required this.rightButtonText,
|
||||
@required this.actionLeftButton,
|
||||
@required this.actionRightButton,
|
||||
this.alertBarrierDismissible = true
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
final String alertContent;
|
||||
final String leftButtonText;
|
||||
final String rightButtonText;
|
||||
final VoidCallback actionLeftButton;
|
||||
final VoidCallback actionRightButton;
|
||||
final bool alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
@override
|
||||
String get contentText => alertContent;
|
||||
@override
|
||||
String get leftActionButtonText => leftButtonText;
|
||||
@override
|
||||
String get rightActionButtonText => rightButtonText;
|
||||
@override
|
||||
VoidCallback get actionLeft => actionLeftButton;
|
||||
@override
|
||||
VoidCallback get actionRight => actionRightButton;
|
||||
@override
|
||||
bool get barrierDismissible => alertBarrierDismissible;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class BaseAlertDialog extends StatelessWidget {
|
||||
String get titleText => '';
|
||||
String get contentText => '';
|
||||
String get leftActionButtonText => '';
|
||||
String get rightActionButtonText => '';
|
||||
VoidCallback get actionLeft => () {};
|
||||
VoidCallback get actionRight => () {};
|
||||
bool get barrierDismissible => true;
|
||||
|
||||
Widget title(BuildContext context) {
|
||||
return Text(
|
||||
titleText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget content(BuildContext context) {
|
||||
return Text(
|
||||
contentText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget actionButtons(BuildContext context) {
|
||||
return Container(
|
||||
width: 300,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)
|
||||
),
|
||||
color: Colors.white
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)),
|
||||
),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.infinity,
|
||||
child: FlatButton(
|
||||
onPressed: actionLeft,
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Text(
|
||||
leftActionButtonText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)),
|
||||
),
|
||||
)
|
||||
),
|
||||
Container(
|
||||
height: 52,
|
||||
width: 1,
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(bottomRight: Radius.circular(24)),
|
||||
),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.infinity,
|
||||
child: FlatButton(
|
||||
onPressed: actionRight,
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Text(
|
||||
rightActionButtonText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.red,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)),
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => barrierDismissible
|
||||
? Navigator.of(context).pop()
|
||||
: null,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Center(
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: Container(
|
||||
width: 300,
|
||||
height: 257,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 300,
|
||||
height: 77,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24)
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: title(context),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 300,
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
Container(
|
||||
width: 300,
|
||||
height: 127,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Center(
|
||||
child: content(context),
|
||||
),
|
||||
),
|
||||
actionButtons(context)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class BaseTextFormField extends StatelessWidget {
|
||||
BaseTextFormField({
|
||||
this.controller,
|
||||
this.keyboardType = TextInputType.text,
|
||||
this.textInputAction = TextInputAction.done,
|
||||
this.textAlign = TextAlign.start,
|
||||
this.autovalidate = false,
|
||||
this.hintText = '',
|
||||
this.maxLines = 1,
|
||||
this.inputFormatters,
|
||||
this.textColor,
|
||||
this.hintColor,
|
||||
this.borderColor,
|
||||
this.prefix,
|
||||
this.suffix,
|
||||
this.suffixIcon,
|
||||
this.enabled = true,
|
||||
this.validator
|
||||
});
|
||||
|
||||
final TextEditingController controller;
|
||||
final TextInputType keyboardType;
|
||||
final TextInputAction textInputAction;
|
||||
final TextAlign textAlign;
|
||||
final bool autovalidate;
|
||||
final String hintText;
|
||||
final int maxLines;
|
||||
final List<TextInputFormatter> inputFormatters;
|
||||
final Color textColor;
|
||||
final Color hintColor;
|
||||
final Color borderColor;
|
||||
final Widget prefix;
|
||||
final Widget suffix;
|
||||
final Widget suffixIcon;
|
||||
final bool enabled;
|
||||
final FormFieldValidator<String> validator;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
keyboardType: keyboardType,
|
||||
textInputAction: textInputAction,
|
||||
textAlign: textAlign,
|
||||
autovalidate: autovalidate,
|
||||
maxLines: maxLines,
|
||||
inputFormatters: inputFormatters,
|
||||
enabled: enabled,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: textColor ?? Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
prefix: prefix,
|
||||
suffix: suffix,
|
||||
suffixIcon: suffixIcon,
|
||||
hintStyle: TextStyle(
|
||||
color: hintColor ?? Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: hintText,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: borderColor ?? Theme.of(context).dividerColor,
|
||||
width: 1.0
|
||||
)
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: borderColor ?? Theme.of(context).dividerColor,
|
||||
width: 1.0
|
||||
)
|
||||
)
|
||||
),
|
||||
validator: validator,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/monero/get_height_by_date.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class BlockchainHeightWidget extends StatefulWidget {
|
||||
BlockchainHeightWidget({GlobalKey key}) : super(key: key);
|
||||
@@ -37,19 +36,27 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 10.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
controller: restoreHeightController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).widgets_restore_from_blockheight,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen, width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor, width: 1.0))),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
),
|
||||
))
|
||||
],
|
||||
@@ -72,18 +79,23 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
onTap: () => _selectDate(context),
|
||||
child: IgnorePointer(
|
||||
child: TextFormField(
|
||||
style: TextStyle(fontSize: 14.0),
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).widgets_restore_from_date,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Palette.cakeGreen,
|
||||
width: 2.0)),
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).focusColor,
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
controller: dateController,
|
||||
validator: (value) {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
|
||||
factory NavBar(
|
||||
@@ -11,16 +8,13 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
|
||||
Widget middle,
|
||||
Widget trailing,
|
||||
Color backgroundColor}) {
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||
|
||||
return NavBar._internal(
|
||||
leading: leading,
|
||||
middle: middle,
|
||||
trailing: trailing,
|
||||
height: _height,
|
||||
backgroundColor:
|
||||
_isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor);
|
||||
backgroundColor: backgroundColor);
|
||||
}
|
||||
|
||||
factory NavBar.withShadow(
|
||||
@@ -29,20 +23,15 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
|
||||
Widget middle,
|
||||
Widget trailing,
|
||||
Color backgroundColor}) {
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||
|
||||
return NavBar._internal(
|
||||
leading: leading,
|
||||
middle: middle,
|
||||
trailing: trailing,
|
||||
height: 80,
|
||||
backgroundColor:
|
||||
_isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
decoration: BoxDecoration(
|
||||
color: _isDarkTheme
|
||||
? Theme.of(context).backgroundColor
|
||||
: backgroundColor,
|
||||
color: backgroundColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color.fromRGBO(132, 141, 198, 0.11),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user