mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-19 05:58:50 +02:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-269-research-if-we-can-avoid-re-requesting-camera-permission-on-web-view-in-buy-screen
This commit is contained in:
@@ -24,7 +24,6 @@ class AddressValidator extends TextValidator {
|
||||
return '[0-9a-zA-Z_]';
|
||||
case CryptoCurrency.usdc:
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.ape:
|
||||
case CryptoCurrency.avaxc:
|
||||
case CryptoCurrency.eth:
|
||||
@@ -156,7 +155,7 @@ class AddressValidator extends TextValidator {
|
||||
return [98, 99, 106];
|
||||
case CryptoCurrency.btt:
|
||||
return [34];
|
||||
case CryptoCurrency.bttbsc:
|
||||
case CryptoCurrency.bttc:
|
||||
return [34];
|
||||
case CryptoCurrency.doge:
|
||||
return [34];
|
||||
@@ -181,7 +180,6 @@ class AddressValidator extends TextValidator {
|
||||
case CryptoCurrency.stx:
|
||||
return [40, 41, 42];
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.mana:
|
||||
case CryptoCurrency.matic:
|
||||
case CryptoCurrency.maticpoly:
|
||||
|
||||
@@ -4,12 +4,19 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/entities/encrypt.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
|
||||
class AuthService with Store {
|
||||
AuthService({required this.secureStorage, required this.sharedPreferences});
|
||||
AuthService({
|
||||
required this.secureStorage,
|
||||
required this.sharedPreferences,
|
||||
required this.settingsStore,
|
||||
});
|
||||
|
||||
final FlutterSecureStorage secureStorage;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
Future<void> setPassword(String password) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
@@ -19,8 +26,7 @@ class AuthService with Store {
|
||||
|
||||
Future<bool> canAuthenticate() async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final walletName =
|
||||
sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
|
||||
final walletName = sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
|
||||
var password = '';
|
||||
|
||||
try {
|
||||
@@ -39,4 +45,25 @@ class AuthService with Store {
|
||||
|
||||
return decodedPin == pin;
|
||||
}
|
||||
|
||||
void saveLastAuthTime() {
|
||||
int timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
sharedPreferences.setInt(PreferencesKey.lastAuthTimeMilliseconds, timestamp);
|
||||
}
|
||||
|
||||
bool requireAuth() {
|
||||
final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds);
|
||||
final duration = _durationToRequireAuth(timestamp ?? 0);
|
||||
final requiredPinInterval = settingsStore.pinTimeOutDuration;
|
||||
|
||||
return duration >= requiredPinInterval.value;
|
||||
}
|
||||
|
||||
int _durationToRequireAuth(int timestamp) {
|
||||
DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||
DateTime now = DateTime.now();
|
||||
Duration timeDifference = now.difference(before);
|
||||
|
||||
return timeDifference.inMinutes;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-7
@@ -13,6 +13,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
|
||||
@@ -308,7 +309,10 @@ Future setup(
|
||||
|
||||
getIt.registerFactory<AuthService>(() => AuthService(
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>()));
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
|
||||
getIt.get<AuthService>(),
|
||||
@@ -384,8 +388,11 @@ Future setup(
|
||||
getIt.get<BalanceViewModel>(),
|
||||
_transactionDescriptionBox));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SendPage(sendViewModel: getIt.get<SendViewModel>()));
|
||||
getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
|
||||
(PaymentRequest? initialPaymentRequest, _) => SendPage(
|
||||
sendViewModel: getIt.get<SendViewModel>(),
|
||||
initialPaymentRequest: initialPaymentRequest,
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => SendTemplatePage(
|
||||
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||
@@ -393,7 +400,10 @@ Future setup(
|
||||
getIt.registerFactory(() => WalletListViewModel(
|
||||
_walletInfoSource,
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletLoadingService>()));
|
||||
getIt.get<WalletLoadingService>(),
|
||||
getIt.get<AuthService>(),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
|
||||
@@ -453,7 +463,7 @@ Future setup(
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return SecuritySettingsViewModel(getIt.get<SettingsStore>());
|
||||
return SecuritySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AuthService>());
|
||||
});
|
||||
|
||||
getIt
|
||||
@@ -785,7 +795,8 @@ Future setup(
|
||||
return IoniaMoreOptionsPage(giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
|
||||
=> IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
@@ -823,4 +834,4 @@ Future setup(
|
||||
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,10 @@ Future defaultSettingsMigration(
|
||||
await addOnionNode(nodes);
|
||||
break;
|
||||
|
||||
case 19:
|
||||
await validateBitcoinSavedTransactionPriority(sharedPreferences);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -154,6 +158,18 @@ Future defaultSettingsMigration(
|
||||
PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
}
|
||||
|
||||
Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async {
|
||||
if (bitcoin == null) {
|
||||
return;
|
||||
}
|
||||
final int? savedBitcoinPriority =
|
||||
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority);
|
||||
if (!bitcoin!.getTransactionPriorities().any((element) => element.raw == savedBitcoinPriority)) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.bitcoinTransactionPriority, bitcoin!.getMediumTransactionPriority().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addOnionNode(Box<Node> nodes) async {
|
||||
final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081";
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ class LanguageService {
|
||||
'uk': 'Українська (Ukrainian)',
|
||||
'zh': '中文 (Chinese)',
|
||||
'hr': 'Hrvatski (Croatian)',
|
||||
'it': 'Italiano (Italian)'
|
||||
'it': 'Italiano (Italian)',
|
||||
'th': 'ภาษาไทย (Thai)',
|
||||
'ar': 'العربية (Arabic)'
|
||||
};
|
||||
|
||||
static const Map<String, String> localeCountryCode = {
|
||||
@@ -36,7 +38,9 @@ class LanguageService {
|
||||
'uk': 'ukr',
|
||||
'zh': 'chn',
|
||||
'hr': 'hrv',
|
||||
'it': 'ita'
|
||||
'it': 'ita',
|
||||
'th': 'tha',
|
||||
'ar': 'sau'
|
||||
};
|
||||
|
||||
static final list = <String, String> {};
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
enum PinCodeRequiredDuration {
|
||||
always(0),
|
||||
tenminutes(10),
|
||||
onehour(60);
|
||||
|
||||
const PinCodeRequiredDuration(this.value);
|
||||
final int value;
|
||||
|
||||
static PinCodeRequiredDuration deserialize({required int raw}) =>
|
||||
PinCodeRequiredDuration.values.firstWhere((e) => e.value == raw);
|
||||
|
||||
@override
|
||||
String toString(){
|
||||
String label = '';
|
||||
switch (this) {
|
||||
case PinCodeRequiredDuration.always:
|
||||
label = S.current.always;
|
||||
break;
|
||||
case PinCodeRequiredDuration.tenminutes:
|
||||
label = S.current.minutes_to_pin_code('10');
|
||||
break;
|
||||
case PinCodeRequiredDuration.onehour:
|
||||
label = S.current.minutes_to_pin_code('60');
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,9 @@ class PreferencesKey {
|
||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
static const pinTimeOutDuration = 'pin_timeout_duration';
|
||||
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
|
||||
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name)
|
||||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||
|
||||
@@ -24,6 +24,9 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
||||
static const simpleSwap =
|
||||
ExchangeProviderDescription(title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png');
|
||||
|
||||
static const all =
|
||||
ExchangeProviderDescription(title: 'All trades', raw: 5, image:'');
|
||||
|
||||
static ExchangeProviderDescription deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
@@ -36,6 +39,8 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
||||
return sideShift;
|
||||
case 4:
|
||||
return simpleSwap;
|
||||
case 5:
|
||||
return all;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.xhv,
|
||||
CryptoCurrency.dcr,
|
||||
CryptoCurrency.husd,
|
||||
CryptoCurrency.kmd,
|
||||
CryptoCurrency.mkr,
|
||||
CryptoCurrency.near,
|
||||
@@ -38,6 +37,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
CryptoCurrency.rvn,
|
||||
CryptoCurrency.scrt,
|
||||
CryptoCurrency.stx,
|
||||
CryptoCurrency.bttc,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
|
||||
@@ -37,7 +37,7 @@ class IoniaGiftCard {
|
||||
purchaseAmount: element['PurchaseAmount'] as double,
|
||||
actualAmount: element['ActualAmount'] as double,
|
||||
totalTransactionAmount: element['TotalTransactionAmount'] as double,
|
||||
totalDashTransactionAmount: element['TotalDashTransactionAmount'] as double,
|
||||
totalDashTransactionAmount: (element['TotalDashTransactionAmount'] as double?) ?? 0.0,
|
||||
remainingAmount: element['RemainingAmount'] as double,
|
||||
isActive: element['IsActive'] as bool,
|
||||
isEmpty: element['IsEmpty'] as bool,
|
||||
|
||||
@@ -148,8 +148,8 @@ class IoniaService {
|
||||
|
||||
// Redeem
|
||||
|
||||
Future<void> redeem(IoniaGiftCard giftCard) async {
|
||||
await chargeGiftCard(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
|
||||
Future<void> redeem({required int giftCardId, required double amount}) async {
|
||||
await chargeGiftCard(giftCardId: giftCardId, amount: amount);
|
||||
}
|
||||
|
||||
// Get Gift Card
|
||||
|
||||
+6
-7
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||
@@ -40,6 +41,7 @@ import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
final rootKey = GlobalKey<RootState>();
|
||||
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
|
||||
|
||||
Future<void> main() async {
|
||||
try {
|
||||
@@ -127,7 +129,7 @@ Future<void> main() async {
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
initialMigrationVersion: 18);
|
||||
initialMigrationVersion: 19);
|
||||
runApp(App());
|
||||
} catch (e, stacktrace) {
|
||||
runApp(MaterialApp(
|
||||
@@ -203,12 +205,6 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
//_handleInitialUri();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stream?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _handleInitialUri() async {
|
||||
try {
|
||||
final uri = await getInitialUri();
|
||||
@@ -256,6 +252,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(builder: (BuildContext context) {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final authService = getIt.get<AuthService>();
|
||||
final settingsStore = appStore.settingsStore;
|
||||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
@@ -280,7 +277,9 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
appStore: appStore,
|
||||
authenticationStore: authenticationStore,
|
||||
navigatorKey: navigatorKey,
|
||||
authService: authService,
|
||||
child: MaterialApp(
|
||||
navigatorObservers: [routeObserver],
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: settingsStore.theme,
|
||||
|
||||
+6
-1
@@ -25,6 +25,7 @@ import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.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';
|
||||
@@ -216,8 +217,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
builder: (_) => getIt.get<DashboardPage>());
|
||||
|
||||
case Routes.send:
|
||||
final initialPaymentRequest = settings.arguments as PaymentRequest?;
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>());
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>(
|
||||
param1: initialPaymentRequest,
|
||||
));
|
||||
|
||||
case Routes.sendTemplate:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
||||
@@ -72,10 +72,10 @@ class ContactListPage extends BasePage {
|
||||
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(
|
||||
|
||||
@@ -21,6 +21,12 @@ class WalletMenu {
|
||||
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:
|
||||
@@ -29,18 +35,12 @@ class WalletMenu {
|
||||
Navigator.of(context).pushNamed(Routes.securityBackupPage);
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.privacy,
|
||||
title: S.current.privacy_settings,
|
||||
image:
|
||||
Image.asset('assets/images/eye_menu.png', height: 16, width: 16),
|
||||
Image.asset('assets/images/privacy_menu.png', height: 16, width: 16),
|
||||
handler: () {
|
||||
Navigator.of(context).pushNamed(Routes.privacyPage);
|
||||
}),
|
||||
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.display_settings,
|
||||
image: Image.asset('assets/images/eye_menu.png',
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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}'));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -4,6 +4,7 @@ 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:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
@@ -25,11 +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}) : _formKey = GlobalKey<FormState>();
|
||||
SendPage({
|
||||
required this.sendViewModel,
|
||||
this.initialPaymentRequest,
|
||||
}) : _formKey = GlobalKey<FormState>();
|
||||
|
||||
final SendViewModel sendViewModel;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final controller = PageController(initialPage: 0);
|
||||
final PaymentRequest? initialPaymentRequest;
|
||||
|
||||
bool _effectsInstalled = false;
|
||||
|
||||
@@ -116,6 +121,7 @@ class SendPage extends BasePage {
|
||||
key: output.key,
|
||||
output: output,
|
||||
sendViewModel: sendViewModel,
|
||||
initialPaymentRequest: initialPaymentRequest,
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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';
|
||||
@@ -20,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(),
|
||||
@@ -49,6 +57,7 @@ class SendCardState extends State<SendCard>
|
||||
|
||||
final Output output;
|
||||
final SendViewModel sendViewModel;
|
||||
final PaymentRequest? initialPaymentRequest;
|
||||
|
||||
final TextEditingController addressController;
|
||||
final TextEditingController cryptoAmountController;
|
||||
@@ -61,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);
|
||||
@@ -512,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;
|
||||
@@ -605,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
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';
|
||||
@@ -25,22 +27,26 @@ class SecurityBackupPage extends BasePage {
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.showKeys);
|
||||
}
|
||||
}),
|
||||
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: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.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(
|
||||
@@ -65,10 +71,12 @@ class SecurityBackupPage extends BasePage {
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
_securitySettingsViewModel
|
||||
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
_securitySettingsViewModel
|
||||
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
|
||||
auth.close();
|
||||
@@ -78,6 +86,16 @@ class SecurityBackupPage extends BasePage {
|
||||
}
|
||||
});
|
||||
}),
|
||||
Observer(builder: (_) {
|
||||
return SettingsPickerCell<PinCodeRequiredDuration>(
|
||||
title: S.current.require_pin_after,
|
||||
items: PinCodeRequiredDuration.values,
|
||||
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
|
||||
onItemSelected: (PinCodeRequiredDuration code) {
|
||||
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
|
||||
},
|
||||
);
|
||||
}),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,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',
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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!),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -217,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,
|
||||
+2
-2
@@ -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(
|
||||
@@ -8,12 +8,11 @@ part'trade_filter_store.g.dart';
|
||||
class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
|
||||
|
||||
abstract class TradeFilterStoreBase with Store {
|
||||
TradeFilterStoreBase(
|
||||
{this.displayXMRTO = true,
|
||||
this.displayChangeNow = true,
|
||||
this.displayMorphToken = true,
|
||||
this.displaySimpleSwap = true,
|
||||
});
|
||||
TradeFilterStoreBase() : displayXMRTO = true,
|
||||
displayChangeNow = true,
|
||||
displaySideShift = true,
|
||||
displayMorphToken = true,
|
||||
displaySimpleSwap = true;
|
||||
|
||||
@observable
|
||||
bool displayXMRTO;
|
||||
@@ -21,26 +20,50 @@ abstract class TradeFilterStoreBase with Store {
|
||||
@observable
|
||||
bool displayChangeNow;
|
||||
|
||||
@observable
|
||||
bool displaySideShift;
|
||||
|
||||
@observable
|
||||
bool displayMorphToken;
|
||||
|
||||
@observable
|
||||
bool displaySimpleSwap;
|
||||
|
||||
@computed
|
||||
bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap;
|
||||
|
||||
@action
|
||||
void toggleDisplayExchange(ExchangeProviderDescription provider) {
|
||||
switch (provider) {
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
displayChangeNow = !displayChangeNow;
|
||||
break;
|
||||
case ExchangeProviderDescription.sideShift:
|
||||
displaySideShift = !displaySideShift;
|
||||
break;
|
||||
case ExchangeProviderDescription.simpleSwap:
|
||||
displaySimpleSwap = !displaySimpleSwap;
|
||||
break;
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
displayXMRTO = !displayXMRTO;
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
displayMorphToken = !displayMorphToken;
|
||||
break;
|
||||
case ExchangeProviderDescription.simpleSwap:
|
||||
displaySimpleSwap = !displaySimpleSwap;
|
||||
case ExchangeProviderDescription.all:
|
||||
if (displayAllTrades) {
|
||||
displayChangeNow = false;
|
||||
displaySideShift = false;
|
||||
displayXMRTO = false;
|
||||
displayMorphToken = false;
|
||||
displaySimpleSwap = false;
|
||||
} else {
|
||||
displayChangeNow = true;
|
||||
displaySideShift = true;
|
||||
displayXMRTO = true;
|
||||
displayMorphToken = true;
|
||||
displaySimpleSwap = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -48,13 +71,15 @@ abstract class TradeFilterStoreBase with Store {
|
||||
List<TradeListItem> filtered({required List<TradeListItem> trades, required WalletBase wallet}) {
|
||||
final _trades =
|
||||
trades.where((item) => item.trade.walletId == wallet.id).toList();
|
||||
final needToFilter = !displayChangeNow || !displayXMRTO || !displayMorphToken || !displaySimpleSwap;
|
||||
final needToFilter = !displayAllTrades;
|
||||
|
||||
return needToFilter
|
||||
? _trades
|
||||
.where((item) =>
|
||||
(displayXMRTO &&
|
||||
item.trade.provider == ExchangeProviderDescription.xmrto) ||
|
||||
(displaySideShift &&
|
||||
item.trade.provider == ExchangeProviderDescription.sideShift) ||
|
||||
(displayChangeNow &&
|
||||
item.trade.provider ==
|
||||
ExchangeProviderDescription.changeNow) ||
|
||||
|
||||
@@ -31,13 +31,8 @@ abstract class TradesStoreBase with Store {
|
||||
void setTrade(Trade trade) => this.trade = trade;
|
||||
|
||||
@action
|
||||
Future<void> updateTradeList() async {
|
||||
if (trade == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
trades = tradesSource.values.map((trade) => TradeListItem(
|
||||
trade: trade!,
|
||||
settingsStore: settingsStore)).toList();
|
||||
}
|
||||
Future<void> updateTradeList() async => trades =
|
||||
tradesSource.values.map((trade) => TradeListItem(
|
||||
trade: trade,
|
||||
settingsStore: settingsStore)).toList();
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'transaction_filter_store.g.dart';
|
||||
|
||||
@@ -8,8 +10,8 @@ class TransactionFilterStore = TransactionFilterStoreBase
|
||||
with _$TransactionFilterStore;
|
||||
|
||||
abstract class TransactionFilterStoreBase with Store {
|
||||
TransactionFilterStoreBase(
|
||||
{this.displayIncoming = true, this.displayOutgoing = true});
|
||||
TransactionFilterStoreBase() : displayIncoming = true,
|
||||
displayOutgoing = true;
|
||||
|
||||
@observable
|
||||
bool displayIncoming;
|
||||
@@ -23,11 +25,31 @@ abstract class TransactionFilterStoreBase with Store {
|
||||
@observable
|
||||
DateTime? endDate;
|
||||
|
||||
@action
|
||||
void toggleIncoming() => displayIncoming = !displayIncoming;
|
||||
@computed
|
||||
bool get displayAll => displayIncoming && displayOutgoing;
|
||||
|
||||
@action
|
||||
void toggleOutgoing() => displayOutgoing = !displayOutgoing;
|
||||
void toggleAll() {
|
||||
if (displayAll) {
|
||||
displayOutgoing = false;
|
||||
displayIncoming = false;
|
||||
} else {
|
||||
displayOutgoing = true;
|
||||
displayIncoming = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
void toggleIncoming() {
|
||||
displayIncoming = !displayIncoming;
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
void toggleOutgoing() {
|
||||
displayOutgoing = !displayOutgoing;
|
||||
}
|
||||
|
||||
@action
|
||||
void changeStartDate(DateTime date) => startDate = date;
|
||||
@@ -37,8 +59,7 @@ abstract class TransactionFilterStoreBase with Store {
|
||||
|
||||
List<TransactionListItem> filtered({required List<TransactionListItem> transactions}) {
|
||||
var _transactions = <TransactionListItem>[];
|
||||
final needToFilter = !displayOutgoing ||
|
||||
!displayIncoming ||
|
||||
final needToFilter = !displayAll ||
|
||||
(startDate != null && endDate != null);
|
||||
|
||||
if (needToFilter) {
|
||||
@@ -50,7 +71,7 @@ abstract class TransactionFilterStoreBase with Store {
|
||||
&& (endDate?.isAfter(item.transaction.date) ?? false);
|
||||
}
|
||||
|
||||
if (allowed && (!displayOutgoing || !displayIncoming)) {
|
||||
if (allowed && (!displayAll)) {
|
||||
allowed = (displayOutgoing &&
|
||||
item.transaction.direction ==
|
||||
TransactionDirection.outgoing) ||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
@@ -17,7 +18,6 @@ import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
part 'settings_store.g.dart';
|
||||
|
||||
@@ -41,6 +41,7 @@ abstract class SettingsStoreBase with Store {
|
||||
required this.shouldShowYatPopup,
|
||||
required this.isBitcoinBuyEnabled,
|
||||
required this.actionlistDisplayMode,
|
||||
required this.pinTimeOutDuration,
|
||||
TransactionPriority? initialBitcoinTransactionPriority,
|
||||
TransactionPriority? initialMoneroTransactionPriority,
|
||||
TransactionPriority? initialHavenTransactionPriority,
|
||||
@@ -141,6 +142,11 @@ abstract class SettingsStoreBase with Store {
|
||||
(String languageCode) => sharedPreferences.setString(
|
||||
PreferencesKey.currentLanguageCode, languageCode));
|
||||
|
||||
reaction(
|
||||
(_) => pinTimeOutDuration,
|
||||
(PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt(
|
||||
PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
|
||||
|
||||
reaction(
|
||||
(_) => balanceDisplayMode,
|
||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
@@ -162,6 +168,7 @@ abstract class SettingsStoreBase with Store {
|
||||
|
||||
static const defaultPinLength = 4;
|
||||
static const defaultActionsMode = 11;
|
||||
static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
|
||||
|
||||
@observable
|
||||
FiatCurrency fiatCurrency;
|
||||
@@ -193,6 +200,9 @@ abstract class SettingsStoreBase with Store {
|
||||
@observable
|
||||
int pinCodeLength;
|
||||
|
||||
@observable
|
||||
PinCodeRequiredDuration pinTimeOutDuration;
|
||||
|
||||
@computed
|
||||
ThemeData get theme => currentTheme.themeData;
|
||||
|
||||
@@ -288,6 +298,11 @@ abstract class SettingsStoreBase with Store {
|
||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
||||
defaultActionsMode));
|
||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
||||
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
|
||||
final pinCodeTimeOutDuration = timeOutDuration != null
|
||||
? PinCodeRequiredDuration.deserialize(raw: timeOutDuration)
|
||||
: defaultPinCodeTimeOutDuration;
|
||||
|
||||
// If no value
|
||||
if (pinLength == null || pinLength == 0) {
|
||||
pinLength = defaultPinLength;
|
||||
@@ -343,6 +358,7 @@ abstract class SettingsStoreBase with Store {
|
||||
initialTheme: savedTheme,
|
||||
actionlistDisplayMode: actionListDisplayMode,
|
||||
initialPinLength: pinLength,
|
||||
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||
initialLanguageCode: savedLanguageCode,
|
||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
class PaymentRequest {
|
||||
PaymentRequest(this.address, this.amount, this.note);
|
||||
PaymentRequest(this.address, this.amount, this.note, this.scheme);
|
||||
|
||||
factory PaymentRequest.fromUri(Uri uri) {
|
||||
factory PaymentRequest.fromUri(Uri? uri) {
|
||||
var address = "";
|
||||
var amount = "";
|
||||
var note = "";
|
||||
var scheme = "";
|
||||
|
||||
if (uri != null) {
|
||||
address = uri.path;
|
||||
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
|
||||
note = uri.queryParameters['tx_description']
|
||||
?? uri.queryParameters['message'] ?? "";
|
||||
scheme = uri.scheme;
|
||||
}
|
||||
|
||||
return PaymentRequest(address, amount, note);
|
||||
return PaymentRequest(address, amount, note, scheme);
|
||||
}
|
||||
|
||||
final String address;
|
||||
final String amount;
|
||||
final String note;
|
||||
final String scheme;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
|
||||
class RouteAwareWidget extends StatefulWidget {
|
||||
RouteAwareWidget(
|
||||
{required this.child,
|
||||
this.pushToWidget,
|
||||
this.pushToNextWidget,
|
||||
this.popWidget,
|
||||
this.popNextWidget});
|
||||
|
||||
final Widget child;
|
||||
final Function()? pushToWidget;
|
||||
final Function()? pushToNextWidget;
|
||||
final Function()? popWidget;
|
||||
final Function()? popNextWidget;
|
||||
|
||||
@override
|
||||
State<RouteAwareWidget> createState() => RouteAwareWidgetState();
|
||||
}
|
||||
|
||||
class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
routeObserver.unsubscribe(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didPush() {
|
||||
if (widget.pushToWidget != null) {
|
||||
widget.pushToWidget!();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPushNext() {
|
||||
if (widget.pushToNextWidget != null) {
|
||||
widget.pushToNextWidget!();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPop() {
|
||||
if (widget.popWidget != null) {
|
||||
widget.popWidget!();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPopNext() {
|
||||
if (widget.popNextWidget != null) {
|
||||
widget.popNextWidget!();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => widget.child;
|
||||
}
|
||||
@@ -14,10 +14,12 @@ part 'auth_view_model.g.dart';
|
||||
class AuthViewModel = AuthViewModelBase with _$AuthViewModel;
|
||||
|
||||
abstract class AuthViewModelBase with Store {
|
||||
AuthViewModelBase(this._authService, this._sharedPreferences,
|
||||
this._settingsStore, this._biometricAuth)
|
||||
AuthViewModelBase(
|
||||
this._authService, this._sharedPreferences, this._settingsStore, this._biometricAuth)
|
||||
: _failureCounter = 0,
|
||||
state = InitialExecutionState();
|
||||
state = InitialExecutionState() {
|
||||
reaction((_) => state, _saveLastAuthTime);
|
||||
}
|
||||
|
||||
static const maxFailedLogins = 3;
|
||||
static const banTimeout = 180; // 3 minutes
|
||||
@@ -28,8 +30,7 @@ abstract class AuthViewModelBase with Store {
|
||||
|
||||
int get pinLength => _settingsStore.pinCodeLength;
|
||||
|
||||
bool get isBiometricalAuthenticationAllowed =>
|
||||
_settingsStore.allowBiometricalAuthentication;
|
||||
bool get isBiometricalAuthenticationAllowed => _settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
@observable
|
||||
int _failureCounter;
|
||||
@@ -114,8 +115,14 @@ abstract class AuthViewModelBase with Store {
|
||||
state = ExecutedSuccessfullyState();
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _saveLastAuthTime(ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
_authService.saveLastAuthTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,25 +58,44 @@ abstract class DashboardViewModelBase with Store {
|
||||
isShowThirdYatIntroduction = false,
|
||||
filterItems = {
|
||||
S.current.transactions: [
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayAll,
|
||||
caption: S.current.all_transactions,
|
||||
onChanged: transactionFilterStore.toggleAll),
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayIncoming,
|
||||
caption: S.current.incoming,
|
||||
onChanged: (value) => transactionFilterStore.toggleIncoming()),
|
||||
onChanged:transactionFilterStore.toggleIncoming),
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayOutgoing,
|
||||
caption: S.current.outgoing,
|
||||
onChanged: (value) => transactionFilterStore.toggleOutgoing()),
|
||||
onChanged: transactionFilterStore.toggleOutgoing),
|
||||
// FilterItem(
|
||||
// value: () => false,
|
||||
// caption: S.current.transactions_by_date,
|
||||
// onChanged: null),
|
||||
],
|
||||
S.current.trades: [
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayAllTrades,
|
||||
caption: S.current.all_trades,
|
||||
onChanged: () => tradeFilterStore
|
||||
.toggleDisplayExchange(ExchangeProviderDescription.all)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayChangeNow,
|
||||
caption: 'Change.NOW',
|
||||
onChanged: (value) => tradeFilterStore
|
||||
caption: ExchangeProviderDescription.changeNow.title,
|
||||
onChanged: () => tradeFilterStore
|
||||
.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displaySideShift,
|
||||
caption: ExchangeProviderDescription.sideShift.title,
|
||||
onChanged: () => tradeFilterStore
|
||||
.toggleDisplayExchange(ExchangeProviderDescription.sideShift)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displaySimpleSwap,
|
||||
caption: ExchangeProviderDescription.simpleSwap.title,
|
||||
onChanged: () => tradeFilterStore
|
||||
.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)),
|
||||
]
|
||||
},
|
||||
subname = '',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class FilterItem {
|
||||
FilterItem({
|
||||
required this.value,
|
||||
@@ -6,5 +8,5 @@ class FilterItem {
|
||||
|
||||
bool Function() value;
|
||||
String caption;
|
||||
Function(bool) onChanged;
|
||||
Function onChanged;
|
||||
}
|
||||
@@ -1,29 +1,51 @@
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
part 'ionia_custom_redeem_view_model.g.dart';
|
||||
|
||||
class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
|
||||
|
||||
abstract class IoniaCustomRedeemViewModelBase with Store {
|
||||
IoniaCustomRedeemViewModelBase(this.giftCard)
|
||||
: amount = 0;
|
||||
IoniaCustomRedeemViewModelBase({
|
||||
required this.giftCard,
|
||||
required this.ioniaService,
|
||||
}) : amount = 0,
|
||||
redeemState = InitialExecutionState();
|
||||
|
||||
final IoniaGiftCard giftCard;
|
||||
|
||||
final IoniaService ioniaService;
|
||||
|
||||
@observable
|
||||
ExecutionState redeemState;
|
||||
|
||||
@observable
|
||||
double amount;
|
||||
|
||||
@computed
|
||||
double get remaining => amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
|
||||
double get remaining =>
|
||||
amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
|
||||
|
||||
@computed
|
||||
String get formattedRemaining => remaining.toStringAsFixed(2);
|
||||
String get formattedRemaining => remaining.toStringAsFixed(2);
|
||||
|
||||
@computed
|
||||
bool get disableRedeem => amount > giftCard.remainingAmount;
|
||||
|
||||
@action
|
||||
void updateAmount(String text){
|
||||
amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')) ?? 0);
|
||||
void updateAmount(String text) {
|
||||
amount = double.tryParse(text.replaceAll(',', '.')) ?? 0;
|
||||
}
|
||||
|
||||
}
|
||||
@action
|
||||
Future<void> addCustomRedeem() async {
|
||||
try {
|
||||
redeemState = IsExecutingState();
|
||||
await ioniaService.redeem(giftCardId: giftCard.id, amount: amount);
|
||||
redeemState = ExecutedSuccessfullyState();
|
||||
} catch (e) {
|
||||
redeemState = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,21 +6,19 @@ import 'package:device_display_brightness/device_display_brightness.dart';
|
||||
|
||||
part 'ionia_gift_card_details_view_model.g.dart';
|
||||
|
||||
class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase with _$IoniaGiftCardDetailsViewModel;
|
||||
class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase
|
||||
with _$IoniaGiftCardDetailsViewModel;
|
||||
|
||||
abstract class IoniaGiftCardDetailsViewModelBase with Store {
|
||||
|
||||
IoniaGiftCardDetailsViewModelBase({
|
||||
required this.ioniaService,
|
||||
required this.giftCard})
|
||||
: redeemState = InitialExecutionState(),
|
||||
remainingAmount = giftCard.remainingAmount,
|
||||
brightness = 0;
|
||||
IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard})
|
||||
: redeemState = InitialExecutionState(),
|
||||
remainingAmount = giftCard.remainingAmount,
|
||||
brightness = 0;
|
||||
|
||||
final IoniaService ioniaService;
|
||||
|
||||
|
||||
double brightness;
|
||||
|
||||
|
||||
@observable
|
||||
IoniaGiftCard giftCard;
|
||||
|
||||
@@ -35,21 +33,22 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
|
||||
giftCard.remainingAmount = remainingAmount;
|
||||
try {
|
||||
redeemState = IsExecutingState();
|
||||
await ioniaService.redeem(giftCard);
|
||||
await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
|
||||
giftCard = await ioniaService.getGiftCard(id: giftCard.id);
|
||||
redeemState = ExecutedSuccessfullyState();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
redeemState = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void updateRemaining(double amount){
|
||||
remainingAmount = amount;
|
||||
Future<void> refeshCard() async {
|
||||
giftCard = await ioniaService.getGiftCard(id: giftCard.id);
|
||||
remainingAmount = giftCard.remainingAmount;
|
||||
}
|
||||
|
||||
void increaseBrightness() async {
|
||||
brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
await DeviceDisplayBrightness.setBrightness(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class SendViewModelBase with Store {
|
||||
|
||||
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
||||
}
|
||||
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@@ -180,6 +180,8 @@ abstract class SendViewModelBase with Store {
|
||||
|
||||
WalletType get walletType => _wallet.type;
|
||||
|
||||
String? get walletCurrencyName => _wallet.currency.name?.toLowerCase();
|
||||
|
||||
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
||||
|
||||
@computed
|
||||
@@ -306,7 +308,7 @@ abstract class SendViewModelBase with Store {
|
||||
@action
|
||||
void onClose() =>
|
||||
_settingsStore.fiatCurrency = fiatFromSettings;
|
||||
|
||||
|
||||
@action
|
||||
void setFiatCurrency(FiatCurrency fiat) =>
|
||||
_settingsStore.fiatCurrency = fiat;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
@@ -7,19 +9,33 @@ part 'security_settings_view_model.g.dart';
|
||||
class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel;
|
||||
|
||||
abstract class SecuritySettingsViewModelBase with Store {
|
||||
SecuritySettingsViewModelBase(this._settingsStore) : _biometricAuth = BiometricAuth();
|
||||
SecuritySettingsViewModelBase(
|
||||
this._settingsStore,
|
||||
this._authService,
|
||||
) : _biometricAuth = BiometricAuth();
|
||||
|
||||
final BiometricAuth _biometricAuth;
|
||||
final SettingsStore _settingsStore;
|
||||
final AuthService _authService;
|
||||
|
||||
@computed
|
||||
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
@computed
|
||||
PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration;
|
||||
|
||||
@action
|
||||
Future<bool> biometricAuthenticated() async {
|
||||
return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated();
|
||||
}
|
||||
|
||||
@action
|
||||
void setAllowBiometricalAuthentication(bool value) => _settingsStore.allowBiometricalAuthentication = value;
|
||||
void setAllowBiometricalAuthentication(bool value) =>
|
||||
_settingsStore.allowBiometricalAuthentication = value;
|
||||
|
||||
@action
|
||||
setPinCodeRequiredDuration(PinCodeRequiredDuration duration) =>
|
||||
_settingsStore.pinTimeOutDuration = duration;
|
||||
|
||||
bool checkPinCodeRiquired() => _authService.requireAuth();
|
||||
}
|
||||
|
||||
@@ -142,17 +142,5 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
items.add(TrackTradeListItem(
|
||||
title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
||||
}
|
||||
|
||||
if (trade.createdAt != null) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_created_at,
|
||||
value: trade.createdAt != null ? dateFormat.format(trade.createdAt!).toString() : ''));
|
||||
}
|
||||
|
||||
if (trade.from != null && trade.to != null) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_pair,
|
||||
value: '${trade.from.toString()} → ${trade.to.toString()}'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||
{required WalletBase wallet, dynamic item})
|
||||
: isEdit = item != null,
|
||||
state = AddressEditOrCreateStateInitial(),
|
||||
label = item?.name as String? ?? '',
|
||||
label = item?.fullName as String? ?? '',
|
||||
_item = item,
|
||||
_wallet = wallet;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
@@ -15,9 +15,12 @@ part 'wallet_list_view_model.g.dart';
|
||||
class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel;
|
||||
|
||||
abstract class WalletListViewModelBase with Store {
|
||||
WalletListViewModelBase(this._walletInfoSource, this._appStore,
|
||||
this._walletLoadingService)
|
||||
: wallets = ObservableList<WalletListItem>() {
|
||||
WalletListViewModelBase(
|
||||
this._walletInfoSource,
|
||||
this._appStore,
|
||||
this._walletLoadingService,
|
||||
this._authService,
|
||||
) : wallets = ObservableList<WalletListItem>() {
|
||||
_updateList();
|
||||
}
|
||||
|
||||
@@ -27,6 +30,7 @@ abstract class WalletListViewModelBase with Store {
|
||||
final AppStore _appStore;
|
||||
final Box<WalletInfo> _walletInfoSource;
|
||||
final WalletLoadingService _walletLoadingService;
|
||||
final AuthService _authService;
|
||||
|
||||
WalletType get currentWalletType => _appStore.wallet!.type;
|
||||
|
||||
@@ -47,12 +51,20 @@ abstract class WalletListViewModelBase with Store {
|
||||
|
||||
void _updateList() {
|
||||
wallets.clear();
|
||||
wallets.addAll(_walletInfoSource.values.map((info) => WalletListItem(
|
||||
name: info.name,
|
||||
type: info.type,
|
||||
key: info.key,
|
||||
isCurrent: info.name == _appStore.wallet!.name &&
|
||||
info.type == _appStore.wallet!.type,
|
||||
isEnabled: availableWalletTypes.contains(info.type))));
|
||||
wallets.addAll(
|
||||
_walletInfoSource.values.map(
|
||||
(info) => WalletListItem(
|
||||
name: info.name,
|
||||
type: info.type,
|
||||
key: info.key,
|
||||
isCurrent: info.name == _appStore.wallet!.name && info.type == _appStore.wallet!.type,
|
||||
isEnabled: availableWalletTypes.contains(info.type),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool checkIfAuthRequired() {
|
||||
return _authService.requireAuth();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user