Merge branch '4.0.8' of github.com:cake-tech/cake_wallet_private into btc

This commit is contained in:
M 2020-11-17 14:33:35 +02:00
commit c5b739d36a
32 changed files with 364 additions and 195 deletions

View file

@ -1,5 +1,5 @@
# Cake Wallet
The project description, motivation, build scripts, instructions, tests will be added soon (Spring 2020);
The project description, motivation, build scripts, instructions, tests will be added soon (Spring 202X);
Copyright (c) 2020 Cake Technologies LLC.

View file

@ -6,6 +6,8 @@
<application
android:label="Cake Wallet"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

View file

@ -1,6 +1,15 @@
package com.cakewallet.cake_wallet;
import io.flutter.embedding.android.FlutterActivity;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterFragmentActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
public class MainActivity extends FlutterFragmentActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

View file

@ -1,6 +1,13 @@
package com.cakewallet.cake_wallet
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine){
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

View file

@ -371,7 +371,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.3;
MARKETING_VERSION = 4.0.8;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -511,7 +511,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.3;
MARKETING_VERSION = 4.0.8;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -545,7 +545,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.3;
MARKETING_VERSION = 4.0.8;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View file

@ -2,12 +2,14 @@ import 'package:cake_wallet/bitcoin/bitcoin_wallet_service.dart';
import 'package:cake_wallet/core/wallet_service.dart';
import 'package:cake_wallet/entities/biometric_auth.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/load_current_wallet.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/monero/monero_wallet_service.dart';
import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/node.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
@ -200,6 +202,12 @@ Future setup(
}
authPageState.changeProcessText('Loading the wallet');
if (loginError != null) {
authPageState
.changeProcessText('ERROR: ${loginError.toString()}');
}
ReactionDisposer _reaction;
_reaction = reaction((_) => appStore.wallet, (Object _) {
_reaction?.reaction?.dispose();

View file

@ -19,3 +19,10 @@ Future<String> pathForWalletDir({@required String name, @required WalletType ty
Future<String> pathForWallet({@required String name, @required WalletType type}) async =>
await pathForWalletDir(name: name, type: type)
.then((path) => path + '/$name');
Future<String> outdatedAndroidPathForWalletDir({String name}) async {
final directory = await getApplicationDocumentsDirectory();
final pathDir = directory.path + '/$name';
return pathDir;
}

View file

@ -82,37 +82,32 @@ final dates = {
"2020-8": 2153983,
"2020-9": 2176466,
"2020-10": 2198453,
"2020-11": 2221803
"2020-11": 2220000
};
final heightCoefficient = 0.7;
int getHeigthByDate({DateTime date}) {
final raw = '${date.year}' + '-' + '${date.month}';
var endHeight = dates[raw] ?? 0;
int preLastYear = date.year;
int preLastMonth = date.month - 1;
final lastHeight = dates.values.last;
int startHeight;
int endHeight;
int height;
if (endHeight <= 0) {
if ((dates[raw] == null)||(dates[raw] == lastHeight)) {
startHeight = dates.values.toList()[dates.length - 2];
endHeight = dates.values.toList()[dates.length - 1];
final preLastDate =
dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
preLastYear = preLastDate.year;
preLastMonth = preLastDate.month;
final heightPerDay = (endHeight - startHeight) / 31;
final daysHeight = (heightCoefficient * (date.day - 1) * heightPerDay).round();
height = endHeight + daysHeight;
} else {
preLastYear = date.year;
preLastMonth = date.month - 1;
startHeight = dates[raw];
final index = dates.values.toList().indexOf(startHeight);
endHeight = dates.values.toList()[index + 1];
final heightPerDay = ((endHeight - startHeight) / 31).round();
final daysHeight = (date.day - 1) * heightPerDay;
height = startHeight + daysHeight - heightPerDay;
}
if (preLastMonth <= 0) {
preLastMonth = 12;
preLastYear -= 1;
}
final startRaw = '$preLastYear' + '-' + '$preLastMonth';
final startHeight = dates[startRaw];
final diff = endHeight - startHeight;
final heightPerDay = diff / 30;
final daysHeight = date.day * heightPerDay.round();
final height = endHeight + daysHeight;
return height;
}

View file

@ -20,7 +20,7 @@ abstract class MoneroAccountListBase with Store {
bool _isRefreshing;
bool _isUpdating;
Future update() async {
void update() async {
if (_isUpdating) {
return;
}

View file

@ -121,8 +121,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
_onAccountChangeReaction?.reaction?.dispose();
}
Future<bool> validate() async {
await accountList.update();
bool validate() {
accountList.update();
final accountListLength = accountList.accounts?.length ?? 0;
if (accountListLength <= 0) {

View file

@ -27,7 +27,7 @@ class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials {
class MoneroWalletLoadingException implements Exception {
@override
String toString() => 'The wallet is damaged.';
String toString() => 'Failure to load the wallet.';
}
class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
@ -93,6 +93,11 @@ class MoneroWalletService extends WalletService<
Future<MoneroWallet> openWallet(String name, String password) async {
try {
final path = await pathForWallet(name: name, type: WalletType.monero);
if (!File(path).existsSync()) {
await repairOldAndroidWallet(name);
}
await monero_wallet_manager
.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhere(
@ -100,18 +105,18 @@ class MoneroWalletService extends WalletService<
orElse: () => null);
final wallet = MoneroWallet(
filename: monero_wallet.getFilename(), walletInfo: walletInfo);
final isValid = await wallet.validate();
final isValid = wallet.validate();
if (!isValid) {
if (wallet.seed?.isNotEmpty ?? false) {
// if (wallet.seed?.isNotEmpty ?? false) {
// let restore from seed in this case;
final seed = wallet.seed;
final credentials = MoneroRestoreWalletFromSeedCredentials(
name: name, password: password, mnemonic: seed, height: 2000000)
..walletInfo = walletInfo;
await remove(name);
return restoreFromSeed(credentials);
}
// final seed = wallet.seed;
// final credentials = MoneroRestoreWalletFromSeedCredentials(
// name: name, password: password, mnemonic: seed, height: 2000000)
// ..walletInfo = walletInfo;
// await remove(name);
// return restoreFromSeed(credentials);
// }
throw MoneroWalletLoadingException();
}
@ -187,4 +192,38 @@ class MoneroWalletService extends WalletService<
rethrow;
}
}
Future<void> repairOldAndroidWallet(String name) async {
try {
if (!Platform.isAndroid) {
return;
}
final oldAndroidWalletDirPath =
await outdatedAndroidPathForWalletDir(name: name);
final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) {
throw MoneroWalletLoadingException();
}
final newWalletDirPath =
await pathForWalletDir(name: name, type: WalletType.monero);
dir.listSync().forEach((f) {
final file = File(f.path);
final name = f.path.split('/').last;
final newPath = newWalletDirPath + '/$name';
final newFile = File(newPath);
print(file.path);
if (!newFile.existsSync()) {
newFile.createSync();
}
newFile.writeAsBytesSync(file.readAsBytesSync());
});
} catch (e) {
print(e.toString());
throw MoneroWalletLoadingException();
}
}
}

View file

@ -5,6 +5,14 @@ import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/core/amount_converter.dart';
import 'package:cake_wallet/core/pending_transaction.dart';
class DoubleSpendException implements Exception {
DoubleSpendException();
@override
String toString() =>
'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough XMR in your available balance, or previous transactions are not yet fully processed.';
}
class PendingMoneroTransaction with PendingTransaction {
PendingMoneroTransaction(this.pendingTransactionDescription);
@ -22,7 +30,18 @@ class PendingMoneroTransaction with PendingTransaction {
CryptoCurrency.xmr, pendingTransactionDescription.fee);
@override
Future<void> commit() async =>
Future<void> commit() async {
try {
monero_transaction_history.commitTransactionFromPointerAddress(
address: pendingTransactionDescription.pointerAddress);
} catch (e) {
final message = e.toString();
if (message.contains('Reason: double spend')) {
throw DoubleSpendException();
}
rethrow;
}
}
}

View file

@ -7,13 +7,19 @@ import 'package:cake_wallet/store/authentication_store.dart';
ReactionDisposer _onAuthenticationStateChange;
dynamic loginError;
void startAuthenticationStateChange(AuthenticationStore authenticationStore,
@required GlobalKey<NavigatorState> navigatorKey) {
_onAuthenticationStateChange ??= autorun((_) async {
final state = authenticationStore.state;
if (state == AuthenticationState.installed) {
try {
await loadCurrentWallet();
} catch(e) {
loginError = e;
}
return;
}

View file

@ -13,6 +13,6 @@ void startCurrentFiatChangeReaction(AppStore appStore, SettingsStore settingsSto
(_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
final cryptoCurrency = appStore.wallet.currency;
fiatConversionStore.price = await FiatConversionService.fetchPrice(
cryptoCurrency, settingsStore.fiatCurrency);
cryptoCurrency, fiatCurrency);
});
}

View file

@ -40,13 +40,14 @@ class AuthPageState extends State<AuthPage> {
reaction((_) => widget.authViewModel.state, (ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_authBar?.dismiss();
if (widget.onAuthenticationFinished != null) {
widget.onAuthenticationFinished(true, this);
} else {
_authBar?.dismiss();
showBar<void>(context, S.of(context).authenticated);
}
});
setState(() {});
}
if (state is IsExecutingState) {

View file

@ -48,14 +48,15 @@ abstract class BasePage extends StatelessWidget {
return null;
}
final _backButton = Image.asset('assets/images/back_arrow.png',
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color);
final _backButton = Icon(Icons.arrow_back_ios,
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color,
size: 16,);
final _closeButton =
isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage;
return SizedBox(
height: 37,
width: isModalBackButton ? 37 : 20,
width: 37,
child: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@ -15,9 +16,10 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_h
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
class ReceivePage extends BasePage {
ReceivePage({this.addressListViewModel});
ReceivePage({this.addressListViewModel}) : _cryptoAmountFocus = FocusNode();
final WalletAddressListViewModel addressListViewModel;
@ -33,6 +35,8 @@ class ReceivePage extends BasePage {
@override
Color get titleColor => Colors.white;
final FocusNode _cryptoAmountFocus;
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) => Container(
@ -67,7 +71,20 @@ class ReceivePage extends BasePage {
@override
Widget body(BuildContext context) {
return SingleChildScrollView(
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
nextFocus: false,
actions: [
KeyboardActionsItem(
focusNode: _cryptoAmountFocus,
toolbarButtons: [(_) => KeyboardDoneButton()],
)
]),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
@ -75,7 +92,7 @@ class ReceivePage extends BasePage {
child: QRWidget(
addressListViewModel: addressListViewModel,
isAmountFieldShow: true,
),
amountTextFieldFocusNode: _cryptoAmountFocus),
),
Observer(
builder: (_) => ListView.separated(
@ -99,7 +116,8 @@ class ReceivePage extends BasePage {
icon: Icon(
Icons.arrow_forward_ios,
size: 14,
color: Theme.of(context).textTheme.display1.color,
color:
Theme.of(context).textTheme.display1.color,
));
}
@ -111,7 +129,8 @@ class ReceivePage extends BasePage {
icon: Icon(
Icons.add,
size: 20,
color: Theme.of(context).textTheme.display1.color,
color:
Theme.of(context).textTheme.display1.color,
));
}
@ -136,7 +155,8 @@ class ReceivePage extends BasePage {
isCurrent: isCurrent,
backgroundColor: backgroundColor,
textColor: textColor,
onTap: (_) => addressListViewModel.setAddress(item),
onTap: (_) =>
addressListViewModel.setAddress(item),
onEdit: () => Navigator.of(context).pushNamed(
Routes.newSubaddress,
arguments: item));
@ -154,6 +174,6 @@ class ReceivePage extends BasePage {
})),
],
),
);
));
}
}

View file

@ -11,7 +11,9 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_v
class QRWidget extends StatelessWidget {
QRWidget(
{@required this.addressListViewModel, this.isAmountFieldShow = false})
{@required this.addressListViewModel,
this.isAmountFieldShow = false,
this.amountTextFieldFocusNode})
: amountController = TextEditingController(),
_formKey = GlobalKey<FormState>() {
amountController.addListener(() => addressListViewModel.amount =
@ -21,6 +23,7 @@ class QRWidget extends StatelessWidget {
final WalletAddressListViewModel addressListViewModel;
final bool isAmountFieldShow;
final TextEditingController amountController;
final FocusNode amountTextFieldFocusNode;
final GlobalKey<FormState> _formKey;
@override
@ -68,6 +71,7 @@ class QRWidget extends StatelessWidget {
child: Form(
key: _formKey,
child: BaseTextFormField(
focusNode: amountTextFieldFocusNode,
controller: amountController,
keyboardType: TextInputType.numberWithOptions(
decimal: true),

View file

@ -21,23 +21,9 @@ class RescanPage extends BasePage {
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
child:
Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Column(
children: <Widget>[
BlockchainHeightWidget(key: _blockchainHeightWidgetKey),
Padding(
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
child: Text(
S.of(context).restore_from_date_or_blockheight,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context).hintColor
),
),
)
],
),
BlockchainHeightWidget(key: _blockchainHeightWidgetKey,
onHeightOrDateEntered: (value) =>
_rescanViewModel.isButtonEnabled = value),
Observer(
builder: (_) => LoadingPrimaryButton(
isLoading:
@ -51,6 +37,7 @@ class RescanPage extends BasePage {
},
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isDisabled: !_rescanViewModel.isButtonEnabled,
))
]),
);

View file

@ -6,7 +6,10 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class WalletRestoreFromKeysFrom extends StatefulWidget {
WalletRestoreFromKeysFrom({Key key}) : super(key: key);
WalletRestoreFromKeysFrom({Key key, this.onHeightOrDateEntered})
: super(key: key);
final Function (bool) onHeightOrDateEntered;
@override
WalletRestoreFromKeysFromState createState() =>
@ -63,7 +66,9 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
hintText: S.of(context).restore_spend_key_private,
maxLines: null)),
BlockchainHeightWidget(
key: blockchainHeightKey, onHeightChange: (_) => null)
key: blockchainHeightKey,
onHeightChange: (_) => null,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
]),
));
}

View file

@ -7,10 +7,12 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
class WalletRestoreFromSeedForm extends StatefulWidget {
WalletRestoreFromSeedForm({Key key, this.blockHeightFocusNode})
WalletRestoreFromSeedForm({Key key, this.blockHeightFocusNode,
this.onHeightOrDateEntered})
: super(key: key);
final FocusNode blockHeightFocusNode;
final Function (bool) onHeightOrDateEntered;
@override
WalletRestoreFromSeedFormState createState() =>
@ -63,7 +65,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
readOnly: true)))),
BlockchainHeightWidget(
focusNode: widget.blockHeightFocusNode,
key: blockchainHeightKey)
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
]));
}

View file

@ -28,8 +28,12 @@ class WalletRestorePage extends BasePage {
_pages.addAll([
WalletRestoreFromSeedForm(
key: walletRestoreFromSeedFormKey,
blockHeightFocusNode: _blockHeightFocusNode),
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey)
blockHeightFocusNode: _blockHeightFocusNode,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value),
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value)
]);
}
@ -72,6 +76,21 @@ class WalletRestorePage extends BasePage {
}
});
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode)
{
walletRestoreViewModel.isButtonEnabled = false;
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
});
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Expanded(
child: PageView.builder(
@ -113,7 +132,8 @@ class WalletRestorePage extends BasePage {
.accentTextTheme
.headline
.decorationColor,
isLoading: walletRestoreViewModel.state is IsExecutingState);
isLoading: walletRestoreViewModel.state is IsExecutingState,
isDisabled: !walletRestoreViewModel.isButtonEnabled,);
},
))
]);

View file

@ -6,10 +6,12 @@ import 'package:cake_wallet/monero/get_height_by_date.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class BlockchainHeightWidget extends StatefulWidget {
BlockchainHeightWidget({GlobalKey key, this.onHeightChange, this.focusNode})
BlockchainHeightWidget({GlobalKey key, this.onHeightChange, this.focusNode,
this.onHeightOrDateEntered})
: super(key: key);
final Function(int) onHeightChange;
final Function(bool) onHeightOrDateEntered;
final FocusNode focusNode;
@override
@ -26,6 +28,13 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
@override
void initState() {
restoreHeightController.addListener(() {
if (restoreHeightController.text.isNotEmpty) {
widget.onHeightOrDateEntered?.call(true);
}
else {
widget.onHeightOrDateEntered?.call(false);
dateController.text = '';
}
try {
_changeHeight(restoreHeightController.text != null &&
restoreHeightController.text.isNotEmpty
@ -83,6 +92,18 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
))
],
),
Padding(
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
child: Text(
S.of(context).restore_from_date_or_blockheight,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context).hintColor
),
),
)
],
);
}
@ -92,7 +113,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
final date = await getDate(
context: context,
initialDate: now.subtract(Duration(days: 1)),
firstDate: DateTime(2014, DateTime.april),
firstDate: DateTime(2014, DateTime.may),
lastDate: now);
if (date != null) {

View file

@ -77,7 +77,7 @@ class SeedWidgetState extends State<SeedWidget> {
fontSize: 16.0, color: Theme.of(context).hintColor))),
Padding(
padding: EdgeInsets.only(right: 40, top: 10),
child: ValidableAnnotatedEditableText(
child: ValidatableAnnotatedEditableText(
cursorColor: Colors.blue,
backgroundCursorColor: Colors.blue,
validStyle: TextStyle(

View file

@ -22,8 +22,8 @@ class TextAnnotation extends Comparable<TextAnnotation> {
int compareTo(TextAnnotation other) => text.compareTo(other.text);
}
class ValidableAnnotatedEditableText extends EditableText {
ValidableAnnotatedEditableText({
class ValidatableAnnotatedEditableText extends EditableText {
ValidatableAnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
@ -49,7 +49,7 @@ class ValidableAnnotatedEditableText extends EditableText {
controller: controller,
cursorColor: cursorColor,
style: validStyle,
keyboardType: TextInputType.text,
keyboardType: TextInputType.visiblePassword,
autocorrect: false,
autofocus: false,
selectionColor: selectionColor,
@ -73,14 +73,14 @@ class ValidableAnnotatedEditableText extends EditableText {
final TextStyle invalidStyle;
@override
ValidableAnnotatedEditableTextState createState() =>
ValidableAnnotatedEditableTextState();
ValidatableAnnotatedEditableTextState createState() =>
ValidatableAnnotatedEditableTextState();
}
class ValidableAnnotatedEditableTextState extends EditableTextState {
class ValidatableAnnotatedEditableTextState extends EditableTextState {
@override
ValidableAnnotatedEditableText get widget =>
super.widget as ValidableAnnotatedEditableText;
ValidatableAnnotatedEditableText get widget =>
super.widget as ValidatableAnnotatedEditableText;
List<Annotation> getRanges() {
final result = List<Annotation>();

View file

@ -110,6 +110,8 @@ abstract class AuthViewModelBase with Store {
if (isAuthenticated) {
state = ExecutedSuccessfullyState();
} else {
state = FailureState('Failure biometric authentication');
}
}
} catch(e) {

View file

@ -78,9 +78,8 @@ abstract class DashboardViewModelBase with Store {
.transactionHistory.transactions.values
.map((transaction) => TransactionListItem(
transaction: transaction,
price: price,
fiatCurrency: appStore.settingsStore.fiatCurrency,
displayMode: balanceDisplayMode)));
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
_reaction = reaction((_) => appStore.wallet, _onWalletChange);
// FIXME: fixme
@ -89,9 +88,8 @@ abstract class DashboardViewModelBase with Store {
transactions,
(TransactionInfo val) => TransactionListItem(
transaction: val,
price: price,
fiatCurrency: appStore.settingsStore.fiatCurrency,
displayMode: balanceDisplayMode));
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore));
final _wallet = wallet;
@ -185,8 +183,7 @@ abstract class DashboardViewModelBase with Store {
transactions.addAll(wallet.transactionHistory.transactions.values.map(
(transaction) => TransactionListItem(
transaction: transaction,
price: price,
fiatCurrency: appStore.settingsStore.fiatCurrency,
displayMode: balanceDisplayMode)));
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
}
}

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/mobx.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
@ -8,15 +9,21 @@ import 'package:cake_wallet/monero/monero_transaction_info.dart';
import 'package:cake_wallet/monero/monero_amount_format.dart';
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
class TransactionListItem extends ActionListItem with Keyable {
TransactionListItem(
{this.transaction, this.price, this.fiatCurrency, this.displayMode});
{this.transaction, this.balanceViewModel, this.settingsStore});
final TransactionInfo transaction;
final double price;
final FiatCurrency fiatCurrency;
final BalanceDisplayMode displayMode;
final BalanceViewModel balanceViewModel;
final SettingsStore settingsStore;
double get price => balanceViewModel.price;
FiatCurrency get fiatCurrency => settingsStore.fiatCurrency;
BalanceDisplayMode get displayMode => settingsStore.balanceDisplayMode;
@override
dynamic get keyIndex => transaction.id;

View file

@ -10,12 +10,16 @@ enum RescanWalletState { rescaning, none }
abstract class RescanViewModelBase with Store {
RescanViewModelBase(this._wallet) {
state = RescanWalletState.none;
isButtonEnabled = false;
}
@observable
RescanWalletState state;
final WalletBase _wallet;
@observable
bool isButtonEnabled;
@action
Future<void> rescanCurrentWallet({int restoreHeight}) async {
state = RescanWalletState.rescaning;

View file

@ -23,6 +23,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
Box<WalletInfo> walletInfoSource,
{@required WalletType type})
: super(appStore, walletInfoSource, type: type, isRecovery: true) {
isButtonEnabled = false;
mode = WalletRestoreMode.seed;
_walletCreationService.changeWalletType(type: WalletType.monero);
}
@ -30,6 +31,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
@observable
WalletRestoreMode mode;
@observable
bool isButtonEnabled;
final WalletCreationService _walletCreationService;
@override

View file

@ -401,10 +401,10 @@ packages:
description:
path: "."
ref: cake
resolved-ref: a734c2ea3239f9153dba6f5bec740e1df54ee754
resolved-ref: d4d68a9c1e4c45eb236cd7a5a2fac84c394a7605
url: "https://github.com/cake-tech/flutter_secure_storage.git"
source: git
version: "3.3.55"
version: "3.3.57"
flutter_slidable:
dependency: "direct main"
description:
@ -498,7 +498,7 @@ packages:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.18"
version: "2.1.19"
intl:
dependency: "direct main"
description:
@ -1000,7 +1000,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.3"
version: "1.7.4"
xdg_directories:
dependency: transitive
description:

View file

@ -11,7 +11,7 @@ description: Cake Wallet.
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 4.0.4+14
version: 4.0.8+20
environment:
sdk: ">=2.7.0 <3.0.0"
@ -31,6 +31,7 @@ dependencies:
git:
url: https://github.com/cake-tech/flutter_secure_storage.git
ref: cake
version: 3.3.57
provider: ^3.1.0
rxdart: ^0.22.2
yaml: ^2.1.16