Fix issues from code review

This commit is contained in:
Godwin Asuquo 2023-03-01 23:44:15 +02:00
parent dbfbadffda
commit b0175719b9
11 changed files with 165 additions and 83 deletions

View file

@ -77,14 +77,6 @@ jobs:
run: | run: |
cd /opt/android/cake_wallet cd /opt/android/cake_wallet
flutter packages pub run tool/generate_localization.dart flutter packages pub run tool/generate_localization.dart
- name: Upgrade flutter packages
run: |
cd /opt/android/cake_wallet
cd cw_core && flutter pub upgrade && cd ..
cd cw_monero && flutter pub upgrade && cd ..
cd cw_bitcoin && flutter pub upgrade && cd ..
cd cw_haven && flutter pub upgrade && cd ..
- name: Build generated code - name: Build generated code
run: | run: |

View file

@ -1,10 +1,12 @@
import 'dart:io' show File, Platform; import 'dart:io' show File, Platform;
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:share_plus/share_plus.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -142,7 +144,9 @@ Future defaultSettingsMigration(
case 19: case 19:
await validateBitcoinSavedTransactionPriority(sharedPreferences); await validateBitcoinSavedTransactionPriority(sharedPreferences);
break; break;
case 20:
await migrateExchangeStatus(sharedPreferences);
break;
default: default:
break; break;
} }
@ -501,3 +505,13 @@ Future<void> changeDefaultHavenNode(
await node.save(); await node.save();
}); });
} }
Future<void> migrateExchangeStatus(SharedPreferences sharedPreferences) async {
final isExchangeDisabled = sharedPreferences.getBool(PreferencesKey.disableExchangeKey);
if (isExchangeDisabled == null) {
return;
}
await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, isExchangeDisabled
? ExchangeApiMode.disabled.raw : ExchangeApiMode.enabled.raw);
}

View file

@ -0,0 +1,39 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/enumerable_item.dart';
class ExchangeApiMode extends EnumerableItem<int> with Serializable<int> {
const ExchangeApiMode({required String title, required int raw}) : super(title: title, raw: raw);
static const all = [ExchangeApiMode.enabled, ExchangeApiMode.torOnly, ExchangeApiMode.disabled];
static const enabled = ExchangeApiMode(raw: 0, title: 'Enabled');
static const torOnly = ExchangeApiMode(raw: 1, title: 'Tor only');
static const disabled = ExchangeApiMode(raw: 2, title: 'Disabled');
static ExchangeApiMode deserialize({required int raw}) {
switch (raw) {
case 0:
return enabled;
case 1:
return torOnly;
case 2:
return disabled;
default:
throw Exception('Unexpected token: $raw for ExchangeApiMode deserialize');
}
}
@override
String toString() {
switch (this) {
case ExchangeApiMode.enabled:
return S.current.enabled;
case ExchangeApiMode.torOnly:
return S.current.tor_only;
case ExchangeApiMode.disabled:
return S.current.disabled;
default:
return '';
}
}
}

View file

@ -14,7 +14,7 @@ abstract class ExchangeProvider {
bool get isAvailable; bool get isAvailable;
bool get isEnabled; bool get isEnabled;
bool get supportsFixedRate; bool get supportsFixedRate;
bool get shouldUseOnionAddress => false; bool get supportsOnionAddress => false;
@override @override
String toString() => title; String toString() => title;

View file

@ -13,9 +13,11 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:http/http.dart'; import 'package:http/http.dart';
class TrocadorExchangeProvider extends ExchangeProvider { class TrocadorExchangeProvider extends ExchangeProvider {
TrocadorExchangeProvider() TrocadorExchangeProvider({this.useTorOnly = false})
: _lastUsedRateId = '', : _lastUsedRateId = '',
super(pairList: _supportedPairs()); super(pairList: _supportedPairs());
bool useTorOnly;
static const List<CryptoCurrency> _notSupported = [ static const List<CryptoCurrency> _notSupported = [
CryptoCurrency.scrt, CryptoCurrency.scrt,
@ -83,7 +85,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
params['id'] = _lastUsedRateId; params['id'] = _lastUsedRateId;
} }
final String apiAuthority = shouldUseOnionAddress ? await _getAuthority() : clearNetAuthority; final String apiAuthority = await _getAuthority();
final uri = Uri.https(apiAuthority, createTradePath, params); final uri = Uri.https(apiAuthority, createTradePath, params);
final response = await get(uri); final response = await get(uri);
@ -142,7 +144,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
'name': from.name, 'name': from.name,
}; };
final String apiAuthority = shouldUseOnionAddress ? await _getAuthority() : clearNetAuthority; final String apiAuthority = await _getAuthority();
final uri = Uri.https(apiAuthority, coinPath, params); final uri = Uri.https(apiAuthority, coinPath, params);
final response = await get(uri); final response = await get(uri);
@ -178,7 +180,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
return 0.0; return 0.0;
} }
final String apiAuthority = shouldUseOnionAddress ? await _getAuthority() : clearNetAuthority; final String apiAuthority = await _getAuthority();
final params = <String, String>{ final params = <String, String>{
'api_key': apiKey, 'api_key': apiKey,
@ -214,7 +216,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
@override @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final String apiAuthority = shouldUseOnionAddress ? await _getAuthority() : clearNetAuthority; final String apiAuthority = await _getAuthority();
final uri = Uri.https(apiAuthority, tradePath, {'api_key': apiKey, 'id': id}); final uri = Uri.https(apiAuthority, tradePath, {'api_key': apiKey, 'id': id});
return get(uri).then((response) { return get(uri).then((response) {
if (response.statusCode != 200) { if (response.statusCode != 200) {
@ -265,7 +267,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
bool get supportsFixedRate => true; bool get supportsFixedRate => true;
@override @override
bool get shouldUseOnionAddress => true; bool get supportsOnionAddress => true;
@override @override
String get title => 'Trocador'; String get title => 'Trocador';
@ -297,11 +299,21 @@ class TrocadorExchangeProvider extends ExchangeProvider {
} }
Future<String> _getAuthority() async { Future<String> _getAuthority() async {
if(!supportsOnionAddress){
return clearNetAuthority;
}
try { try {
if (useTorOnly) {
return onionApiAuthority;
}
final uri = Uri.https(onionApiAuthority, '/api/trade'); final uri = Uri.https(onionApiAuthority, '/api/trade');
await get(uri); await get(uri);
return onionApiAuthority; return onionApiAuthority;
} catch (e) { } catch (e) {
return clearNetAuthority; return clearNetAuthority;
} }
} }

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
@ -48,43 +49,55 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
padding: EdgeInsets.only(top: 24), padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection( child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24), contentPadding: EdgeInsets.only(bottom: 24),
content: Observer( content: Column(
builder: (_) => Column( crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, children: [
children: [ Observer(
SettingsChoicesCell( builder: (_) {
ChoicesListItem<FiatApiMode>( return SettingsSwitcherCell(
title: S.current.fiat_api, title: S.current.disable_fiat,
items: FiatApiMode.all, value: widget.privacySettingsViewModel.fiatApi == FiatApiMode.disabled,
selectedItem: widget.privacySettingsViewModel.fiatApi, onValueChange: (BuildContext context, bool value) {
onItemSelected: (FiatApiMode mode) => widget.privacySettingsViewModel.setFiatMode(value);
widget.privacySettingsViewModel.setFiatMode(mode), });
), }
), ),
SettingsChoicesCell( Observer(
ChoicesListItem<FiatApiMode>( builder: (_) {
title: S.current.exchange, return SettingsChoicesCell(
items: FiatApiMode.all, ChoicesListItem<ExchangeApiMode>(
selectedItem: widget.privacySettingsViewModel.exchangeStatus, title: S.current.exchange,
onItemSelected: (FiatApiMode mode) => items: ExchangeApiMode.all,
widget.privacySettingsViewModel.setEnableExchange(mode), selectedItem: widget.privacySettingsViewModel.exchangeStatus,
), onItemSelected: (ExchangeApiMode mode) =>
), widget.privacySettingsViewModel.setEnableExchange(mode),
SettingsSwitcherCell(
title: S.current.add_custom_node,
value: widget.privacySettingsViewModel.addCustomNode,
onValueChange: (_, __) => widget.privacySettingsViewModel.toggleAddCustomNode(),
),
if (widget.privacySettingsViewModel.addCustomNode)
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: NodeForm(
formKey: _formKey,
nodeViewModel: widget.nodeViewModel,
), ),
) );
], }
), ),
Observer(
builder: (_) {
return Column(
children: [
SettingsSwitcherCell(
title: S.current.add_custom_node,
value: widget.privacySettingsViewModel.addCustomNode,
onValueChange: (_, __) => widget.privacySettingsViewModel.toggleAddCustomNode(),
),
if (widget.privacySettingsViewModel.addCustomNode)
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: NodeForm(
formKey: _formKey,
nodeViewModel: widget.nodeViewModel,
),
)
],
);
}
),
],
), ),
bottomSectionPadding: EdgeInsets.all(24), bottomSectionPadding: EdgeInsets.all(24),
bottomSection: Column( bottomSection: Column(

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
@ -24,20 +25,18 @@ class PrivacyPage extends BasePage {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SettingsSwitcherCell(
title: S.current.disable_fiat,
value: _privacySettingsViewModel.isFiatDisabled,
onValueChange: (BuildContext context, bool value) {
_privacySettingsViewModel.setFiatMode(value);
}),
SettingsChoicesCell( SettingsChoicesCell(
ChoicesListItem<FiatApiMode>( ChoicesListItem<ExchangeApiMode>(
title: S.current.fiat_api,
items: FiatApiMode.all,
selectedItem: _privacySettingsViewModel.fiatApi,
onItemSelected: (FiatApiMode mode) => _privacySettingsViewModel.setFiatMode(mode),
),
),
SettingsChoicesCell(
ChoicesListItem<FiatApiMode>(
title: S.current.exchange, title: S.current.exchange,
items: FiatApiMode.all, items: ExchangeApiMode.all,
selectedItem: _privacySettingsViewModel.exchangeStatus, selectedItem: _privacySettingsViewModel.exchangeStatus,
onItemSelected: (FiatApiMode mode) => _privacySettingsViewModel.setEnableExchange(mode), onItemSelected: (ExchangeApiMode mode) => _privacySettingsViewModel.setEnableExchange(mode),
), ),
), ),
SettingsSwitcherCell( SettingsSwitcherCell(

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
@ -31,7 +32,7 @@ abstract class SettingsStoreBase with Store {
required bool initialSaveRecipientAddress, required bool initialSaveRecipientAddress,
required FiatApiMode initialFiatMode, required FiatApiMode initialFiatMode,
required bool initialAllowBiometricalAuthentication, required bool initialAllowBiometricalAuthentication,
required FiatApiMode initialExchangeStatus, required ExchangeApiMode initialExchangeStatus,
required ThemeBase initialTheme, required ThemeBase initialTheme,
required int initialPinLength, required int initialPinLength,
required String initialLanguageCode, required String initialLanguageCode,
@ -154,7 +155,7 @@ abstract class SettingsStoreBase with Store {
reaction( reaction(
(_) => exchangeStatus, (_) => exchangeStatus,
(FiatApiMode mode) => sharedPreferences.setInt( (ExchangeApiMode mode) => sharedPreferences.setInt(
PreferencesKey.exchangeStatusKey, mode.serialize())); PreferencesKey.exchangeStatusKey, mode.serialize()));
this this
@ -192,7 +193,7 @@ abstract class SettingsStoreBase with Store {
bool allowBiometricalAuthentication; bool allowBiometricalAuthentication;
@observable @observable
FiatApiMode exchangeStatus; ExchangeApiMode exchangeStatus;
@observable @observable
ThemeBase currentTheme; ThemeBase currentTheme;
@ -284,9 +285,9 @@ abstract class SettingsStoreBase with Store {
final allowBiometricalAuthentication = sharedPreferences final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false; false;
final exchangeStatus = FiatApiMode.deserialize( final exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences raw: sharedPreferences
.getInt(PreferencesKey.exchangeStatusKey) ?? FiatApiMode.enabled.raw); .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
final legacyTheme = final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index ? ThemeType.dark.index
@ -401,9 +402,9 @@ abstract class SettingsStoreBase with Store {
allowBiometricalAuthentication = sharedPreferences allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
allowBiometricalAuthentication; allowBiometricalAuthentication;
exchangeStatus = FiatApiMode.deserialize( exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences raw: sharedPreferences
.getInt(PreferencesKey.exchangeStatusKey) ?? FiatApiMode.enabled.raw); .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
final legacyTheme = final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index ? ThemeType.dark.index

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -12,7 +13,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) : _addCustomNode = false; AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) : _addCustomNode = false;
@computed @computed
FiatApiMode get exchangeStatus => _settingsStore.exchangeStatus; ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus;
@computed @computed
FiatApiMode get fiatApi => _settingsStore.fiatApiMode; FiatApiMode get fiatApi => _settingsStore.fiatApiMode;
@ -28,12 +29,16 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
bool get addCustomNode => _addCustomNode; bool get addCustomNode => _addCustomNode;
@action @action
void setFiatMode(FiatApiMode value) { void setFiatMode(bool value) {
_settingsStore.fiatApiMode = value; if (value) {
_settingsStore.fiatApiMode = FiatApiMode.disabled;
return;
}
_settingsStore.fiatApiMode = FiatApiMode.enabled;
} }
@action @action
void setEnableExchange(FiatApiMode value) { void setEnableExchange(ExchangeApiMode value) {
_settingsStore.exchangeStatus = value; _settingsStore.exchangeStatus = value;
} }

View file

@ -56,6 +56,7 @@ abstract class ExchangeViewModelBase with Store {
isDepositAddressEnabled = false, isDepositAddressEnabled = false,
isReceiveAddressEnabled = false, isReceiveAddressEnabled = false,
isReceiveAmountEditable = false, isReceiveAmountEditable = false,
_providerUseTorOnly = false,
receiveCurrencies = <CryptoCurrency>[], receiveCurrencies = <CryptoCurrency>[],
depositCurrencies = <CryptoCurrency>[], depositCurrencies = <CryptoCurrency>[],
limits = Limits(min: 0, max: 0), limits = Limits(min: 0, max: 0),
@ -65,6 +66,7 @@ abstract class ExchangeViewModelBase with Store {
depositCurrency = wallet.currency, depositCurrency = wallet.currency,
providerList = [], providerList = [],
selectedProviders = ObservableList<ExchangeProvider>() { selectedProviders = ObservableList<ExchangeProvider>() {
_providerUseTorOnly = _settingsStore.exchangeStatus == FiatApiMode.torOnly;
_setProviders(); _setProviders();
const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano]; const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano];
const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp, const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp,
@ -121,18 +123,18 @@ abstract class ExchangeViewModelBase with Store {
_calculateBestRate(); _calculateBestRate();
}); });
} }
bool _providerUseTorOnly;
final WalletBase wallet; final WalletBase wallet;
final Box<Trade> trades; final Box<Trade> trades;
final ExchangeTemplateStore _exchangeTemplateStore; final ExchangeTemplateStore _exchangeTemplateStore;
final TradesStore tradesStore; final TradesStore tradesStore;
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
final _allProviders = [ List<ExchangeProvider> get _allProviders => [
ChangeNowExchangeProvider(), ChangeNowExchangeProvider(),
SideShiftExchangeProvider(), SideShiftExchangeProvider(),
SimpleSwapExchangeProvider(), SimpleSwapExchangeProvider(),
TrocadorExchangeProvider(), TrocadorExchangeProvider(useTorOnly: _providerUseTorOnly),
]; ];
@observable @observable
@ -695,7 +697,7 @@ abstract class ExchangeViewModelBase with Store {
void _setProviders(){ void _setProviders(){
if (_settingsStore.exchangeStatus == FiatApiMode.torOnly) { if (_settingsStore.exchangeStatus == FiatApiMode.torOnly) {
providerList = _allProviders.where((provider) => provider.shouldUseOnionAddress).toList(); providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
} else { } else {
providerList = _allProviders; providerList = _allProviders;
} }

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
@ -12,23 +13,27 @@ abstract class PrivacySettingsViewModelBase with Store {
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
@computed @computed
FiatApiMode get exchangeStatus => _settingsStore.exchangeStatus; ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus;
@computed @computed
bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;
@computed @computed
FiatApiMode get fiatApi => _settingsStore.fiatApiMode; bool get isFiatDisabled => _settingsStore.fiatApiMode == FiatApiMode.disabled;
@action @action
void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value; void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value;
@action @action
void setEnableExchange(FiatApiMode value) => _settingsStore.exchangeStatus = value; void setEnableExchange(ExchangeApiMode value) => _settingsStore.exchangeStatus = value;
@action @action
void setFiatMode(FiatApiMode value) { void setFiatMode(bool value) {
_settingsStore.fiatApiMode = value; if (value) {
_settingsStore.fiatApiMode = FiatApiMode.disabled;
return;
}
_settingsStore.fiatApiMode = FiatApiMode.enabled;
} }
} }