Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-237-enhance-error-catching-reporting

This commit is contained in:
OmarHatem
2023-01-06 16:18:21 +02:00
166 changed files with 4306 additions and 2203 deletions
+26 -88
View File
@@ -9,24 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart';
class ContactListPage extends BasePage {
ContactListPage(this.contactListViewModel, {this.isEditable = true});
ContactListPage(this.contactListViewModel);
final ContactListViewModel contactListViewModel;
final bool isEditable;
@override
String get title => S.current.address_book;
@override
Widget? trailing(BuildContext context) {
if (!isEditable) {
if (!contactListViewModel.isEditable) {
return null;
}
@@ -60,21 +58,24 @@ class ContactListPage extends BasePage {
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Observer(
builder: (_) {
return CollapsibleSectionList(
builder: (_) {
final contacts = contactListViewModel.contactsToShow;
final walletContacts = contactListViewModel.walletContactsToShow;
return CollapsibleSectionList(
context: context,
sectionCount: 2,
themeColor: Theme.of(context).primaryTextTheme.headline6!.color!,
dividerThemeColor:
Theme.of(context).primaryTextTheme.caption!.decorationColor!,
sectionTitleBuilder: (_, int sectionIndex) {
var title = 'Contacts';
var title = S.current.contact_list_contacts;
if (sectionIndex == 0) {
title = 'My wallets';
title = S.current.contact_list_wallets;
}
return Container(
@@ -82,35 +83,37 @@ class ContactListPage extends BasePage {
child: Text(title, style: TextStyle(fontSize: 36)));
},
itemCounter: (int sectionIndex) => sectionIndex == 0
? contactListViewModel.walletContacts.length
: contactListViewModel.contacts.length,
? walletContacts.length
: contacts.length,
itemBuilder: (_, sectionIndex, index) {
if (sectionIndex == 0) {
final walletInfo = contactListViewModel.walletContacts[index];
final walletInfo = walletContacts[index];
return generateRaw(context, walletInfo);
}
final contact = contactListViewModel.contacts[index];
final contact = contacts[index];
final content = generateRaw(context, contact);
return !isEditable
? content
: Slidable(
return contactListViewModel.isEditable
? Slidable(
key: Key('${contact.key}'),
endActionPane: _actionPane(context, contact),
child: content,
);
)
: content;
},
);
},
));
);})
);
}
Widget generateRaw(BuildContext context, ContactBase contact) {
final image = _getCurrencyImage(contact.type);
final image = contact.type.iconPath;
final currencyIcon = image != null ? Image.asset(image, height: 24, width: 24)
: const SizedBox(height: 24, width: 24);
return GestureDetector(
onTap: () async {
if (!isEditable) {
if (!contactListViewModel.isEditable) {
Navigator.of(context).pop(contact);
return;
}
@@ -131,12 +134,10 @@ class ContactListPage extends BasePage {
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
image ?? Offstage(),
currencyIcon,
Expanded(
child: Padding(
padding: image != null
? EdgeInsets.only(left: 12)
: EdgeInsets.only(left: 0),
padding: EdgeInsets.only(left: 12),
child: Text(
contact.name,
style: TextStyle(
@@ -152,69 +153,6 @@ class ContactListPage extends BasePage {
);
}
Image? _getCurrencyImage(CryptoCurrency currency) {
Image? image;
switch (currency) {
case CryptoCurrency.xmr:
image =
Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
break;
case CryptoCurrency.ada:
image = Image.asset('assets/images/ada.png', height: 24, width: 24);
break;
case CryptoCurrency.bch:
image = Image.asset('assets/images/bch.png', height: 24, width: 24);
break;
case CryptoCurrency.bnb:
image = Image.asset('assets/images/bnb.png', height: 24, width: 24);
break;
case CryptoCurrency.btc:
image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
break;
case CryptoCurrency.dai:
image = Image.asset('assets/images/dai.png', height: 24, width: 24);
break;
case CryptoCurrency.dash:
image = Image.asset('assets/images/dash.png', height: 24, width: 24);
break;
case CryptoCurrency.eos:
image = Image.asset('assets/images/eos.png', height: 24, width: 24);
break;
case CryptoCurrency.eth:
image = Image.asset('assets/images/eth.png', height: 24, width: 24);
break;
case CryptoCurrency.ltc:
image =
Image.asset('assets/images/litecoin.png', height: 24, width: 24);
break;
case CryptoCurrency.nano:
image = Image.asset('assets/images/nano.png', height: 24, width: 24);
break;
case CryptoCurrency.trx:
image = Image.asset('assets/images/trx.png', height: 24, width: 24);
break;
case CryptoCurrency.usdt:
image = Image.asset('assets/images/usdt.png', height: 24, width: 24);
break;
case CryptoCurrency.usdterc20:
image = Image.asset('assets/images/usdterc.png', height: 24, width: 24);
break;
case CryptoCurrency.xlm:
image = Image.asset('assets/images/xlm.png', height: 24, width: 24);
break;
case CryptoCurrency.xrp:
image = Image.asset('assets/images/xrp.png', height: 24, width: 24);
break;
case CryptoCurrency.xhv:
image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
break;
default:
image = null;
}
return image;
}
Future<bool> showAlertDialog(BuildContext context) async {
return await showPopUp<bool>(
context: context,
@@ -60,7 +60,7 @@ class DashboardPage extends BasePage {
Widget middle(BuildContext context) {
return SyncIndicator(dashboardViewModel: walletViewModel,
onTap: () => Navigator.of(context, rootNavigator: true)
.pushNamed(Routes.nodeList));
.pushNamed(Routes.connectionSync));
}
@override
+51 -85
View File
@@ -1,81 +1,64 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu_item.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
// FIXME: terrible design
class WalletMenu {
WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] {
items.addAll([
WalletMenuItem(
title: S.current.reconnect,
image: Image.asset('assets/images/reconnect_menu.png',
height: 16, width: 16),
handler: () => _presentReconnectAlert(context)),
if (hasRescan)
WalletMenuItem(
title: S.current.rescan,
image: Image.asset('assets/images/filter_icon.png',
height: 16, width: 16, color: Palette.darkBlue),
handler: () => Navigator.of(context).pushNamed(Routes.rescan)),
WalletMenuItem(
title: S.current.wallets,
image: Image.asset('assets/images/wallet_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.walletList)),
WalletMenuItem(
title: S.current.nodes,
image: Image.asset('assets/images/nodes_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.nodeList)),
WalletMenuItem(
title: S.current.show_keys,
image:
Image.asset('assets/images/key_menu.png', height: 16, width: 16),
handler: () {
Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route: Routes.showKeys);
}
});
}),
WalletMenuItem(
title: S.current.address_book_menu,
image: Image.asset('assets/images/open_book_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.addressBook)),
WalletMenuItem(
title: S.current.backup,
image: Image.asset('assets/images/restore_wallet.png',
height: 16,
width: 16,
color: Palette.darkBlue),
handler: () {
Navigator.of(context).pushNamed(
Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route:Routes.backup);
}
});
}),
WalletMenuItem(
title: S.current.settings_title,
image: Image.asset('assets/images/settings_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.settings)),
WalletMenuItem(
title: S.current.settings_support,
image: Image.asset('assets/images/question_mark.png',
height: 16, width: 16, color: Palette.darkBlue),
handler: () => Navigator.of(context).pushNamed(Routes.support)),
WalletMenuItem(
title: S.current.connection_sync,
image: Image.asset('assets/images/nodes_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.connectionSync),
),
WalletMenuItem(
title: S.current.wallets,
image: Image.asset('assets/images/wallet_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.walletList),
),
WalletMenuItem(
title: S.current.address_book_menu,
image: Image.asset('assets/images/open_book_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.addressBook),
),
WalletMenuItem(
title: S.current.security_and_backup,
image:
Image.asset('assets/images/key_menu.png', height: 16, width: 16),
handler: () {
Navigator.of(context).pushNamed(Routes.securityBackupPage);
}),
WalletMenuItem(
title: S.current.privacy_settings,
image:
Image.asset('assets/images/privacy_menu.png', height: 16, width: 16),
handler: () {
Navigator.of(context).pushNamed(Routes.privacyPage);
}),
WalletMenuItem(
title: S.current.display_settings,
image: Image.asset('assets/images/eye_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.displaySettingsPage),
),
WalletMenuItem(
title: S.current.other_settings,
image: Image.asset('assets/images/settings_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.otherSettingsPage),
),
WalletMenuItem(
title: S.current.settings_support,
image: Image.asset('assets/images/question_mark.png',
height: 16, width: 16, color: Palette.darkBlue),
handler: () => Navigator.of(context).pushNamed(Routes.support),
),
]);
}
@@ -86,23 +69,6 @@ class WalletMenu {
void action(int index) {
final item = items[index];
item?.handler();
}
Future<void> _presentReconnectAlert(BuildContext context) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).reconnection,
alertContent: S.of(context).reconnect_alert_text,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () async {
Navigator.of(context).pop();
await reconnect?.call();
},
actionLeftButton: () => Navigator.of(context).pop());
});
item.handler();
}
}
@@ -9,12 +9,7 @@ class FilterTile extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.only(
top: 18,
bottom: 18,
left: 24,
right: 24
),
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
child: child,
);
}
@@ -1,25 +1,26 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/checkbox_widget.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
class FilterWidget extends StatelessWidget {
FilterWidget({required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
final backVector = Image.asset('assets/images/back_vector.png',
color: Palette.darkBlueCraiola
);
final closeIcon = Image.asset('assets/images/close.png', color: Palette.darkBlueCraiola);
@override
Widget build(BuildContext context) {
const sectionDivider = const SectionDivider();
return AlertBackground(
child: Stack(
alignment: Alignment.center,
@@ -27,129 +28,82 @@ class FilterWidget extends StatelessWidget {
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
S.of(context).filters,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
Padding(
padding: EdgeInsets.only(
left: 24,
right: 24,
top: 24
),
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(14)),
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => Container(
height: 1,
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).filter_by,
style: TextStyle(
color: Theme.of(context).primaryTextTheme.overline!.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
),
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
final section = dashboardViewModel.filterItems.values.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(
top: 20,
left: 24,
right: 24
),
child: Text(
title,
style: TextStyle(
color: Theme.of(context).accentTextTheme!.subtitle1!.color!,
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: 'Lato',
decoration: TextDecoration.none
sectionDivider,
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => sectionDivider,
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
final section = dashboardViewModel.filterItems.values.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
child: Text(
title,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
),
),
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
separatorBuilder: (context, _) => Container(
height: 1,
padding: EdgeInsets.only(left: 24),
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: Container(
height: 1,
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!,
),
),
itemBuilder: (_, index2) {
final item = section[index2];
final content = item.onChanged != null
? CheckboxWidget(
value: item.value(),
caption: item.caption,
onChanged: item.onChanged
)
: GestureDetector(
onTap: () async {
//final List<DateTime> picked =
//await date_rage_picker.showDatePicker(
// context: context,
// initialFirstDate: DateTime.now()
// .subtract(Duration(days: 1)),
// initialLastDate: (DateTime.now()),
// firstDate: DateTime(2015),
// lastDate: DateTime.now()
// .add(Duration(days: 1)));
//if (picked != null && picked.length == 2) {
// dashboardViewModel.transactionFilterStore
// .changeStartDate(picked.first);
// dashboardViewModel.transactionFilterStore
// .changeEndDate(picked.last);
//}
},
child: Padding(
padding: EdgeInsets.only(left: 32),
child: Text(
item.caption,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
decoration: TextDecoration.none
),
),
),
);
return FilterTile(child: content);
},
)
],
);
},
),
ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
itemBuilder: (_, index2) {
final item = section[index2];
final content = Observer(
builder: (_) => StandardCheckbox(
value: item.value(),
caption: item.caption,
gradientBackground: true,
borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) => item.onChanged(),
));
return FilterTile(child: content);
},
)
],
);
},
),
]),
),
),
),
],
),
AlertCloseButton(image: backVector)
AlertCloseButton(image: closeIcon)
],
),
);
}
}
}
@@ -6,6 +6,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:url_launcher/url_launcher.dart';
class MarketPlacePage extends StatelessWidget {
@@ -48,6 +49,15 @@ class MarketPlacePage extends StatelessWidget {
title: S.of(context).cake_pay_title,
subTitle: S.of(context).cake_pay_subtitle,
),
SizedBox(height: 20),
MarketPlaceItem(
onTap: () => launchUrl(
Uri.https("buy.cakepay.com"),
mode: LaunchMode.externalApplication,
),
title: S.of(context).cake_pay_web_cards_title,
subTitle: S.of(context).cake_pay_web_cards_subtitle,
),
],
),
),
@@ -72,7 +82,7 @@ class MarketPlacePage extends StatelessWidget {
buttonAction: () => Navigator.of(context).pop());
});
break;
default:
default:
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
}
}
@@ -57,7 +57,9 @@ class TransactionsPage extends StatelessWidget {
formattedDate: DateFormat('HH:mm')
.format(transaction.date),
formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: item.formattedFiatAmount,
formattedFiatAmount:
dashboardViewModel.balanceViewModel.isFiatDisabled
? '' : item.formattedFiatAmount,
isPending: transaction.isPending));
}
@@ -40,7 +40,6 @@ class ExchangePage extends BasePage {
final ExchangeViewModel exchangeViewModel;
final depositKey = GlobalKey<ExchangeCardState>();
final receiveKey = GlobalKey<ExchangeCardState>();
final checkBoxKey = GlobalKey<StandardCheckboxState>();
final _formKey = GlobalKey<FormState>();
final _depositAmountFocus = FocusNode();
final _depositAddressFocus = FocusNode();
@@ -339,7 +338,6 @@ class ExchangePage extends BasePage {
mainAxisAlignment: MainAxisAlignment.start,
children: [
StandardCheckbox(
key: checkBoxKey,
value: exchangeViewModel.isFixedRateMode,
caption: S.of(context).fixed_rate,
onChanged: (value) =>
@@ -682,12 +680,6 @@ class ExchangePage extends BasePage {
}
});
reaction((_) => exchangeViewModel.isFixedRateMode, (bool value) {
if (checkBoxKey.currentState!.value != exchangeViewModel.isFixedRateMode) {
checkBoxKey.currentState!.value = exchangeViewModel.isFixedRateMode;
}
});
depositAddressController.addListener(
() => exchangeViewModel.depositAddress = depositAddressController.text);
@@ -56,7 +56,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
.where((element) =>
(element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) ||
(element.tag != null ? element.tag!.toLowerCase().contains(subString.toLowerCase()) : false) ||
(element.name != null ? element.name!.toLowerCase().contains(subString.toLowerCase()) : false))
(element.fullName != null ? element.fullName!.toLowerCase().contains(subString.toLowerCase()) : false))
.toList();
return;
}
@@ -395,7 +395,8 @@ class ExchangeCardState extends State<ExchangeCard> {
buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator,
onPushPasteButton: widget.onPushPasteButton,
onPushAddressBookButton: widget.onPushAddressBookButton
onPushAddressBookButton: widget.onPushAddressBookButton,
selectedCurrency: _selectedCurrency
),
)
@@ -8,7 +8,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
@@ -194,7 +194,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
final item = widget.exchangeTradeViewModel.items[index];
final value = item.data ?? fetchingLabel;
final content = StandartListRow(
final content = ListRow(
title: item.title,
value: value,
valueFontSize: 14,
@@ -378,12 +378,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
});
},
actionLeftButton: () => Navigator.of(context).pop(),
feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel.pendingTransactionFeeFiatAmount
+ ' ' + widget.exchangeTradeViewModel.sendViewModel.fiat.title,
fiatAmountValue: widget.exchangeTradeViewModel.sendViewModel
.pendingTransactionFiatAmount +
' ' +
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
feeFiatAmount: widget.exchangeTradeViewModel
.pendingTransactionFeeFiatAmountFormatted,
fiatAmountValue: widget.exchangeTradeViewModel
.pendingTransactionFiatAmountValueFormatted,
outputs: widget.exchangeTradeViewModel.sendViewModel
.outputs);
});
@@ -1,3 +1,4 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
@@ -18,12 +19,11 @@ class IoniaCustomRedeemPage extends BasePage {
) : _amountFieldFocus = FocusNode(),
_amountController = TextEditingController() {
_amountController.addListener(() {
ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
});
}
final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
@override
String get title => S.current.custom_redeem_amount;
@@ -50,7 +50,7 @@ class IoniaCustomRedeemPage extends BasePage {
disableScroll: true,
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!,
keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
nextFocus: false,
actions: [
KeyboardActionsItem(
@@ -67,10 +67,11 @@ class IoniaCustomRedeemPage extends BasePage {
Container(
padding: EdgeInsets.symmetric(horizontal: 25),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme!.subtitle1!.color!,
Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!,
Theme.of(context).primaryTextTheme.subtitle1!.color!,
Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
], begin: Alignment.topLeft, end: Alignment.bottomRight),
),
child: Column(
@@ -85,11 +86,11 @@ class IoniaCustomRedeemPage extends BasePage {
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
hintText: '1000',
placeholderTextStyle: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline5!.color!,
color: Theme.of(context).primaryTextTheme.headline5!.color!,
fontWeight: FontWeight.w500,
fontSize: 36,
),
borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!,
borderColor: Theme.of(context).primaryTextTheme.headline5!.color!,
textColor: Colors.white,
textStyle: TextStyle(
color: Colors.white,
@@ -114,14 +115,17 @@ class IoniaCustomRedeemPage extends BasePage {
),
),
SizedBox(height: 8),
Observer(builder: (_)=>
!ioniaCustomRedeemViewModel.disableRedeem ?
Center(
child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline5!.color!,
),),
) : SizedBox.shrink(),
Observer(
builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem
? Center(
child: Text(
'\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
style: TextStyle(
color: Theme.of(context).primaryTextTheme.headline5!.color!,
),
),
)
: SizedBox.shrink(),
),
SizedBox(height: 24),
],
@@ -131,30 +135,37 @@ class IoniaCustomRedeemPage extends BasePage {
padding: const EdgeInsets.all(24.0),
child: CardItem(
title: giftCard.legalName,
backgroundColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!.withOpacity(0.1),
backgroundColor: Theme.of(context)
.accentTextTheme
.headline1!
.backgroundColor!
.withOpacity(0.1),
discount: giftCard.remainingAmount,
isAmount: true,
discountBackground: AssetImage('assets/images/red_badge_discount.png'),
titleColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!,
titleColor: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
subtitleColor: Theme.of(context).hintColor,
subTitle: S.of(context).online,
logoUrl: giftCard.logoUrl,
),
),
),
],
),
bottomSection: Column(
children: [
Padding(
padding: EdgeInsets.only(bottom: 12),
child: PrimaryButton(
onPressed: () {
Navigator.of(context).pop(_amountController.text);
},
isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
text: S.of(context).add_custom_redemption,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
textColor: Colors.white,
Observer(
builder: (_) => Padding(
padding: EdgeInsets.only(bottom: 12),
child: LoadingPrimaryButton(
isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState,
isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
text: S.of(context).add_custom_redemption,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) {
Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString());
}),
),
),
),
SizedBox(height: 30),
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/typography.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/route_aware.dart';
import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
import 'package:device_display_brightness/device_display_brightness.dart';
import 'package:flutter/material.dart';
@@ -32,7 +33,7 @@ class IoniaGiftCardDetailPage extends BasePage {
final _backButton = Icon(
Icons.arrow_back_ios,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
size: 16,
);
return Padding(
@@ -43,14 +44,11 @@ class IoniaGiftCardDetailPage extends BasePage {
child: ButtonTheme(
minWidth: double.minPositive,
child: TextButton(
// FIX-ME: Style
// FIX-ME: Style
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
//padding: EdgeInsets.all(0),
onPressed: () {
onClose(context);
DeviceDisplayBrightness.setBrightness(viewModel.brightness);
},
onPressed: ()=> onClose(context),
child: _backButton),
),
),
@@ -61,13 +59,13 @@ class IoniaGiftCardDetailPage extends BasePage {
Widget middle(BuildContext context) {
return Text(
viewModel.giftCard.legalName,
style: textMediumSemiBold(color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!),
style:
textMediumSemiBold(color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!),
);
}
@override
Widget body(BuildContext context) {
viewModel.increaseBrightness();
reaction((_) => viewModel.redeemState, (ExecutionState state) {
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -84,7 +82,12 @@ class IoniaGiftCardDetailPage extends BasePage {
}
});
return ScrollableWithBottomSection(
return RouteAwareWidget(
pushToWidget: ()=> viewModel.increaseBrightness(),
pushToNextWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
popNextWidget: ()=> viewModel.increaseBrightness(),
popWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.all(24),
content: Column(
children: [
@@ -102,20 +105,21 @@ class IoniaGiftCardDetailPage extends BasePage {
title: S.of(context).gift_card_number,
subTitle: viewModel.giftCard.cardNumber,
),
if (viewModel.giftCard.cardPin?.isNotEmpty ?? false)
...[Divider(height: 30),
if (viewModel.giftCard.cardPin.isNotEmpty) ...[
Divider(height: 30),
buildIoniaTile(
context,
title: S.of(context).pin_number,
subTitle: viewModel.giftCard.cardPin,
)],
)
],
Divider(height: 30),
Observer(builder: (_) =>
buildIoniaTile(
context,
title: S.of(context).amount,
subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00',
)),
Observer(
builder: (_) => buildIoniaTile(
context,
title: S.of(context).amount,
subTitle: viewModel.remainingAmount.toStringAsFixed(2),
)),
Divider(height: 50),
TextIconButton(
label: S.of(context).how_to_use_card,
@@ -130,29 +134,28 @@ class IoniaGiftCardDetailPage extends BasePage {
if (!viewModel.giftCard.isEmpty) {
return Column(
children: [
//PrimaryButton(
// onPressed: () async {
// final amount = await Navigator.of(context)
// .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as String;
// if (amount != null) {
// viewModel.updateRemaining(double.parse(amount));
// }
// },
// text: S.of(context).more_options,
// color: Theme.of(context).accentTextTheme!.caption!.color!,
// textColor: Theme.of(context).primaryTextTheme!.headline6!.color!,
//),
//SizedBox(height: 12),
PrimaryButton(
onPressed: () async {
await Navigator.of(context).pushNamed(
Routes.ioniaMoreOptionsPage,
arguments: [viewModel.giftCard]) as String?;
viewModel.refeshCard();
},
text: S.of(context).more_options,
color: Theme.of(context).accentTextTheme.caption!.color!,
textColor: Theme.of(context).primaryTextTheme.headline6!.color!,
),
SizedBox(height: 12),
LoadingPrimaryButton(
isLoading: viewModel.redeemState is IsExecutingState,
onPressed: () => viewModel.redeem().then(
(_) {
Navigator.of(context)
.pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
Navigator.of(context).pushNamedAndRemoveUntil(
Routes.ioniaManageCardsPage, (route) => route.isFirst);
},
),
text: S.of(context).mark_as_redeemed,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
),
],
@@ -163,17 +166,16 @@ class IoniaGiftCardDetailPage extends BasePage {
},
),
),
);
));
}
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
return IoniaTile(
title: title,
subTitle: subTitle,
onTap: () {
Clipboard.setData(ClipboardData(text: subTitle));
showBar<void>(context,
S.of(context).transaction_details_copied(title));
title: title,
subTitle: subTitle,
onTap: () {
Clipboard.setData(ClipboardData(text: subTitle));
showBar<void>(context, S.of(context).transaction_details_copied(title));
});
}
@@ -184,10 +186,10 @@ class IoniaGiftCardDetailPage extends BasePage {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return IoniaAlertModal(
return IoniaAlertModal(
title: S.of(context).how_to_use_card,
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: viewModel.giftCard.instructions
.map((instruction) {
return [
@@ -196,13 +198,13 @@ class IoniaGiftCardDetailPage extends BasePage {
child: Text(
instruction.header,
style: textLargeSemiBold(
color: Theme.of(context).textTheme!.headline3!.color!,
color: Theme.of(context).textTheme.headline3!.color!,
),
)),
Text(
instruction.body,
style: textMedium(
color: Theme.of(context).textTheme!.headline3!.color!,
color: Theme.of(context).textTheme.headline3!.color!,
),
)
];
@@ -210,7 +212,7 @@ class IoniaGiftCardDetailPage extends BasePage {
.expand((e) => e)
.toList()),
actionTitle: S.of(context).send_got_it,
);
);
});
}
}
@@ -118,7 +118,7 @@ class IoniaManageCardsPage extends BasePage {
width: 32,
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
color: Theme.of(context).textTheme!.headline6!.backgroundColor!,
border: Border.all(
color: Colors.white.withOpacity(0.2),
),
@@ -5,7 +5,6 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/typography.dart';
import 'package:flutter/material.dart';
class IoniaMoreOptionsPage extends BasePage {
IoniaMoreOptionsPage(this.giftCard);
@@ -16,7 +15,7 @@ class IoniaMoreOptionsPage extends BasePage {
return Text(
S.current.more_options,
style: textMediumSemiBold(
color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!,
color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
),
);
}
@@ -27,40 +26,45 @@ class IoniaMoreOptionsPage extends BasePage {
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 10,),
Center(child: Text(S.of(context).choose_from_available_options, style: textMedium(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
),)),
SizedBox(height: 40,),
InkWell(
onTap: () async {
final amount = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String;
if(amount.isNotEmpty){
Navigator.pop(context, amount);
}
},
child: _GradiantContainer(
content: Padding(
padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
child: Text(
S.of(context).custom_redeem_amount,
style: textXLargeSemiBold(),
),
),
),
)
],
),
children: [
SizedBox(
height: 10,
),
Center(
child: Text(
S.of(context).choose_from_available_options,
style: textMedium(
color: Theme.of(context).primaryTextTheme.headline6!.color!,
),
),
),
SizedBox(height: 40),
InkWell(
onTap: () async {
final amount = await Navigator.of(context)
.pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?;
if (amount != null && amount.isNotEmpty) {
Navigator.pop(context);
}
},
child: _GradiantContainer(
content: Padding(
padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
child: Text(
S.of(context).custom_redeem_amount,
style: textXLargeSemiBold(),
),
),
),
)
],
),
);
}
}
class _GradiantContainer extends StatelessWidget {
const _GradiantContainer({
Key? key,
required this.content
}) : super(key: key);
const _GradiantContainer({Key? key, required this.content}) : super(key: key);
final Widget content;
@@ -20,7 +20,7 @@ class IoniaFilterModal extends StatelessWidget {
padding: EdgeInsets.all(10),
child: Image.asset(
'assets/images/mini_search_icon.png',
color: Theme.of(context).accentColor,
color: Theme.of(context).textTheme.subtitle2!.color!,
),
);
return Scaffold(
@@ -53,7 +53,7 @@ class IoniaFilterModal extends StatelessWidget {
prefixIcon: searchIcon,
hintText: S.of(context).search_category,
contentPadding: EdgeInsets.only(bottom: 5),
fillColor: Theme.of(context).textTheme!.subtitle1!.backgroundColor!,
fillColor: Theme.of(context).primaryTextTheme!.caption!.decorationColor!.withOpacity(0.5),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(8),
@@ -1,4 +1,5 @@
import 'dart:ui';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -84,10 +85,7 @@ class MoneroAccountListPage extends StatelessWidget {
padding: EdgeInsets.zero,
controller: controller,
separatorBuilder: (context, index) =>
Container(
height: 1,
color: Theme.of(context).dividerColor,
),
const SectionDivider(),
itemCount: accounts.length ?? 0,
itemBuilder: (context, index) {
final account = accounts[index];
@@ -0,0 +1,111 @@
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class AdvancedPrivacySettingsPage extends BasePage {
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
@override
String get title => S.current.privacy_settings;
@override
Widget body(BuildContext context) =>
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
}
class AdvancedPrivacySettingsBody extends StatefulWidget {
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
: super(key: key);
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
@override
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
}
class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBody> {
_AdvancedPrivacySettingsBodyState();
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...widget.privacySettingsViewModel.settings.map(
(item) => Observer(
builder: (_) => SettingsSwitcherCell(
title: item.title,
value: item.value(),
onValueChange: item.onValueChange,
),
),
),
Observer(
builder: (_) {
if (widget.privacySettingsViewModel.addCustomNode) {
return Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: NodeForm(
formKey: _formKey,
nodeViewModel: widget.nodeViewModel,
),
);
}
return const SizedBox();
},
),
],
),
bottomSectionPadding: EdgeInsets.all(24),
bottomSection: Column(
children: [
LoadingPrimaryButton(
onPressed: () {
if (widget.privacySettingsViewModel.addCustomNode) {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
return;
}
widget.nodeViewModel.save(saveAsCurrent: true);
}
Navigator.pop(context);
},
text: S.of(context).continue_text,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
),
const SizedBox(height: 25),
Padding(
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15),
child: Text(
S.of(context).settings_can_be_changed_later,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).accentTextTheme.headline2?.color,
),
),
),
],
),
),
);
}
}
+24 -12
View File
@@ -200,18 +200,30 @@ class _WalletNameFormState extends State<WalletNameForm> {
]
]),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Observer(
builder: (context) {
return LoadingPrimaryButton(
onPressed: _confirmForm,
text: S.of(context).seed_language_next,
color: Colors.green,
textColor: Colors.white,
isLoading: _walletNewVM.state is IsExecutingState,
isDisabled: _walletNewVM.name.isEmpty,
);
},
EdgeInsets.all(24),
bottomSection: Column(
children: [
Observer(
builder: (context) {
return LoadingPrimaryButton(
onPressed: _confirmForm,
text: S.of(context).seed_language_next,
color: Colors.green,
textColor: Colors.white,
isLoading: _walletNewVM.state is IsExecutingState,
isDisabled: _walletNewVM.name.isEmpty,
);
},
),
const SizedBox(height: 25),
GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
},
child: Text(S.of(context).advanced_privacy_settings),
),
],
)),
);
}
@@ -1,16 +1,13 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/node_address_validator.dart';
import 'package:cake_wallet/core/node_port_validator.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
@@ -108,76 +105,10 @@ class NodeCreateOrEditPage extends BasePage {
padding: EdgeInsets.only(left: 24, right: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24.0),
content: Form(
key: _formKey,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _addressController,
hintText: S.of(context).node_address,
validator: NodeAddressValidator(),
)
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _portController,
hintText: S.of(context).node_port,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: false),
validator: NodePortValidator(),
)
)
],
),
SizedBox(height: 10.0),
if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _loginController,
hintText: S.of(context).login,
)
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _passwordController,
hintText: S.of(context).password,
)
)
],
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeCreateOrEditViewModel.useSSL,
onChanged: (value) =>
nodeCreateOrEditViewModel.useSSL = value,
caption: S.of(context).use_ssl,
))
],
))
]
],
)),
content: NodeForm(
formKey: _formKey,
nodeViewModel: nodeCreateOrEditViewModel,
),
bottomSectionPadding: EdgeInsets.only(bottom: 24),
bottomSection: Observer(
builder: (_) => Row(
-166
View File
@@ -1,166 +0,0 @@
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/node.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class NodeListPage extends BasePage {
NodeListPage(this.nodeListViewModel);
@override
String get title => S.current.nodes;
final NodeListViewModel nodeListViewModel;
@override
Widget trailing(context) {
return Container(
height: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
color: Theme.of(context).accentTextTheme.caption!.color!),
child: ButtonTheme(
minWidth: double.minPositive,
child: TextButton(
onPressed: () async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).node_reset_settings_title,
alertContent:
S.of(context).nodes_list_reset_to_default_message,
rightButtonText: S.of(context).reset,
leftButtonText: S.of(context).cancel,
actionRightButton: () async {
Navigator.of(context).pop();
await nodeListViewModel.reset();
},
actionLeftButton: () => Navigator.of(context).pop());
});
},
child: Text(
S.of(context).reset,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: Palette.blueCraiola),
)),
),
);
}
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Observer(
builder: (BuildContext context) {
return SectionStandardList(
sectionCount: 2,
context: context,
itemCounter: (int sectionIndex) {
if (sectionIndex == 0) {
return 1;
}
return nodeListViewModel.nodes.length;
},
itemBuilder: (_, sectionIndex, index) {
if (sectionIndex == 0) {
return NodeHeaderListRow(
title: S.of(context).add_new_node,
onTap: (_) async => await Navigator.of(context)
.pushNamed(Routes.newNode));
}
final node = nodeListViewModel.nodes[index];
final isSelected =
node.keyIndex == nodeListViewModel.currentNode.keyIndex;
final nodeListRow = NodeListRow(
title: node.uriRaw,
isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) async {
if (isSelected) {
return;
}
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle:
S.of(context).change_current_node_title,
alertContent: S
.of(context)
.change_current_node(node.uriRaw),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () =>
Navigator.of(context).pop(),
actionRightButton: () async {
await nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop();
});
});
});
final dismissibleRow = Slidable(
key: Key('${node.keyIndex}'),
startActionPane: _actionPane(context, node),
endActionPane: _actionPane(context, node),
child: nodeListRow,
);
return isSelected ? nodeListRow : dismissibleRow;
});
},
),
);
}
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (context) async {
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).remove_node,
alertContent:
S.of(context).remove_node_message,
rightButtonText: S.of(context).remove,
leftButtonText: S.of(context).cancel,
actionRightButton: () =>
Navigator.pop(context, true),
actionLeftButton: () =>
Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
await nodeListViewModel.delete(node);
}
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
}
@@ -0,0 +1,151 @@
import 'package:cake_wallet/core/node_address_validator.dart';
import 'package:cake_wallet/core/node_port_validator.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:mobx/mobx.dart';
class NodeForm extends StatelessWidget {
NodeForm({
required this.nodeViewModel,
required this.formKey,
}) : _addressController = TextEditingController(),
_portController = TextEditingController(),
_loginController = TextEditingController(),
_passwordController = TextEditingController() {
reaction((_) => nodeViewModel.address, (String address) {
if (address != _addressController.text) {
_addressController.text = address;
}
});
reaction((_) => nodeViewModel.port, (String port) {
if (port != _portController.text) {
_portController.text = port;
}
});
if (nodeViewModel.hasAuthCredentials) {
reaction((_) => nodeViewModel.login, (String login) {
if (login != _loginController.text) {
_loginController.text = login;
}
});
reaction((_) => nodeViewModel.password, (String password) {
if (password != _passwordController.text) {
_passwordController.text = password;
}
});
}
_addressController
.addListener(() => nodeViewModel.address = _addressController.text);
_portController
.addListener(() => nodeViewModel.port = _portController.text);
_loginController
.addListener(() => nodeViewModel.login = _loginController.text);
_passwordController
.addListener(() => nodeViewModel.password = _passwordController.text);
}
final NodeCreateOrEditViewModel nodeViewModel;
final GlobalKey<FormState> formKey;
final TextEditingController _addressController;
final TextEditingController _portController;
final TextEditingController _loginController;
final TextEditingController _passwordController;
@override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _addressController,
hintText: S.of(context).node_address,
validator: NodeAddressValidator(),
),
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _portController,
hintText: S.of(context).node_port,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: false),
validator: NodePortValidator(),
))
],
),
SizedBox(height: 10.0),
if (nodeViewModel.hasAuthCredentials) ...[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _loginController,
hintText: S.of(context).login,
))
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _passwordController,
hintText: S.of(context).password,
))
],
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.useSSL,
onChanged: (value) => nodeViewModel.useSSL = value,
caption: S.of(context).use_ssl,
),
)
],
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.trusted,
onChanged: (value) => nodeViewModel.trusted = value,
caption: S.of(context).trusted,
),
),
],
),
),
]
],
),
);
}
}
@@ -37,7 +37,10 @@ class NodeHeaderListRow extends StandardListRow {
@override
Widget buildTrailing(BuildContext context) {
return Icon(Icons.add,
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0);
return SizedBox(
width: 20,
child: Icon(Icons.add,
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0),
);
}
}
@@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
class OrderDetailsPage extends BasePage {
@@ -57,7 +57,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
if (item is TrackTradeListItem) {
return GestureDetector(
onTap: item.onTap,
child: StandartListRow(
child: ListRow(
title: '${item.title}', value: '${item.value}'));
} else {
return GestureDetector(
@@ -65,7 +65,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
Clipboard.setData(ClipboardData(text: '${item.value}'));
showBar<void>(context, S.of(context).copied_to_clipboard);
},
child: StandartListRow(
child: ListRow(
title: '${item.title}', value: '${item.value}'));
}
});
+2 -2
View File
@@ -1,4 +1,5 @@
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -135,8 +136,7 @@ class ReceivePage extends BasePage {
Observer(
builder: (_) => ListView.separated(
padding: EdgeInsets.all(0),
separatorBuilder: (context, _) => Container(
height: 1, color: Theme.of(context).dividerColor),
separatorBuilder: (context, _) => const SectionDivider(),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: addressListViewModel.items.length,
+67 -14
View File
@@ -1,23 +1,28 @@
import 'dart:async';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:uni_links/uni_links.dart';
class Root extends StatefulWidget {
Root(
{required Key key,
required this.authenticationStore,
required this.appStore,
required this.child,
required this.navigatorKey})
: super(key: key);
Root({
required Key key,
required this.authenticationStore,
required this.appStore,
required this.child,
required this.navigatorKey,
required this.authService,
}) : super(key: key);
final AuthenticationStore authenticationStore;
final AppStore appStore;
final GlobalKey<NavigatorState> navigatorKey;
final AuthService authService;
final Widget child;
@override
@@ -26,22 +31,56 @@ class Root extends StatefulWidget {
class RootState extends State<Root> with WidgetsBindingObserver {
RootState()
: _isInactiveController = StreamController<bool>.broadcast(),
_isInactive = false,
_postFrameCallback = false;
: _isInactiveController = StreamController<bool>.broadcast(),
_isInactive = false,
_requestAuth = true,
_postFrameCallback = false;
Stream<bool> get isInactive => _isInactiveController.stream;
StreamController<bool> _isInactiveController;
bool _isInactive;
bool _postFrameCallback;
bool _requestAuth;
StreamSubscription<Uri?>? stream;
Uri? launchUri;
@override
void initState() {
_requestAuth = widget.authService.requireAuth();
_isInactiveController = StreamController<bool>.broadcast();
_isInactive = false;
_postFrameCallback = false;
WidgetsBinding.instance.addObserver(this);
super.initState();
initUniLinks();
}
@override
void dispose() {
stream?.cancel();
super.dispose();
}
/// handle app links while the app is already started
/// whether its in the foreground or in the background.
Future<void> initUniLinks() async {
try {
stream = uriLinkStream.listen((Uri? uri) {
handleDeepLinking(uri);
});
handleDeepLinking(await getInitialUri());
} catch (e) {
print(e);
}
}
void handleDeepLinking(Uri? uri) {
if (uri == null || !mounted) return;
launchUri = uri;
}
@override
@@ -52,11 +91,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
return;
}
if (!_isInactive &&
widget.authenticationStore.state == AuthenticationState.allowed) {
if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) {
setState(() => _setInactive(true));
}
break;
case AppLifecycleState.resumed:
setState(() {
_requestAuth = widget.authService.requireAuth();
});
break;
default:
break;
@@ -65,7 +108,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
@override
Widget build(BuildContext context) {
if (_isInactive && !_postFrameCallback) {
if (_isInactive && !_postFrameCallback && _requestAuth) {
_postFrameCallback = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
@@ -75,9 +118,19 @@ class RootState extends State<Root> with WidgetsBindingObserver {
}
_reset();
auth.close();
auth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
});
});
} else if (launchUri != null) {
widget.navigatorKey.currentState?.pushNamed(
Routes.send,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
}
return WillPopScope(onWillPop: () async => false, child: widget.child);
+11 -16
View File
@@ -1,13 +1,11 @@
import 'dart:ui';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/template_tile.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
@@ -28,13 +26,15 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:cw_core/crypto_currency.dart';
class SendPage extends BasePage {
SendPage({required this.sendViewModel,required this.settingsViewModel }) : _formKey = GlobalKey<FormState>(),fiatFromSettings = settingsViewModel.fiatCurrency;
SendPage({
required this.sendViewModel,
this.initialPaymentRequest,
}) : _formKey = GlobalKey<FormState>();
final SendViewModel sendViewModel;
final SettingsViewModel settingsViewModel;
final GlobalKey<FormState> _formKey;
final controller = PageController(initialPage: 0);
final FiatCurrency fiatFromSettings ;
final PaymentRequest? initialPaymentRequest;
bool _effectsInstalled = false;
@@ -55,7 +55,7 @@ class SendPage extends BasePage {
@override
void onClose(BuildContext context) {
settingsViewModel.setFiatCurrency(fiatFromSettings);
sendViewModel.onClose();
Navigator.of(context).pop();
}
@@ -121,6 +121,7 @@ class SendPage extends BasePage {
key: output.key,
output: output,
sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
);
});
},
@@ -236,7 +237,7 @@ class SendPage extends BasePage {
if(template.isCurrencySelected){
output.setCryptoAmount(template.amount);
}else{
settingsViewModel.setFiatCurrency(fiatFromTemplate);
sendViewModel.setFiatCurrency(fiatFromTemplate);
output.setFiatAmount(template.amountFiat);
}
output.resetParsedAddress();
@@ -386,16 +387,10 @@ class SendPage extends BasePage {
amount: S.of(context).send_amount,
amountValue:
sendViewModel.pendingTransaction!.amountFormatted,
fiatAmountValue:
sendViewModel.pendingTransactionFiatAmount +
' ' +
sendViewModel.fiat.title,
fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted,
fee: S.of(context).send_fee,
feeValue: sendViewModel.pendingTransaction!.feeFormatted,
feeFiatAmount:
sendViewModel.pendingTransactionFeeFiatAmount +
' ' +
sendViewModel.fiat.title,
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
outputs: sendViewModel.outputs,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
@@ -1,4 +1,5 @@
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
@@ -70,10 +71,7 @@ class ChooseYatAddressButtonsState extends State<ChooseYatAddressButtons> {
controller: controller,
padding: EdgeInsets.all(0),
itemCount: itemCount,
separatorBuilder: (_, __) => Container(
height: 1,
color: Theme.of(context).dividerColor,
),
separatorBuilder: (_, __) => const SectionDivider(),
itemBuilder: (context, index) {
final address = addresses[index];
+53 -10
View File
@@ -1,11 +1,11 @@
import 'dart:ui';
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -21,21 +21,28 @@ class SendCard extends StatefulWidget {
SendCard({
Key? key,
required this.output,
required this.sendViewModel}) : super(key: key);
required this.sendViewModel,
this.initialPaymentRequest,
}) : super(key: key);
final Output output;
final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
@override
SendCardState createState() => SendCardState(
output: output,
sendViewModel: sendViewModel
sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
);
}
class SendCardState extends State<SendCard>
with AutomaticKeepAliveClientMixin<SendCard> {
SendCardState({required this.output, required this.sendViewModel})
SendCardState({
required this.output,
required this.sendViewModel,
this.initialPaymentRequest})
: addressController = TextEditingController(),
cryptoAmountController = TextEditingController(),
fiatAmountController = TextEditingController(),
@@ -50,6 +57,7 @@ class SendCardState extends State<SendCard>
final Output output;
final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
final TextEditingController addressController;
final TextEditingController cryptoAmountController;
@@ -62,6 +70,27 @@ class SendCardState extends State<SendCard>
bool _effectsInstalled = false;
@override
void initState() {
super.initState();
/// if the current wallet doesn't match the one in the qr code
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName != initialPaymentRequest!.scheme.toLowerCase()) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: S.of(context).unmatched_currencies,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
});
}
}
@override
Widget build(BuildContext context) {
super.build(context);
@@ -155,6 +184,7 @@ class SendCardState extends State<SendCard>
await output.fetchParsedAddress(context);
},
validator: validator,
selectedCurrency: sendViewModel.currency,
);
}),
if (output.isParsedAddress) Padding(
@@ -332,7 +362,8 @@ class SendCardState extends State<SendCard>
],
),
)),
Padding(
if (!sendViewModel.isFiatDisabled)
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: fiatAmountFocus,
@@ -438,8 +469,9 @@ class SendCardState extends State<SendCard>
Padding(
padding:
EdgeInsets.only(top: 5),
child: Text(
output
child: sendViewModel.isFiatDisabled
? const SizedBox(height: 14)
: Text(output
.estimatedFeeFiatAmount
+ ' ' +
sendViewModel
@@ -510,8 +542,12 @@ class SendCardState extends State<SendCard>
}
void _setEffects(BuildContext context) {
addressController.text = output.address;
cryptoAmountController.text = output.cryptoAmount;
if (output.address.isNotEmpty) {
addressController.text = output.address;
}
if (output.cryptoAmount.isNotEmpty) {
cryptoAmountController.text = output.cryptoAmount;
}
fiatAmountController.text = output.fiatAmount;
noteController.text = output.note;
extractedAddressController.text = output.extractedAddress;
@@ -603,6 +639,13 @@ class SendCardState extends State<SendCard>
extractedAddressController.text = extractedAddress;
});
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName == initialPaymentRequest!.scheme.toLowerCase()) {
addressController.text = initialPaymentRequest!.address;
cryptoAmountController.text = initialPaymentRequest!.amount;
noteController.text = initialPaymentRequest!.note;
}
_effectsInstalled = true;
}
@@ -0,0 +1,155 @@
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/node.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class ConnectionSyncPage extends BasePage {
ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel);
@override
String get title => S.current.connection_sync;
final NodeListViewModel nodeListViewModel;
final DashboardViewModel dashboardViewModel;
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SettingsCellWithArrow(
title: S.current.reconnect,
handler: (context) => _presentReconnectAlert(context),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.rescan,
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
NodeHeaderListRow(
title: S.of(context).add_new_node,
onTap: (_) async => await Navigator.of(context).pushNamed(Routes.newNode),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SizedBox(height: 100),
Observer(
builder: (BuildContext context) {
return Flexible(
child: SectionStandardList(
sectionCount: 1,
context: context,
dividerPadding: EdgeInsets.symmetric(horizontal: 24),
itemCounter: (int sectionIndex) {
return nodeListViewModel.nodes.length;
},
itemBuilder: (_, sectionIndex, index) {
final node = nodeListViewModel.nodes[index];
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
final nodeListRow = NodeListRow(
title: node.uriRaw,
isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) async {
if (isSelected) {
return;
}
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_current_node_title,
alertContent: S.of(context).change_current_node(node.uriRaw),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () async {
await nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop();
},
);
});
},
);
final dismissibleRow = Slidable(
key: Key('${node.keyIndex}'),
startActionPane: _actionPane(context, node),
endActionPane: _actionPane(context, node),
child: nodeListRow,
);
return isSelected ? nodeListRow : dismissibleRow;
},
),
);
},
),
],
),
);
}
Future<void> _presentReconnectAlert(BuildContext context) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).reconnection,
alertContent: S.of(context).reconnect_alert_text,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () async {
Navigator.of(context).pop();
await dashboardViewModel.reconnect();
},
actionLeftButton: () => Navigator.of(context).pop());
},
);
}
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (context) async {
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).remove_node,
alertContent: S.of(context).remove_node_message,
rightButtonText: S.of(context).remove,
leftButtonText: S.of(context).cancel,
actionRightButton: () => Navigator.pop(context, true),
actionLeftButton: () => Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
await nodeListViewModel.delete(node);
}
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
}
@@ -0,0 +1,81 @@
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class DisplaySettingsPage extends BasePage {
DisplaySettingsPage(this._displaySettingsViewModel);
@override
String get title => S.current.display_settings;
final DisplaySettingsViewModel _displaySettingsViewModel;
@override
Widget body(BuildContext context) {
return Observer(builder: (_) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
SettingsSwitcherCell(
title: S.current.settings_display_balance,
value: _displaySettingsViewModel.shouldDisplayBalance,
onValueChange: (_, bool value) {
_displaySettingsViewModel.setShouldDisplayBalance(value);
}),
//if (!isHaven) it does not work correctly
if(!_displaySettingsViewModel.disabledFiatApiMode)
SettingsPickerCell<FiatCurrency>(
title: S.current.settings_currency,
searchHintText: S.current.search_currency,
items: FiatCurrency.all,
selectedItem: _displaySettingsViewModel.fiatCurrency,
onItemSelected: (FiatCurrency currency) => _displaySettingsViewModel.setFiatCurrency(currency),
images: FiatCurrency.all.map((e) => Image.asset("assets/images/flags/${e.countryCode}.png")).toList(),
isGridView: true,
matchingCriteria: (FiatCurrency currency, String searchText) {
return currency.title.toLowerCase().contains(searchText) ||
currency.fullName.toLowerCase().contains(searchText);
},
),
SettingsPickerCell<String>(
title: S.current.settings_change_language,
searchHintText: S.current.search_language,
items: LanguageService.list.keys.toList(),
displayItem: (dynamic code) {
return LanguageService.list[code] ?? '';
},
selectedItem: _displaySettingsViewModel.languageCode,
onItemSelected: _displaySettingsViewModel.onLanguageSelected,
images: LanguageService.list.keys
.map((e) => Image.asset("assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
.toList(),
matchingCriteria: (String code, String searchText) {
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
},
),
SettingsChoicesCell(
ChoicesListItem<ThemeBase>(
title: S.current.color_theme,
items: ThemeList.all,
selectedItem: _displaySettingsViewModel.theme,
onItemSelected: (ThemeBase theme) => _displaySettingsViewModel.setTheme(theme),
),
),
],
),
);
});
}
}
@@ -0,0 +1,45 @@
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class OtherSettingsPage extends BasePage {
OtherSettingsPage(this._otherSettingsViewModel);
@override
String get title => S.current.other_settings;
final OtherSettingsViewModel _otherSettingsViewModel;
@override
Widget body(BuildContext context) {
return Observer(builder: (_) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(children: [
SettingsPickerCell(
title: S.current.settings_fee_priority,
items: priorityForWalletType(_otherSettingsViewModel.walletType),
displayItem: _otherSettingsViewModel.getDisplayPriority,
selectedItem: _otherSettingsViewModel.transactionPriority,
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
),
SettingsCellWithArrow(
title: S.current.settings_terms_and_conditions,
handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.readDisclaimer),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
Spacer(),
SettingsVersionCell(title: S.of(context).version(_otherSettingsViewModel.currentVersion))
]),
);
});
}
}
@@ -0,0 +1,47 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class PrivacyPage extends BasePage {
PrivacyPage(this._privacySettingsViewModel);
@override
String get title => S.current.privacy_settings;
final PrivacySettingsViewModel _privacySettingsViewModel;
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Observer(builder: (_) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SettingsSwitcherCell(
title: S.current.disable_fiat,
value: _privacySettingsViewModel.isFiatDisabled,
onValueChange: (BuildContext context, bool value) {
_privacySettingsViewModel.setFiatMode(value);
}),
SettingsSwitcherCell(
title: S.current.disable_exchange,
value: _privacySettingsViewModel.disableExchange,
onValueChange: (BuildContext context, bool value) {
_privacySettingsViewModel.setEnableExchange(value);
}),
SettingsSwitcherCell(
title: S.current.settings_save_recipient_address,
value: _privacySettingsViewModel.shouldSaveRecipientAddress,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setShouldSaveRecipientAddress(value);
})
],
);
}),
);
}
}
@@ -0,0 +1,102 @@
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class SecurityBackupPage extends BasePage {
SecurityBackupPage(this._securitySettingsViewModel);
@override
String get title => S.current.security_and_backup;
final SecuritySettingsViewModel _securitySettingsViewModel;
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(mainAxisSize: MainAxisSize.min, children: [
SettingsCellWithArrow(
title: S.current.show_keys,
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
? Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route: Routes.showKeys);
}
})
: Navigator.of(context).pushNamed(Routes.showKeys),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.create_backup,
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
? Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route: Routes.backup);
}
})
: Navigator.of(context).pushNamed(Routes.backup),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.settings_change_pin,
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
auth.close(
route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
setupPinContext.close();
},
);
})),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.settings_allow_biometrical_authentication,
value: _securitySettingsViewModel.allowBiometricalAuthentication,
onValueChange: (BuildContext context, bool value) {
if (value) {
Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (isAuthenticatedSuccessfully) {
if (await _securitySettingsViewModel.biometricAuthenticated()) {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
} else {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
auth.close();
});
} else {
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
}
});
}),
Observer(builder: (_) {
return SettingsPickerCell<PinCodeRequiredDuration>(
title: S.current.require_pin_after,
items: PinCodeRequiredDuration.values,
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
onItemSelected: (PinCodeRequiredDuration code) {
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
},
);
}),
]),
);
}
}
-98
View File
@@ -1,98 +0,0 @@
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/link_list_item.dart';
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/switcher_list_item.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_link_provider_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
class SettingsPage extends BasePage {
SettingsPage(this.settingsViewModel);
final SettingsViewModel settingsViewModel;
@override
String get title => S.current.settings_title;
@override
Widget body(BuildContext context) {
// FIX-ME: Added `context` it was not used here before, maby bug ?
return SectionStandardList(
context: context,
sectionCount: settingsViewModel.sections.length,
itemCounter: (int sectionIndex) {
if (sectionIndex < settingsViewModel.sections.length) {
return settingsViewModel.sections[sectionIndex].length;
}
return 0;
},
itemBuilder: (_, sectionIndex, itemIndex) {
final item = settingsViewModel.sections[sectionIndex][itemIndex];
if (item is PickerListItem) {
return Observer(builder: (_) {
return SettingsPickerCell<Object>(
displayItem: item.displayItem,
title: item.title,
selectedItem: item.selectedItem(),
items: item.items,
onItemSelected: (dynamic value) => item.onItemSelected(value),
images: item.images,
searchHintText: item.searchHintText,
isGridView: item.isGridView,
matchingCriteria: (dynamic value, String searchText) => item.matchingCriteria(value, searchText),
);
});
}
if (item is SwitcherListItem) {
return Observer(builder: (_) {
return SettingsSwitcherCell(
title: item.title,
value: item.value(),
onValueChange: item.onValueChange);
});
}
if (item is RegularListItem) {
return SettingsCellWithArrow(
title: item.title, handler: item.handler);
}
if (item is LinkListItem) {
return SettingsLinkProviderCell(
title: item.title,
icon: item.icon,
link: item.link,
linkTitle: item.linkTitle);
}
if (item is VersionListItem) {
return Observer(builder: (_) {
return SettingsVersionCell(
title:
S.of(context).version(settingsViewModel.currentVersion));
});
}
if (item is ChoicesListItem) {
return SettingsChoicesCell(item);
}
return Container();
});
}
}
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
class SettingsPickerCell<ItemType extends Object> extends StandardListRow {
class SettingsPickerCell<ItemType> extends StandardListRow {
SettingsPickerCell(
{required String title,
required this.selectedItem,
@@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standart_switch.dart';
import 'package:cake_wallet/src/widgets/standard_switch.dart';
class SettingsSwitcherCell extends StandardListRow {
SettingsSwitcherCell(
@@ -11,6 +11,6 @@ class SettingsSwitcherCell extends StandardListRow {
final void Function(BuildContext context, bool value)? onValueChange;
@override
Widget buildTrailing(BuildContext context) => StandartSwitch(
Widget buildTrailing(BuildContext context) => StandardSwitch(
value: value, onTaped: () => onValueChange?.call(context, !value));
}
@@ -1,6 +1,6 @@
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standart_list_card.dart';
import 'package:cake_wallet/src/widgets/standart_list_status_row.dart';
import 'package:cake_wallet/src/widgets/standard_list_card.dart';
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/trade_details_view_model.dart';
import 'package:flutter/material.dart';
@@ -9,7 +9,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
@@ -62,18 +62,18 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
if (item is TrackTradeListItem) {
return GestureDetector(
onTap: item.onTap,
child: StandartListRow(
child: ListRow(
title: '${item.title}', value: '${item.value}'));
}
if (item is DetailsListStatusItem) {
return StandartListStatusRow(
return StandardListStatusRow(
title: item.title,
value: item.value);
}
if (item is TradeDetailsListCardItem) {
return TradeDatailsStandartListCard(
return TradeDetailsStandardListCard(
id: item.id,
create: item.createdAt,
pair: item.pair,
@@ -86,7 +86,7 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
Clipboard.setData(ClipboardData(text: '${item.value}'));
showBar<void>(context, S.of(context).copied_to_clipboard);
},
child: StandartListRow(
child: ListRow(
title: '${item.title}', value: '${item.value}'));
});
});
@@ -6,7 +6,7 @@ import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
@@ -42,7 +42,7 @@ class TransactionDetailsPage extends BasePage {
S.of(context).transaction_details_copied(item.title));
},
child:
StandartListRow(title: '${item.title}:', value: item.value),
ListRow(title: '${item.title}:', value: item.value),
);
}
@@ -50,7 +50,7 @@ class TransactionDetailsPage extends BasePage {
return GestureDetector(
onTap: item.onTap,
child:
StandartListRow(title: '${item.title}:', value: item.value),
ListRow(title: '${item.title}:', value: item.value),
);
}
@@ -5,7 +5,7 @@ import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_details_view_model.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_switch_item.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -30,7 +30,7 @@ class UnspentCoinsDetailsPage extends BasePage {
final item = unspentCoinsDetailsViewModel.items[index];
if (item is StandartListItem) {
return StandartListRow(
return ListRow(
title: '${item.title}:',
value: item.value);
}
@@ -1,4 +1,4 @@
import 'package:cake_wallet/src/widgets/standart_switch.dart';
import 'package:cake_wallet/src/widgets/standard_switch.dart';
import 'package:flutter/material.dart';
class UnspentCoinsSwitchRow extends StatelessWidget {
@@ -33,7 +33,7 @@ class UnspentCoinsSwitchRow extends StatelessWidget {
textAlign: TextAlign.left),
Padding(
padding: EdgeInsets.only(top: 12),
child: StandartSwitch(
child: StandardSwitch(
value: switchValue,
onTaped: () => onSwitchValueChange(!switchValue))
)
@@ -1,4 +1,5 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -6,7 +7,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
class WalletKeysPage extends BasePage {
@@ -57,10 +58,7 @@ class WalletKeysPage extends BasePage {
height: 1,
padding: EdgeInsets.only(left: 24),
color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!,
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
child: const SectionDivider(),
),
itemCount: walletKeysViewModel.items.length,
itemBuilder: (BuildContext context, int index) {
@@ -71,7 +69,7 @@ class WalletKeysPage extends BasePage {
Clipboard.setData(ClipboardData(text: item.value));
showBar<void>(context, S.of(context).copied_key_to_clipboard(item.title));
},
child: StandartListRow(
child: ListRow(
title: item.title + ':',
value: item.value,
),
@@ -220,68 +220,88 @@ class WalletListBodyState extends State<WalletListBody> {
}
Future<void> _loadWallet(WalletListItem wallet) async {
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
}
if (await widget.walletListViewModel.checkIfAuthRequired()) {
await Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
}
try {
auth.changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
await widget.walletListViewModel.loadWallet(wallet);
auth.hideProgressText();
auth.close();
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop();
});
} catch (e) {
auth.changeProcessText(
S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
}
});
} else {
try {
auth.changeProcessText(
S.of(context).wallet_list_loading_wallet(wallet.name));
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
await widget.walletListViewModel.loadWallet(wallet);
auth.hideProgressText();
auth.close();
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop();
});
hideProgressText();
Navigator.of(context).pop();
} catch (e) {
auth.changeProcessText(S
.of(context)
.wallet_list_failed_to_load(wallet.name, e.toString()));
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
}
});
}
}
Future<void> _removeWallet(WalletListItem wallet) async {
await Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
}
bool confirmed = false;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).delete_wallet,
alertContent: S.of(context).delete_wallet_confirm_message(wallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).delete,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () {
confirmed = true;
Navigator.of(context).pop();
},
);
});
if (confirmed) {
try {
auth.changeProcessText(
S.of(context).wallet_list_removing_wallet(wallet.name));
await widget.walletListViewModel.remove(wallet);
} catch (e) {
auth.changeProcessText(S
.of(context)
.wallet_list_failed_to_remove(wallet.name, e.toString()));
if (widget.walletListViewModel.checkIfAuthRequired()) {
await Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
return;
}
}
_onSuccessfulAuth(wallet, auth);
});
} else {
_onSuccessfulAuth(wallet, null);
}
}
auth.close();
});
void _onSuccessfulAuth(WalletListItem wallet, AuthPageState? auth) async {
bool confirmed = false;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).delete_wallet,
alertContent: S.of(context).delete_wallet_confirm_message(wallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).delete,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () {
confirmed = true;
Navigator.of(context).pop();
},
);
});
if (confirmed) {
try {
auth != null
? auth.changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name))
: changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name));
await widget.walletListViewModel.remove(wallet);
} catch (e) {
auth != null
? auth.changeProcessText(
S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()),
)
: changeProcessText(
S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()),
);
}
}
auth?.close();
}
void changeProcessText(String text) {
@@ -294,16 +314,16 @@ class WalletListBodyState extends State<WalletListBody> {
}
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (_) => _removeWallet(wallet),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (_) => _removeWallet(wallet),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
}
+5 -2
View File
@@ -4,6 +4,7 @@ import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:cake_wallet/entities/contact_base.dart';
import 'package:cw_core/crypto_currency.dart';
enum AddressTextFieldOption { paste, qrCode, addressBook }
@@ -26,7 +27,8 @@ class AddressTextField extends StatelessWidget {
this.hintStyle,
this.validator,
this.onPushPasteButton,
this.onPushAddressBookButton});
this.onPushAddressBookButton,
this.selectedCurrency});
static const prefixIconWidth = 34.0;
static const prefixIconHeight = 34.0;
@@ -47,6 +49,7 @@ class AddressTextField extends StatelessWidget {
final FocusNode? focusNode;
final Function(BuildContext context)? onPushPasteButton;
final Function(BuildContext context)? onPushAddressBookButton;
final CryptoCurrency? selectedCurrency;
@override
Widget build(BuildContext context) {
@@ -207,7 +210,7 @@ class AddressTextField extends StatelessWidget {
Future<void> _presetAddressBookPicker(BuildContext context) async {
final contact = await Navigator.of(context, rootNavigator: true)
.pushNamed(Routes.pickerAddressBook);
.pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency);
if (contact is ContactBase && contact.address != null) {
controller?.text = contact.address;
+4 -12
View File
@@ -1,4 +1,5 @@
import 'dart:ui';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
@@ -76,10 +77,7 @@ class BaseAlertDialog extends StatelessWidget {
),
)),
),
Container(
width: 1,
color: Theme.of(context).dividerColor,
),
const SectionDivider(),
Expanded(
child: TextButton(
onPressed: actionRight,
@@ -140,10 +138,7 @@ class BaseAlertDialog extends StatelessWidget {
isDividerExists
? Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
child: const SectionDivider(),
)
: Offstage(),
Padding(
@@ -152,10 +147,7 @@ class BaseAlertDialog extends StatelessWidget {
)
],
),
Container(
height: 1,
color: Theme.of(context).dividerColor,
),
const SectionDivider(),
actionButtons(context)
],
),
@@ -1,8 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class StandartListRow extends StatelessWidget {
StandartListRow(
class ListRow extends StatelessWidget {
ListRow(
{required this.title,
required this.value,
this.titleFontSize = 14,
+4 -5
View File
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
class Picker<Item extends Object> extends StatefulWidget {
class Picker<Item> extends StatefulWidget {
Picker({
required this.selectedAtIndex,
required this.items,
@@ -39,7 +39,7 @@ class Picker<Item extends Object> extends StatefulWidget {
_PickerState<Item> createState() => _PickerState<Item>(items, images, onItemSelected);
}
class _PickerState<Item> extends State<Picker> {
class _PickerState<Item> extends State<Picker<Item>> {
_PickerState(this.items, this.images, this.onItemSelected);
final Function(Item) onItemSelected;
@@ -59,7 +59,7 @@ class _PickerState<Item> extends State<Picker> {
images = [];
for (int i=0;i<widget.items.length;i++) {
if (widget.matchingCriteria?.call(widget.items[i], searchController.text) ?? true) {
items.add(widget.items[i] as Item);
items.add(widget.items[i]);
images.add(widget.images[i]);
}
}
@@ -238,8 +238,7 @@ class _PickerState<Item> extends State<Picker> {
child: Padding(
padding: EdgeInsets.only(left: image != null ? 12 : 0),
child: Text(
// What a hack (item as) ?
widget.displayItem?.call(item as Object) ?? item.toString(),
widget.displayItem?.call(item) ?? item.toString(),
style: TextStyle(
fontSize: 14,
fontFamily: 'Lato',
+13
View File
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class SectionDivider extends StatelessWidget {
const SectionDivider();
@override
Widget build(BuildContext context) {
return Container(
height: 1,
color: Theme.of(context).dividerColor,
);
}
}
+44 -57
View File
@@ -2,42 +2,42 @@ import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class StandardCheckbox extends StatefulWidget {
StandardCheckbox({
Key? key,
required this.value,
this.caption = '',
required this.onChanged})
: super(key: key);
class StandardCheckbox extends StatelessWidget {
StandardCheckbox(
{required this.value,
this.caption = '',
this.gradientBackground = false,
this.borderColor,
this.iconColor,
required this.onChanged});
final bool value;
final String caption;
final bool gradientBackground;
final Color? borderColor;
final Color? iconColor;
final Function(bool) onChanged;
@override
StandardCheckboxState createState() =>
StandardCheckboxState(value, caption, onChanged);
}
class StandardCheckboxState extends State<StandardCheckbox> {
StandardCheckboxState(this.value, this.caption, this.onChanged);
bool value;
String caption;
Function(bool) onChanged;
void changeValue(bool newValue) {
setState(() => value = newValue);
}
@override
Widget build(BuildContext context) {
final baseGradient = LinearGradient(colors: [
Theme.of(context).primaryTextTheme.subtitle1!.color!,
Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
], begin: Alignment.centerLeft, end: Alignment.centerRight);
final boxBorder = Border.all(
color: borderColor ?? Theme.of(context).primaryTextTheme.caption!.color!, width: 1.0);
final checkedBoxDecoration = BoxDecoration(
gradient: gradientBackground ? baseGradient : null,
border: gradientBackground ? null : boxBorder,
borderRadius: BorderRadius.all(Radius.circular(8.0)));
final uncheckedBoxDecoration =
BoxDecoration(border: boxBorder, borderRadius: BorderRadius.all(Radius.circular(8.0)));
return GestureDetector(
onTap: () {
value = !value;
onChanged(value);
setState(() {});
},
onTap: () => onChanged(!value),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
@@ -45,38 +45,25 @@ class StandardCheckboxState extends State<StandardCheckbox> {
Container(
height: 24.0,
width: 24.0,
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.primaryTextTheme!
.caption!
.color!,
width: 1.0),
borderRadius: BorderRadius.all(
Radius.circular(8.0)),
color: Theme.of(context).backgroundColor),
decoration: value ? checkedBoxDecoration : uncheckedBoxDecoration,
child: value
? Icon(
Icons.check,
color: Colors.blue,
size: 20.0,
)
: Offstage(),
? Icon(
Icons.check,
color: iconColor ?? Colors.blue,
size: 20.0,
)
: Offstage(),
),
if (caption.isNotEmpty) Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
caption,
style: TextStyle(
fontSize: 16.0,
color: Theme.of(context)
.primaryTextTheme!
.headline6!
.color!),
)
)
if (caption.isNotEmpty)
Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
caption,
style: TextStyle(
fontSize: 16.0, color: Theme.of(context).primaryTextTheme!.headline6!.color!),
))
],
),
);
}
}
}
+6 -4
View File
@@ -1,6 +1,6 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/widgets/standart_list_card.dart';
import 'package:cake_wallet/src/widgets/standart_list_status_row.dart';
import 'package:cake_wallet/src/widgets/standard_list_card.dart';
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
import 'package:flutter/material.dart';
class StandardListRow extends StatelessWidget {
@@ -123,6 +123,7 @@ class SectionStandardList extends StatelessWidget {
required this.itemBuilder,
required this.sectionCount,
required BuildContext context,
this.dividerPadding = const EdgeInsets.only(left: 24),
this.themeColor,
this.dividerThemeColor,
this.sectionTitleBuilder,
@@ -149,6 +150,7 @@ class SectionStandardList extends StatelessWidget {
final List<Widget> totalRows;
final Color? themeColor;
final Color? dividerThemeColor;
final EdgeInsets dividerPadding;
List<Widget> transform(
bool hasTopSeparator,
@@ -178,7 +180,7 @@ class SectionStandardList extends StatelessWidget {
items.add(sectionIndex + 1 != sectionCount
? SectionHeaderListRow()
: StandardListSeparator(padding: EdgeInsets.only(left: 24)));
: StandardListSeparator(padding: dividerPadding));
}
return items;
@@ -215,7 +217,7 @@ class SectionStandardList extends StatelessWidget {
return Container();
}
if (row is StandartListStatusRow || row is TradeDatailsStandartListCard) {
if (row is StandardListStatusRow || row is TradeDetailsStandardListCard) {
return Container();
}
@@ -2,8 +2,8 @@ import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/themes/theme_base.dart';
class TradeDatailsStandartListCard extends StatelessWidget {
TradeDatailsStandartListCard(
class TradeDetailsStandardListCard extends StatelessWidget {
TradeDetailsStandardListCard(
{required this.id,
required this.create,
required this.pair,
@@ -3,8 +3,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.da
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class StandartListStatusRow extends StatelessWidget {
StandartListStatusRow({required this.title, required this.value});
class StandardListStatusRow extends StatelessWidget {
StandardListStatusRow({required this.title, required this.value});
final String title;
final String value;
@@ -1,17 +1,17 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class StandartSwitch extends StatefulWidget {
const StandartSwitch({required this.value, required this.onTaped});
class StandardSwitch extends StatefulWidget {
const StandardSwitch({required this.value, required this.onTaped});
final bool value;
final VoidCallback onTaped;
@override
StandartSwitchState createState() => StandartSwitchState();
StandardSwitchState createState() => StandardSwitchState();
}
class StandartSwitchState extends State<StandartSwitch> {
class StandardSwitchState extends State<StandardSwitch> {
@override
Widget build(BuildContext context) {
return GestureDetector(