mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-22 06:28:39 +02:00
Add additional Buy Provider (#1071)
* CW-466 Add Buy Options Page * CW-466 Add Buy Options * CW-466 Add Default Buy Provider to Other Settings * CW-466 Onramper is working from Buy Options * CW-466 Onramper is working from Buy Options * CW-466 Translation improvements * CW-466 Add Onramper & Robinhood Logos * CW-466 Implement Robinhood Flow * CW-466 Fix Robinhood Flow * CW-466 Add RH-Secrets * CW-466 Have RH Translation in English only * Add missing URI details * CW-466 Implement default Buy Provider * CW-466 Fix Padding Buy Provider Options * CW-466 Fix Bitcoin and Litecoin Signatures * CW-466 Fix Error Message * CW-466 Resolve requested changes * Add exception handler to robinhood API calls * CW-466 Fix Theming --------- Co-authored-by: Justin Ehrenhofer <justin.ehrenhofer@gmail.com> Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Justin Ehrenhofer
OmarHatem
parent
ce4d375abf
commit
d972363417
@@ -1,10 +1,13 @@
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class OnRamperBuyProvider {
|
||||
OnRamperBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
|
||||
@@ -69,4 +72,13 @@ class OnRamperBuyProvider {
|
||||
'cardColor': cardColor
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
final uri = requestUrl(context);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
|
||||
} else {
|
||||
await launchUrl(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class RobinhoodBuyProvider {
|
||||
RobinhoodBuyProvider({required WalletBase wallet})
|
||||
: this._wallet = wallet;
|
||||
|
||||
final WalletBase _wallet;
|
||||
|
||||
static const _baseUrl = 'applink.robinhood.com';
|
||||
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
|
||||
|
||||
String get _applicationId => secrets.robinhoodApplicationId;
|
||||
String get _apiSecret => secrets.robinhoodCIdApiSecret;
|
||||
|
||||
bool get isAvailable =>
|
||||
[WalletType.bitcoin, WalletType.litecoin, WalletType.ethereum].contains(_wallet.type);
|
||||
|
||||
String getSignature(String message) {
|
||||
switch (_wallet.type) {
|
||||
case WalletType.ethereum:
|
||||
return _wallet.signMessage(message);
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoin:
|
||||
return _wallet.signMessage(message, address: _wallet.walletAddresses.address);
|
||||
default:
|
||||
throw Exception("WalletType is not available for Robinhood");
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getConnectId() async {
|
||||
final walletAddress = _wallet.walletAddresses.address;
|
||||
final valid_until = (DateTime.now().millisecondsSinceEpoch / 1000).round() + 10;
|
||||
final message = "$_apiSecret:${valid_until}";
|
||||
|
||||
final signature = getSignature(message);
|
||||
|
||||
final uri = Uri.https(_cIdBaseUrl, "/api/robinhood");
|
||||
|
||||
var response = await http.post(uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json
|
||||
.encode({'valid_until': valid_until, 'wallet': walletAddress, 'signature': signature}));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String;
|
||||
} else {
|
||||
throw Exception('Provider currently unavailable. Status: ${response.statusCode} ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uri> requestUrl() async {
|
||||
final connectId = await getConnectId();
|
||||
final networkName = _wallet.currency.fullName?.toUpperCase().replaceAll(" ", "_");
|
||||
|
||||
return Uri.https(_baseUrl, '/u/connect', <String, dynamic>{
|
||||
'applicationId': _applicationId,
|
||||
'connectId': connectId,
|
||||
'walletAddress': _wallet.walletAddresses.address,
|
||||
'userIdentifier': _wallet.walletAddresses.address,
|
||||
'supportedNetworks': networkName
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
try {
|
||||
final uri = await requestUrl();
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} catch (e, s) {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s));
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: "Robinhood Connect",
|
||||
alertContent: S.of(context).buy_provider_unavailable,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,6 +208,7 @@ class BackupService {
|
||||
final isAppSecure = data[PreferencesKey.isAppSecureKey] as bool?;
|
||||
final disableBuy = data[PreferencesKey.disableBuyKey] as bool?;
|
||||
final disableSell = data[PreferencesKey.disableSellKey] as bool?;
|
||||
final defaultBuyProvider = data[PreferencesKey.defaultBuyProvider] as int?;
|
||||
final currentTransactionPriorityKeyLegacy =
|
||||
data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int?;
|
||||
final allowBiometricalAuthentication =
|
||||
@@ -276,6 +277,9 @@ class BackupService {
|
||||
if (disableSell != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell);
|
||||
|
||||
if (defaultBuyProvider != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.defaultBuyProvider, defaultBuyProvider);
|
||||
|
||||
if (currentTransactionPriorityKeyLegacy != null)
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy, currentTransactionPriorityKeyLegacy);
|
||||
@@ -476,6 +480,7 @@ class BackupService {
|
||||
_sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
|
||||
PreferencesKey.disableBuyKey: _sharedPreferences.getBool(PreferencesKey.disableBuyKey),
|
||||
PreferencesKey.disableSellKey: _sharedPreferences.getBool(PreferencesKey.disableSellKey),
|
||||
PreferencesKey.defaultBuyProvider: _sharedPreferences.getInt(PreferencesKey.defaultBuyProvider),
|
||||
PreferencesKey.isDarkThemeLegacy:
|
||||
_sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy),
|
||||
PreferencesKey.currentPinLength: _sharedPreferences.getInt(PreferencesKey.currentPinLength),
|
||||
|
||||
+7
-5
@@ -3,6 +3,7 @@ import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/core/yat_service.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
@@ -15,6 +16,7 @@ import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_dashboard_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||
@@ -95,7 +97,6 @@ import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
|
||||
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
|
||||
@@ -688,6 +689,9 @@ Future<void> setup({
|
||||
editingNode: editingNode,
|
||||
isSelected: isSelected));
|
||||
|
||||
getIt.registerFactory<RobinhoodBuyProvider>(
|
||||
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
@@ -816,6 +820,8 @@ Future<void> setup({
|
||||
|
||||
getIt.registerFactory(() => BuyAmountViewModel());
|
||||
|
||||
getIt.registerFactory(() => BuyOptionsPage());
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
@@ -824,10 +830,6 @@ Future<void> setup({
|
||||
wallet: wallet!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<BuyWebViewPage, List, void>((List args, _) {
|
||||
final url = args.first as String;
|
||||
final buyViewModel = args[1] as BuyViewModel;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
enum BuyProviderType {
|
||||
AskEachTime,
|
||||
Robinhood,
|
||||
Onramper;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
switch (this) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
return S.current.ask_each_time;
|
||||
case BuyProviderType.Robinhood:
|
||||
return "Robinhood";
|
||||
case BuyProviderType.Onramper:
|
||||
return "Onramper";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
@@ -41,23 +43,30 @@ class MainActions {
|
||||
isEnabled: (viewModel) => viewModel.isEnabledBuyAction,
|
||||
canShow: (viewModel) => viewModel.hasBuyAction,
|
||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||
final defaultBuyProvider = viewModel.defaultBuyProvider;
|
||||
final walletType = viewModel.type;
|
||||
|
||||
if (!viewModel.isEnabledBuyAction) return;
|
||||
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.monero:
|
||||
if (viewModel.isEnabledBuyAction) {
|
||||
final uri = getIt.get<OnRamperBuyProvider>().requestUrl(context);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
|
||||
} else {
|
||||
await launchUrl(uri);
|
||||
}
|
||||
switch (defaultBuyProvider) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
Navigator.pushNamed(context, Routes.buy);
|
||||
break;
|
||||
case BuyProviderType.Onramper:
|
||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
case BuyProviderType.Robinhood:
|
||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WalletType.monero:
|
||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
default:
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
|
||||
@@ -13,6 +13,7 @@ class PreferencesKey {
|
||||
static const isAppSecureKey = 'is_app_secure';
|
||||
static const disableBuyKey = 'disable_buy';
|
||||
static const disableSellKey = 'disable_sell';
|
||||
static const defaultBuyProvider = 'default_buy_provider';
|
||||
static const currentFiatApiModeKey = 'current_fiat_api_mode';
|
||||
static const allowBiometricalAuthenticationKey =
|
||||
'allow_biometrical_authentication';
|
||||
|
||||
+3
-5
@@ -7,9 +7,9 @@ import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||
@@ -383,10 +383,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
builder: (_) =>
|
||||
getIt.get<OrderDetailsPage>(param1: settings.arguments as Order));
|
||||
|
||||
case Routes.preOrder:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
getIt.get<PreOrderPage>());
|
||||
case Routes.buy:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<BuyOptionsPage>());
|
||||
|
||||
case Routes.buyWebView:
|
||||
final args = settings.arguments as List;
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class Routes {
|
||||
static const supportLiveChat = '/support/live_chat';
|
||||
static const supportOtherLinks = '/support/other';
|
||||
static const orderDetails = '/order_details';
|
||||
static const preOrder = '/pre_order';
|
||||
static const buy = '/buy';
|
||||
static const buyWebView = '/buy_web_view';
|
||||
static const unspentCoinsList = '/unspent_coins_list';
|
||||
static const unspentCoinsDetails = '/unspent_coins_details';
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BuyOptionsPage extends BasePage {
|
||||
final iconDarkRobinhood = 'assets/images/robinhood_dark.png';
|
||||
final iconLightRobinhood = 'assets/images/robinhood_light.png';
|
||||
final iconDarkOnramper = 'assets/images/onramper_dark.png';
|
||||
final iconLightOnramper = 'assets/images/onramper_light.png';
|
||||
|
||||
@override
|
||||
String get title => S.current.buy;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final isLightMode = Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
|
||||
final iconRobinhood =
|
||||
Image.asset(isLightMode ? iconLightRobinhood : iconDarkRobinhood, height: 40, width: 40);
|
||||
final iconOnramper =
|
||||
Image.asset(isLightMode ? iconLightOnramper : iconDarkOnramper, height: 40, width: 40);
|
||||
|
||||
return Container(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 330),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconRobinhood,
|
||||
title: "Robinhood Connect",
|
||||
description: S.of(context).robinhood_option_description,
|
||||
onPressed: () async =>
|
||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconOnramper,
|
||||
title: "Onramper",
|
||||
description: S.of(context).onramper_option_description,
|
||||
onPressed: () async =>
|
||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
S.of(context).select_buy_provider_notice,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/widgets/buy_list_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class PreOrderPage extends BasePage {
|
||||
PreOrderPage({required this.buyViewModel})
|
||||
: _amountFocus = FocusNode(),
|
||||
_amountController = TextEditingController() {
|
||||
_amountController.addListener(() {
|
||||
final amount = _amountController.text;
|
||||
|
||||
if (amount != buyViewModel.buyAmountViewModel.amount) {
|
||||
buyViewModel.buyAmountViewModel.amount = amount;
|
||||
buyViewModel.selectedProvider = null;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => buyViewModel.buyAmountViewModel.amount, (String amount) {
|
||||
if (_amountController.text != amount) {
|
||||
_amountController.text = amount;
|
||||
}
|
||||
if (amount.isEmpty) {
|
||||
buyViewModel.selectedProvider = null;
|
||||
buyViewModel.isShowProviderButtons = false;
|
||||
} else {
|
||||
buyViewModel.isShowProviderButtons = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
|
||||
|
||||
final BuyViewModel buyViewModel;
|
||||
final FocusNode _amountFocus;
|
||||
final TextEditingController _amountController;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy + ' ' + walletTypeToString(buyViewModel.wallet.type);
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
Widget trailing(context) => TrailButton(
|
||||
caption: S.of(context).clear,
|
||||
onPressed: () => buyViewModel.reset());
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _amountFocus,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
height: 0,
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Observer(builder: (_) => Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(colors: [
|
||||
Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
|
||||
Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
|
||||
], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 100, bottom: 65),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 210,
|
||||
child: BaseTextFormField(
|
||||
focusNode: _amountFocus,
|
||||
controller: _amountController,
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
|
||||
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(_amountPattern))],
|
||||
prefixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => Picker(
|
||||
hintText: S.current.search_currency,
|
||||
items: FiatCurrency.currenciesAvailableToBuyWith,
|
||||
selectedAtIndex:
|
||||
FiatCurrency.currenciesAvailableToBuyWith.indexOf(buyViewModel.fiatCurrency),
|
||||
onItemSelected: (FiatCurrency selectedCurrency) {
|
||||
buyViewModel.buyAmountViewModel.fiatCurrency = selectedCurrency;
|
||||
},
|
||||
images: FiatCurrency.currenciesAvailableToBuyWith
|
||||
.map((e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
|
||||
.toList(),
|
||||
isGridView: true,
|
||||
matchingCriteria: (FiatCurrency currency, String searchText) {
|
||||
return currency.title.toLowerCase().contains(searchText) ||
|
||||
currency.fullName.toLowerCase().contains(searchText);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.keyboard_arrow_down, color: Colors.white),
|
||||
Text(
|
||||
buyViewModel.fiatCurrency.title + ': ',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
hintText: '0.00',
|
||||
borderColor: Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderBottomPanelColor,
|
||||
borderWidth: 0.5,
|
||||
textStyle: TextStyle(fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 36,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (buyViewModel.isShowProviderButtons) Padding(
|
||||
padding: EdgeInsets.only(top: 38, bottom: 18),
|
||||
child: Text(
|
||||
S.of(context).buy_with + ':',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold
|
||||
),
|
||||
)
|
||||
),
|
||||
if (buyViewModel.isShowProviderButtons)
|
||||
...buyViewModel.items.map(
|
||||
(item) => Observer(builder: (_) =>
|
||||
FutureBuilder<BuyAmount>(
|
||||
future: item.buyAmount,
|
||||
builder: (context, AsyncSnapshot<BuyAmount> snapshot) {
|
||||
double sourceAmount;
|
||||
double destAmount;
|
||||
double achAmount;
|
||||
int minAmount;
|
||||
|
||||
if (snapshot.hasData && snapshot.data != null) {
|
||||
sourceAmount = snapshot.data!.sourceAmount;
|
||||
destAmount = snapshot.data!.destAmount;
|
||||
minAmount = snapshot.data!.minAmount;
|
||||
achAmount = snapshot.data!.achSourceAmount ?? 0;
|
||||
} else {
|
||||
sourceAmount = 0.0;
|
||||
destAmount = 0.0;
|
||||
minAmount = 0;
|
||||
achAmount = 0;
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 15, top: 20, right: 15),
|
||||
child: Observer(builder: (_) {
|
||||
return BuyListItem(
|
||||
selectedProvider:
|
||||
buyViewModel.selectedProvider,
|
||||
provider: item.provider,
|
||||
sourceAmount: sourceAmount,
|
||||
sourceCurrency: buyViewModel.fiatCurrency,
|
||||
destAmount: destAmount,
|
||||
destCurrency: buyViewModel.cryptoCurrency,
|
||||
achSourceAmount: achAmount,
|
||||
onTap: ((buyViewModel.doubleAmount != 0.0)
|
||||
&& (snapshot.hasData)) ? () =>
|
||||
onSelectBuyProvider(
|
||||
context: context,
|
||||
provider: item.provider,
|
||||
sourceAmount: sourceAmount,
|
||||
minAmount: minAmount
|
||||
) : null
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
))
|
||||
)
|
||||
],
|
||||
)),
|
||||
bottomSectionPadding:
|
||||
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () => onPresentProvider(context: context),
|
||||
text: buyViewModel.selectedProvider == null
|
||||
? S.of(context).buy
|
||||
: S.of(context).buy_with +
|
||||
' ${buyViewModel.selectedProvider!.description.title}',
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
isLoading: buyViewModel.isRunning,
|
||||
isDisabled: (buyViewModel.selectedProvider == null) ||
|
||||
buyViewModel.isDisabled
|
||||
);
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void onSelectBuyProvider({required BuildContext context, required BuyProvider provider,
|
||||
required double sourceAmount, required int minAmount}) {
|
||||
|
||||
if ((provider is MoonPayBuyProvider)&&
|
||||
(buyViewModel.buyAmountViewModel.doubleAmount < minAmount)) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: 'MoonPay',
|
||||
alertContent: S.of(context).moonpay_alert_text(
|
||||
minAmount.toString(),
|
||||
buyViewModel.fiatCurrency.toString()),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
return;
|
||||
}
|
||||
buyViewModel.selectedProvider = provider;
|
||||
sourceAmount > 0
|
||||
? buyViewModel.isDisabled = false
|
||||
: buyViewModel.isDisabled = true;
|
||||
}
|
||||
|
||||
Future<void> onPresentProvider({required BuildContext context}) async {
|
||||
if (buyViewModel.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
buyViewModel.isRunning = true;
|
||||
final url = await buyViewModel.fetchUrl();
|
||||
|
||||
if (url.isNotEmpty) {
|
||||
if (buyViewModel.selectedProvider is MoonPayBuyProvider) {
|
||||
if (await canLaunch(url)) await launch(url);
|
||||
} else {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.buyWebView,
|
||||
arguments: [url, buyViewModel]);
|
||||
}
|
||||
}
|
||||
|
||||
buyViewModel.reset();
|
||||
buyViewModel.isRunning = false;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
|
||||
@@ -9,7 +10,6 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/restore_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
@@ -35,7 +35,7 @@ class RestoreOptionsPage extends BasePage {
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
RestoreButton(
|
||||
OptionTile(
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context, Routes.restoreWalletFromSeedKeys,
|
||||
arguments: isNewInstall),
|
||||
@@ -45,7 +45,7 @@ class RestoreOptionsPage extends BasePage {
|
||||
if (isNewInstall)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
child: OptionTile(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
@@ -53,7 +53,7 @@ class RestoreOptionsPage extends BasePage {
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
child: OptionTile(
|
||||
onPressed: () async {
|
||||
bool isPinSet = false;
|
||||
if (isNewInstall) {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
|
||||
class RestoreButton extends StatelessWidget {
|
||||
const RestoreButton(
|
||||
{required this.onPressed,
|
||||
required this.image,
|
||||
required this.title,
|
||||
required this.description});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Image image;
|
||||
final String title;
|
||||
final String description;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 170,
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.topLeft,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
color: Theme.of(context).cardColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
image,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.extension<TransactionTradeTheme>()!
|
||||
.detailsTitlesColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
@@ -33,6 +35,13 @@ class OtherSettingsPage extends BasePage {
|
||||
selectedItem: _otherSettingsViewModel.transactionPriority,
|
||||
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
|
||||
),
|
||||
SettingsPickerCell(
|
||||
title: S.current.default_buy_provider,
|
||||
items: BuyProviderType.values,
|
||||
displayItem: _otherSettingsViewModel.getBuyProviderType,
|
||||
selectedItem: _otherSettingsViewModel.buyProviderType,
|
||||
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected,
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
|
||||
@@ -25,4 +25,4 @@ class SettingsVersionCell extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/support/widgets/support_tiles.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/view_model/support_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -32,7 +32,7 @@ class SupportPage extends BasePage {
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: SupportTile(
|
||||
child: OptionTile(
|
||||
image: imageLiveSupport,
|
||||
title: S.of(context).support_title_live_chat,
|
||||
description: S.of(context).support_description_live_chat,
|
||||
@@ -47,7 +47,7 @@ class SupportPage extends BasePage {
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: SupportTile(
|
||||
child: OptionTile(
|
||||
image: imageWalletGuides,
|
||||
title: S.of(context).support_title_guides,
|
||||
description: S.of(context).support_description_guides,
|
||||
@@ -56,7 +56,7 @@ class SupportPage extends BasePage {
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: SupportTile(
|
||||
child: OptionTile(
|
||||
image: imageMoreLinks,
|
||||
title: S.of(context).support_title_other_links,
|
||||
description: S.of(context).support_description_other_links,
|
||||
|
||||
+5
-6
@@ -1,9 +1,8 @@
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SupportTile extends StatelessWidget {
|
||||
const SupportTile(
|
||||
class OptionTile extends StatelessWidget {
|
||||
const OptionTile(
|
||||
{required this.onPressed,
|
||||
required this.image,
|
||||
required this.title,
|
||||
@@ -45,7 +44,7 @@ class SupportTile extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
color: Theme.of(context).extension<OptionTileTheme>()!.titleColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
@@ -55,7 +54,7 @@ class SupportTile extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
color: Theme.of(context).extension<OptionTileTheme>()!.descriptionColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
@@ -47,6 +48,7 @@ abstract class SettingsStoreBase with Store {
|
||||
required bool initialAppSecure,
|
||||
required bool initialDisableBuy,
|
||||
required bool initialDisableSell,
|
||||
required BuyProviderType initialDefaultBuyProvider,
|
||||
required FiatApiMode initialFiatMode,
|
||||
required bool initialAllowBiometricalAuthentication,
|
||||
required String initialTotpSecretKey,
|
||||
@@ -99,6 +101,7 @@ abstract class SettingsStoreBase with Store {
|
||||
isAppSecure = initialAppSecure,
|
||||
disableBuy = initialDisableBuy,
|
||||
disableSell = initialDisableSell,
|
||||
defaultBuyProvider = initialDefaultBuyProvider,
|
||||
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
|
||||
exchangeStatus = initialExchangeStatus,
|
||||
currentTheme = initialTheme,
|
||||
@@ -200,6 +203,11 @@ abstract class SettingsStoreBase with Store {
|
||||
(bool disableSell) =>
|
||||
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
|
||||
|
||||
reaction(
|
||||
(_) => defaultBuyProvider,
|
||||
(BuyProviderType defaultBuyProvider) =>
|
||||
sharedPreferences.setInt(PreferencesKey.defaultBuyProvider, defaultBuyProvider.index));
|
||||
|
||||
reaction(
|
||||
(_) => autoGenerateSubaddressStatus,
|
||||
(AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt(
|
||||
@@ -380,6 +388,9 @@ abstract class SettingsStoreBase with Store {
|
||||
@observable
|
||||
bool disableSell;
|
||||
|
||||
@observable
|
||||
BuyProviderType defaultBuyProvider;
|
||||
|
||||
@observable
|
||||
bool allowBiometricalAuthentication;
|
||||
|
||||
@@ -535,6 +546,7 @@ abstract class SettingsStoreBase with Store {
|
||||
final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
|
||||
final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
|
||||
final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
||||
final defaultBuyProvider = BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0];
|
||||
final currentFiatApiMode = FiatApiMode.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
|
||||
FiatApiMode.enabled.raw);
|
||||
@@ -661,6 +673,7 @@ abstract class SettingsStoreBase with Store {
|
||||
initialAppSecure: isAppSecure,
|
||||
initialDisableBuy: disableBuy,
|
||||
initialDisableSell: disableSell,
|
||||
initialDefaultBuyProvider: defaultBuyProvider,
|
||||
initialFiatMode: currentFiatApiMode,
|
||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
initialCake2FAPresetOptions: selectedCake2FAPreset,
|
||||
@@ -747,6 +760,7 @@ abstract class SettingsStoreBase with Store {
|
||||
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
|
||||
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
|
||||
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
|
||||
defaultBuyProvider = BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0];
|
||||
allowBiometricalAuthentication =
|
||||
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
allowBiometricalAuthentication;
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:cake_wallet/themes/extensions/info_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/order_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/pin_code_theme.dart';
|
||||
@@ -215,6 +216,10 @@ class DarkTheme extends ThemeBase {
|
||||
qrCodeColor: PaletteDark.lightBlueGrey,
|
||||
qrWidgetCopyButtonColor: PaletteDark.lightBlueGrey);
|
||||
|
||||
@override
|
||||
OptionTileTheme get optionTileTheme => OptionTileTheme(
|
||||
titleColor: primaryTextColor, descriptionColor: primaryTextColor, useDarkImage: false);
|
||||
|
||||
@override
|
||||
ThemeData get themeData => super.themeData.copyWith(
|
||||
dividerColor: PaletteDark.dividerColor,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OptionTileTheme extends ThemeExtension<OptionTileTheme> {
|
||||
final Color titleColor;
|
||||
final Color descriptionColor;
|
||||
final bool useDarkImage;
|
||||
|
||||
OptionTileTheme(
|
||||
{required this.titleColor, required this.descriptionColor, this.useDarkImage = false});
|
||||
|
||||
@override
|
||||
OptionTileTheme copyWith({Color? titleColor, Color? descriptionColor, bool? useDarkImage}) =>
|
||||
OptionTileTheme(
|
||||
titleColor: titleColor ?? this.titleColor,
|
||||
descriptionColor: descriptionColor ?? this.descriptionColor,
|
||||
useDarkImage: useDarkImage ?? this.useDarkImage);
|
||||
|
||||
@override
|
||||
OptionTileTheme lerp(ThemeExtension<OptionTileTheme>? other, double t) {
|
||||
if (other is! OptionTileTheme) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return OptionTileTheme(
|
||||
titleColor: Color.lerp(titleColor, other.titleColor, t) ?? titleColor,
|
||||
descriptionColor:
|
||||
Color.lerp(descriptionColor, other.descriptionColor, t) ?? descriptionColor,
|
||||
useDarkImage: other.useDarkImage);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/indicator_dot_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
@@ -103,6 +104,10 @@ class HighContrastTheme extends MoneroLightTheme {
|
||||
ReceivePageTheme get receivePageTheme => super.receivePageTheme.copyWith(
|
||||
tilesTextColor: Colors.white, iconsBackgroundColor: Colors.grey, iconsColor: Colors.black);
|
||||
|
||||
@override
|
||||
OptionTileTheme get optionTileTheme => OptionTileTheme(
|
||||
titleColor: Colors.white, descriptionColor: Colors.white, useDarkImage: false);
|
||||
|
||||
@override
|
||||
ThemeData get themeData => super.themeData.copyWith(
|
||||
disabledColor: Colors.grey,
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:cake_wallet/themes/extensions/info_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/order_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/pin_code_theme.dart';
|
||||
@@ -215,6 +216,10 @@ class LightTheme extends ThemeBase {
|
||||
qrCodeColor: Colors.white,
|
||||
qrWidgetCopyButtonColor: PaletteDark.lightBlueGrey);
|
||||
|
||||
@override
|
||||
OptionTileTheme get optionTileTheme => OptionTileTheme(
|
||||
titleColor: primaryTextColor, descriptionColor: primaryTextColor, useDarkImage: true);
|
||||
|
||||
@override
|
||||
ThemeData get themeData => super.themeData.copyWith(
|
||||
dividerColor: Palette.paleBlue,
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:cake_wallet/themes/extensions/info_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/order_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/pin_code_theme.dart';
|
||||
@@ -114,6 +115,8 @@ abstract class ThemeBase {
|
||||
|
||||
QRCodeTheme get qrCodeTheme;
|
||||
|
||||
OptionTileTheme get optionTileTheme;
|
||||
|
||||
ThemeData get themeData => generatedThemeData.copyWith(
|
||||
primaryColor: primaryColor,
|
||||
cardColor: containerColor,
|
||||
@@ -144,6 +147,7 @@ abstract class ThemeBase {
|
||||
accountListTheme,
|
||||
receivePageTheme,
|
||||
qrCodeTheme,
|
||||
optionTileTheme
|
||||
],
|
||||
scrollbarTheme: generatedThemeData.scrollbarTheme.copyWith(
|
||||
thumbColor: MaterialStateProperty.all(scrollbarTheme.thumbColor),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
@@ -277,6 +278,9 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
Map<String, List<FilterItem>> filterItems;
|
||||
|
||||
|
||||
BuyProviderType get defaultBuyProvider => settingsStore.defaultBuyProvider;
|
||||
|
||||
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
|
||||
|
||||
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
@@ -48,6 +49,9 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@computed
|
||||
BuyProviderType get buyProviderType { return _settingsStore.defaultBuyProvider; }
|
||||
|
||||
String getDisplayPriority(dynamic priority) {
|
||||
final _priority = priority as TransactionPriority;
|
||||
|
||||
@@ -59,6 +63,16 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
return priority.toString();
|
||||
}
|
||||
|
||||
String getBuyProviderType (dynamic buyProviderType) {
|
||||
final _buyProviderType = buyProviderType as BuyProviderType;
|
||||
|
||||
return _buyProviderType.toString();
|
||||
}
|
||||
|
||||
void onDisplayPrioritySelected(TransactionPriority priority) =>
|
||||
_settingsStore.priority[_wallet.type] = priority;
|
||||
|
||||
void onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
|
||||
_settingsStore.defaultBuyProvider = buyProviderType;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user