Merge redesign part 5.

This commit is contained in:
M 2020-09-10 17:51:59 +03:00
commit 6e6a081685
38 changed files with 1805 additions and 964 deletions

View file

@ -1,4 +1,2 @@
- -
uri: electrum2.hodlister.co:50002 uri: electrumx.cakewallet.com:50002
-
uri: bitcoin.electrumx.multicoin.co:50002

View file

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSFaceIDUsageDescription</key>
<string>Enable Face ID for fast and secure access to wallets and private keys</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@ -23,7 +25,7 @@
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Cake Wallet requires access to your phones camera.</string> <string>Used for scan QR code</string>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>

View file

@ -204,6 +204,10 @@ Future setup(
getIt.registerFactory<AuthPage>( getIt.registerFactory<AuthPage>(
() => AuthPage( () => AuthPage(
allowBiometricalAuthentication: getIt
.get<AppStore>()
.settingsStore
.allowBiometricalAuthentication,
authViewModel: getIt.get<AuthViewModel>(), authViewModel: getIt.get<AuthViewModel>(),
onAuthenticationFinished: (isAuthenticated, __) { onAuthenticationFinished: (isAuthenticated, __) {
if (isAuthenticated) { if (isAuthenticated) {
@ -215,10 +219,18 @@ Future setup(
getIt getIt
.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), void>( .registerFactoryParam<AuthPage, void Function(bool, AuthPageState), void>(
(onAuthFinished, _) => AuthPage( (onAuthFinished, _) {
authViewModel: getIt.get<AuthViewModel>(), final allowBiometricalAuthentication =
onAuthenticationFinished: onAuthFinished, getIt.get<AppStore>().settingsStore.allowBiometricalAuthentication;
closable: false));
print('allowBiometricalAuthentication $allowBiometricalAuthentication');
return AuthPage(
allowBiometricalAuthentication: allowBiometricalAuthentication,
authViewModel: getIt.get<AuthViewModel>(),
onAuthenticationFinished: onAuthFinished,
closable: false);
});
getIt.registerFactory<DashboardPage>(() => DashboardPage( getIt.registerFactory<DashboardPage>(() => DashboardPage(
walletViewModel: getIt.get<DashboardViewModel>(), walletViewModel: getIt.get<DashboardViewModel>(),
@ -313,8 +325,9 @@ Future setup(
getIt.get<ContactService>(), getIt.get<ContactService>(),
contactSource)); contactSource));
getIt.registerFactoryParam<ContactListPage, bool, void>((bool isEditable, _) => getIt.registerFactoryParam<ContactListPage, bool, void>(
ContactListPage(getIt.get<ContactListViewModel>(), isEditable: isEditable)); (bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(),
isEditable: isEditable));
getIt.registerFactoryParam<ContactPage, Contact, void>((Contact contact, _) => getIt.registerFactoryParam<ContactPage, Contact, void>((Contact contact, _) =>
ContactPage(getIt.get<ContactViewModel>(param1: contact))); ContactPage(getIt.get<ContactViewModel>(param1: contact)));

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/domain/monero/monero_transaction_creation_credentials.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_monero/wallet.dart'; import 'package:cw_monero/wallet.dart';
@ -18,7 +19,8 @@ import 'package:cake_wallet/src/domain/monero/subaddress.dart';
import 'package:cake_wallet/src/domain/common/node.dart'; import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/core/pending_transaction.dart'; import 'package:cake_wallet/core/pending_transaction.dart';
import 'package:cake_wallet/src/domain/common/transaction_priority.dart'; import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart' as cfa; import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart'
as cfa;
part 'monero_wallet.g.dart'; part 'monero_wallet.g.dart';
@ -137,16 +139,16 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
@override @override
Future<PendingTransaction> createTransaction(Object credentials) async { Future<PendingTransaction> createTransaction(Object credentials) async {
// final _credentials = credentials as MoneroTransactionCreationCredentials; final _credentials = credentials as MoneroTransactionCreationCredentials;
// final transactionDescription = await transaction_history.createTransaction( // final transactionDescription = await transaction_history.createTransaction(
// address: _credentials.address, // address: _credentials.address,
// paymentId: _credentials.paymentId, // paymentId: _credentials.paymentId,
// amount: _credentials.amount, // amount: _credentials.amount,
// priorityRaw: _credentials.priority.serialize(), // priorityRaw: _credentials.priority.serialize(),
// accountIndex: _account.value.id); // accountIndex: _account.value.id);
//
// return PendingTransaction.fromTransactionDescription( // return PendingTransaction.fromTransactionDescription(
// transactionDescription); // transactionDescription);
} }
@override @override

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:cake_wallet/monero/monero_wallet.dart'; import 'package:cake_wallet/monero/monero_wallet.dart';
import 'package:cake_wallet/core/wallet_credentials.dart'; import 'package:cake_wallet/core/wallet_credentials.dart';
import 'package:cake_wallet/core/wallet_service.dart'; import 'package:cake_wallet/core/wallet_service.dart';
@ -60,7 +62,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception fop wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); print('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
@ -72,7 +74,7 @@ class MoneroWalletService extends WalletService<
final path = await pathForWallet(name: name, type: WalletType.monero); final path = await pathForWallet(name: name, type: WalletType.monero);
return monero_wallet_manager.isWalletExist(path: path); return monero_wallet_manager.isWalletExist(path: path);
} catch (e) { } catch (e) {
// TODO: Implement Exception fop wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); print('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
@ -83,26 +85,21 @@ class MoneroWalletService extends WalletService<
try { try {
final path = await pathForWallet(name: name, type: WalletType.monero); final path = await pathForWallet(name: name, type: WalletType.monero);
monero_wallet_manager.openWallet(path: path, password: password); monero_wallet_manager.openWallet(path: path, password: password);
// final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
// final walletInfo = walletInfoSource.values
// .firstWhere((info) => info.id == id, orElse: () => null);
final wallet = MoneroWallet(filename: monero_wallet.getFilename()); final wallet = MoneroWallet(filename: monero_wallet.getFilename());
await wallet.init(); await wallet.init();
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception fop wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); print('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
Future<void> remove(String wallet) async { @override
// TODO: implement remove Future<void> remove(String wallet) async =>
throw UnimplementedError(); File(await pathForWalletDir(name: wallet, type: WalletType.bitcoin))
} .delete(recursive: true);
@override @override
Future<MoneroWallet> restoreFromKeys( Future<MoneroWallet> restoreFromKeys(
@ -125,7 +122,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception fop wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); print('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
@ -149,7 +146,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception fop wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); print('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }

View file

@ -90,6 +90,8 @@ class PaletteDark {
static const Color distantBlue = Color.fromRGBO(72, 85, 131, 1.0); static const Color distantBlue = Color.fromRGBO(72, 85, 131, 1.0);
static const Color moderateVioletBlue = Color.fromRGBO(62, 73, 113, 1.0); static const Color moderateVioletBlue = Color.fromRGBO(62, 73, 113, 1.0);
static const Color deepVioletBlue = Color.fromRGBO(52, 66, 104, 1.0); static const Color deepVioletBlue = Color.fromRGBO(52, 66, 104, 1.0);
static const Color lightPurpleBlue = Color.fromRGBO(120, 133, 170, 1.0);
static const Color indicatorVioletBlue = Color.fromRGBO(59, 72, 119, 1.0);
// FIXME: Rename. // FIXME: Rename.
static const Color eee = Color.fromRGBO(236, 239, 245, 1.0); static const Color eee = Color.fromRGBO(236, 239, 245, 1.0);

View file

@ -24,7 +24,8 @@ import 'package:cake_wallet/store/dashboard/fiat_convertation_store.dart';
// FIXME: move me // FIXME: move me
Future<void> loadCurrentWallet() async { Future<void> loadCurrentWallet() async {
final appStore = getIt.get<AppStore>(); final appStore = getIt.get<AppStore>();
final name = getIt.get<SharedPreferences>().getString('current_wallet_name'); final name = 'test';
getIt.get<SharedPreferences>().getString('current_wallet_name');
final typeRaw = final typeRaw =
getIt.get<SharedPreferences>().getInt('current_wallet_type') ?? 0; getIt.get<SharedPreferences>().getInt('current_wallet_type') ?? 0;
final type = deserializeFromInt(typeRaw); final type = deserializeFromInt(typeRaw);

View file

@ -3,22 +3,28 @@ import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
class BiometricAuth { class BiometricAuth {
final _localAuth = LocalAuthentication();
Future<bool> isAuthenticated() async { Future<bool> isAuthenticated() async {
final LocalAuthentication _localAuth = LocalAuthentication();
try { try {
return await _localAuth.authenticateWithBiometrics( return await _localAuth.authenticateWithBiometrics(
localizedReason: S.current.biometric_auth_reason, localizedReason: S.current.biometric_auth_reason,
useErrorDialogs: true, useErrorDialogs: true,
stickyAuth: false stickyAuth: false);
); } on PlatformException catch (e) {
} on PlatformException
catch(e) {
print(e); print(e);
} }
return false; return false;
} }
} Future<bool> canCheckBiometrics() async {
try {
return await _localAuth.canCheckBiometrics;
} on PlatformException catch (e) {
print(e);
}
return false;
}
}

View file

@ -0,0 +1,38 @@
// import 'package:hive/hive.dart';
// import 'package:mobx/mobx.dart';
// import 'package:cake_wallet/src/domain/common/contact.dart';
// import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
// part 'contact_model.g.dart';
// class ContactModel = ContactModelBase with _$ContactModel;
// abstract class ContactModelBase with Store {
// ContactModelBase(this._contacts, {Contact contact}) : _contact = contact {
// name = _contact?.name;
// address = _contact?.address;
// currency = _contact?.type;
// _contacts.watch(key: contact.key).listen((event) {
// });
// }
// @observable
// String name;
// @observable
// String address;
// @observable
// CryptoCurrency currency;
// // @computed
// // bool get isReady =>
// // (name?.isNotEmpty ?? false) &&
// // (currency?.toString()?.isNotEmpty ?? false) &&
// // (address?.isNotEmpty ?? false);
// final Box<ContactBase> _contacts;
// final Contact _contact;
// }

View file

@ -107,7 +107,7 @@ Future<void> changeMoneroCurrentNodeToDefault(
} }
Node getBitcoinDefaultElectrumServer({@required Box<Node> nodes}) { Node getBitcoinDefaultElectrumServer({@required Box<Node> nodes}) {
final uri = 'bitcoin.electrumx.multicoin.co:50002'; final uri = 'electrumx.cakewallet.com:50002';
return nodes.values return nodes.values
.firstWhere((Node node) => node.uri == uri, orElse: () => null) ?? .firstWhere((Node node) => node.uri == uri, orElse: () => null) ??

View file

@ -30,7 +30,7 @@ class Language with ChangeNotifier {
} }
static Future<String> localeDetection() async { static Future<String> localeDetection() async {
String locale = await Devicelocale.currentLocale; var locale = await Devicelocale.currentLocale;
locale = Intl.shortLocale(locale); locale = Intl.shortLocale(locale);
return languages.keys.contains(locale) ? locale : 'en'; return languages.keys.contains(locale) ? locale : 'en';

View file

@ -5,19 +5,20 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/auth_state.dart'; import 'package:cake_wallet/view_model/auth_state.dart';
import 'package:cake_wallet/view_model/auth_view_model.dart'; import 'package:cake_wallet/view_model/auth_view_model.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/src/domain/common/biometric_auth.dart'; import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
typedef OnAuthenticationFinished = void Function(bool, AuthPageState); typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
class AuthPage extends StatefulWidget { class AuthPage extends StatefulWidget {
AuthPage( AuthPage(
{this.onAuthenticationFinished, {@required this.allowBiometricalAuthentication,
this.onAuthenticationFinished,
this.authViewModel, this.authViewModel,
this.closable = true}); this.closable = true});
final AuthViewModel authViewModel; final AuthViewModel authViewModel;
final OnAuthenticationFinished onAuthenticationFinished; final OnAuthenticationFinished onAuthenticationFinished;
final bool allowBiometricalAuthentication;
final bool closable; final bool closable;
@override @override
@ -95,6 +96,27 @@ class AuthPageState extends State<AuthPage> {
}); });
} }
}); });
if (widget.allowBiometricalAuthentication) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
print('post');
await Future<void>.delayed(Duration(milliseconds: 100));
print('after timeout');
final biometricAuth = BiometricAuth();
final isAuth = await biometricAuth.isAuthenticated();
if (isAuth) {
widget.authViewModel.biometricAuth();
_key.currentState.showSnackBar(
SnackBar(
content: Text(S.of(context).authenticated),
backgroundColor: Colors.green,
),
);
}
});
}
super.initState(); super.initState();
} }
@ -111,27 +133,7 @@ class AuthPageState extends State<AuthPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// final authStore = Provider.of<AuthStore>(context); print('start');
// final settingsStore = Provider.of<SettingsStore>(context);
// if (settingsStore.allowBiometricalAuthentication) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// final biometricAuth = BiometricAuth();
// biometricAuth.isAuthenticated().then(
// (isAuth) {
// if (isAuth) {
// authStore.biometricAuth();
// _key.currentState.showSnackBar(
// SnackBar(
// content: Text(S.of(context).authenticated),
// backgroundColor: Colors.green,
// ),
// );
// }
// }
// );
// });
// }
return Scaffold( return Scaffold(
key: _key, key: _key,

View file

@ -1,4 +1,5 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -132,6 +133,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
_fileText, _fileText,
style: TextStyle( style: TextStyle(
fontSize: 12.0, fontSize: 12.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).primaryTextTheme.title.color color: Theme.of(context).primaryTextTheme.title.color
), ),
)) ))
@ -169,7 +171,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
xmrtoUrl, xmrtoUrl,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
color: Colors.blue, color: Palette.blueCraiola,
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
decoration: TextDecoration.underline), decoration: TextDecoration.underline),
@ -190,7 +192,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
changenowUrl, changenowUrl,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
color: Colors.blue, color: Palette.blueCraiola,
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
decoration: TextDecoration.underline), decoration: TextDecoration.underline),
@ -211,7 +213,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
morphUrl, morphUrl,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
color: Colors.blue, color: Palette.blueCraiola,
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
decoration: TextDecoration.underline), decoration: TextDecoration.underline),

View file

@ -1,4 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -27,93 +29,85 @@ class FaqFormState extends State<FaqForm> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final addIcon = Icon(Icons.add, color: Theme.of(context).primaryTextTheme.title.color); final addIcon = Icon(Icons.add, color: Theme.of(context).primaryTextTheme.title.color);
final removeIcon = Icon(Icons.remove, color: Colors.green); final removeIcon = Icon(Icons.remove, color: Palette.blueCraiola);
return Container( return Container(
padding: EdgeInsets.only(top: 12), padding: EdgeInsets.only(top: 12, left: 24),
child: Container( child: FutureBuilder(
color: Theme.of(context).accentTextTheme.headline.color, builder: (context, snapshot) {
child: FutureBuilder( final faqItems = jsonDecode(snapshot.data.toString()) as List;
builder: (context, snapshot) {
final faqItems = jsonDecode(snapshot.data.toString()) as List;
if (snapshot.hasData) { if (snapshot.hasData) {
setIconsAndColors(context, faqItems.length, addIcon); setIconsAndColors(context, faqItems.length, addIcon);
} }
return SingleChildScrollView( return SingleChildScrollView(
child: ListView.separated( child: Column(
shrinkWrap: true, children: <Widget>[
physics: NeverScrollableScrollPhysics(), StandardListSeparator(),
itemBuilder: (BuildContext context, int index) { ListView.separated(
final itemTitle = faqItems[index]["question"].toString(); shrinkWrap: true,
final itemChild = faqItems[index]["answer"].toString(); physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
final itemTitle = faqItems[index]["question"].toString();
final itemChild = faqItems[index]["answer"].toString();
return ExpansionTile( return ListTileTheme(
title: Padding( contentPadding: EdgeInsets.fromLTRB(0, 6, 24, 6),
padding: EdgeInsets.only(left: 8, top: 12, bottom: 12), child: ExpansionTile(
child: Text( title: Text(
itemTitle, itemTitle,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
color: colors[index] color: colors[index]
),
), ),
), trailing: icons[index],
), onExpansionChanged: (value) {
trailing: Padding( setState(() {
padding: EdgeInsets.only(right: 24), if (value) {
child: Container( icons[index] = removeIcon;
width: double.minPositive, colors[index] = Palette.blueCraiola;
child: Center( } else {
child: icons[index] icons[index] = addIcon;
), colors[index] = Theme.of(context).primaryTextTheme.title.color;
), }
), });
backgroundColor: Theme.of(context).accentTextTheme.headline.backgroundColor, },
onExpansionChanged: (value) {
setState(() {
if (value) {
icons[index] = removeIcon;
colors[index] = Colors.green;
} else {
icons[index] = addIcon;
colors[index] = Theme.of(context).primaryTextTheme.title.color;
}
});
},
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Expanded( Row(
child: Container( mainAxisAlignment: MainAxisAlignment.start,
padding: EdgeInsets.only( children: <Widget>[
left: 24.0, Expanded(
right: 24.0, child: Container(
bottom: 8 padding: EdgeInsets.only(
), right: 24.0,
child: Text( ),
itemChild, child: Text(
style: TextStyle( itemChild,
fontSize: 12, style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color fontSize: 14,
), fontWeight: FontWeight.normal,
), color: Theme.of(context).primaryTextTheme.title.color
)) ),
),
))
],
)
], ],
) ),
], );
); },
}, separatorBuilder: (_, __) =>
separatorBuilder: (_, __) => StandardListSeparator(),
Container(color: Theme.of(context).dividerColor, height: 1.0), itemCount: faqItems == null ? 0 : faqItems.length,
itemCount: faqItems == null ? 0 : faqItems.length, )
), ],
); ),
}, );
future: rootBundle.loadString(getFaqPath(context)), },
), future: rootBundle.loadString(getFaqPath(context)),
), ),
); );
} }

View file

@ -108,7 +108,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
Text(title, Text(title,
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color)), color: Theme.of(context).primaryTextTheme.title.color)),
Spacer(flex: 3), Spacer(flex: 3),
Container( Container(
@ -126,7 +126,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
shape: BoxShape.circle, shape: BoxShape.circle,
color: isFilled color: isFilled
? Theme.of(context).primaryTextTheme.title.color ? Theme.of(context).primaryTextTheme.title.color
: Theme.of(context).primaryTextTheme.caption.color, : Theme.of(context)
.accentTextTheme
.body1
.color
.withOpacity(0.25),
)); ));
}), }),
), ),
@ -143,7 +147,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
_changePinLengthText(), _changePinLengthText(),
style: TextStyle( style: TextStyle(
fontSize: 14.0, fontSize: 14.0,
color: Theme.of(context).primaryTextTheme.caption.color), fontWeight: FontWeight.normal,
color: Theme.of(context)
.accentTextTheme
.body1
.decorationColor),
)) ))
], ],
Spacer(flex: 1), Spacer(flex: 1),
@ -227,7 +235,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
child: Text('$index', child: Text('$index',
style: TextStyle( style: TextStyle(
fontSize: 30.0, fontSize: 30.0,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w600,
color: Theme.of(context) color: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.title .title

View file

@ -1,3 +1,5 @@
import 'package:cake_wallet/src/screens/settings/widgets/language_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -16,29 +18,13 @@ class ChangeLanguage extends BasePage {
final settingsStore = Provider.of<SettingsStore>(context); final settingsStore = Provider.of<SettingsStore>(context);
final currentLanguage = Provider.of<Language>(context); final currentLanguage = Provider.of<Language>(context);
final currentColor = Colors.green;
final notCurrentColor = Theme.of(context).primaryTextTheme.title.color;
final shortDivider = Container(
height: 1,
padding: EdgeInsets.only(left: 24),
color: Theme.of(context).accentTextTheme.title.backgroundColor,
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
);
final longDivider = Container(
height: 1,
color: Theme.of(context).dividerColor,
);
return Container( return Container(
padding: EdgeInsets.only(top: 10.0), padding: EdgeInsets.only(top: 10.0),
child: ListView.builder( child: SectionStandardList(
itemCount: languages.values.length, sectionCount: 1,
itemBuilder: (BuildContext context, int index) { context: context,
itemCounter: (int sectionIndex) => languages.values.length,
itemBuilder: (_, sectionIndex, index) {
final item = languages.values.elementAt(index); final item = languages.values.elementAt(index);
final code = languages.keys.elementAt(index); final code = languages.keys.elementAt(index);
@ -46,52 +32,30 @@ class ChangeLanguage extends BasePage {
? false ? false
: code == settingsStore.languageCode; : code == settingsStore.languageCode;
return Column( return LanguageRow(
children: <Widget>[ title: item,
index == 0 ? longDivider : Offstage(), isSelected: isCurrent,
Container( handler: (context) async {
padding: EdgeInsets.only(top: 4, bottom: 4), if (!isCurrent) {
color: Theme.of(context).accentTextTheme.title.backgroundColor, await showDialog<void>(
child: ListTile( context: context,
contentPadding: EdgeInsets.only(left: 24, right: 24), builder: (BuildContext context) {
title: Text( return AlertWithTwoActions(
item, alertTitle: S.of(context).change_language,
style: TextStyle( alertContent: S.of(context).change_language_to(item),
fontSize: 14.0, leftButtonText: S.of(context).change,
fontWeight: FontWeight.w600, rightButtonText: S.of(context).cancel,
color: isCurrent ? currentColor : notCurrentColor actionLeftButton: () {
), settingsStore.saveLanguageCode(
), languageCode: code);
trailing: isCurrent currentLanguage.setCurrentLanguage(code);
? Icon(Icons.done, color: currentColor) Navigator.of(context).pop();
: Offstage(), },
onTap: () async { actionRightButton: () => Navigator.of(context).pop()
if (!isCurrent) { );
await showDialog<void>( });
context: context, }
builder: (BuildContext context) { },
return AlertWithTwoActions(
alertTitle: S.of(context).change_language,
alertContent: S.of(context).change_language_to(item),
leftButtonText: S.of(context).change,
rightButtonText: S.of(context).cancel,
actionLeftButton: () {
settingsStore.saveLanguageCode(
languageCode: code);
currentLanguage.setCurrentLanguage(code);
Navigator.of(context).pop();
},
actionRightButton: () => Navigator.of(context).pop()
);
});
}
},
),
),
item == languages.values.last
? longDivider
: shortDivider
],
); );
}, },
) )

View file

@ -1,3 +1,5 @@
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -41,6 +43,7 @@ class SettingsPage extends BasePage {
return SettingsPickerCell<dynamic>( return SettingsPickerCell<dynamic>(
title: item.title, title: item.title,
selectedItem: item.selectedItem(), selectedItem: item.selectedItem(),
isAlwaysShowScrollThumb: item.isAlwaysShowScrollThumb,
items: item.items, items: item.items,
onItemSelected: (dynamic value) => item.onItemSelected(value), onItemSelected: (dynamic value) => item.onItemSelected(value),
); );
@ -57,7 +60,8 @@ class SettingsPage extends BasePage {
} }
if (item is RegularListItem) { if (item is RegularListItem) {
return SettingsCellWithArrow(title: item.title); return SettingsCellWithArrow(
title: item.title, handler: item.handler);
} }
if (item is LinkListItem) { if (item is LinkListItem) {
@ -68,6 +72,14 @@ class SettingsPage extends BasePage {
linkTitle: item.linkTitle); linkTitle: item.linkTitle);
} }
if (item is VersionListItem) {
return Observer(builder: (_) {
return SettingsVersionCell(
title:
S.of(context).version(settingsViewModel.currentVersion));
});
}
return Container(); return Container();
}); });
} }

View file

@ -0,0 +1,30 @@
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
class LanguageRow extends StandardListRow {
LanguageRow({@required String title, @required this.isSelected, @required Function(BuildContext context) handler}) :
super(title: title, isSelected: isSelected, onTap: handler);
@override
final bool isSelected;
@override
Widget buildCenter(BuildContext context, {@required bool hasLeftOffset}) {
return Expanded(
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
if (hasLeftOffset) SizedBox(width: 10),
Text(title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: titleColor(context)))
]));
}
@override
Widget buildTrailing(BuildContext context) =>
isSelected
? Icon(Icons.done, color: Palette.blueCraiola)
: Offstage();
}

View file

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
class SettingsCellWithArrow extends StandardListRow { class SettingsCellWithArrow extends StandardListRow {
SettingsCellWithArrow({@required String title}) SettingsCellWithArrow({@required String title, @required Function(BuildContext context) handler})
: super(title: title, isSelected: false); : super(title: title, isSelected: false, onTap: handler);
@override @override
Widget buildTrailing(BuildContext context) => Widget buildTrailing(BuildContext context) =>
Image.asset('assets/images/select_arrow.png', Image.asset('assets/images/select_arrow.png',
color: Theme.of(context).primaryTextTheme.caption.color); color: Theme.of(context).primaryTextTheme.overline.color);
} }

View file

@ -1,5 +1,7 @@
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:url_launcher/url_launcher.dart';
class SettingsLinkProviderCell extends StandardListRow { class SettingsLinkProviderCell extends StandardListRow {
SettingsLinkProviderCell( SettingsLinkProviderCell(
@ -7,7 +9,7 @@ class SettingsLinkProviderCell extends StandardListRow {
@required this.icon, @required this.icon,
@required this.link, @required this.link,
@required this.linkTitle}) @required this.linkTitle})
: super(title: title, isSelected: false); : super(title: title, isSelected: false, onTap: (BuildContext context) => _launchUrl(link) );
final String icon; final String icon;
final String link; final String link;
@ -20,5 +22,11 @@ class SettingsLinkProviderCell extends StandardListRow {
@override @override
Widget buildTrailing(BuildContext context) => Text(linkTitle, Widget buildTrailing(BuildContext context) => Text(linkTitle,
style: TextStyle( style: TextStyle(
fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.blue)); fontSize: 14.0,
fontWeight: FontWeight.w500,
color: Palette.blueCraiola));
static void _launchUrl(String url) async {
if (await canLaunch(url)) await launch(url);
}
} }

View file

@ -8,7 +8,8 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
{@required String title, {@required String title,
this.selectedItem, this.selectedItem,
this.items, this.items,
this.onItemSelected}) this.onItemSelected,
this.isAlwaysShowScrollThumb})
: super( : super(
title: title, title: title,
isSelected: false, isSelected: false,
@ -22,12 +23,15 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
selectedAtIndex: selectedAtIndex, selectedAtIndex: selectedAtIndex,
title: S.current.please_select, title: S.current.please_select,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
onItemSelected: (ItemType item) => onItemSelected?.call(item))); isAlwaysShowScrollThumb: isAlwaysShowScrollThumb,
onItemSelected: (ItemType item) =>
onItemSelected?.call(item)));
}); });
final ItemType selectedItem; final ItemType selectedItem;
final List<ItemType> items; final List<ItemType> items;
final void Function(ItemType item) onItemSelected; final void Function(ItemType item) onItemSelected;
final bool isAlwaysShowScrollThumb;
@override @override
Widget buildTrailing(BuildContext context) { Widget buildTrailing(BuildContext context) {
@ -37,7 +41,7 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
style: TextStyle( style: TextStyle(
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.caption.color), color: Theme.of(context).primaryTextTheme.overline.color),
); );
} }
} }

View file

@ -8,9 +8,9 @@ class SettingsSwitcherCell extends StandardListRow {
: super(title: title, isSelected: false); : super(title: title, isSelected: false);
final bool value; final bool value;
final void Function(bool value) onValueChange; final void Function(BuildContext context, bool value) onValueChange;
@override @override
Widget buildTrailing(BuildContext context) => Widget buildTrailing(BuildContext context) => StandartSwitch(
StandartSwitch(value: value, onTaped: () => onValueChange(!value)); value: value, onTaped: () => onValueChange(context, !value));
} }

View file

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class SettingsVersionCell extends StatelessWidget {
SettingsVersionCell({@required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(bottom: 24),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
title,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context).primaryTextTheme.overline.color
),
)
],
),
);
}
}

View file

@ -53,7 +53,7 @@ class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
state.clear(); state.clear();
} else { } else {
if (listEquals<int>(state.pin, _originalPin)) { if (listEquals<int>(state.pin, _originalPin)) {
final String pin = state.pin.fold("", (ac, val) => ac + '$val'); final String pin = state.pin.fold('', (ac, val) => ac + '$val');
_userStore.set(password: pin); _userStore.set(password: pin);
_settingsStore.setDefaultPinLength(pinLength: state.pinLength); _settingsStore.setDefaultPinLength(pinLength: state.pinLength);

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -36,10 +37,14 @@ class WalletMenu {
]; ];
final List<Image> listImages = [ final List<Image> listImages = [
Image.asset('assets/images/load.png', height: 24, width: 24, color: Colors.white), Image.asset('assets/images/load.png',
Image.asset('assets/images/eye_action.png', height: 24, width: 24, color: Colors.white), height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/trash.png', height: 24, width: 24, color: Colors.white), Image.asset('assets/images/eye_action.png',
Image.asset('assets/images/scanner.png', height: 24, width: 24, color: Colors.white) height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/trash.png',
height: 24, width: 24, color: Colors.white),
Image.asset('assets/images/scanner.png',
height: 24, width: 24, color: Colors.white)
]; ];
List<String> generateItemsForWalletMenu(bool isCurrentWallet) { List<String> generateItemsForWalletMenu(bool isCurrentWallet) {
@ -87,10 +92,11 @@ class WalletMenu {
return images; return images;
} }
void action(int index, WalletListItem wallet, bool isCurrentWallet) { Future<void> action(
int index, WalletListItem wallet, bool isCurrentWallet) async {
switch (index) { switch (index) {
case 0: case 0:
Navigator.of(context).pushNamed(Routes.auth, arguments: await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async { (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) { if (!isAuthenticatedSuccessfully) {
return; return;
@ -110,7 +116,7 @@ class WalletMenu {
}); });
break; break;
case 1: case 1:
Navigator.of(context).pushNamed(Routes.auth, arguments: await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async { (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) { if (!isAuthenticatedSuccessfully) {
return; return;
@ -120,7 +126,23 @@ class WalletMenu {
}); });
break; break;
case 2: case 2:
Navigator.of(context).pushNamed(Routes.auth, arguments: final isComfirmed = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: 'Remove wallet',
alertContent: S.of(context).confirm_delete_wallet,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).remove,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () => Navigator.of(context).pop(true));
});
if (isComfirmed == null || !isComfirmed) {
return;
}
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async { (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) { if (!isAuthenticatedSuccessfully) {
return; return;
@ -139,7 +161,7 @@ class WalletMenu {
}); });
break; break;
case 3: case 3:
Navigator.of(context).pushNamed(Routes.rescan); await Navigator.of(context).pushNamed(Routes.rescan);
break; break;
default: default:
break; break;

View file

@ -123,9 +123,7 @@ class PickerState<Item> extends State<Picker> {
mainAxisAlignment: widget.mainAxisAlignment, mainAxisAlignment: widget.mainAxisAlignment,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
image != null image ?? Offstage(),
? image
: Offstage(),
Padding( Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: image != null ? 12 : 0 left: image != null ? 12 : 0

View file

@ -206,85 +206,84 @@ class SeedWidgetState extends State<SeedWidget> {
fit: FlexFit.tight, fit: FlexFit.tight,
flex: 2, flex: 2,
child: Container( child: Container(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24), bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24)), bottomRight: Radius.circular(24)),
gradient: LinearGradient(colors: [ gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme.subhead.color, Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context).primaryTextTheme.subhead.decorationColor, Theme.of(context).primaryTextTheme.subhead.decorationColor,
], ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
begin: Alignment.topLeft, child: Column(
end: Alignment.bottomRight) children: <Widget>[
), CupertinoNavigationBar(
child: Column( leading: widget.leading,
children: <Widget>[ middle: widget.middle,
CupertinoNavigationBar( backgroundColor: Colors.transparent,
leading: widget.leading, border: null,
middle: widget.middle, ),
backgroundColor: Colors.transparent, Expanded(
border: null, child: Container(
), padding: EdgeInsets.all(24),
Expanded( alignment: Alignment.topLeft,
child: Container( child: SingleChildScrollView(
padding: EdgeInsets.all(24), child: Column(
alignment: Alignment.topLeft, mainAxisAlignment: MainAxisAlignment.start,
child: SingleChildScrollView( crossAxisAlignment: CrossAxisAlignment.start,
child: Column( children: <Widget>[
mainAxisAlignment: MainAxisAlignment.start, Text(
crossAxisAlignment: CrossAxisAlignment.start, S.of(context).restore_active_seed,
children: <Widget>[ style: TextStyle(
Text( fontSize: 14,
S.of(context).restore_active_seed, fontWeight: FontWeight.w500,
style: TextStyle( color: Theme.of(context)
fontSize: 14, .textTheme
fontWeight: FontWeight.w500, .overline
color: .backgroundColor),
Theme.of(context).textTheme.overline.backgroundColor), ),
), Padding(
Padding( padding: EdgeInsets.only(top: 5),
padding: EdgeInsets.only(top: 5), child: Wrap(
child: Wrap( children: items.map((item) {
children: items.map((item) { final isValid =
final isValid = widget.validator.isValid(item); widget.validator.isValid(item);
final isSelected = selectedItem == item; final isSelected = selectedItem == item;
return InkWell( return InkWell(
onTap: () => onMnemonicTap(item), onTap: () => onMnemonicTap(item),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isValid
? Colors.transparent
: Palette.red),
margin: EdgeInsets.only(
right: 7, bottom: 8),
child: Text(
item.toString(),
style: TextStyle(
color: isValid color: isValid
? Colors.transparent ? Colors.white
: Palette.red), : Colors.grey,
margin: EdgeInsets.only(right: 7, bottom: 8), fontSize: 16,
child: Text( fontWeight: isSelected
item.toString(), ? FontWeight.w900
style: TextStyle( : FontWeight.w600,
color: isValid decoration: isSelected
? Colors.white ? TextDecoration.underline
: Colors.grey, : TextDecoration.none),
fontSize: 16, )),
fontWeight: isSelected );
? FontWeight.w900 }).toList(),
: FontWeight.w600, ))
decoration: isSelected ],
? TextDecoration.underline
: TextDecoration.none),
)),
);
}).toList(),
))
],
),
), ),
) ),
) ))
], ],
) )),
),
), ),
Flexible( Flexible(
fit: FlexFit.tight, fit: FlexFit.tight,
@ -372,11 +371,17 @@ class SeedWidgetState extends State<SeedWidget> {
errorText: _errorMessage, errorText: _errorMessage,
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).accentTextTheme.subtitle.backgroundColor, color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
width: 1.0)), width: 1.0)),
enabledBorder: UnderlineInputBorder( enabledBorder: UnderlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).accentTextTheme.subtitle.backgroundColor, color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
width: 1.0))), width: 1.0))),
enableInteractiveSelection: false, enableInteractiveSelection: false,
), ),

View file

@ -41,18 +41,17 @@ class StandardListRow extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: _titleColor(context))) color: titleColor(context)))
])); ]));
} }
Widget buildTrailing(BuildContext context) => null; Widget buildTrailing(BuildContext context) => null;
Color _titleColor(BuildContext context) => isSelected Color titleColor(BuildContext context) => isSelected
? Palette.blueCraiola ? Palette.blueCraiola
: Theme.of(context).primaryTextTheme.title.color; : Theme.of(context).primaryTextTheme.title.color;
Color _backgroundColor(BuildContext context) { Color _backgroundColor(BuildContext context) {
// return Theme.of(context).accentTextTheme.subtitle.decorationColor;
return Theme.of(context).backgroundColor; return Theme.of(context).backgroundColor;
} }
} }
@ -114,16 +113,20 @@ class SectionStandardList extends StatelessWidget {
{@required this.itemCounter, {@required this.itemCounter,
@required this.itemBuilder, @required this.itemBuilder,
@required this.sectionCount, @required this.sectionCount,
this.hasTopSeparator = false,
BuildContext context}) BuildContext context})
: totalRows = transform(context, sectionCount, itemCounter, itemBuilder); : totalRows = transform(hasTopSeparator, context, sectionCount,
itemCounter, itemBuilder);
final int sectionCount; final int sectionCount;
final bool hasTopSeparator;
final int Function(int sectionIndex) itemCounter; final int Function(int sectionIndex) itemCounter;
final Widget Function(BuildContext context, int sectionIndex, int itemIndex) final Widget Function(BuildContext context, int sectionIndex, int itemIndex)
itemBuilder; itemBuilder;
final List<Widget> totalRows; final List<Widget> totalRows;
static List<Widget> transform( static List<Widget> transform(
bool hasTopSeparator,
BuildContext context, BuildContext context,
int sectionCount, int sectionCount,
int Function(int sectionIndex) itemCounter, int Function(int sectionIndex) itemCounter,
@ -132,9 +135,9 @@ class SectionStandardList extends StatelessWidget {
final items = <Widget>[]; final items = <Widget>[];
for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) { for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
/*if (sectionIndex == 0) { if ((sectionIndex == 0)&&(hasTopSeparator)) {
items.add(StandardListSeparator()); items.add(StandardListSeparator(padding: EdgeInsets.only(left: 24)));
}*/ }
final itemCount = itemCounter(sectionIndex); final itemCount = itemCounter(sectionIndex);

View file

@ -26,7 +26,7 @@ class StandartSwitchState extends State<StandartSwitch> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget.value color: widget.value
? Colors.green ? Colors.green
: PaletteDark.distantBlue, : Theme.of(context).accentTextTheme.display4.color,
borderRadius: BorderRadius.all(Radius.circular(14.0))), borderRadius: BorderRadius.all(Radius.circular(14.0))),
child: Container( child: Container(
width: 24.0, width: 24.0,

View file

@ -47,6 +47,11 @@ abstract class SettingsStoreBase with Store {
this.nodes = ObservableMap<WalletType, Node>.of(nodes); this.nodes = ObservableMap<WalletType, Node>.of(nodes);
_sharedPreferences = sharedPreferences; _sharedPreferences = sharedPreferences;
_nodeSource = nodeSource; _nodeSource = nodeSource;
reaction(
(_) => allowBiometricalAuthentication,
(bool biometricalAuthentication) => sharedPreferences.setBool(
allowBiometricalAuthenticationKey, biometricalAuthentication));
} }
static const currentNodeIdKey = 'current_node_id'; static const currentNodeIdKey = 'current_node_id';
@ -62,9 +67,6 @@ abstract class SettingsStoreBase with Store {
static const currentPinLength = 'current_pin_length'; static const currentPinLength = 'current_pin_length';
static const currentLanguageCode = 'language_code'; static const currentLanguageCode = 'language_code';
// @observable
// Node node;
@observable @observable
FiatCurrency fiatCurrency; FiatCurrency fiatCurrency;

View file

@ -160,6 +160,13 @@ class Themes {
color: Palette.darkGray, // hint text (new wallet page) color: Palette.darkGray, // hint text (new wallet page)
decorationColor: Palette.periwinkleCraiola // underline (new wallet page) decorationColor: Palette.periwinkleCraiola // underline (new wallet page)
), ),
display4: TextStyle(
color: Palette.darkGray, // switch background (settings page)
),
body1: TextStyle(
color: Palette.darkGray, // indicators (PIN code)
decorationColor: Palette.darkGray // switch (PIN code)
)
), ),
@ -331,6 +338,13 @@ class Themes {
color: PaletteDark.cyanBlue, // hint text (new wallet page) color: PaletteDark.cyanBlue, // hint text (new wallet page)
decorationColor: PaletteDark.darkGrey // underline (new wallet page) decorationColor: PaletteDark.darkGrey // underline (new wallet page)
), ),
display4: TextStyle(
color: PaletteDark.deepVioletBlue, // switch background (settings page)
),
body1: TextStyle(
color: PaletteDark.indicatorVioletBlue, // indicators (PIN code)
decorationColor: PaletteDark.lightPurpleBlue // switch (PIN code)
)
), ),

View file

@ -6,13 +6,15 @@ class PickerListItem<ItemType> extends SettingsListItem {
{@required String title, {@required String title,
@required this.selectedItem, @required this.selectedItem,
@required this.items, @required this.items,
void Function(ItemType item) onItemSelected}) void Function(ItemType item) onItemSelected,
this.isAlwaysShowScrollThumb = false})
: _onItemSelected = onItemSelected, : _onItemSelected = onItemSelected,
super(title); super(title);
final ItemType Function() selectedItem; final ItemType Function() selectedItem;
final List<ItemType> items; final List<ItemType> items;
final void Function(ItemType item) _onItemSelected; final void Function(ItemType item) _onItemSelected;
final bool isAlwaysShowScrollThumb;
void onItemSelected(dynamic item) { void onItemSelected(dynamic item) {
if (item is ItemType) { if (item is ItemType) {

View file

@ -1,8 +1,10 @@
import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/theme_changer_store.dart'; import 'package:cake_wallet/store/theme_changer_store.dart';
import 'package:cake_wallet/themes.dart'; import 'package:cake_wallet/themes.dart';
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -19,6 +21,7 @@ import 'package:cake_wallet/view_model/settings/picker_list_item.dart';
import 'package:cake_wallet/view_model/settings/regular_list_item.dart'; import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
import 'package:cake_wallet/view_model/settings/settings_list_item.dart'; import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; import 'package:cake_wallet/view_model/settings/switcher_list_item.dart';
import 'package:package_info/package_info.dart';
part 'settings_view_model.g.dart'; part 'settings_view_model.g.dart';
@ -27,7 +30,11 @@ class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel;
abstract class SettingsViewModelBase with Store { abstract class SettingsViewModelBase with Store {
SettingsViewModelBase(this._settingsStore, WalletBase wallet) SettingsViewModelBase(this._settingsStore, WalletBase wallet)
: itemHeaders = {}, : itemHeaders = {},
_walletType = wallet.type { _walletType = wallet.type,
_biometricAuth = BiometricAuth() {
currentVersion = '';
PackageInfo.fromPlatform().then(
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
sections = [ sections = [
[ [
PickerListItem( PickerListItem(
@ -37,17 +44,22 @@ abstract class SettingsViewModelBase with Store {
PickerListItem( PickerListItem(
title: S.current.settings_currency, title: S.current.settings_currency,
items: FiatCurrency.all, items: FiatCurrency.all,
selectedItem: () => fiatCurrency), isAlwaysShowScrollThumb: true,
selectedItem: () => fiatCurrency,
onItemSelected: (FiatCurrency currency) =>
setFiatCurrency(currency)),
PickerListItem( PickerListItem(
title: S.current.settings_fee_priority, title: S.current.settings_fee_priority,
items: _transactionPriorities(wallet.type), items: _transactionPriorities(wallet.type),
selectedItem: () => transactionPriority, selectedItem: () => transactionPriority,
isAlwaysShowScrollThumb: true,
onItemSelected: (TransactionPriority priority) => onItemSelected: (TransactionPriority priority) =>
_settingsStore.transactionPriority = priority), _settingsStore.transactionPriority = priority),
SwitcherListItem( SwitcherListItem(
title: S.current.settings_save_recipient_address, title: S.current.settings_save_recipient_address,
value: () => shouldSaveRecipientAddress, value: () => shouldSaveRecipientAddress,
onValueChange: (bool value) => setShouldSaveRecipientAddress(value)) onValueChange: (_, bool value) =>
setShouldSaveRecipientAddress(value))
], ],
[ [
RegularListItem( RegularListItem(
@ -72,12 +84,32 @@ abstract class SettingsViewModelBase with Store {
SwitcherListItem( SwitcherListItem(
title: S.current.settings_allow_biometrical_authentication, title: S.current.settings_allow_biometrical_authentication,
value: () => allowBiometricalAuthentication, value: () => allowBiometricalAuthentication,
onValueChange: (bool value) => onValueChange: (BuildContext context, bool value) {
setAllowBiometricalAuthentication(value)), if (value) {
Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully,
AuthPageState auth) async {
if (isAuthenticatedSuccessfully) {
if (await _biometricAuth.canCheckBiometrics() &&
await _biometricAuth.isAuthenticated()) {
setAllowBiometricalAuthentication(
isAuthenticatedSuccessfully);
}
} else {
setAllowBiometricalAuthentication(
isAuthenticatedSuccessfully);
}
Navigator.of(context).pop();
});
} else {
setAllowBiometricalAuthentication(value);
}
}),
SwitcherListItem( SwitcherListItem(
title: S.current.settings_dark_mode, title: S.current.settings_dark_mode,
value: () => _settingsStore.isDarkTheme, value: () => _settingsStore.isDarkTheme,
onValueChange: (bool value) { onValueChange: (_, bool value) {
_settingsStore.isDarkTheme = value; _settingsStore.isDarkTheme = value;
getIt getIt
.get<ThemeChangerStore>() .get<ThemeChangerStore>()
@ -119,11 +151,20 @@ abstract class SettingsViewModelBase with Store {
title: S.current.settings_terms_and_conditions, title: S.current.settings_terms_and_conditions,
handler: (BuildContext context) => handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.disclaimer), Navigator.of(context).pushNamed(Routes.disclaimer),
),
RegularListItem(
title: S.current.faq,
handler: (BuildContext context) =>
Navigator.pushNamed(context, Routes.faq),
) )
] ],
[VersionListItem(title: currentVersion)]
]; ];
} }
@observable
String currentVersion;
@computed @computed
Node get node => _settingsStore.getCurrentNode(_walletType); Node get node => _settingsStore.getCurrentNode(_walletType);
@ -151,10 +192,18 @@ abstract class SettingsViewModelBase with Store {
_settingsStore.allowBiometricalAuthentication; _settingsStore.allowBiometricalAuthentication;
final Map<String, String> itemHeaders; final Map<String, String> itemHeaders;
List<List<SettingsListItem>> sections;
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
final WalletType _walletType; final WalletType _walletType;
List<List<SettingsListItem>> sections; final BiometricAuth _biometricAuth;
@action
void setBalanceDisplayMode(BalanceDisplayMode value) =>
_settingsStore.balanceDisplayMode = value;
@action
void setFiatCurrency(FiatCurrency value) =>
_settingsStore.fiatCurrency = value;
@action @action
void setShouldSaveRecipientAddress(bool value) => void setShouldSaveRecipientAddress(bool value) =>
_settingsStore.shouldSaveRecipientAddress = value; _settingsStore.shouldSaveRecipientAddress = value;
@ -190,11 +239,6 @@ abstract class SettingsViewModelBase with Store {
@action @action
void _showTrades() => actionlistDisplayMode.add(ActionListDisplayMode.trades); void _showTrades() => actionlistDisplayMode.add(ActionListDisplayMode.trades);
//
// @observable
// int defaultPinLength;
// bool isDarkTheme;
static List<TransactionPriority> _transactionPriorities(WalletType type) { static List<TransactionPriority> _transactionPriorities(WalletType type) {
switch (type) { switch (type) {
case WalletType.monero: case WalletType.monero:

View file

@ -1,13 +1,14 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:cake_wallet/view_model/settings/settings_list_item.dart'; import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
class SwitcherListItem extends SettingsListItem { class SwitcherListItem extends SettingsListItem {
SwitcherListItem( SwitcherListItem(
{@required String title, {@required String title,
@required this.value, @required this.value,
@required this.onValueChange}) @required this.onValueChange})
: super(title); : super(title);
final bool Function() value; final bool Function() value;
final void Function(bool value) onValueChange; final void Function(BuildContext context, bool value) onValueChange;
} }

View file

@ -0,0 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
class VersionListItem extends SettingsListItem {
VersionListItem({@required String title}) : super(title);
}

View file

@ -27,7 +27,7 @@ abstract class WalletCreationVMBase with Store {
final bool isRecovery; final bool isRecovery;
Box<WalletInfo> _walletInfoSource; final Box<WalletInfo> _walletInfoSource;
Future<void> create({dynamic options}) async { Future<void> create({dynamic options}) async {
try { try {

View file

@ -1,7 +1,7 @@
{ {
"welcome" : "Welcome to", "welcome" : "Welcome to",
"cake_wallet" : "Cake Wallet", "cake_wallet" : "Cake Wallet",
"first_wallet_text" : "Awesome wallet for Monero", "first_wallet_text" : "Awesome wallet for Monero and Bitcoin",
"please_make_selection" : "Please make selection below to create or recover your wallet.", "please_make_selection" : "Please make selection below to create or recover your wallet.",
"create_new" : "Create New Wallet", "create_new" : "Create New Wallet",
"restore_wallet" : "Restore Wallet", "restore_wallet" : "Restore Wallet",