mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
TMP
This commit is contained in:
commit
598b8c9b9c
49 changed files with 1019 additions and 885 deletions
Binary file not shown.
Before Width: | Height: | Size: 549 B |
BIN
assets/images/2.0x/paste_ios.png
Normal file
BIN
assets/images/2.0x/paste_ios.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
Binary file not shown.
Before Width: | Height: | Size: 603 B |
BIN
assets/images/3.0x/paste_ios.png
Normal file
BIN
assets/images/3.0x/paste_ios.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
Binary file not shown.
Before Width: | Height: | Size: 403 B |
BIN
assets/images/paste_ios.png
Normal file
BIN
assets/images/paste_ios.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
|
@ -354,7 +354,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -493,7 +493,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -526,7 +526,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
|
20
lib/di.dart
20
lib/di.dart
|
@ -15,6 +15,7 @@ import 'package:cake_wallet/src/screens/faq/faq_page.dart';
|
|||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/nodes_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/change_language.dart';
|
||||
|
@ -56,6 +57,7 @@ import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -222,10 +224,10 @@ Future setup(
|
|||
addressEditOrCreateViewModel:
|
||||
getIt.get<WalletAddressEditOrCreateViewModel>(param1: item)));
|
||||
|
||||
// getIt.get<SendTemplateStore>()
|
||||
getIt.registerFactory<SendViewModel>(() => SendViewModel(
|
||||
getIt.get<AppStore>().wallet,
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SendTemplateStore>(),
|
||||
getIt.get<FiatConversionStore>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
|
@ -318,10 +320,10 @@ Future setup(
|
|||
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
exchangeTemplateStore: getIt.get<ExchangeTemplateStore>(),
|
||||
trades: tradesSource,
|
||||
tradesStore: getIt.get<TradesStore>()));
|
||||
getIt.get<AppStore>().wallet,
|
||||
tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>()));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
|
@ -371,4 +373,12 @@ Future setup(
|
|||
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory(() => LanguageListPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
|
||||
(type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) =>
|
||||
WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ Future<void> migrate_android_v1() async {
|
|||
await android_migrate_wallets(appDocDir: appDocDir);
|
||||
}
|
||||
|
||||
Future<void> ios_migrate_v1(Box<WalletInfo> walletInfoSource, Box<Trade> tradeSource, Box<Contact> contactSource) async {
|
||||
Future<void> ios_migrate_v1(Box<WalletInfo> walletInfoSource,
|
||||
Box<Trade> tradeSource, Box<Contact> contactSource) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
if (prefs.getBool('ios_migration_v1_completed') ?? false) {
|
||||
|
@ -390,7 +391,7 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
|||
|
||||
Future<void> ios_migrate_address_book(Box<Contact> contactSource) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
|
||||
if (prefs.getBool('ios_migration_address_book_completed') ?? false) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ class S implements WidgetsLocalizations {
|
|||
String get paste => "Paste";
|
||||
String get payment_id => "Payment ID: ";
|
||||
String get pending => " (pending)";
|
||||
String get picker_description => "To choose ChangeNOW or MorphToken, please change your trading pair first";
|
||||
String get pin_is_incorrect => "PIN is incorrect";
|
||||
String get placeholder_contacts => "Your contacts will be displayed here";
|
||||
String get placeholder_transactions => "Your transactions will be displayed here";
|
||||
|
@ -711,6 +712,8 @@ class $de extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Wallet einlegen";
|
||||
@override
|
||||
String get picker_description => "Um ChangeNOW oder MorphToken zu wählen, ändern Sie bitte zuerst Ihr Handelspaar";
|
||||
@override
|
||||
String get sending => "Senden";
|
||||
@override
|
||||
String get restore_restore_wallet => "Wallet wiederherstellen";
|
||||
|
@ -1353,6 +1356,8 @@ class $hi extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "वॉलेट लोड करें";
|
||||
@override
|
||||
String get picker_description => "ChangeNOW या MorphToken चुनने के लिए, कृपया अपनी ट्रेडिंग जोड़ी को पहले बदलें";
|
||||
@override
|
||||
String get sending => "भेजना";
|
||||
@override
|
||||
String get restore_restore_wallet => "वॉलेट को पुनर्स्थापित करें";
|
||||
|
@ -1995,6 +2000,8 @@ class $ru extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Загрузка кошелька";
|
||||
@override
|
||||
String get picker_description => "Чтобы выбрать ChangeNOW или MorphToken, сначала смените пару для обмена";
|
||||
@override
|
||||
String get sending => "Отправка";
|
||||
@override
|
||||
String get restore_restore_wallet => "Восстановить кошелёк";
|
||||
|
@ -2637,6 +2644,8 @@ class $ko extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "지갑로드";
|
||||
@override
|
||||
String get picker_description => "ChangeNOW 또는 MorphToken을 선택하려면 먼저 거래 쌍을 변경하십시오.";
|
||||
@override
|
||||
String get sending => "배상";
|
||||
@override
|
||||
String get restore_restore_wallet => "월렛 복원";
|
||||
|
@ -3279,6 +3288,8 @@ class $pt extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Abrir carteira";
|
||||
@override
|
||||
String get picker_description => "Para escolher ChangeNOW ou MorphToken, altere primeiro o seu par de negociação";
|
||||
@override
|
||||
String get sending => "Enviando";
|
||||
@override
|
||||
String get restore_restore_wallet => "Restaurar carteira";
|
||||
|
@ -3921,6 +3932,8 @@ class $uk extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Завантаження гаманця";
|
||||
@override
|
||||
String get picker_description => "Щоб вибрати ChangeNOW або MorphToken, спочатку змініть пару для обміну";
|
||||
@override
|
||||
String get sending => "Відправлення";
|
||||
@override
|
||||
String get restore_restore_wallet => "Відновити гаманець";
|
||||
|
@ -4563,6 +4576,8 @@ class $ja extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "ウォレットをロード";
|
||||
@override
|
||||
String get picker_description => "ChangeNOWまたはMorphTokenを選択するには、最初にトレーディングペアを変更してください";
|
||||
@override
|
||||
String get sending => "送信";
|
||||
@override
|
||||
String get restore_restore_wallet => "ウォレットを復元";
|
||||
|
@ -5209,6 +5224,8 @@ class $pl extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Załaduj portfel";
|
||||
@override
|
||||
String get picker_description => "Aby wybrać ChangeNOW lub MorphToken, najpierw zmień swoją parę handlową";
|
||||
@override
|
||||
String get sending => "Wysyłanie";
|
||||
@override
|
||||
String get restore_restore_wallet => "Przywróć portfel";
|
||||
|
@ -5851,6 +5868,8 @@ class $es extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Billetera de carga";
|
||||
@override
|
||||
String get picker_description => "Para elegir ChangeNOW o MorphToken, primero cambie su par comercial";
|
||||
@override
|
||||
String get sending => "Enviando";
|
||||
@override
|
||||
String get restore_restore_wallet => "Recuperar Cartera";
|
||||
|
@ -6493,6 +6512,8 @@ class $nl extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "Portemonnee laden";
|
||||
@override
|
||||
String get picker_description => "Om ChangeNOW of MorphToken te kiezen, moet u eerst uw handelspaar wijzigen";
|
||||
@override
|
||||
String get sending => "Bezig met verzenden";
|
||||
@override
|
||||
String get restore_restore_wallet => "Portemonnee herstellen";
|
||||
|
@ -7135,6 +7156,8 @@ class $zh extends S {
|
|||
@override
|
||||
String get wallet_list_load_wallet => "装入钱包";
|
||||
@override
|
||||
String get picker_description => "要選擇ChangeNOW或MorphToken,請先更改您的交易對";
|
||||
@override
|
||||
String get sending => "正在发送";
|
||||
@override
|
||||
String get restore_restore_wallet => "恢复钱包";
|
||||
|
|
|
@ -120,7 +120,7 @@ class App extends StatelessWidget {
|
|||
settingsStore.isDarkTheme ? Brightness.light : Brightness.dark;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
final initialRoute = authenticationStore.state == AuthenticationState.denied
|
||||
? Routes.welcome
|
||||
? Routes.disclaimer
|
||||
: Routes.login;
|
||||
|
||||
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -128,7 +129,7 @@ class Router {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<SetupPinCodePage>(
|
||||
param1: (BuildContext context, dynamic _) =>
|
||||
Navigator.pushNamed(context, Routes.restoreWalletFromSeed)),
|
||||
Navigator.pushNamed(context, Routes.restoreWallet)),
|
||||
fullscreenDialog: true);
|
||||
|
||||
case Routes.seed:
|
||||
|
@ -136,6 +137,11 @@ class Router {
|
|||
builder: (_) =>
|
||||
getIt.get<WalletSeedPage>(param1: settings.arguments as bool));
|
||||
|
||||
case Routes.restoreWallet:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
getIt.get<WalletRestorePage>(param1: WalletType.monero));
|
||||
|
||||
case Routes.restoreWalletFromSeed:
|
||||
// final args = settings.arguments as List<dynamic>;
|
||||
final type = WalletType.monero; //args.first as WalletType;
|
||||
|
@ -144,8 +150,7 @@ class Router {
|
|||
// : LanguageList.english;
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) =>
|
||||
RestoreWalletFromSeedPage(type: type));
|
||||
builder: (_) => RestoreWalletFromSeedPage(type: type));
|
||||
|
||||
case Routes.restoreWalletFromKeys:
|
||||
final args = settings.arguments as List<dynamic>;
|
||||
|
|
|
@ -46,4 +46,5 @@ class Routes {
|
|||
static const sendTemplate = '/send_template';
|
||||
static const exchangeTemplate = '/exchange_template';
|
||||
static const restoreWalletType = '/restore_wallet_type';
|
||||
static const restoreWallet = '/restore_wallet';
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -19,26 +20,28 @@ class DisclaimerPage extends BasePage {
|
|||
String get title => 'Terms of Use';
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => DisclaimerPageBody(isReadOnly: true);
|
||||
Widget leading(BuildContext context) =>
|
||||
isReadOnly ? super.leading(context) : null;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => DisclaimerPageBody(isReadOnly: isReadOnly);
|
||||
}
|
||||
|
||||
class DisclaimerPageBody extends StatefulWidget {
|
||||
DisclaimerPageBody({this.isReadOnly = true});
|
||||
DisclaimerPageBody({this.isReadOnly});
|
||||
|
||||
final bool isReadOnly;
|
||||
|
||||
@override
|
||||
DisclaimerBodyState createState() => DisclaimerBodyState(false);
|
||||
DisclaimerBodyState createState() => DisclaimerBodyState();
|
||||
}
|
||||
|
||||
class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
DisclaimerBodyState(this._isAccepted);
|
||||
|
||||
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';
|
||||
|
||||
final bool _isAccepted;
|
||||
bool _checked = false;
|
||||
String _fileText = '';
|
||||
|
||||
|
@ -51,26 +54,10 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _showAlertDialog(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
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()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _afterLayout(Duration _) => _showAlertDialog(context);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getFileLines();
|
||||
if (_isAccepted) WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -87,8 +74,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
padding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
|
@ -102,13 +88,10 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? SizedBox(
|
||||
),
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
)
|
||||
: Offstage(),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
|
@ -254,8 +237,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
],
|
||||
)),
|
||||
if (!widget.isReadOnly) ...[
|
||||
!_isAccepted
|
||||
? Row(
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
|
@ -303,25 +285,19 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
)),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
!_isAccepted
|
||||
? Container(
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: _checked ? () {} : null,
|
||||
onPressed: _checked ? () =>
|
||||
Navigator.of(context).popAndPushNamed(Routes.welcome)
|
||||
: null,
|
||||
text: 'Accept',
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
_isAccepted
|
||||
? SizedBox(
|
||||
height: 24.0,
|
||||
)
|
||||
: Offstage()
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
|
|
@ -173,6 +173,7 @@ class ExchangePage extends BasePage {
|
|||
initialIsAddressEditable:
|
||||
exchangeViewModel.isDepositAddressEnabled,
|
||||
isAmountEstimated: false,
|
||||
hasRefundAddress: true,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) =>
|
||||
exchangeViewModel.changeDepositCurrency(
|
||||
|
@ -306,8 +307,7 @@ class ExchangePage extends BasePage {
|
|||
),
|
||||
Observer(builder: (_) {
|
||||
final templates = exchangeViewModel.templates;
|
||||
final itemCount =
|
||||
exchangeViewModel.templates.length;
|
||||
final itemCount = templates.length;
|
||||
|
||||
return ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
@ -337,24 +337,22 @@ class ExchangePage extends BasePage {
|
|||
alertContent: S
|
||||
.of(context)
|
||||
.confirm_delete_template,
|
||||
leftButtonText:
|
||||
S.of(context).delete,
|
||||
rightButtonText:
|
||||
S.of(context).delete,
|
||||
leftButtonText:
|
||||
S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
actionRightButton: () {
|
||||
Navigator.of(
|
||||
dialogContext)
|
||||
.pop();
|
||||
exchangeViewModel
|
||||
.exchangeTemplateStore
|
||||
.remove(
|
||||
.removeTemplate(
|
||||
template:
|
||||
template);
|
||||
exchangeViewModel
|
||||
.exchangeTemplateStore
|
||||
.update();
|
||||
.updateTemplate();
|
||||
},
|
||||
actionRightButton: () =>
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(
|
||||
dialogContext)
|
||||
.pop());
|
||||
|
|
|
@ -134,6 +134,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
initialIsAddressEditable: exchangeViewModel
|
||||
.isDepositAddressEnabled,
|
||||
isAmountEstimated: false,
|
||||
hasRefundAddress: true,
|
||||
currencies: CryptoCurrency.all,
|
||||
onCurrencySelected: (currency) =>
|
||||
exchangeViewModel.changeDepositCurrency(
|
||||
|
@ -220,7 +221,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
PrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
exchangeViewModel.exchangeTemplateStore.addTemplate(
|
||||
exchangeViewModel.addTemplate(
|
||||
amount: exchangeViewModel.depositAmount,
|
||||
depositCurrency:
|
||||
exchangeViewModel.depositCurrency.toString(),
|
||||
|
@ -229,7 +230,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
provider: exchangeViewModel.provider.toString(),
|
||||
depositAddress: exchangeViewModel.depositAddress,
|
||||
receiveAddress: exchangeViewModel.receiveAddress);
|
||||
exchangeViewModel.exchangeTemplateStore.update();
|
||||
exchangeViewModel.updateTemplate();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -18,6 +18,7 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.initialIsAmountEditable,
|
||||
this.initialIsAddressEditable,
|
||||
this.isAmountEstimated,
|
||||
this.hasRefundAddress = false,
|
||||
this.currencies,
|
||||
this.onCurrencySelected,
|
||||
this.imageArrow,
|
||||
|
@ -38,6 +39,7 @@ class ExchangeCard extends StatefulWidget {
|
|||
final bool initialIsAmountEditable;
|
||||
final bool initialIsAddressEditable;
|
||||
final bool isAmountEstimated;
|
||||
final bool hasRefundAddress;
|
||||
final Image imageArrow;
|
||||
final Color currencyButtonColor;
|
||||
final Color addressButtonsColor;
|
||||
|
@ -228,23 +230,25 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
: Offstage(),
|
||||
]),
|
||||
),
|
||||
_isAddressEditable
|
||||
? Offstage()
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).textTheme.subhead.decorationColor),
|
||||
)),
|
||||
!_isAddressEditable && widget.hasRefundAddress
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).textTheme.subhead.decorationColor),
|
||||
))
|
||||
: Offstage(),
|
||||
_isAddressEditable
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address : null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
|
|
|
@ -58,11 +58,13 @@ class PresentProviderPicker extends StatelessWidget {
|
|||
final items = exchangeViewModel.providersForCurrentPair();
|
||||
final selectedItem = items.indexOf(exchangeViewModel.provider);
|
||||
final images = <Image>[];
|
||||
String description;
|
||||
|
||||
for (var provider in items) {
|
||||
switch (provider.description) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
images.add(Image.asset('assets/images/xmr_btc.png'));
|
||||
description = S.of(context).picker_description;
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
images.add(Image.asset('assets/images/change_now.png'));
|
||||
|
@ -79,6 +81,7 @@ class PresentProviderPicker extends StatelessWidget {
|
|||
images: images,
|
||||
selectedAtIndex: selectedItem,
|
||||
title: S.of(context).change_exchange_provider,
|
||||
description: description,
|
||||
onItemSelected: (ExchangeProvider provider) =>
|
||||
exchangeViewModel.changeProvider(provider: provider)),
|
||||
context: context);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/src/screens/restore/restore_from_keys.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
|
@ -30,6 +31,7 @@ class RestoreWalletFromSeedPage extends BasePage {
|
|||
String get title => S.current.restore_title_from_seed;
|
||||
|
||||
final controller = PageController(initialPage: 0);
|
||||
List<Widget> _pages;
|
||||
|
||||
Widget _page(BuildContext context, int index) {
|
||||
if (_pages == null || _pages.isEmpty) {
|
||||
|
@ -49,48 +51,12 @@ class RestoreWalletFromSeedPage extends BasePage {
|
|||
|
||||
void _setPages(BuildContext context) {
|
||||
_pages = <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 25, right: 25),
|
||||
child: Column(children: [
|
||||
SeedWidget(
|
||||
maxLength: mnemonicLength(WalletType.monero),
|
||||
onMnemonicChange: (seed) => null,
|
||||
onFinish: () => null,
|
||||
// Navigator.of(context).pushNamed(
|
||||
// Routes.restoreWalletFromSeedDetails,
|
||||
// arguments: [WalletType.monero, '', '']),
|
||||
validator: SeedValidator(type: WalletType.monero, language: ''),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final selected = await showPopUp<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
SeedLanguagePicker(selected: 'English')); //key: _pickerKey
|
||||
print('Seletec $selected');
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: IgnorePointer(child: BaseTextFormField(
|
||||
enableInteractiveSelection: false,
|
||||
readOnly: true,
|
||||
hintText: 'Language',
|
||||
initialValue: 'English (Seed language)')))),
|
||||
BlockchainHeightWidget(
|
||||
// key: _blockchainHeightKey,
|
||||
onHeightChange: (height) {
|
||||
// widget.walletRestorationFromKeysVM.height = height;
|
||||
print(height);
|
||||
})
|
||||
])),
|
||||
WalletRestoreFromSeedForm(),
|
||||
RestoreFromKeysFrom(),
|
||||
// Container(color: Colors.yellow)
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _pages;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
|
@ -198,15 +164,15 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
|||
child: Column(children: [
|
||||
SeedWidget(
|
||||
// key: _seedKey,
|
||||
maxLength: mnemonicLength(widget.type),
|
||||
onMnemonicChange: (seed) => null,
|
||||
onFinish: () => Navigator.of(context).pushNamed(
|
||||
Routes.restoreWalletFromSeedDetails,
|
||||
arguments: [widget.type, widget.language, mnemonic()]),
|
||||
leading: widget.leading,
|
||||
middle: widget.middle,
|
||||
validator:
|
||||
SeedValidator(type: widget.type, language: widget.language),
|
||||
// maxLength: mnemonicLength(widget.type),
|
||||
// onMnemonicChange: (seed) => null,
|
||||
// onFinish: () => Navigator.of(context).pushNamed(
|
||||
// Routes.restoreWalletFromSeedDetails,
|
||||
// arguments: [widget.type, widget.language, mnemonic()]),
|
||||
// leading: widget.leading,
|
||||
// middle: widget.middle,
|
||||
// validator:
|
||||
// SeedValidator(type: widget.type, language: widget.language),
|
||||
),
|
||||
BlockchainHeightWidget(
|
||||
// key: _blockchainHeightKey,
|
||||
|
|
70
lib/src/screens/restore/wallet_restore_from_keys_form.dart
Normal file
70
lib/src/screens/restore/wallet_restore_from_keys_form.dart
Normal file
|
@ -0,0 +1,70 @@
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
|
||||
class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||
WalletRestoreFromKeysFrom({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
WalletRestoreFromKeysFromState createState() =>
|
||||
WalletRestoreFromKeysFromState();
|
||||
}
|
||||
|
||||
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||
WalletRestoreFromKeysFromState()
|
||||
: formKey = GlobalKey<FormState>(),
|
||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||
nameController = TextEditingController(),
|
||||
addressController = TextEditingController(),
|
||||
viewKeyController = TextEditingController(),
|
||||
spendKeyController = TextEditingController();
|
||||
|
||||
final GlobalKey<FormState> formKey;
|
||||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||
final TextEditingController nameController;
|
||||
final TextEditingController addressController;
|
||||
final TextEditingController viewKeyController;
|
||||
final TextEditingController spendKeyController;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
addressController.dispose();
|
||||
viewKeyController.dispose();
|
||||
spendKeyController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 25, right: 25),
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Column(children: <Widget>[
|
||||
BaseTextFormField(
|
||||
controller: addressController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
hintText: S.of(context).restore_address),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: viewKeyController,
|
||||
hintText: S.of(context).restore_view_key_private,
|
||||
maxLines: null)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: spendKeyController,
|
||||
hintText: S.of(context).restore_spend_key_private,
|
||||
maxLines: null)),
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey, onHeightChange: (_) => null)
|
||||
]),
|
||||
));
|
||||
}
|
||||
}
|
73
lib/src/screens/restore/wallet_restore_from_seed_form.dart
Normal file
73
lib/src/screens/restore/wallet_restore_from_seed_form.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
|
||||
class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||
WalletRestoreFromSeedForm({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
WalletRestoreFromSeedFormState createState() =>
|
||||
WalletRestoreFromSeedFormState('English');
|
||||
}
|
||||
|
||||
class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||
WalletRestoreFromSeedFormState(this.language)
|
||||
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
|
||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||
languageController = TextEditingController();
|
||||
|
||||
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
|
||||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||
final TextEditingController languageController;
|
||||
String language;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_setLanguageLabel(language);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 25, right: 25),
|
||||
child: Column(children: [
|
||||
SeedWidget(key: seedWidgetStateKey),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final selected = await showPopUp<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
SeedLanguagePicker(selected: language));
|
||||
_changeLanguage(selected);
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: languageController,
|
||||
enableInteractiveSelection: false,
|
||||
readOnly: true)))),
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey,
|
||||
onHeightChange: (height) {
|
||||
print(height);
|
||||
})
|
||||
]));
|
||||
}
|
||||
|
||||
void _changeLanguage(String language) {
|
||||
setState(() {
|
||||
this.language = language;
|
||||
_setLanguageLabel(language);
|
||||
});
|
||||
}
|
||||
|
||||
void _setLanguageLabel(String language) =>
|
||||
languageController.text = '$language (Seed language)';
|
||||
}
|
127
lib/src/screens/restore/wallet_restore_page.dart
Normal file
127
lib/src/screens/restore/wallet_restore_page.dart
Normal file
|
@ -0,0 +1,127 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
|
||||
class WalletRestorePage extends BasePage {
|
||||
WalletRestorePage(this.walletRestoreViewModel)
|
||||
: walletRestoreFromSeedFormKey =
|
||||
GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey =
|
||||
GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
_pages = [],
|
||||
_controller = PageController(initialPage: 0) {
|
||||
_pages.addAll([
|
||||
WalletRestoreFromSeedForm(key: walletRestoreFromSeedFormKey),
|
||||
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey)
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) => Observer(
|
||||
builder: (_) => Text(
|
||||
walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? S.current.restore_title_from_seed
|
||||
: S.current.restore_title_from_keys,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Poppins',
|
||||
color: titleColor ??
|
||||
Theme.of(context).primaryTextTheme.title.color),
|
||||
));
|
||||
|
||||
@override
|
||||
String get title => S.current.restore_title_from_seed;
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final PageController _controller;
|
||||
final List<Widget> _pages;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
reaction((_) => walletRestoreViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.new_wallet,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Expanded(
|
||||
child: PageView.builder(
|
||||
onPageChanged: (page) {
|
||||
walletRestoreViewModel.mode =
|
||||
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
|
||||
},
|
||||
controller: _controller,
|
||||
itemCount: _pages.length,
|
||||
itemBuilder: (_, index) => _pages[index])),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SmoothPageIndicator(
|
||||
controller: _controller,
|
||||
count: _pages.length,
|
||||
effect: ColorTransitionEffect(
|
||||
spacing: 6.0,
|
||||
radius: 6.0,
|
||||
dotWidth: 6.0,
|
||||
dotHeight: 6.0,
|
||||
dotColor: Theme.of(context).hintColor.withOpacity(0.5),
|
||||
activeDotColor: Theme.of(context).hintColor),
|
||||
)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 40, left: 25, right: 25),
|
||||
child: PrimaryButton(
|
||||
text: S.of(context).restore_recover,
|
||||
isDisabled: false,
|
||||
onPressed: () =>
|
||||
walletRestoreViewModel.create(options: _credentials()),
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white)),
|
||||
]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _credentials() {
|
||||
final credentials = <String, dynamic>{};
|
||||
|
||||
if (walletRestoreViewModel.mode == WalletRestoreMode.seed) {
|
||||
credentials['seed'] = walletRestoreFromSeedFormKey
|
||||
.currentState.seedWidgetStateKey.currentState.text;
|
||||
credentials['height'] = walletRestoreFromSeedFormKey
|
||||
.currentState.blockchainHeightKey.currentState.height;
|
||||
} else {
|
||||
credentials['address'] =
|
||||
walletRestoreFromKeysFormKey.currentState.addressController.text;
|
||||
credentials['viewKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState.viewKeyController.text;
|
||||
credentials['spendKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState.spendKeyController.text;
|
||||
credentials['height'] = walletRestoreFromKeysFormKey
|
||||
.currentState.blockchainHeightKey.currentState.height;
|
||||
}
|
||||
|
||||
return credentials;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/entities/transaction_priority.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -416,53 +418,53 @@ class SendPage extends BasePage {
|
|||
)),
|
||||
),
|
||||
),
|
||||
// Observer(
|
||||
// builder: (_) {
|
||||
// final templates = sendViewModel.templates;
|
||||
// final itemCount = templates.length;
|
||||
Observer(
|
||||
builder: (_) {
|
||||
final templates = sendViewModel.templates;
|
||||
final itemCount = templates.length;
|
||||
|
||||
// return ListView.builder(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// shrinkWrap: true,
|
||||
// physics: NeverScrollableScrollPhysics(),
|
||||
// itemCount: itemCount,
|
||||
// itemBuilder: (context, index) {
|
||||
// final template = templates[index];
|
||||
return ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: itemCount,
|
||||
itemBuilder: (context, index) {
|
||||
final template = templates[index];
|
||||
|
||||
// return TemplateTile(
|
||||
// key: UniqueKey(),
|
||||
// to: template.name,
|
||||
// amount: template.amount,
|
||||
// from: template.cryptoCurrency,
|
||||
// onTap: () {
|
||||
// _addressController.text = template.address;
|
||||
// _cryptoAmountController.text = template.amount;
|
||||
// getOpenaliasRecord(context);
|
||||
// },
|
||||
// onRemove: () {
|
||||
// showPopUp<void>(
|
||||
// context: context,
|
||||
// builder: (dialogContext) {
|
||||
// return AlertWithTwoActions(
|
||||
// alertTitle: S.of(context).template,
|
||||
// alertContent: S.of(context).confirm_delete_template,
|
||||
// leftButtonText: S.of(context).delete,
|
||||
// rightButtonText: S.of(context).cancel,
|
||||
// actionLeftButton: () {
|
||||
// Navigator.of(dialogContext).pop();
|
||||
// sendViewModel.sendTemplateStore.remove(template: template);
|
||||
// sendViewModel.sendTemplateStore.update();
|
||||
// },
|
||||
// actionRightButton: () => Navigator.of(dialogContext).pop()
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// )
|
||||
return TemplateTile(
|
||||
key: UniqueKey(),
|
||||
to: template.name,
|
||||
amount: template.amount,
|
||||
from: template.cryptoCurrency,
|
||||
onTap: () {
|
||||
_addressController.text = template.address;
|
||||
_cryptoAmountController.text = template.amount;
|
||||
getOpenaliasRecord(context);
|
||||
},
|
||||
onRemove: () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).template,
|
||||
alertContent: S.of(context).confirm_delete_template,
|
||||
rightButtonText: S.of(context).delete,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
sendViewModel.removeTemplate(template: template);
|
||||
sendViewModel.updateTemplate();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(dialogContext).pop()
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -507,6 +509,14 @@ class SendPage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
_fiatAmountController.addListener(() {
|
||||
final amount = _fiatAmountController.text;
|
||||
|
||||
if (amount != sendViewModel.fiatAmount) {
|
||||
sendViewModel.setFiatAmount(amount);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.sendAll, (bool all) {
|
||||
if (all) {
|
||||
_cryptoAmountController.text = S.current.all;
|
||||
|
@ -571,9 +581,9 @@ class SendPage extends BasePage {
|
|||
sendViewModel.pendingTransaction.amountFormatted,
|
||||
fee: S.of(context).send_fee,
|
||||
feeValue: sendViewModel.pendingTransaction.feeFormatted,
|
||||
leftButtonText: S.of(context).ok,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
Navigator.of(context).pop();
|
||||
sendViewModel.commitTransaction();
|
||||
showPopUp<void>(
|
||||
|
@ -670,7 +680,7 @@ class SendPage extends BasePage {
|
|||
});
|
||||
});
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop());
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ class SendTemplatePage extends BasePage {
|
|||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
RegExp('[\\-|\\ ]'))
|
||||
],
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 9),
|
||||
|
@ -172,7 +172,7 @@ class SendTemplatePage extends BasePage {
|
|||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ |\\,]'))
|
||||
RegExp('[\\-|\\ ]'))
|
||||
],
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 9),
|
||||
|
@ -210,12 +210,12 @@ class SendTemplatePage extends BasePage {
|
|||
bottomSection: PrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
// sendViewModel.sendTemplateStore.addTemplate(
|
||||
// name: _nameController.text,
|
||||
// address: _addressController.text,
|
||||
// cryptoCurrency: sendViewModel.currency.title,
|
||||
// amount: _cryptoAmountController.text);
|
||||
// sendViewModel.sendTemplateStore.update();
|
||||
sendViewModel.addTemplate(
|
||||
name: _nameController.text,
|
||||
address: _addressController.text,
|
||||
cryptoCurrency: sendViewModel.currency.title,
|
||||
amount: _cryptoAmountController.text);
|
||||
sendViewModel.updateTemplate();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
@ -249,6 +249,22 @@ class SendTemplatePage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
_cryptoAmountController.addListener(() {
|
||||
final amount = _cryptoAmountController.text;
|
||||
|
||||
if (amount != sendViewModel.cryptoAmount) {
|
||||
sendViewModel.setCryptoAmount(amount);
|
||||
}
|
||||
});
|
||||
|
||||
_fiatAmountController.addListener(() {
|
||||
final amount = _fiatAmountController.text;
|
||||
|
||||
if (amount != sendViewModel.fiatAmount) {
|
||||
sendViewModel.setFiatAmount(amount);
|
||||
}
|
||||
});
|
||||
|
||||
_addressController.addListener(() {
|
||||
final address = _addressController.text;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Poppins',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
|
@ -64,6 +65,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Poppins',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
|
@ -79,6 +81,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Poppins',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
|
@ -88,6 +91,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Poppins',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
|
|
|
@ -175,7 +175,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
SizedBox(height: 10.0),
|
||||
PrimaryImageButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pushNamed(Routes.restoreWalletFromSeed),
|
||||
Navigator.of(context).pushNamed(Routes.restoreWallet),
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).wallet_list_restore_wallet,
|
||||
color: Theme.of(context).accentTextTheme.caption.color,
|
||||
|
|
|
@ -14,118 +14,178 @@ class WelcomePage extends BasePage {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).backgroundColor,
|
||||
backgroundColor: Theme
|
||||
.of(context)
|
||||
.backgroundColor,
|
||||
resizeToAvoidBottomPadding: false,
|
||||
body: SafeArea(child: body(context)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final welcomeImage = getIt.get<SettingsStore>().isDarkTheme
|
||||
final welcomeImage = getIt
|
||||
.get<SettingsStore>()
|
||||
.isDarkTheme
|
||||
? welcomeImageDark : welcomeImageLight;
|
||||
|
||||
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Theme.of(context).accentTextTheme.headline.decorationColor);
|
||||
color: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.headline
|
||||
.decorationColor);
|
||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Theme.of(context).primaryTextTheme.title.color);
|
||||
color: Theme
|
||||
.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: welcomeImage, fit: BoxFit.fill)
|
||||
)
|
||||
),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
return WillPopScope(onWillPop: () async => false, child: Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: welcomeImage, fit: BoxFit.fill)
|
||||
)
|
||||
),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Text(
|
||||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.color,
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Text(
|
||||
S
|
||||
.of(context)
|
||||
.welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S.of(context).cake_wallet,
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S
|
||||
.of(context)
|
||||
.cake_wallet,
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S.of(context).first_wallet_text,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.color,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S
|
||||
.of(context)
|
||||
.first_wallet_text,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).accentTextTheme.display3.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: Theme.of(context).accentTextTheme.subtitle.decorationColor,
|
||||
textColor: Theme.of(context).accentTextTheme.headline.decorationColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).restore_wallet,
|
||||
color: Theme.of(context).accentTextTheme.caption.color,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S
|
||||
.of(context)
|
||||
.please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.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: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.subtitle
|
||||
.decorationColor,
|
||||
textColor: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.headline
|
||||
.decorationColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context,
|
||||
Routes.restoreWalletOptionsFromWelcome),
|
||||
image: restoreWalletImage,
|
||||
text: S
|
||||
.of(context)
|
||||
.restore_wallet,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.accentTextTheme
|
||||
.caption
|
||||
.color,
|
||||
textColor: Theme
|
||||
.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
);
|
||||
],
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ class AddressTextField extends StatelessWidget {
|
|||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/duplicate.png',
|
||||
'assets/images/paste_ios.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme
|
||||
|
|
161
lib/src/widgets/annotated_editable_text.dart
Normal file
161
lib/src/widgets/annotated_editable_text.dart
Normal file
|
@ -0,0 +1,161 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class Annotation extends Comparable<Annotation> {
|
||||
Annotation({@required this.range, this.style});
|
||||
|
||||
final TextRange range;
|
||||
final TextStyle style;
|
||||
|
||||
@override
|
||||
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
|
||||
}
|
||||
|
||||
class TextAnnotation extends Comparable<TextAnnotation> {
|
||||
TextAnnotation({@required this.text, this.style});
|
||||
|
||||
final TextStyle style;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
int compareTo(TextAnnotation other) => text.compareTo(other.text);
|
||||
}
|
||||
|
||||
class AnnotatedEditableText extends EditableText {
|
||||
AnnotatedEditableText({
|
||||
Key key,
|
||||
FocusNode focusNode,
|
||||
TextEditingController controller,
|
||||
TextStyle style,
|
||||
ValueChanged<String> onChanged,
|
||||
ValueChanged<String> onSubmitted,
|
||||
Color cursorColor,
|
||||
Color selectionColor,
|
||||
Color backgroundCursorColor,
|
||||
TextSelectionControls selectionControls,
|
||||
@required this.words,
|
||||
}) : textAnnotations = words
|
||||
.map((word) => TextAnnotation(
|
||||
text: word,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
backgroundColor: Colors.transparent,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 20)))
|
||||
.toList(),
|
||||
super(
|
||||
maxLines: null,
|
||||
key: key,
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
cursorColor: cursorColor,
|
||||
style: style,
|
||||
keyboardType: TextInputType.text,
|
||||
autocorrect: false,
|
||||
autofocus: false,
|
||||
selectionColor: selectionColor,
|
||||
selectionControls: selectionControls,
|
||||
backgroundCursorColor: backgroundCursorColor,
|
||||
onChanged: onChanged,
|
||||
onSubmitted: onSubmitted,
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: true,
|
||||
cut: true,
|
||||
paste: true,
|
||||
selectAll: true,
|
||||
),
|
||||
enableSuggestions: false,
|
||||
enableInteractiveSelection: true,
|
||||
showSelectionHandles: true,
|
||||
showCursor: true,
|
||||
) {
|
||||
textAnnotations.add(TextAnnotation(
|
||||
text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
final List<String> words;
|
||||
final List<TextAnnotation> textAnnotations;
|
||||
|
||||
@override
|
||||
AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
|
||||
}
|
||||
|
||||
class AnnotatedEditableTextState extends EditableTextState {
|
||||
@override
|
||||
AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
|
||||
|
||||
List<Annotation> getRanges() {
|
||||
final source = widget.textAnnotations
|
||||
.map((item) => range(item.text, textEditingValue.text)
|
||||
.map((range) => Annotation(style: item.style, range: range)))
|
||||
.expand((e) => e)
|
||||
.toList();
|
||||
final result = List<Annotation>();
|
||||
final text = textEditingValue.text;
|
||||
source.sort();
|
||||
Annotation prev;
|
||||
|
||||
for (var item in source) {
|
||||
if (prev == null) {
|
||||
if (item.range.start > 0) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: 0, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.black, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
result.add(item);
|
||||
prev = item;
|
||||
continue;
|
||||
} else {
|
||||
if (prev.range.end > item.range.start) {
|
||||
// throw StateError('Invalid (intersecting) ranges for annotated field');
|
||||
} else if (prev.range.end < item.range.start) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: prev.range.end, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.red, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
result.add(item);
|
||||
prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.length > 0 && result.last.range.end < text.length) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: result.last.range.end, end: text.length),
|
||||
style: TextStyle( backgroundColor: Colors.transparent)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<TextRange> range(String pattern, String source) {
|
||||
final result = List<TextRange>();
|
||||
|
||||
for (int index = source.indexOf(pattern);
|
||||
index >= 0;
|
||||
index = source.indexOf(pattern, index + 1)) {
|
||||
final start = index;
|
||||
final end = start + pattern.length;
|
||||
result.add(TextRange(start: start, end: end));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan buildTextSpan() {
|
||||
final text = textEditingValue.text;
|
||||
final ranges = getRanges();
|
||||
|
||||
if (ranges.isNotEmpty) {
|
||||
return TextSpan(
|
||||
style: widget.style,
|
||||
children: ranges
|
||||
.map((item) => TextSpan(
|
||||
style: item.style, text: item.range.textInside(text)))
|
||||
.toList());
|
||||
}
|
||||
|
||||
return TextSpan(style: widget.style, text: text);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/utils/date_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -88,7 +89,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
|||
|
||||
Future _selectDate(BuildContext context) async {
|
||||
final now = DateTime.now();
|
||||
final date = await showDatePicker(
|
||||
final date = await getDate(
|
||||
context: context,
|
||||
initialDate: now.subtract(Duration(days: 1)),
|
||||
firstDate: DateTime(2014, DateTime.april),
|
||||
|
|
|
@ -12,6 +12,7 @@ class Picker<Item extends Object> extends StatefulWidget {
|
|||
@required this.items,
|
||||
this.images,
|
||||
@required this.title,
|
||||
this.description,
|
||||
@required this.onItemSelected,
|
||||
this.mainAxisAlignment = MainAxisAlignment.start,
|
||||
this.isAlwaysShowScrollThumb = false
|
||||
|
@ -21,6 +22,7 @@ class Picker<Item extends Object> extends StatefulWidget {
|
|||
final List<Item> items;
|
||||
final List<Image> images;
|
||||
final String title;
|
||||
final String description;
|
||||
final Function(Item) onItemSelected;
|
||||
final MainAxisAlignment mainAxisAlignment;
|
||||
final bool isAlwaysShowScrollThumb;
|
||||
|
@ -145,6 +147,26 @@ class PickerState<Item> extends State<Picker> {
|
|||
);
|
||||
},
|
||||
),
|
||||
((widget.description != null)
|
||||
&&(widget.description.isNotEmpty))
|
||||
? Positioned(
|
||||
bottom: 24,
|
||||
left: 24,
|
||||
right: 24,
|
||||
child: Text(
|
||||
widget.description,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Poppins',
|
||||
decoration: TextDecoration.none,
|
||||
color: Theme.of(context).primaryTextTheme
|
||||
.title.color
|
||||
),
|
||||
)
|
||||
)
|
||||
: Offstage(),
|
||||
widget.isAlwaysShowScrollThumb
|
||||
? CakeScrollbar(
|
||||
backgroundHeight: backgroundHeight,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/widgets/annotated_editable_text.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -10,367 +11,33 @@ import 'package:cake_wallet/entities/mnemonic_item.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class Annotation extends Comparable<Annotation> {
|
||||
Annotation({@required this.range, this.style});
|
||||
|
||||
final TextRange range;
|
||||
final TextStyle style;
|
||||
|
||||
@override
|
||||
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
|
||||
}
|
||||
|
||||
class TextAnnotation extends Comparable<TextAnnotation> {
|
||||
TextAnnotation({@required this.text, this.style});
|
||||
|
||||
final TextStyle style;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
int compareTo(TextAnnotation other) => text.compareTo(other.text);
|
||||
}
|
||||
|
||||
class AnnotatedEditableText extends EditableText {
|
||||
AnnotatedEditableText({
|
||||
Key key,
|
||||
FocusNode focusNode,
|
||||
TextEditingController controller,
|
||||
TextStyle style,
|
||||
ValueChanged<String> onChanged,
|
||||
ValueChanged<String> onSubmitted,
|
||||
Color cursorColor,
|
||||
Color selectionColor,
|
||||
Color backgroundCursorColor,
|
||||
TextSelectionControls selectionControls,
|
||||
@required this.words,
|
||||
}) : textAnnotations = words
|
||||
.map((word) => TextAnnotation(
|
||||
text: word,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
backgroundColor: Colors.transparent,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 20)))
|
||||
.toList(),
|
||||
super(
|
||||
maxLines: null,
|
||||
key: key,
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
cursorColor: cursorColor,
|
||||
style: style,
|
||||
keyboardType: TextInputType.text,
|
||||
autocorrect: false,
|
||||
autofocus: false,
|
||||
selectionColor: selectionColor,
|
||||
selectionControls: selectionControls,
|
||||
backgroundCursorColor: backgroundCursorColor,
|
||||
onChanged: onChanged,
|
||||
onSubmitted: onSubmitted,
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: true,
|
||||
cut: true,
|
||||
paste: true,
|
||||
selectAll: true,
|
||||
),
|
||||
enableSuggestions: false,
|
||||
enableInteractiveSelection: true,
|
||||
showSelectionHandles: true,
|
||||
showCursor: true,
|
||||
) {
|
||||
textAnnotations.add(TextAnnotation(
|
||||
text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
final List<String> words;
|
||||
final List<TextAnnotation> textAnnotations;
|
||||
|
||||
@override
|
||||
AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
|
||||
}
|
||||
|
||||
class AnnotatedEditableTextState extends EditableTextState {
|
||||
@override
|
||||
AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
|
||||
|
||||
List<Annotation> getRanges() {
|
||||
final source = widget.textAnnotations
|
||||
.map((item) => range(item.text, textEditingValue.text)
|
||||
.map((range) => Annotation(style: item.style, range: range)))
|
||||
.expand((e) => e)
|
||||
.toList();
|
||||
final result = List<Annotation>();
|
||||
final text = textEditingValue.text;
|
||||
source.sort();
|
||||
Annotation prev;
|
||||
|
||||
for (var item in source) {
|
||||
if (prev == null) {
|
||||
if (item.range.start > 0) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: 0, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.black, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
result.add(item);
|
||||
prev = item;
|
||||
continue;
|
||||
} else {
|
||||
if (prev.range.end > item.range.start) {
|
||||
// throw StateError('Invalid (intersecting) ranges for annotated field');
|
||||
} else if (prev.range.end < item.range.start) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: prev.range.end, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.red, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
result.add(item);
|
||||
prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.length > 0 && result.last.range.end < text.length) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: result.last.range.end, end: text.length),
|
||||
style: TextStyle( backgroundColor: Colors.transparent)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<TextRange> range(String pattern, String source) {
|
||||
final result = List<TextRange>();
|
||||
|
||||
for (int index = source.indexOf(pattern);
|
||||
index >= 0;
|
||||
index = source.indexOf(pattern, index + 1)) {
|
||||
final start = index;
|
||||
final end = start + pattern.length;
|
||||
result.add(TextRange(start: start, end: end));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan buildTextSpan() {
|
||||
final text = textEditingValue.text;
|
||||
final ranges = getRanges();
|
||||
|
||||
if (ranges.isNotEmpty) {
|
||||
return TextSpan(
|
||||
style: widget.style,
|
||||
children: ranges
|
||||
.map((item) => TextSpan(
|
||||
style: item.style, text: item.range.textInside(text)))
|
||||
.toList());
|
||||
}
|
||||
|
||||
return TextSpan(style: widget.style, text: text);
|
||||
}
|
||||
}
|
||||
|
||||
class SeedWidget extends StatefulWidget {
|
||||
SeedWidget(
|
||||
{Key key,
|
||||
this.maxLength,
|
||||
this.onMnemonicChange,
|
||||
this.onFinish,
|
||||
this.leading,
|
||||
this.middle,
|
||||
this.validator})
|
||||
: super(key: key);
|
||||
|
||||
final int maxLength;
|
||||
final Function(List<MnemonicItem>) onMnemonicChange;
|
||||
final Function() onFinish;
|
||||
final SeedValidator validator;
|
||||
final Widget leading;
|
||||
final Widget middle;
|
||||
SeedWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
SeedWidgetState createState() => SeedWidgetState(maxLength: maxLength);
|
||||
SeedWidgetState createState() => SeedWidgetState();
|
||||
}
|
||||
|
||||
class SeedWidgetState extends State<SeedWidget> {
|
||||
SeedWidgetState({this.maxLength});
|
||||
SeedWidgetState()
|
||||
: controller = TextEditingController(),
|
||||
focusNode = FocusNode(),
|
||||
words =
|
||||
SeedValidator.getWordList(type: WalletType.monero, language: 'en');
|
||||
|
||||
List<MnemonicItem> items = <MnemonicItem>[];
|
||||
final int maxLength;
|
||||
final _seedController = TextEditingController();
|
||||
final _seedTextFieldKey = GlobalKey();
|
||||
MnemonicItem selectedItem;
|
||||
bool isValid;
|
||||
String errorMessage;
|
||||
final TextEditingController controller;
|
||||
final FocusNode focusNode;
|
||||
final List<String> words;
|
||||
bool _showPlaceholder;
|
||||
|
||||
List<MnemonicItem> currentMnemonics;
|
||||
bool isCurrentMnemonicValid;
|
||||
String _errorMessage;
|
||||
String get text => controller.text;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
showPlaceholder = true;
|
||||
isValid = false;
|
||||
isCurrentMnemonicValid = false;
|
||||
_seedController
|
||||
.addListener(() => changeCurrentMnemonic(_seedController.text));
|
||||
focusNode.addListener(() => setState(() =>
|
||||
showPlaceholder = !focusNode.hasFocus && controller.text.isEmpty));
|
||||
_showPlaceholder = true;
|
||||
}
|
||||
|
||||
void addMnemonic(String text) {
|
||||
setState(() => items.add(MnemonicItem(text: text.trim().toLowerCase())));
|
||||
_seedController.text = '';
|
||||
|
||||
if (widget.onMnemonicChange != null) {
|
||||
widget.onMnemonicChange(items);
|
||||
}
|
||||
}
|
||||
|
||||
void mnemonicFromText(String text) {
|
||||
final splitted = text.split(' ');
|
||||
|
||||
if (splitted.length >= 2) {
|
||||
for (final text in splitted) {
|
||||
if (text == ' ' || text.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedItem != null) {
|
||||
editTextOfSelectedMnemonic(text);
|
||||
} else {
|
||||
addMnemonic(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void selectMnemonic(MnemonicItem item) {
|
||||
setState(() {
|
||||
selectedItem = item;
|
||||
currentMnemonics = [item];
|
||||
|
||||
_seedController
|
||||
..text = item.text
|
||||
..selection = TextSelection.collapsed(offset: item.text.length);
|
||||
});
|
||||
}
|
||||
|
||||
void onMnemonicTap(MnemonicItem item) {
|
||||
if (selectedItem == item) {
|
||||
setState(() => selectedItem = null);
|
||||
_seedController.text = '';
|
||||
return;
|
||||
}
|
||||
|
||||
selectMnemonic(item);
|
||||
}
|
||||
|
||||
void editTextOfSelectedMnemonic(String text) {
|
||||
setState(() => selectedItem.changeText(text));
|
||||
selectedItem = null;
|
||||
_seedController.text = '';
|
||||
|
||||
if (widget.onMnemonicChange != null) {
|
||||
widget.onMnemonicChange(items);
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
setState(() {
|
||||
items = [];
|
||||
selectedItem = null;
|
||||
_seedController.text = '';
|
||||
|
||||
if (widget.onMnemonicChange != null) {
|
||||
widget.onMnemonicChange(items);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void invalidate() => setState(() => isValid = false);
|
||||
|
||||
void validated() => setState(() => isValid = true);
|
||||
|
||||
void setErrorMessage(String errorMessage) =>
|
||||
setState(() => this.errorMessage = errorMessage);
|
||||
|
||||
void replaceText(String text) {
|
||||
setState(() => items = []);
|
||||
mnemonicFromText(text);
|
||||
}
|
||||
|
||||
void changeCurrentMnemonic(String text) {
|
||||
setState(() {
|
||||
final trimmedText = text.trim();
|
||||
final splitted = trimmedText.split(' ');
|
||||
_errorMessage = null;
|
||||
|
||||
if (text == null) {
|
||||
currentMnemonics = [];
|
||||
isCurrentMnemonicValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
currentMnemonics =
|
||||
splitted.map((text) => MnemonicItem(text: text)).toList();
|
||||
|
||||
var isValid = true;
|
||||
|
||||
for (final word in currentMnemonics) {
|
||||
isValid = widget.validator.isValid(word);
|
||||
|
||||
if (!isValid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
isCurrentMnemonicValid = isValid;
|
||||
});
|
||||
}
|
||||
|
||||
void saveCurrentMnemonicToItems() {
|
||||
setState(() {
|
||||
if (selectedItem != null) {
|
||||
selectedItem.changeText(currentMnemonics.first.text.trim());
|
||||
selectedItem = null;
|
||||
} else {
|
||||
items.addAll(currentMnemonics);
|
||||
}
|
||||
|
||||
currentMnemonics = [];
|
||||
_seedController.text = '';
|
||||
});
|
||||
}
|
||||
|
||||
void showErrorIfExist() {
|
||||
setState(() => _errorMessage =
|
||||
!isCurrentMnemonicValid ? S.current.incorrect_seed : null);
|
||||
}
|
||||
|
||||
bool isSeedValid() {
|
||||
bool isValid;
|
||||
|
||||
for (final item in items) {
|
||||
isValid = widget.validator.isValid(item);
|
||||
|
||||
if (!isValid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
final controller = TextEditingController();
|
||||
final focusNode = FocusNode();
|
||||
|
||||
bool showPlaceholder;
|
||||
|
||||
final words =
|
||||
SeedValidator.getWordList(type: WalletType.monero, language: 'en');
|
||||
|
||||
Future<void> _pasteAddress() async {
|
||||
final value = await Clipboard.getData('text/plain');
|
||||
|
||||
|
@ -381,7 +48,6 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print('build');
|
||||
return Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -389,7 +55,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
children: [
|
||||
Stack(children: [
|
||||
SizedBox(height: 35),
|
||||
if (showPlaceholder)
|
||||
if (_showPlaceholder)
|
||||
Positioned(
|
||||
top: 10,
|
||||
left: 0,
|
||||
|
@ -418,15 +84,15 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
child: InkWell(
|
||||
onTap: () async => _pasteAddress(),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).hintColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset('assets/images/duplicate.png',
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor)),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).hintColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
// child: Image.asset('assets/images/duplicate.png',
|
||||
// color: Theme.of(context)
|
||||
// .primaryTextTheme
|
||||
// .display1
|
||||
// .decorationColor)
|
||||
),
|
||||
)))
|
||||
]),
|
||||
Container(
|
||||
|
@ -434,237 +100,5 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
height: 1.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.backgroundColor),
|
||||
]));
|
||||
// return Container(
|
||||
// child: Column(children: [
|
||||
// Flexible(
|
||||
// fit: FlexFit.tight,
|
||||
// flex: 2,
|
||||
// child: Container(
|
||||
// width: double.infinity,
|
||||
// height: double.infinity,
|
||||
// padding: EdgeInsets.all(0),
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.only(
|
||||
// bottomLeft: Radius.circular(24),
|
||||
// bottomRight: Radius.circular(24)),
|
||||
// gradient: LinearGradient(colors: [
|
||||
// Theme.of(context).primaryTextTheme.subhead.color,
|
||||
// Theme.of(context).primaryTextTheme.subhead.decorationColor,
|
||||
// ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
|
||||
// child: Column(
|
||||
// children: <Widget>[
|
||||
// CupertinoNavigationBar(
|
||||
// leading: widget.leading,
|
||||
// middle: widget.middle,
|
||||
// backgroundColor: Colors.transparent,
|
||||
// border: null,
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.all(24),
|
||||
// alignment: Alignment.topLeft,
|
||||
// child: SingleChildScrollView(
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: <Widget>[
|
||||
// Text(
|
||||
// S.of(context).restore_active_seed,
|
||||
// style: TextStyle(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// color: Theme.of(context)
|
||||
// .textTheme
|
||||
// .overline
|
||||
// .backgroundColor),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.only(top: 5),
|
||||
// child: Wrap(
|
||||
// children: items.map((item) {
|
||||
// final isValid =
|
||||
// widget.validator.isValid(item);
|
||||
// final isSelected = selectedItem == item;
|
||||
//
|
||||
// return InkWell(
|
||||
// onTap: () => onMnemonicTap(item),
|
||||
// child: Container(
|
||||
// decoration: BoxDecoration(
|
||||
// color: isValid
|
||||
// ? Colors.transparent
|
||||
// : Palette.red),
|
||||
// margin: EdgeInsets.only(
|
||||
// right: 7, bottom: 8),
|
||||
// child: Text(
|
||||
// item.toString(),
|
||||
// style: TextStyle(
|
||||
// color: isValid
|
||||
// ? Colors.white
|
||||
// : Colors.grey,
|
||||
// fontSize: 16,
|
||||
// fontWeight: isSelected
|
||||
// ? FontWeight.w900
|
||||
// : FontWeight.w600,
|
||||
// decoration: isSelected
|
||||
// ? TextDecoration.underline
|
||||
// : TextDecoration.none),
|
||||
// )),
|
||||
// );
|
||||
// }).toList(),
|
||||
// ))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ))
|
||||
// ],
|
||||
// )),
|
||||
// ),
|
||||
// Flexible(
|
||||
// fit: FlexFit.tight,
|
||||
// flex: 3,
|
||||
// child: Padding(
|
||||
// padding:
|
||||
// EdgeInsets.only(left: 24, top: 48, right: 24, bottom: 24),
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// children: <Widget>[
|
||||
// Text(
|
||||
// S.of(context).restore_new_seed,
|
||||
// style: TextStyle(
|
||||
// fontSize: 20,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// color:
|
||||
// Theme.of(context).primaryTextTheme.title.color),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.only(top: 24),
|
||||
// child: TextFormField(
|
||||
// key: _seedTextFieldKey,
|
||||
// onFieldSubmitted: (text) => isCurrentMnemonicValid
|
||||
// ? saveCurrentMnemonicToItems()
|
||||
// : null,
|
||||
// style: TextStyle(
|
||||
// fontSize: 16.0,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// color:
|
||||
// Theme.of(context).primaryTextTheme.title.color),
|
||||
// controller: _seedController,
|
||||
// textInputAction: TextInputAction.done,
|
||||
// decoration: InputDecoration(
|
||||
// suffixIcon: GestureDetector(
|
||||
// behavior: HitTestBehavior.opaque,
|
||||
// child: ConstrainedBox(
|
||||
// constraints: BoxConstraints(maxWidth: 145),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: <Widget>[
|
||||
// Text('${items.length}/$maxLength',
|
||||
// style: TextStyle(
|
||||
// color: Theme.of(context)
|
||||
// .accentTextTheme
|
||||
// .display2
|
||||
// .decorationColor,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// fontSize: 16)),
|
||||
// SizedBox(width: 10),
|
||||
// InkWell(
|
||||
// onTap: () async =>
|
||||
// Clipboard.getData('text/plain').then(
|
||||
// (clipboard) =>
|
||||
// replaceText(clipboard.text)),
|
||||
// child: Container(
|
||||
// height: 35,
|
||||
// padding: EdgeInsets.all(7),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Theme.of(context)
|
||||
// .accentTextTheme
|
||||
// .caption
|
||||
// .color,
|
||||
// borderRadius:
|
||||
// BorderRadius.circular(10.0)),
|
||||
// child: Text(
|
||||
// S.of(context).paste,
|
||||
// style: TextStyle(
|
||||
// color: Palette.blueCraiola),
|
||||
// )),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// hintStyle: TextStyle(
|
||||
// color: Theme.of(context)
|
||||
// .accentTextTheme
|
||||
// .display2
|
||||
// .decorationColor,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// fontSize: 16),
|
||||
// hintText:
|
||||
// S.of(context).restore_from_seed_placeholder,
|
||||
// errorText: _errorMessage,
|
||||
// focusedBorder: UnderlineInputBorder(
|
||||
// borderSide: BorderSide(
|
||||
// color: Theme.of(context)
|
||||
// .accentTextTheme
|
||||
// .subtitle
|
||||
// .backgroundColor,
|
||||
// width: 1.0)),
|
||||
// enabledBorder: UnderlineInputBorder(
|
||||
// borderSide: BorderSide(
|
||||
// color: Theme.of(context)
|
||||
// .accentTextTheme
|
||||
// .subtitle
|
||||
// .backgroundColor,
|
||||
// width: 1.0))),
|
||||
// enableInteractiveSelection: false,
|
||||
// ),
|
||||
// )
|
||||
// ]),
|
||||
// )),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Flexible(
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.only(right: 8),
|
||||
// child: PrimaryButton(
|
||||
// onPressed: clear,
|
||||
// text: S.of(context).clear,
|
||||
// color: Colors.orange,
|
||||
// textColor: Colors.white,
|
||||
// isDisabled: items.isEmpty,
|
||||
// ),
|
||||
// )),
|
||||
// Flexible(
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.only(left: 8),
|
||||
// child: (selectedItem == null && items.length == maxLength)
|
||||
// ? PrimaryButton(
|
||||
// text: S.of(context).restore_next,
|
||||
// isDisabled: !isSeedValid(),
|
||||
// onPressed: () => widget.onFinish != null
|
||||
// ? widget.onFinish()
|
||||
// : null,
|
||||
// color: Theme.of(context).accentTextTheme.body2.color,
|
||||
// textColor: Colors.white)
|
||||
// : PrimaryButton(
|
||||
// text: selectedItem != null
|
||||
// ? S.of(context).save
|
||||
// : S.of(context).add_new_word,
|
||||
// onPressed: () => isCurrentMnemonicValid
|
||||
// ? saveCurrentMnemonicToItems()
|
||||
// : null,
|
||||
// onDisabledPressed: () => showErrorIfExist(),
|
||||
// isDisabled: !isCurrentMnemonicValid,
|
||||
// color: Theme.of(context).accentTextTheme.body2.color,
|
||||
// textColor: Colors.white),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ))
|
||||
// ]),
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
|
54
lib/utils/date_picker.dart
Normal file
54
lib/utils/date_picker.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
import 'dart:io';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Future<DateTime> getDate({
|
||||
@required BuildContext context,
|
||||
@required DateTime initialDate,
|
||||
@required DateTime firstDate,
|
||||
@required DateTime lastDate}) {
|
||||
|
||||
if (Platform.isIOS) {
|
||||
return _buildCupertinoDataPicker(context, initialDate, firstDate, lastDate);
|
||||
}
|
||||
|
||||
return _buildMaterialDataPicker(context, initialDate, firstDate, lastDate);
|
||||
}
|
||||
|
||||
Future<DateTime> _buildMaterialDataPicker(
|
||||
BuildContext context,
|
||||
DateTime initialDate,
|
||||
DateTime firstDate,
|
||||
DateTime lastDate) async {
|
||||
return await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
helpText: '');
|
||||
}
|
||||
|
||||
Future<DateTime> _buildCupertinoDataPicker(
|
||||
BuildContext context,
|
||||
DateTime initialDate,
|
||||
DateTime firstDate,
|
||||
DateTime lastDate) async {
|
||||
DateTime date;
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height / 3,
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.date,
|
||||
onDateTimeChanged: (picked) => date = picked,
|
||||
initialDateTime: initialDate,
|
||||
minimumDate: firstDate,
|
||||
maximumDate: lastDate,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
return date;
|
||||
}
|
|
@ -27,10 +27,10 @@ class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
|
|||
|
||||
abstract class ExchangeViewModelBase with Store {
|
||||
ExchangeViewModelBase(
|
||||
{this.wallet,
|
||||
this.wallet,
|
||||
this.trades,
|
||||
this.exchangeTemplateStore,
|
||||
this.tradesStore}) {
|
||||
this._exchangeTemplateStore,
|
||||
this.tradesStore) {
|
||||
providerList = [
|
||||
XMRTOExchangeProvider(),
|
||||
ChangeNowExchangeProvider(),
|
||||
|
@ -54,7 +54,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
final WalletBase wallet;
|
||||
final Box<Trade> trades;
|
||||
final ExchangeTemplateStore exchangeTemplateStore;
|
||||
final ExchangeTemplateStore _exchangeTemplateStore;
|
||||
final TradesStore tradesStore;
|
||||
|
||||
@observable
|
||||
|
@ -101,7 +101,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
ObservableList<ExchangeTemplate> get templates =>
|
||||
exchangeTemplateStore.templates;
|
||||
_exchangeTemplateStore.templates;
|
||||
|
||||
@action
|
||||
void changeProvider({ExchangeProvider provider}) {
|
||||
|
@ -267,6 +267,22 @@ abstract class ExchangeViewModelBase with Store {
|
|||
_onPairChange();
|
||||
}
|
||||
|
||||
void updateTemplate() => _exchangeTemplateStore.update();
|
||||
|
||||
void addTemplate({String amount, String depositCurrency, String receiveCurrency,
|
||||
String provider, String depositAddress, String receiveAddress}) =>
|
||||
_exchangeTemplateStore.addTemplate(
|
||||
amount: amount,
|
||||
depositCurrency: depositCurrency,
|
||||
receiveCurrency: receiveCurrency,
|
||||
provider: provider,
|
||||
depositAddress: depositAddress,
|
||||
receiveAddress: receiveAddress
|
||||
);
|
||||
|
||||
void removeTemplate({ExchangeTemplate template}) =>
|
||||
_exchangeTemplateStore.remove(template: template);
|
||||
|
||||
List<ExchangeProvider> providersForCurrentPair() {
|
||||
return _providersForPair(from: depositCurrency, to: receiveCurrency);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/template_validator.dart';
|
||||
|
@ -29,7 +31,8 @@ class SendViewModel = SendViewModelBase with _$SendViewModel;
|
|||
|
||||
abstract class SendViewModelBase with Store {
|
||||
SendViewModelBase(
|
||||
this._wallet, this._settingsStore, this._fiatConversationStore)
|
||||
this._wallet, this._settingsStore, this._sendTemplateStore,
|
||||
this._fiatConversationStore)
|
||||
: state = InitialExecutionState(),
|
||||
_cryptoNumberFormat = NumberFormat(),
|
||||
sendAll = false {
|
||||
|
@ -88,8 +91,12 @@ abstract class SendViewModelBase with Store {
|
|||
@computed
|
||||
bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
|
||||
|
||||
@computed
|
||||
ObservableList<Template> get templates => _sendTemplateStore.templates;
|
||||
|
||||
final WalletBase _wallet;
|
||||
final SettingsStore _settingsStore;
|
||||
final SendTemplateStore _sendTemplateStore;
|
||||
final FiatConversionStore _fiatConversationStore;
|
||||
final NumberFormat _cryptoNumberFormat;
|
||||
|
||||
|
@ -219,4 +226,17 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
_cryptoNumberFormat.maximumFractionDigits = maximumFractionDigits;
|
||||
}
|
||||
|
||||
void updateTemplate() => _sendTemplateStore.update();
|
||||
|
||||
void addTemplate({String name, String address, String cryptoCurrency,
|
||||
String amount}) => _sendTemplateStore
|
||||
.addTemplate(
|
||||
name: name,
|
||||
address: address,
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
amount: amount);
|
||||
|
||||
void removeTemplate({Template template}) =>
|
||||
_sendTemplateStore.remove(template: template);
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ abstract class SettingsViewModelBase with Store {
|
|||
RegularListItem(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.disclaimer),
|
||||
Navigator.of(context).pushNamed(Routes.readDisclaimer),
|
||||
),
|
||||
RegularListItem(
|
||||
title: S.current.faq,
|
||||
|
|
54
lib/view_model/wallet_restore_view_model.dart
Normal file
54
lib/view_model/wallet_restore_view_model.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_credentials.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
|
||||
part 'wallet_restore_view_model.g.dart';
|
||||
|
||||
enum WalletRestoreMode { seed, keys }
|
||||
|
||||
class WalletRestoreViewModel = WalletRestoreViewModelBase
|
||||
with _$WalletRestoreViewModel;
|
||||
|
||||
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
WalletRestoreViewModelBase(AppStore appStore, this._walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
{@required WalletType type})
|
||||
: super(appStore, walletInfoSource, type: type, isRecovery: true) {
|
||||
mode = WalletRestoreMode.seed;
|
||||
}
|
||||
|
||||
@observable
|
||||
WalletRestoreMode mode;
|
||||
|
||||
final WalletCreationService _walletCreationService;
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic options) {
|
||||
final password = generateWalletPassword(type);
|
||||
|
||||
// switch (type) {
|
||||
// case WalletType.monero:
|
||||
// return MoneroRestoreWalletFromSeedCredentials(
|
||||
// name: name, height: height, mnemonic: seed, password: password);
|
||||
// case WalletType.bitcoin:
|
||||
// return BitcoinRestoreWalletFromSeedCredentials(
|
||||
// name: name, mnemonic: seed, password: password);
|
||||
// default:
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<WalletBase> process(WalletCredentials credentials) async =>
|
||||
_walletCreationService.restoreFromSeed(credentials);
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Vorlage",
|
||||
"confirm_delete_template" : "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?",
|
||||
"confirm_delete_wallet" : "Diese Aktion löscht diese Brieftasche. Möchten Sie fortfahren?"
|
||||
"confirm_delete_wallet" : "Diese Aktion löscht diese Brieftasche. Möchten Sie fortfahren?",
|
||||
|
||||
"picker_description" : "Um ChangeNOW oder MorphToken zu wählen, ändern Sie bitte zuerst Ihr Handelspaar"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Template",
|
||||
"confirm_delete_template" : "This action will delete this template. Do you wish to continue?",
|
||||
"confirm_delete_wallet" : "This action will delete this wallet. Do you wish to continue?"
|
||||
"confirm_delete_wallet" : "This action will delete this wallet. Do you wish to continue?",
|
||||
|
||||
"picker_description" : "To choose ChangeNOW or MorphToken, please change your trading pair first"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Plantilla",
|
||||
"confirm_delete_template" : "Esta acción eliminará esta plantilla. ¿Desea continuar?",
|
||||
"confirm_delete_wallet" : "Esta acción eliminará esta billetera. ¿Desea continuar?"
|
||||
"confirm_delete_wallet" : "Esta acción eliminará esta billetera. ¿Desea continuar?",
|
||||
|
||||
"picker_description" : "Para elegir ChangeNOW o MorphToken, primero cambie su par comercial"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "खाका",
|
||||
"confirm_delete_template" : "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
|
||||
"confirm_delete_wallet" : "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?"
|
||||
"confirm_delete_wallet" : "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
|
||||
|
||||
"picker_description" : "ChangeNOW या MorphToken चुनने के लिए, कृपया अपनी ट्रेडिंग जोड़ी को पहले बदलें"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "テンプレート",
|
||||
"confirm_delete_template" : "この操作により、このテンプレートが削除されます。 続行しますか?",
|
||||
"confirm_delete_wallet" : "このアクションにより、このウォレットが削除されます。 続行しますか?"
|
||||
"confirm_delete_wallet" : "このアクションにより、このウォレットが削除されます。 続行しますか?",
|
||||
|
||||
"picker_description" : "ChangeNOWまたはMorphTokenを選択するには、最初にトレーディングペアを変更してください"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "주형",
|
||||
"confirm_delete_template" : "이 작업은이 템플릿을 삭제합니다. 계속 하시겠습니까?",
|
||||
"confirm_delete_wallet" : "이 작업은이 지갑을 삭제합니다. 계속 하시겠습니까?"
|
||||
"confirm_delete_wallet" : "이 작업은이 지갑을 삭제합니다. 계속 하시겠습니까?",
|
||||
|
||||
"picker_description" : "ChangeNOW 또는 MorphToken을 선택하려면 먼저 거래 쌍을 변경하십시오."
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Sjabloon",
|
||||
"confirm_delete_template" : "Met deze actie wordt deze sjabloon verwijderd. Wilt u doorgaan?",
|
||||
"confirm_delete_wallet" : "Met deze actie wordt deze portemonnee verwijderd. Wilt u doorgaan?"
|
||||
"confirm_delete_wallet" : "Met deze actie wordt deze portemonnee verwijderd. Wilt u doorgaan?",
|
||||
|
||||
"picker_description" : "Om ChangeNOW of MorphToken te kiezen, moet u eerst uw handelspaar wijzigen"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Szablon",
|
||||
"confirm_delete_template" : "Ta czynność usunie ten szablon. Czy chcesz kontynuować?",
|
||||
"confirm_delete_wallet" : "Ta czynność usunie ten portfel. Czy chcesz kontynuować?"
|
||||
"confirm_delete_wallet" : "Ta czynność usunie ten portfel. Czy chcesz kontynuować?",
|
||||
|
||||
"picker_description" : "Aby wybrać ChangeNOW lub MorphToken, najpierw zmień swoją parę handlową"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Modelo",
|
||||
"confirm_delete_template" : "Esta ação excluirá este modelo. Você deseja continuar?",
|
||||
"confirm_delete_wallet" : "Esta ação excluirá esta carteira. Você deseja continuar?"
|
||||
"confirm_delete_wallet" : "Esta ação excluirá esta carteira. Você deseja continuar?",
|
||||
|
||||
"picker_description" : "Para escolher ChangeNOW ou MorphToken, altere primeiro o seu par de negociação"
|
||||
}
|
||||
|
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Шаблон",
|
||||
"confirm_delete_template" : "Это действие удалит шаблон. Вы хотите продолжить?",
|
||||
"confirm_delete_wallet" : "Это действие удалит кошелек. Вы хотите продолжить?"
|
||||
"confirm_delete_wallet" : "Это действие удалит кошелек. Вы хотите продолжить?",
|
||||
|
||||
"picker_description" : "Чтобы выбрать ChangeNOW или MorphToken, сначала смените пару для обмена"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "Шаблон",
|
||||
"confirm_delete_template" : "Ця дія видалить шаблон. Ви хочете продовжити?",
|
||||
"confirm_delete_wallet" : "Ця дія видалить гаманець. Ви хочете продовжити?"
|
||||
"confirm_delete_wallet" : "Ця дія видалить гаманець. Ви хочете продовжити?",
|
||||
|
||||
"picker_description" : "Щоб вибрати ChangeNOW або MorphToken, спочатку змініть пару для обміну"
|
||||
}
|
|
@ -389,5 +389,7 @@
|
|||
|
||||
"template" : "模板",
|
||||
"confirm_delete_template" : "此操作將刪除此模板。 你想繼續嗎?",
|
||||
"confirm_delete_wallet" : "此操作將刪除此錢包。 你想繼續嗎?"
|
||||
"confirm_delete_wallet" : "此操作將刪除此錢包。 你想繼續嗎?",
|
||||
|
||||
"picker_description" : "要選擇ChangeNOW或MorphToken,請先更改您的交易對"
|
||||
}
|
Loading…
Reference in a new issue