mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-30 14:36:06 +00:00
Merge branch 'main' into CW-122-Rework-filter-on-the-transactions-list-screen
This commit is contained in:
commit
00c008ed8b
52 changed files with 738 additions and 338 deletions
|
@ -16,7 +16,7 @@
|
||||||
android:requestLegacyExternalStorage="true">
|
android:requestLegacyExternalStorage="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleInstance"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
@ -39,6 +39,15 @@
|
||||||
android:scheme="cakewallet"
|
android:scheme="cakewallet"
|
||||||
android:host="y.at" />
|
android:host="y.at" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<!-- currencies qr code scheme -->
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="bitcoin" />
|
||||||
|
<data android:scheme="monero" />
|
||||||
|
<data android:scheme="litecoin" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
|
|
BIN
assets/images/2.0x/privacy_menu.png
Normal file
BIN
assets/images/2.0x/privacy_menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/3.0x/privacy_menu.png
Normal file
BIN
assets/images/3.0x/privacy_menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/images/privacy_menu.png
Normal file
BIN
assets/images/privacy_menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 548 B |
|
@ -303,7 +303,7 @@ class ElectrumClient {
|
||||||
Future<List<int>> feeRates() async {
|
Future<List<int>> feeRates() async {
|
||||||
try {
|
try {
|
||||||
final topDoubleString = await estimatefee(p: 1);
|
final topDoubleString = await estimatefee(p: 1);
|
||||||
final middleDoubleString = await estimatefee(p: 20);
|
final middleDoubleString = await estimatefee(p: 5);
|
||||||
final bottomDoubleString = await estimatefee(p: 100);
|
final bottomDoubleString = await estimatefee(p: 100);
|
||||||
final top =
|
final top =
|
||||||
(stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000)
|
(stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000)
|
||||||
|
|
|
@ -21,22 +21,6 @@ class MoneroTransactionPriority extends TransactionPriority {
|
||||||
static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
|
static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
|
||||||
static const standard = slow;
|
static const standard = slow;
|
||||||
|
|
||||||
|
|
||||||
static List<MoneroTransactionPriority> forWalletType(WalletType type) {
|
|
||||||
switch (type) {
|
|
||||||
case WalletType.monero:
|
|
||||||
return MoneroTransactionPriority.all;
|
|
||||||
case WalletType.bitcoin:
|
|
||||||
return [
|
|
||||||
MoneroTransactionPriority.slow,
|
|
||||||
MoneroTransactionPriority.automatic,
|
|
||||||
MoneroTransactionPriority.fast
|
|
||||||
];
|
|
||||||
default:
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static MoneroTransactionPriority deserialize({required int raw}) {
|
static MoneroTransactionPriority deserialize({required int raw}) {
|
||||||
switch (raw) {
|
switch (raw) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -53,7 +53,7 @@ class Node extends HiveObject with Keyable {
|
||||||
@HiveField(4)
|
@HiveField(4)
|
||||||
bool? useSSL;
|
bool? useSSL;
|
||||||
|
|
||||||
@HiveField(5)
|
@HiveField(5, defaultValue: false)
|
||||||
bool trusted;
|
bool trusted;
|
||||||
|
|
||||||
bool get isSSL => useSSL ?? false;
|
bool get isSSL => useSSL ?? false;
|
||||||
|
|
|
@ -21,18 +21,48 @@
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
<key>CFBundleURLName</key>
|
<key>CFBundleURLName</key>
|
||||||
<string>y.at</string>
|
<string>y.at</string>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>cakewallet</string>
|
<string>cakewallet</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>bitcoin</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>bitcoin</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>monero</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>monero</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>litecoin</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>litecoin</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
|
|
@ -4,12 +4,19 @@ 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:cake_wallet/entities/secret_store_key.dart';
|
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||||
import 'package:cake_wallet/entities/encrypt.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 {
|
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 FlutterSecureStorage secureStorage;
|
||||||
final SharedPreferences sharedPreferences;
|
final SharedPreferences sharedPreferences;
|
||||||
|
final SettingsStore settingsStore;
|
||||||
|
|
||||||
Future<void> setPassword(String password) async {
|
Future<void> setPassword(String password) async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
|
@ -19,8 +26,7 @@ class AuthService with Store {
|
||||||
|
|
||||||
Future<bool> canAuthenticate() async {
|
Future<bool> canAuthenticate() async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
final walletName =
|
final walletName = sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
|
||||||
sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
|
|
||||||
var password = '';
|
var password = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -39,4 +45,25 @@ class AuthService with Store {
|
||||||
|
|
||||||
return decodedPin == pin;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
25
lib/di.dart
25
lib/di.dart
|
@ -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_gift_card_detail_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_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/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_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_buy_card_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_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(
|
getIt.registerFactory<AuthService>(() => AuthService(
|
||||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||||
sharedPreferences: getIt.get<SharedPreferences>()));
|
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||||
|
settingsStore: getIt.get<SettingsStore>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
|
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
|
||||||
getIt.get<AuthService>(),
|
getIt.get<AuthService>(),
|
||||||
|
@ -384,8 +388,11 @@ Future setup(
|
||||||
getIt.get<BalanceViewModel>(),
|
getIt.get<BalanceViewModel>(),
|
||||||
_transactionDescriptionBox));
|
_transactionDescriptionBox));
|
||||||
|
|
||||||
getIt.registerFactory(
|
getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
|
||||||
() => SendPage(sendViewModel: getIt.get<SendViewModel>()));
|
(PaymentRequest? initialPaymentRequest, _) => SendPage(
|
||||||
|
sendViewModel: getIt.get<SendViewModel>(),
|
||||||
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
|
));
|
||||||
|
|
||||||
getIt.registerFactory(() => SendTemplatePage(
|
getIt.registerFactory(() => SendTemplatePage(
|
||||||
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||||
|
@ -393,7 +400,10 @@ Future setup(
|
||||||
getIt.registerFactory(() => WalletListViewModel(
|
getIt.registerFactory(() => WalletListViewModel(
|
||||||
_walletInfoSource,
|
_walletInfoSource,
|
||||||
getIt.get<AppStore>(),
|
getIt.get<AppStore>(),
|
||||||
getIt.get<WalletLoadingService>()));
|
getIt.get<WalletLoadingService>(),
|
||||||
|
getIt.get<AuthService>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
getIt.registerFactory(() =>
|
getIt.registerFactory(() =>
|
||||||
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
|
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
|
||||||
|
@ -453,7 +463,7 @@ Future setup(
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() {
|
||||||
return SecuritySettingsViewModel(getIt.get<SettingsStore>());
|
return SecuritySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AuthService>());
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt
|
getIt
|
||||||
|
@ -785,7 +795,8 @@ Future setup(
|
||||||
return IoniaMoreOptionsPage(giftCard);
|
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, _){
|
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||||
final giftCard = args.first as IoniaGiftCard;
|
final giftCard = args.first as IoniaGiftCard;
|
||||||
|
@ -823,4 +834,4 @@ Future setup(
|
||||||
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
||||||
|
|
||||||
_isSetupFinished = true;
|
_isSetupFinished = true;
|
||||||
}
|
}
|
|
@ -139,6 +139,10 @@ Future defaultSettingsMigration(
|
||||||
await addOnionNode(nodes);
|
await addOnionNode(nodes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 19:
|
||||||
|
await validateBitcoinSavedTransactionPriority(sharedPreferences);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -154,6 +158,18 @@ Future defaultSettingsMigration(
|
||||||
PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
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 {
|
Future<void> addOnionNode(Box<Node> nodes) async {
|
||||||
final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081";
|
final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081";
|
||||||
|
|
||||||
|
|
32
lib/entities/pin_code_required_duration.dart
Normal file
32
lib/entities/pin_code_required_duration.dart
Normal file
|
@ -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 shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
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)
|
static String moneroWalletUpdateV1Key(String name)
|
||||||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||||
|
|
|
@ -37,7 +37,7 @@ class IoniaGiftCard {
|
||||||
purchaseAmount: element['PurchaseAmount'] as double,
|
purchaseAmount: element['PurchaseAmount'] as double,
|
||||||
actualAmount: element['ActualAmount'] as double,
|
actualAmount: element['ActualAmount'] as double,
|
||||||
totalTransactionAmount: element['TotalTransactionAmount'] as double,
|
totalTransactionAmount: element['TotalTransactionAmount'] as double,
|
||||||
totalDashTransactionAmount: element['TotalDashTransactionAmount'] as double,
|
totalDashTransactionAmount: (element['TotalDashTransactionAmount'] as double?) ?? 0.0,
|
||||||
remainingAmount: element['RemainingAmount'] as double,
|
remainingAmount: element['RemainingAmount'] as double,
|
||||||
isActive: element['IsActive'] as bool,
|
isActive: element['IsActive'] as bool,
|
||||||
isEmpty: element['IsEmpty'] as bool,
|
isEmpty: element['IsEmpty'] as bool,
|
||||||
|
|
|
@ -148,8 +148,8 @@ class IoniaService {
|
||||||
|
|
||||||
// Redeem
|
// Redeem
|
||||||
|
|
||||||
Future<void> redeem(IoniaGiftCard giftCard) async {
|
Future<void> redeem({required int giftCardId, required double amount}) async {
|
||||||
await chargeGiftCard(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
|
await chargeGiftCard(giftCardId: giftCardId, amount: amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Gift Card
|
// Get Gift Card
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
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/entities/language_service.dart';
|
||||||
import 'package:cake_wallet/buy/order.dart';
|
import 'package:cake_wallet/buy/order.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||||
|
@ -128,7 +129,7 @@ Future<void> main() async {
|
||||||
exchangeTemplates: exchangeTemplates,
|
exchangeTemplates: exchangeTemplates,
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
initialMigrationVersion: 18);
|
initialMigrationVersion: 19);
|
||||||
runApp(App());
|
runApp(App());
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
runApp(MaterialApp(
|
runApp(MaterialApp(
|
||||||
|
@ -204,12 +205,6 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||||
//_handleInitialUri();
|
//_handleInitialUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
stream?.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleInitialUri() async {
|
Future<void> _handleInitialUri() async {
|
||||||
try {
|
try {
|
||||||
final uri = await getInitialUri();
|
final uri = await getInitialUri();
|
||||||
|
@ -257,6 +252,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Observer(builder: (BuildContext context) {
|
return Observer(builder: (BuildContext context) {
|
||||||
final appStore = getIt.get<AppStore>();
|
final appStore = getIt.get<AppStore>();
|
||||||
|
final authService = getIt.get<AuthService>();
|
||||||
final settingsStore = appStore.settingsStore;
|
final settingsStore = appStore.settingsStore;
|
||||||
final statusBarColor = Colors.transparent;
|
final statusBarColor = Colors.transparent;
|
||||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||||
|
@ -281,6 +277,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||||
appStore: appStore,
|
appStore: appStore,
|
||||||
authenticationStore: authenticationStore,
|
authenticationStore: authenticationStore,
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
|
authService: authService,
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
|
|
|
@ -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/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_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_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/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/node_list/node_create_or_edit_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_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>());
|
builder: (_) => getIt.get<DashboardPage>());
|
||||||
|
|
||||||
case Routes.send:
|
case Routes.send:
|
||||||
|
final initialPaymentRequest = settings.arguments as PaymentRequest?;
|
||||||
|
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>(
|
||||||
|
param1: initialPaymentRequest,
|
||||||
|
));
|
||||||
|
|
||||||
case Routes.sendTemplate:
|
case Routes.sendTemplate:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
|
|
|
@ -21,6 +21,12 @@ class WalletMenu {
|
||||||
height: 16, width: 16),
|
height: 16, width: 16),
|
||||||
handler: () => Navigator.of(context).pushNamed(Routes.walletList),
|
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(
|
WalletMenuItem(
|
||||||
title: S.current.security_and_backup,
|
title: S.current.security_and_backup,
|
||||||
image:
|
image:
|
||||||
|
@ -29,18 +35,12 @@ class WalletMenu {
|
||||||
Navigator.of(context).pushNamed(Routes.securityBackupPage);
|
Navigator.of(context).pushNamed(Routes.securityBackupPage);
|
||||||
}),
|
}),
|
||||||
WalletMenuItem(
|
WalletMenuItem(
|
||||||
title: S.current.privacy,
|
title: S.current.privacy_settings,
|
||||||
image:
|
image:
|
||||||
Image.asset('assets/images/eye_menu.png', height: 16, width: 16),
|
Image.asset('assets/images/privacy_menu.png', height: 16, width: 16),
|
||||||
handler: () {
|
handler: () {
|
||||||
Navigator.of(context).pushNamed(Routes.privacyPage);
|
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(
|
WalletMenuItem(
|
||||||
title: S.current.display_settings,
|
title: S.current.display_settings,
|
||||||
image: Image.asset('assets/images/eye_menu.png',
|
image: Image.asset('assets/images/eye_menu.png',
|
||||||
|
|
|
@ -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/base_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
|
import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
|
||||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
@ -18,12 +19,11 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
) : _amountFieldFocus = FocusNode(),
|
) : _amountFieldFocus = FocusNode(),
|
||||||
_amountController = TextEditingController() {
|
_amountController = TextEditingController() {
|
||||||
_amountController.addListener(() {
|
_amountController.addListener(() {
|
||||||
ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
|
ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
|
final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.custom_redeem_amount;
|
String get title => S.current.custom_redeem_amount;
|
||||||
|
@ -50,7 +50,7 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
disableScroll: true,
|
disableScroll: true,
|
||||||
config: KeyboardActionsConfig(
|
config: KeyboardActionsConfig(
|
||||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!,
|
keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
|
||||||
nextFocus: false,
|
nextFocus: false,
|
||||||
actions: [
|
actions: [
|
||||||
KeyboardActionsItem(
|
KeyboardActionsItem(
|
||||||
|
@ -67,10 +67,11 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 25),
|
padding: EdgeInsets.symmetric(horizontal: 25),
|
||||||
decoration: BoxDecoration(
|
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: [
|
gradient: LinearGradient(colors: [
|
||||||
Theme.of(context).primaryTextTheme!.subtitle1!.color!,
|
Theme.of(context).primaryTextTheme.subtitle1!.color!,
|
||||||
Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!,
|
Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
|
||||||
], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -85,11 +86,11 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
|
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
|
||||||
hintText: '1000',
|
hintText: '1000',
|
||||||
placeholderTextStyle: TextStyle(
|
placeholderTextStyle: TextStyle(
|
||||||
color: Theme.of(context).primaryTextTheme!.headline5!.color!,
|
color: Theme.of(context).primaryTextTheme.headline5!.color!,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
fontSize: 36,
|
fontSize: 36,
|
||||||
),
|
),
|
||||||
borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!,
|
borderColor: Theme.of(context).primaryTextTheme.headline5!.color!,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
@ -114,14 +115,17 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Observer(builder: (_)=>
|
Observer(
|
||||||
!ioniaCustomRedeemViewModel.disableRedeem ?
|
builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem
|
||||||
Center(
|
? Center(
|
||||||
child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
|
child: Text(
|
||||||
style: TextStyle(
|
'\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
|
||||||
color: Theme.of(context).primaryTextTheme!.headline5!.color!,
|
style: TextStyle(
|
||||||
),),
|
color: Theme.of(context).primaryTextTheme.headline5!.color!,
|
||||||
) : SizedBox.shrink(),
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
SizedBox(height: 24),
|
SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
|
@ -131,30 +135,37 @@ class IoniaCustomRedeemPage extends BasePage {
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: CardItem(
|
child: CardItem(
|
||||||
title: giftCard.legalName,
|
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,
|
discount: giftCard.remainingAmount,
|
||||||
isAmount: true,
|
isAmount: true,
|
||||||
discountBackground: AssetImage('assets/images/red_badge_discount.png'),
|
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,
|
subtitleColor: Theme.of(context).hintColor,
|
||||||
subTitle: S.of(context).online,
|
subTitle: S.of(context).online,
|
||||||
logoUrl: giftCard.logoUrl,
|
logoUrl: giftCard.logoUrl,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomSection: Column(
|
bottomSection: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Observer(
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
builder: (_) => Padding(
|
||||||
child: PrimaryButton(
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
onPressed: () {
|
child: LoadingPrimaryButton(
|
||||||
Navigator.of(context).pop(_amountController.text);
|
isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState,
|
||||||
},
|
isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
|
||||||
isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
|
text: S.of(context).add_custom_redemption,
|
||||||
text: S.of(context).add_custom_redemption,
|
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
|
||||||
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
|
textColor: Colors.white,
|
||||||
textColor: Colors.white,
|
onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) {
|
||||||
|
Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString());
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 30),
|
SizedBox(height: 30),
|
||||||
|
|
|
@ -32,7 +32,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
|
|
||||||
final _backButton = Icon(
|
final _backButton = Icon(
|
||||||
Icons.arrow_back_ios,
|
Icons.arrow_back_ios,
|
||||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||||
size: 16,
|
size: 16,
|
||||||
);
|
);
|
||||||
return Padding(
|
return Padding(
|
||||||
|
@ -43,7 +43,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
child: ButtonTheme(
|
child: ButtonTheme(
|
||||||
minWidth: double.minPositive,
|
minWidth: double.minPositive,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
// FIX-ME: Style
|
// FIX-ME: Style
|
||||||
//highlightColor: Colors.transparent,
|
//highlightColor: Colors.transparent,
|
||||||
//splashColor: Colors.transparent,
|
//splashColor: Colors.transparent,
|
||||||
//padding: EdgeInsets.all(0),
|
//padding: EdgeInsets.all(0),
|
||||||
|
@ -61,7 +61,8 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
viewModel.giftCard.legalName,
|
viewModel.giftCard.legalName,
|
||||||
style: textMediumSemiBold(color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!),
|
style:
|
||||||
|
textMediumSemiBold(color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,20 +103,21 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
title: S.of(context).gift_card_number,
|
title: S.of(context).gift_card_number,
|
||||||
subTitle: viewModel.giftCard.cardNumber,
|
subTitle: viewModel.giftCard.cardNumber,
|
||||||
),
|
),
|
||||||
if (viewModel.giftCard.cardPin?.isNotEmpty ?? false)
|
if (viewModel.giftCard.cardPin.isNotEmpty) ...[
|
||||||
...[Divider(height: 30),
|
Divider(height: 30),
|
||||||
buildIoniaTile(
|
buildIoniaTile(
|
||||||
context,
|
context,
|
||||||
title: S.of(context).pin_number,
|
title: S.of(context).pin_number,
|
||||||
subTitle: viewModel.giftCard.cardPin,
|
subTitle: viewModel.giftCard.cardPin,
|
||||||
)],
|
)
|
||||||
|
],
|
||||||
Divider(height: 30),
|
Divider(height: 30),
|
||||||
Observer(builder: (_) =>
|
Observer(
|
||||||
buildIoniaTile(
|
builder: (_) => buildIoniaTile(
|
||||||
context,
|
context,
|
||||||
title: S.of(context).amount,
|
title: S.of(context).amount,
|
||||||
subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00',
|
subTitle: viewModel.remainingAmount.toStringAsFixed(2),
|
||||||
)),
|
)),
|
||||||
Divider(height: 50),
|
Divider(height: 50),
|
||||||
TextIconButton(
|
TextIconButton(
|
||||||
label: S.of(context).how_to_use_card,
|
label: S.of(context).how_to_use_card,
|
||||||
|
@ -130,29 +132,28 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
if (!viewModel.giftCard.isEmpty) {
|
if (!viewModel.giftCard.isEmpty) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
//PrimaryButton(
|
PrimaryButton(
|
||||||
// onPressed: () async {
|
onPressed: () async {
|
||||||
// final amount = await Navigator.of(context)
|
await Navigator.of(context).pushNamed(
|
||||||
// .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as String;
|
Routes.ioniaMoreOptionsPage,
|
||||||
// if (amount != null) {
|
arguments: [viewModel.giftCard]) as String?;
|
||||||
// viewModel.updateRemaining(double.parse(amount));
|
viewModel.refeshCard();
|
||||||
// }
|
},
|
||||||
// },
|
text: S.of(context).more_options,
|
||||||
// text: S.of(context).more_options,
|
color: Theme.of(context).accentTextTheme.caption!.color!,
|
||||||
// color: Theme.of(context).accentTextTheme!.caption!.color!,
|
textColor: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||||
// textColor: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
),
|
||||||
//),
|
SizedBox(height: 12),
|
||||||
//SizedBox(height: 12),
|
|
||||||
LoadingPrimaryButton(
|
LoadingPrimaryButton(
|
||||||
isLoading: viewModel.redeemState is IsExecutingState,
|
isLoading: viewModel.redeemState is IsExecutingState,
|
||||||
onPressed: () => viewModel.redeem().then(
|
onPressed: () => viewModel.redeem().then(
|
||||||
(_) {
|
(_) {
|
||||||
Navigator.of(context)
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||||
.pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
|
Routes.ioniaManageCardsPage, (route) => route.isFirst);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
text: S.of(context).mark_as_redeemed,
|
text: S.of(context).mark_as_redeemed,
|
||||||
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
|
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -168,12 +169,11 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
|
|
||||||
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
||||||
return IoniaTile(
|
return IoniaTile(
|
||||||
title: title,
|
title: title,
|
||||||
subTitle: subTitle,
|
subTitle: subTitle,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Clipboard.setData(ClipboardData(text: subTitle));
|
Clipboard.setData(ClipboardData(text: subTitle));
|
||||||
showBar<void>(context,
|
showBar<void>(context, S.of(context).transaction_details_copied(title));
|
||||||
S.of(context).transaction_details_copied(title));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +184,10 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return IoniaAlertModal(
|
return IoniaAlertModal(
|
||||||
title: S.of(context).how_to_use_card,
|
title: S.of(context).how_to_use_card,
|
||||||
content: Column(
|
content: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: viewModel.giftCard.instructions
|
children: viewModel.giftCard.instructions
|
||||||
.map((instruction) {
|
.map((instruction) {
|
||||||
return [
|
return [
|
||||||
|
@ -196,13 +196,13 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
child: Text(
|
child: Text(
|
||||||
instruction.header,
|
instruction.header,
|
||||||
style: textLargeSemiBold(
|
style: textLargeSemiBold(
|
||||||
color: Theme.of(context).textTheme!.headline3!.color!,
|
color: Theme.of(context).textTheme.headline3!.color!,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Text(
|
Text(
|
||||||
instruction.body,
|
instruction.body,
|
||||||
style: textMedium(
|
style: textMedium(
|
||||||
color: Theme.of(context).textTheme!.headline3!.color!,
|
color: Theme.of(context).textTheme.headline3!.color!,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
@ -210,7 +210,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
.expand((e) => e)
|
.expand((e) => e)
|
||||||
.toList()),
|
.toList()),
|
||||||
actionTitle: S.of(context).send_got_it,
|
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:cake_wallet/typography.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
class IoniaMoreOptionsPage extends BasePage {
|
class IoniaMoreOptionsPage extends BasePage {
|
||||||
IoniaMoreOptionsPage(this.giftCard);
|
IoniaMoreOptionsPage(this.giftCard);
|
||||||
|
|
||||||
|
@ -16,7 +15,7 @@ class IoniaMoreOptionsPage extends BasePage {
|
||||||
return Text(
|
return Text(
|
||||||
S.current.more_options,
|
S.current.more_options,
|
||||||
style: textMediumSemiBold(
|
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),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 10,),
|
SizedBox(
|
||||||
Center(child: Text(S.of(context).choose_from_available_options, style: textMedium(
|
height: 10,
|
||||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
),
|
||||||
),)),
|
Center(
|
||||||
SizedBox(height: 40,),
|
child: Text(
|
||||||
InkWell(
|
S.of(context).choose_from_available_options,
|
||||||
onTap: () async {
|
style: textMedium(
|
||||||
final amount = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String;
|
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||||
if(amount.isNotEmpty){
|
),
|
||||||
Navigator.pop(context, amount);
|
),
|
||||||
}
|
),
|
||||||
},
|
SizedBox(height: 40),
|
||||||
child: _GradiantContainer(
|
InkWell(
|
||||||
content: Padding(
|
onTap: () async {
|
||||||
padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
|
final amount = await Navigator.of(context)
|
||||||
child: Text(
|
.pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?;
|
||||||
S.of(context).custom_redeem_amount,
|
if (amount != null && amount.isNotEmpty) {
|
||||||
style: textXLargeSemiBold(),
|
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 {
|
class _GradiantContainer extends StatelessWidget {
|
||||||
const _GradiantContainer({
|
const _GradiantContainer({Key? key, required this.content}) : super(key: key);
|
||||||
Key? key,
|
|
||||||
required this.content
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final Widget content;
|
final Widget content;
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
import 'dart:async';
|
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:flutter/material.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/authentication_store.dart';
|
import 'package:cake_wallet/store/authentication_store.dart';
|
||||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||||
|
import 'package:uni_links/uni_links.dart';
|
||||||
|
|
||||||
class Root extends StatefulWidget {
|
class Root extends StatefulWidget {
|
||||||
Root(
|
Root({
|
||||||
{required Key key,
|
required Key key,
|
||||||
required this.authenticationStore,
|
required this.authenticationStore,
|
||||||
required this.appStore,
|
required this.appStore,
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.navigatorKey})
|
required this.navigatorKey,
|
||||||
: super(key: key);
|
required this.authService,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
final AuthenticationStore authenticationStore;
|
final AuthenticationStore authenticationStore;
|
||||||
final AppStore appStore;
|
final AppStore appStore;
|
||||||
final GlobalKey<NavigatorState> navigatorKey;
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
|
final AuthService authService;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -26,22 +31,56 @@ class Root extends StatefulWidget {
|
||||||
|
|
||||||
class RootState extends State<Root> with WidgetsBindingObserver {
|
class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
RootState()
|
RootState()
|
||||||
: _isInactiveController = StreamController<bool>.broadcast(),
|
: _isInactiveController = StreamController<bool>.broadcast(),
|
||||||
_isInactive = false,
|
_isInactive = false,
|
||||||
_postFrameCallback = false;
|
_requestAuth = true,
|
||||||
|
_postFrameCallback = false;
|
||||||
|
|
||||||
Stream<bool> get isInactive => _isInactiveController.stream;
|
Stream<bool> get isInactive => _isInactiveController.stream;
|
||||||
StreamController<bool> _isInactiveController;
|
StreamController<bool> _isInactiveController;
|
||||||
bool _isInactive;
|
bool _isInactive;
|
||||||
bool _postFrameCallback;
|
bool _postFrameCallback;
|
||||||
|
bool _requestAuth;
|
||||||
|
|
||||||
|
StreamSubscription<Uri?>? stream;
|
||||||
|
Uri? launchUri;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_requestAuth = widget.authService.requireAuth();
|
||||||
_isInactiveController = StreamController<bool>.broadcast();
|
_isInactiveController = StreamController<bool>.broadcast();
|
||||||
_isInactive = false;
|
_isInactive = false;
|
||||||
_postFrameCallback = false;
|
_postFrameCallback = false;
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
super.initState();
|
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
|
@override
|
||||||
|
@ -52,11 +91,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isInactive &&
|
if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) {
|
||||||
widget.authenticationStore.state == AuthenticationState.allowed) {
|
|
||||||
setState(() => _setInactive(true));
|
setState(() => _setInactive(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.resumed:
|
||||||
|
setState(() {
|
||||||
|
_requestAuth = widget.authService.requireAuth();
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -65,7 +108,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isInactive && !_postFrameCallback) {
|
if (_isInactive && !_postFrameCallback && _requestAuth) {
|
||||||
_postFrameCallback = true;
|
_postFrameCallback = true;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
|
widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
|
||||||
|
@ -75,9 +118,19 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
_reset();
|
_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);
|
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/alert_with_two_actions.dart';
|
||||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||||
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||||
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cake_wallet/view_model/send/output.dart';
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.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';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
class SendPage extends BasePage {
|
class SendPage extends BasePage {
|
||||||
SendPage({required this.sendViewModel}) : _formKey = GlobalKey<FormState>();
|
SendPage({
|
||||||
|
required this.sendViewModel,
|
||||||
|
this.initialPaymentRequest,
|
||||||
|
}) : _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
final SendViewModel sendViewModel;
|
final SendViewModel sendViewModel;
|
||||||
final GlobalKey<FormState> _formKey;
|
final GlobalKey<FormState> _formKey;
|
||||||
final controller = PageController(initialPage: 0);
|
final controller = PageController(initialPage: 0);
|
||||||
|
final PaymentRequest? initialPaymentRequest;
|
||||||
|
|
||||||
bool _effectsInstalled = false;
|
bool _effectsInstalled = false;
|
||||||
|
|
||||||
|
@ -116,6 +121,7 @@ class SendPage extends BasePage {
|
||||||
key: output.key,
|
key: output.key,
|
||||||
output: output,
|
output: output,
|
||||||
sendViewModel: sendViewModel,
|
sendViewModel: sendViewModel,
|
||||||
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
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:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
@ -20,21 +21,28 @@ class SendCard extends StatefulWidget {
|
||||||
SendCard({
|
SendCard({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.output,
|
required this.output,
|
||||||
required this.sendViewModel}) : super(key: key);
|
required this.sendViewModel,
|
||||||
|
this.initialPaymentRequest,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
final Output output;
|
final Output output;
|
||||||
final SendViewModel sendViewModel;
|
final SendViewModel sendViewModel;
|
||||||
|
final PaymentRequest? initialPaymentRequest;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SendCardState createState() => SendCardState(
|
SendCardState createState() => SendCardState(
|
||||||
output: output,
|
output: output,
|
||||||
sendViewModel: sendViewModel
|
sendViewModel: sendViewModel,
|
||||||
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendCardState extends State<SendCard>
|
class SendCardState extends State<SendCard>
|
||||||
with AutomaticKeepAliveClientMixin<SendCard> {
|
with AutomaticKeepAliveClientMixin<SendCard> {
|
||||||
SendCardState({required this.output, required this.sendViewModel})
|
SendCardState({
|
||||||
|
required this.output,
|
||||||
|
required this.sendViewModel,
|
||||||
|
this.initialPaymentRequest})
|
||||||
: addressController = TextEditingController(),
|
: addressController = TextEditingController(),
|
||||||
cryptoAmountController = TextEditingController(),
|
cryptoAmountController = TextEditingController(),
|
||||||
fiatAmountController = TextEditingController(),
|
fiatAmountController = TextEditingController(),
|
||||||
|
@ -49,6 +57,7 @@ class SendCardState extends State<SendCard>
|
||||||
|
|
||||||
final Output output;
|
final Output output;
|
||||||
final SendViewModel sendViewModel;
|
final SendViewModel sendViewModel;
|
||||||
|
final PaymentRequest? initialPaymentRequest;
|
||||||
|
|
||||||
final TextEditingController addressController;
|
final TextEditingController addressController;
|
||||||
final TextEditingController cryptoAmountController;
|
final TextEditingController cryptoAmountController;
|
||||||
|
@ -61,6 +70,27 @@ class SendCardState extends State<SendCard>
|
||||||
|
|
||||||
bool _effectsInstalled = false;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
@ -512,8 +542,12 @@ class SendCardState extends State<SendCard>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setEffects(BuildContext context) {
|
void _setEffects(BuildContext context) {
|
||||||
addressController.text = output.address;
|
if (output.address.isNotEmpty) {
|
||||||
cryptoAmountController.text = output.cryptoAmount;
|
addressController.text = output.address;
|
||||||
|
}
|
||||||
|
if (output.cryptoAmount.isNotEmpty) {
|
||||||
|
cryptoAmountController.text = output.cryptoAmount;
|
||||||
|
}
|
||||||
fiatAmountController.text = output.fiatAmount;
|
fiatAmountController.text = output.fiatAmount;
|
||||||
noteController.text = output.note;
|
noteController.text = output.note;
|
||||||
extractedAddressController.text = output.extractedAddress;
|
extractedAddressController.text = output.extractedAddress;
|
||||||
|
@ -605,6 +639,13 @@ class SendCardState extends State<SendCard>
|
||||||
extractedAddressController.text = extractedAddress;
|
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;
|
_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/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.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/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_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/screens/settings/widgets/settings_switcher_cell.dart';
|
||||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.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: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.show_keys,
|
title: S.current.show_keys,
|
||||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
|
||||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
? Navigator.of(context).pushNamed(Routes.auth,
|
||||||
if (isAuthenticatedSuccessfully) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||||
auth.close(route: Routes.showKeys);
|
if (isAuthenticatedSuccessfully) {
|
||||||
}
|
auth.close(route: Routes.showKeys);
|
||||||
}),
|
}
|
||||||
|
})
|
||||||
|
: Navigator.of(context).pushNamed(Routes.showKeys),
|
||||||
),
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.create_backup,
|
title: S.current.create_backup,
|
||||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
|
||||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
? Navigator.of(context).pushNamed(Routes.auth,
|
||||||
if (isAuthenticatedSuccessfully) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||||
auth.close(route: Routes.backup);
|
if (isAuthenticatedSuccessfully) {
|
||||||
}
|
auth.close(route: Routes.backup);
|
||||||
}),
|
}
|
||||||
|
})
|
||||||
|
: Navigator.of(context).pushNamed(Routes.backup),
|
||||||
),
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
|
@ -65,10 +71,12 @@ class SecurityBackupPage extends BasePage {
|
||||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
if (isAuthenticatedSuccessfully) {
|
if (isAuthenticatedSuccessfully) {
|
||||||
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
||||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
_securitySettingsViewModel
|
||||||
|
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
_securitySettingsViewModel
|
||||||
|
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.close();
|
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);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,68 +220,88 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadWallet(WalletListItem wallet) async {
|
Future<void> _loadWallet(WalletListItem wallet) async {
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
if (await widget.walletListViewModel.checkIfAuthRequired()) {
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
await Navigator.of(context).pushNamed(Routes.auth,
|
||||||
if (!isAuthenticatedSuccessfully) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
return;
|
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 {
|
try {
|
||||||
auth.changeProcessText(
|
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
||||||
S.of(context).wallet_list_loading_wallet(wallet.name));
|
|
||||||
await widget.walletListViewModel.loadWallet(wallet);
|
await widget.walletListViewModel.loadWallet(wallet);
|
||||||
auth.hideProgressText();
|
hideProgressText();
|
||||||
auth.close();
|
Navigator.of(context).pop();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
auth.changeProcessText(S
|
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||||
.of(context)
|
|
||||||
.wallet_list_failed_to_load(wallet.name, e.toString()));
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _removeWallet(WalletListItem wallet) async {
|
Future<void> _removeWallet(WalletListItem wallet) async {
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
if (widget.walletListViewModel.checkIfAuthRequired()) {
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
await Navigator.of(context).pushNamed(Routes.auth,
|
||||||
if (!isAuthenticatedSuccessfully) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
return;
|
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()));
|
|
||||||
}
|
}
|
||||||
}
|
_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) {
|
void changeProcessText(String text) {
|
||||||
|
@ -294,16 +314,16 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
|
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
|
||||||
motion: const ScrollMotion(),
|
motion: const ScrollMotion(),
|
||||||
extentRatio: 0.3,
|
extentRatio: 0.3,
|
||||||
children: [
|
children: [
|
||||||
SlidableAction(
|
SlidableAction(
|
||||||
onPressed: (_) => _removeWallet(wallet),
|
onPressed: (_) => _removeWallet(wallet),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
icon: CupertinoIcons.delete,
|
icon: CupertinoIcons.delete,
|
||||||
label: S.of(context).delete,
|
label: S.of(context).delete,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,8 @@ abstract class TradesStoreBase with Store {
|
||||||
void setTrade(Trade trade) => this.trade = trade;
|
void setTrade(Trade trade) => this.trade = trade;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> updateTradeList() async {
|
Future<void> updateTradeList() async => trades =
|
||||||
if (trade == null) {
|
tradesSource.values.map((trade) => TradeListItem(
|
||||||
return;
|
trade: trade,
|
||||||
}
|
settingsStore: settingsStore)).toList();
|
||||||
|
|
||||||
trades = tradesSource.values.map((trade) => TradeListItem(
|
|
||||||
trade: trade!,
|
|
||||||
settingsStore: settingsStore)).toList();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
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:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.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/monero/monero.dart';
|
||||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_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';
|
part 'settings_store.g.dart';
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
required this.shouldShowYatPopup,
|
required this.shouldShowYatPopup,
|
||||||
required this.isBitcoinBuyEnabled,
|
required this.isBitcoinBuyEnabled,
|
||||||
required this.actionlistDisplayMode,
|
required this.actionlistDisplayMode,
|
||||||
|
required this.pinTimeOutDuration,
|
||||||
TransactionPriority? initialBitcoinTransactionPriority,
|
TransactionPriority? initialBitcoinTransactionPriority,
|
||||||
TransactionPriority? initialMoneroTransactionPriority,
|
TransactionPriority? initialMoneroTransactionPriority,
|
||||||
TransactionPriority? initialHavenTransactionPriority,
|
TransactionPriority? initialHavenTransactionPriority,
|
||||||
|
@ -141,6 +142,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
(String languageCode) => sharedPreferences.setString(
|
(String languageCode) => sharedPreferences.setString(
|
||||||
PreferencesKey.currentLanguageCode, languageCode));
|
PreferencesKey.currentLanguageCode, languageCode));
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => pinTimeOutDuration,
|
||||||
|
(PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt(
|
||||||
|
PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => balanceDisplayMode,
|
(_) => balanceDisplayMode,
|
||||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||||
|
@ -162,6 +168,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
static const defaultPinLength = 4;
|
static const defaultPinLength = 4;
|
||||||
static const defaultActionsMode = 11;
|
static const defaultActionsMode = 11;
|
||||||
|
static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
FiatCurrency fiatCurrency;
|
FiatCurrency fiatCurrency;
|
||||||
|
@ -193,6 +200,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
int pinCodeLength;
|
int pinCodeLength;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
PinCodeRequiredDuration pinTimeOutDuration;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
ThemeData get theme => currentTheme.themeData;
|
ThemeData get theme => currentTheme.themeData;
|
||||||
|
|
||||||
|
@ -288,6 +298,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
||||||
defaultActionsMode));
|
defaultActionsMode));
|
||||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
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 no value
|
||||||
if (pinLength == null || pinLength == 0) {
|
if (pinLength == null || pinLength == 0) {
|
||||||
pinLength = defaultPinLength;
|
pinLength = defaultPinLength;
|
||||||
|
@ -343,6 +358,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
initialTheme: savedTheme,
|
initialTheme: savedTheme,
|
||||||
actionlistDisplayMode: actionListDisplayMode,
|
actionlistDisplayMode: actionListDisplayMode,
|
||||||
initialPinLength: pinLength,
|
initialPinLength: pinLength,
|
||||||
|
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||||
initialLanguageCode: savedLanguageCode,
|
initialLanguageCode: savedLanguageCode,
|
||||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
class PaymentRequest {
|
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 address = "";
|
||||||
var amount = "";
|
var amount = "";
|
||||||
var note = "";
|
var note = "";
|
||||||
|
var scheme = "";
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
address = uri.path;
|
address = uri.path;
|
||||||
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
|
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
|
||||||
note = uri.queryParameters['tx_description']
|
note = uri.queryParameters['tx_description']
|
||||||
?? uri.queryParameters['message'] ?? "";
|
?? uri.queryParameters['message'] ?? "";
|
||||||
|
scheme = uri.scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PaymentRequest(address, amount, note);
|
return PaymentRequest(address, amount, note, scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String address;
|
final String address;
|
||||||
final String amount;
|
final String amount;
|
||||||
final String note;
|
final String note;
|
||||||
|
final String scheme;
|
||||||
}
|
}
|
|
@ -14,10 +14,12 @@ part 'auth_view_model.g.dart';
|
||||||
class AuthViewModel = AuthViewModelBase with _$AuthViewModel;
|
class AuthViewModel = AuthViewModelBase with _$AuthViewModel;
|
||||||
|
|
||||||
abstract class AuthViewModelBase with Store {
|
abstract class AuthViewModelBase with Store {
|
||||||
AuthViewModelBase(this._authService, this._sharedPreferences,
|
AuthViewModelBase(
|
||||||
this._settingsStore, this._biometricAuth)
|
this._authService, this._sharedPreferences, this._settingsStore, this._biometricAuth)
|
||||||
: _failureCounter = 0,
|
: _failureCounter = 0,
|
||||||
state = InitialExecutionState();
|
state = InitialExecutionState() {
|
||||||
|
reaction((_) => state, _saveLastAuthTime);
|
||||||
|
}
|
||||||
|
|
||||||
static const maxFailedLogins = 3;
|
static const maxFailedLogins = 3;
|
||||||
static const banTimeout = 180; // 3 minutes
|
static const banTimeout = 180; // 3 minutes
|
||||||
|
@ -28,8 +30,7 @@ abstract class AuthViewModelBase with Store {
|
||||||
|
|
||||||
int get pinLength => _settingsStore.pinCodeLength;
|
int get pinLength => _settingsStore.pinCodeLength;
|
||||||
|
|
||||||
bool get isBiometricalAuthenticationAllowed =>
|
bool get isBiometricalAuthenticationAllowed => _settingsStore.allowBiometricalAuthentication;
|
||||||
_settingsStore.allowBiometricalAuthentication;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
int _failureCounter;
|
int _failureCounter;
|
||||||
|
@ -114,8 +115,14 @@ abstract class AuthViewModelBase with Store {
|
||||||
state = ExecutedSuccessfullyState();
|
state = ExecutedSuccessfullyState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
state = FailureState(e.toString());
|
state = FailureState(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _saveLastAuthTime(ExecutionState state) {
|
||||||
|
if (state is ExecutedSuccessfullyState) {
|
||||||
|
_authService.saveLastAuthTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_gift_card.dart';
|
||||||
|
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
part 'ionia_custom_redeem_view_model.g.dart';
|
part 'ionia_custom_redeem_view_model.g.dart';
|
||||||
|
|
||||||
class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
|
class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
|
||||||
|
|
||||||
abstract class IoniaCustomRedeemViewModelBase with Store {
|
abstract class IoniaCustomRedeemViewModelBase with Store {
|
||||||
IoniaCustomRedeemViewModelBase(this.giftCard)
|
IoniaCustomRedeemViewModelBase({
|
||||||
: amount = 0;
|
required this.giftCard,
|
||||||
|
required this.ioniaService,
|
||||||
|
}) : amount = 0,
|
||||||
|
redeemState = InitialExecutionState();
|
||||||
|
|
||||||
final IoniaGiftCard giftCard;
|
final IoniaGiftCard giftCard;
|
||||||
|
|
||||||
|
final IoniaService ioniaService;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ExecutionState redeemState;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
double amount;
|
double amount;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
double get remaining => amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
|
double get remaining =>
|
||||||
|
amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get formattedRemaining => remaining.toStringAsFixed(2);
|
String get formattedRemaining => remaining.toStringAsFixed(2);
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get disableRedeem => amount > giftCard.remainingAmount;
|
bool get disableRedeem => amount > giftCard.remainingAmount;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void updateAmount(String text){
|
void updateAmount(String text) {
|
||||||
amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')) ?? 0);
|
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';
|
part 'ionia_gift_card_details_view_model.g.dart';
|
||||||
|
|
||||||
class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase with _$IoniaGiftCardDetailsViewModel;
|
class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase
|
||||||
|
with _$IoniaGiftCardDetailsViewModel;
|
||||||
|
|
||||||
abstract class IoniaGiftCardDetailsViewModelBase with Store {
|
abstract class IoniaGiftCardDetailsViewModelBase with Store {
|
||||||
|
IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard})
|
||||||
IoniaGiftCardDetailsViewModelBase({
|
: redeemState = InitialExecutionState(),
|
||||||
required this.ioniaService,
|
remainingAmount = giftCard.remainingAmount,
|
||||||
required this.giftCard})
|
brightness = 0;
|
||||||
: redeemState = InitialExecutionState(),
|
|
||||||
remainingAmount = giftCard.remainingAmount,
|
|
||||||
brightness = 0;
|
|
||||||
|
|
||||||
final IoniaService ioniaService;
|
final IoniaService ioniaService;
|
||||||
|
|
||||||
double brightness;
|
double brightness;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
IoniaGiftCard giftCard;
|
IoniaGiftCard giftCard;
|
||||||
|
|
||||||
|
@ -35,21 +33,22 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
|
||||||
giftCard.remainingAmount = remainingAmount;
|
giftCard.remainingAmount = remainingAmount;
|
||||||
try {
|
try {
|
||||||
redeemState = IsExecutingState();
|
redeemState = IsExecutingState();
|
||||||
await ioniaService.redeem(giftCard);
|
await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
|
||||||
giftCard = await ioniaService.getGiftCard(id: giftCard.id);
|
giftCard = await ioniaService.getGiftCard(id: giftCard.id);
|
||||||
redeemState = ExecutedSuccessfullyState();
|
redeemState = ExecutedSuccessfullyState();
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
redeemState = FailureState(e.toString());
|
redeemState = FailureState(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void updateRemaining(double amount){
|
Future<void> refeshCard() async {
|
||||||
remainingAmount = amount;
|
giftCard = await ioniaService.getGiftCard(id: giftCard.id);
|
||||||
|
remainingAmount = giftCard.remainingAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void increaseBrightness() async {
|
void increaseBrightness() async {
|
||||||
brightness = await DeviceDisplayBrightness.getBrightness();
|
brightness = await DeviceDisplayBrightness.getBrightness();
|
||||||
await DeviceDisplayBrightness.setBrightness(1.0);
|
await DeviceDisplayBrightness.setBrightness(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ abstract class SendViewModelBase with Store {
|
||||||
|
|
||||||
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
ExecutionState state;
|
ExecutionState state;
|
||||||
|
|
||||||
|
@ -180,6 +180,8 @@ abstract class SendViewModelBase with Store {
|
||||||
|
|
||||||
WalletType get walletType => _wallet.type;
|
WalletType get walletType => _wallet.type;
|
||||||
|
|
||||||
|
String? get walletCurrencyName => _wallet.currency.name?.toLowerCase();
|
||||||
|
|
||||||
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
|
@ -306,7 +308,7 @@ abstract class SendViewModelBase with Store {
|
||||||
@action
|
@action
|
||||||
void onClose() =>
|
void onClose() =>
|
||||||
_settingsStore.fiatCurrency = fiatFromSettings;
|
_settingsStore.fiatCurrency = fiatFromSettings;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void setFiatCurrency(FiatCurrency fiat) =>
|
void setFiatCurrency(FiatCurrency fiat) =>
|
||||||
_settingsStore.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/biometric_auth.dart';
|
||||||
|
import 'package:cake_wallet/entities/pin_code_required_duration.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';
|
||||||
|
|
||||||
|
@ -7,19 +9,33 @@ part 'security_settings_view_model.g.dart';
|
||||||
class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel;
|
class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel;
|
||||||
|
|
||||||
abstract class SecuritySettingsViewModelBase with Store {
|
abstract class SecuritySettingsViewModelBase with Store {
|
||||||
SecuritySettingsViewModelBase(this._settingsStore) : _biometricAuth = BiometricAuth();
|
SecuritySettingsViewModelBase(
|
||||||
|
this._settingsStore,
|
||||||
|
this._authService,
|
||||||
|
) : _biometricAuth = BiometricAuth();
|
||||||
|
|
||||||
final BiometricAuth _biometricAuth;
|
final BiometricAuth _biometricAuth;
|
||||||
final SettingsStore _settingsStore;
|
final SettingsStore _settingsStore;
|
||||||
|
final AuthService _authService;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
|
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<bool> biometricAuthenticated() async {
|
Future<bool> biometricAuthenticated() async {
|
||||||
return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated();
|
return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/core/wallet_loading_service.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
@ -15,9 +15,12 @@ part 'wallet_list_view_model.g.dart';
|
||||||
class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel;
|
class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel;
|
||||||
|
|
||||||
abstract class WalletListViewModelBase with Store {
|
abstract class WalletListViewModelBase with Store {
|
||||||
WalletListViewModelBase(this._walletInfoSource, this._appStore,
|
WalletListViewModelBase(
|
||||||
this._walletLoadingService)
|
this._walletInfoSource,
|
||||||
: wallets = ObservableList<WalletListItem>() {
|
this._appStore,
|
||||||
|
this._walletLoadingService,
|
||||||
|
this._authService,
|
||||||
|
) : wallets = ObservableList<WalletListItem>() {
|
||||||
_updateList();
|
_updateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +30,7 @@ abstract class WalletListViewModelBase with Store {
|
||||||
final AppStore _appStore;
|
final AppStore _appStore;
|
||||||
final Box<WalletInfo> _walletInfoSource;
|
final Box<WalletInfo> _walletInfoSource;
|
||||||
final WalletLoadingService _walletLoadingService;
|
final WalletLoadingService _walletLoadingService;
|
||||||
|
final AuthService _authService;
|
||||||
|
|
||||||
WalletType get currentWalletType => _appStore.wallet!.type;
|
WalletType get currentWalletType => _appStore.wallet!.type;
|
||||||
|
|
||||||
|
@ -47,12 +51,20 @@ abstract class WalletListViewModelBase with Store {
|
||||||
|
|
||||||
void _updateList() {
|
void _updateList() {
|
||||||
wallets.clear();
|
wallets.clear();
|
||||||
wallets.addAll(_walletInfoSource.values.map((info) => WalletListItem(
|
wallets.addAll(
|
||||||
name: info.name,
|
_walletInfoSource.values.map(
|
||||||
type: info.type,
|
(info) => WalletListItem(
|
||||||
key: info.key,
|
name: info.name,
|
||||||
isCurrent: info.name == _appStore.wallet!.name &&
|
type: info.type,
|
||||||
info.type == _appStore.wallet!.type,
|
key: info.key,
|
||||||
isEnabled: availableWalletTypes.contains(info.type))));
|
isCurrent: info.name == _appStore.wallet!.name && info.type == _appStore.wallet!.type,
|
||||||
|
isEnabled: availableWalletTypes.contains(info.type),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkIfAuthRequired() {
|
||||||
|
return _authService.requireAuth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Datenschutz",
|
"privacy": "Datenschutz",
|
||||||
"display_settings": "Anzeigeeinstellungen",
|
"display_settings": "Anzeigeeinstellungen",
|
||||||
"other_settings": "Andere Einstellungen",
|
"other_settings": "Andere Einstellungen",
|
||||||
|
"require_pin_after": "PIN anfordern nach",
|
||||||
|
"always": "immer",
|
||||||
|
"minutes_to_pin_code": "${minute} Minuten",
|
||||||
"disable_exchange": "Exchange deaktivieren",
|
"disable_exchange": "Exchange deaktivieren",
|
||||||
"advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen",
|
"advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen",
|
||||||
"settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden",
|
"settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Deaktiviert",
|
"disabled": "Deaktiviert",
|
||||||
"enabled": "Ermöglicht",
|
"enabled": "Ermöglicht",
|
||||||
"tor_only": "Nur Tor"
|
"tor_only": "Nur Tor",
|
||||||
|
"unmatched_currencies": "Die Währung Ihres aktuellen Wallets stimmt nicht mit der des gescannten QR überein"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Display settings",
|
"display_settings": "Display settings",
|
||||||
"other_settings": "Other settings",
|
"other_settings": "Other settings",
|
||||||
|
"require_pin_after": "Require PIN after",
|
||||||
|
"always": "Always",
|
||||||
|
"minutes_to_pin_code": "${minute} minutes",
|
||||||
"disable_exchange": "Disable exchange",
|
"disable_exchange": "Disable exchange",
|
||||||
"advanced_privacy_settings": "Advanced Privacy Settings",
|
"advanced_privacy_settings": "Advanced Privacy Settings",
|
||||||
"settings_can_be_changed_later": "These settings can be changed later in the app settings",
|
"settings_can_be_changed_later": "These settings can be changed later in the app settings",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"tor_only": "Tor only"
|
"tor_only": "Tor only",
|
||||||
|
"unmatched_currencies": "Your current wallet's currency does not match that of the scanned QR"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Privacidad",
|
"privacy": "Privacidad",
|
||||||
"display_settings": "Configuración de pantalla",
|
"display_settings": "Configuración de pantalla",
|
||||||
"other_settings": "Otras configuraciones",
|
"other_settings": "Otras configuraciones",
|
||||||
|
"require_pin_after": "Requerir PIN después de",
|
||||||
|
"always": "siempre",
|
||||||
|
"minutes_to_pin_code": "${minute} minutos",
|
||||||
"disable_exchange": "Deshabilitar intercambio",
|
"disable_exchange": "Deshabilitar intercambio",
|
||||||
"advanced_privacy_settings": "Configuración avanzada de privacidad",
|
"advanced_privacy_settings": "Configuración avanzada de privacidad",
|
||||||
"settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación",
|
"settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Desactivado",
|
"disabled": "Desactivado",
|
||||||
"enabled": "Activado",
|
"enabled": "Activado",
|
||||||
"tor_only": "solo Tor"
|
"tor_only": "solo Tor",
|
||||||
|
"unmatched_currencies": "La moneda de su billetera actual no coincide con la del QR escaneado"
|
||||||
}
|
}
|
||||||
|
|
|
@ -661,6 +661,9 @@
|
||||||
"privacy": "Confidentialité",
|
"privacy": "Confidentialité",
|
||||||
"display_settings": "Paramètres d'affichage",
|
"display_settings": "Paramètres d'affichage",
|
||||||
"other_settings": "Autres paramètres",
|
"other_settings": "Autres paramètres",
|
||||||
|
"require_pin_after": "NIP requis après",
|
||||||
|
"always": "toujours",
|
||||||
|
"minutes_to_pin_code": "${minute} minutes",
|
||||||
"disable_exchange": "Désactiver l'échange",
|
"disable_exchange": "Désactiver l'échange",
|
||||||
"advanced_privacy_settings": "Paramètres de confidentialité avancés",
|
"advanced_privacy_settings": "Paramètres de confidentialité avancés",
|
||||||
"settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application",
|
"settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application",
|
||||||
|
@ -669,5 +672,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Handicapé",
|
"disabled": "Handicapé",
|
||||||
"enabled": "Activé",
|
"enabled": "Activé",
|
||||||
"tor_only": "Tor uniquement"
|
"tor_only": "Tor uniquement",
|
||||||
|
"unmatched_currencies": "La devise de votre portefeuille actuel ne correspond pas à celle du QR scanné"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,12 +663,17 @@
|
||||||
"privacy": "गोपनीयता",
|
"privacy": "गोपनीयता",
|
||||||
"display_settings": "प्रदर्शन सेटिंग्स",
|
"display_settings": "प्रदर्शन सेटिंग्स",
|
||||||
"other_settings": "अन्य सेटिंग्स",
|
"other_settings": "अन्य सेटिंग्स",
|
||||||
|
"require_pin_after": "इसके बाद पिन आवश्यक है",
|
||||||
|
"always": "हमेशा",
|
||||||
|
"minutes_to_pin_code": "${minute} मिनट",
|
||||||
|
"disable_exchange": "एक्सचेंज अक्षम करें",
|
||||||
"advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स",
|
"advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स",
|
||||||
"settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है",
|
"settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है",
|
||||||
"add_custom_node": "नया कस्टम नोड जोड़ें",
|
"add_custom_node": "नया कस्टम नोड जोड़ें",
|
||||||
"disable_exchange": "एक्सचेंज अक्षम करें",
|
"disable_fiat": "िएट को अक्षम करें",
|
||||||
"fiat_api": "फिएट पैसे API",
|
"fiat_api": "फिएट पैसे API",
|
||||||
"disabled": "अक्षम",
|
"disabled": "अक्षम",
|
||||||
"enabled": "सक्रिय",
|
"enabled": "सक्रिय",
|
||||||
"tor_only": "Tor केवल"
|
"tor_only": "Tor केवल",
|
||||||
|
"unmatched_currencies": "आपके वर्तमान वॉलेट की मुद्रा स्कैन किए गए क्यूआर से मेल नहीं खाती"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Privatnost",
|
"privacy": "Privatnost",
|
||||||
"display_settings": "Postavke zaslona",
|
"display_settings": "Postavke zaslona",
|
||||||
"other_settings": "Ostale postavke",
|
"other_settings": "Ostale postavke",
|
||||||
|
"require_pin_after": "Zahtijevaj PIN nakon",
|
||||||
|
"always": "Uvijek",
|
||||||
|
"minutes_to_pin_code": "${minute} minuta",
|
||||||
"disable_exchange": "Onemogući exchange",
|
"disable_exchange": "Onemogući exchange",
|
||||||
"advanced_privacy_settings": "Napredne postavke privatnosti",
|
"advanced_privacy_settings": "Napredne postavke privatnosti",
|
||||||
"settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije",
|
"settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Onemogućeno",
|
"disabled": "Onemogućeno",
|
||||||
"enabled": "Omogućeno",
|
"enabled": "Omogućeno",
|
||||||
"tor_only": "Samo Tor"
|
"tor_only": "Samo Tor",
|
||||||
|
"unmatched_currencies": "Valuta vašeg trenutnog novčanika ne odgovara onoj na skeniranom QR-u"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Impostazioni di visualizzazione",
|
"display_settings": "Impostazioni di visualizzazione",
|
||||||
"other_settings": "Altre impostazioni",
|
"other_settings": "Altre impostazioni",
|
||||||
|
"require_pin_after": "Richiedi PIN dopo",
|
||||||
|
"always": "sempre",
|
||||||
|
"minutes_to_pin_code": "${minute} minuti",
|
||||||
"disable_exchange": "Disabilita scambio",
|
"disable_exchange": "Disabilita scambio",
|
||||||
"advanced_privacy_settings": "Impostazioni avanzate sulla privacy",
|
"advanced_privacy_settings": "Impostazioni avanzate sulla privacy",
|
||||||
"settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app",
|
"settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Disabilitato",
|
"disabled": "Disabilitato",
|
||||||
"enabled": "Abilitato",
|
"enabled": "Abilitato",
|
||||||
"tor_only": "Solo Tor"
|
"tor_only": "Solo Tor",
|
||||||
|
"unmatched_currencies": "La valuta del tuo portafoglio attuale non corrisponde a quella del QR scansionato"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "プライバシー",
|
"privacy": "プライバシー",
|
||||||
"display_settings": "表示設定",
|
"display_settings": "表示設定",
|
||||||
"other_settings": "その他の設定",
|
"other_settings": "その他の設定",
|
||||||
|
"require_pin_after": "後に PIN が必要",
|
||||||
|
"always": "いつも",
|
||||||
|
"minutes_to_pin_code": "${minute} 分",
|
||||||
"disable_exchange": "交換を無効にする",
|
"disable_exchange": "交換を無効にする",
|
||||||
"advanced_privacy_settings": "高度なプライバシー設定",
|
"advanced_privacy_settings": "高度なプライバシー設定",
|
||||||
"settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます",
|
"settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "不換紙幣 API",
|
"fiat_api": "不換紙幣 API",
|
||||||
"disabled": "無効",
|
"disabled": "無効",
|
||||||
"enabled": "有効",
|
"enabled": "有効",
|
||||||
"tor_only": "Torのみ"
|
"tor_only": "Torのみ",
|
||||||
|
"unmatched_currencies": "現在のウォレットの通貨がスキャンされたQRの通貨と一致しません"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "프라이버시",
|
"privacy": "프라이버시",
|
||||||
"display_settings": "디스플레이 설정",
|
"display_settings": "디스플레이 설정",
|
||||||
"other_settings": "기타 설정",
|
"other_settings": "기타 설정",
|
||||||
|
"require_pin_after": "다음 이후에 PIN 필요",
|
||||||
|
"always": "언제나",
|
||||||
|
"minutes_to_pin_code": "${minute}분",
|
||||||
"disable_exchange": "교환 비활성화",
|
"disable_exchange": "교환 비활성화",
|
||||||
"advanced_privacy_settings": "고급 개인 정보 설정",
|
"advanced_privacy_settings": "고급 개인 정보 설정",
|
||||||
"settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다.",
|
"settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다.",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "명목 화폐 API",
|
"fiat_api": "명목 화폐 API",
|
||||||
"disabled": "장애가 있는",
|
"disabled": "장애가 있는",
|
||||||
"enabled": "사용",
|
"enabled": "사용",
|
||||||
"tor_only": "Tor 뿐"
|
"tor_only": "Tor 뿐",
|
||||||
|
"unmatched_currencies": "현재 지갑의 통화가 스캔한 QR의 통화와 일치하지 않습니다."
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Weergave-instellingen",
|
"display_settings": "Weergave-instellingen",
|
||||||
"other_settings": "Andere instellingen",
|
"other_settings": "Andere instellingen",
|
||||||
|
"require_pin_after": "Pincode vereist na",
|
||||||
|
"always": "altijd",
|
||||||
|
"minutes_to_pin_code": "${minute} minuten",
|
||||||
"disable_exchange": "Uitwisseling uitschakelen",
|
"disable_exchange": "Uitwisseling uitschakelen",
|
||||||
"advanced_privacy_settings": "Geavanceerde privacy-instellingen",
|
"advanced_privacy_settings": "Geavanceerde privacy-instellingen",
|
||||||
"settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen",
|
"settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"disabled": "Gehandicapt",
|
"disabled": "Gehandicapt",
|
||||||
"enabled": "Ingeschakeld",
|
"enabled": "Ingeschakeld",
|
||||||
"tor_only": "Alleen Tor"
|
"tor_only": "Alleen Tor",
|
||||||
|
"unmatched_currencies": "De valuta van uw huidige portemonnee komt niet overeen met die van de gescande QR"
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Prywatność",
|
"privacy": "Prywatność",
|
||||||
"display_settings": "Ustawienia wyświetlania",
|
"display_settings": "Ustawienia wyświetlania",
|
||||||
"other_settings": "Inne ustawienia",
|
"other_settings": "Inne ustawienia",
|
||||||
|
"require_pin_after": "Wymagaj kodu PIN po",
|
||||||
|
"always": "zawsze",
|
||||||
|
"minutes_to_pin_code": "${minute} minut",
|
||||||
"disable_exchange": "Wyłącz wymianę",
|
"disable_exchange": "Wyłącz wymianę",
|
||||||
"advanced_privacy_settings": "Zaawansowane ustawienia prywatności",
|
"advanced_privacy_settings": "Zaawansowane ustawienia prywatności",
|
||||||
"settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji",
|
"settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "API Fiata",
|
"fiat_api": "API Fiata",
|
||||||
"disabled": "Wyłączone",
|
"disabled": "Wyłączone",
|
||||||
"enabled": "Włączony",
|
"enabled": "Włączony",
|
||||||
"tor_only": "Tylko Tor"
|
"tor_only": "Tylko Tor",
|
||||||
|
"unmatched_currencies": "Waluta Twojego obecnego portfela nie odpowiada walucie zeskanowanego kodu QR"
|
||||||
}
|
}
|
||||||
|
|
|
@ -662,6 +662,9 @@
|
||||||
"privacy": "Privacidade",
|
"privacy": "Privacidade",
|
||||||
"display_settings": "Configurações de exibição",
|
"display_settings": "Configurações de exibição",
|
||||||
"other_settings": "Outras configurações",
|
"other_settings": "Outras configurações",
|
||||||
|
"require_pin_after": "Exigir PIN após",
|
||||||
|
"always": "sempre",
|
||||||
|
"minutes_to_pin_code": "${minute} minutos",
|
||||||
"disable_exchange": "Desativar troca",
|
"disable_exchange": "Desativar troca",
|
||||||
"advanced_privacy_settings": "Configurações de privacidade avançadas",
|
"advanced_privacy_settings": "Configurações de privacidade avançadas",
|
||||||
"settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo",
|
"settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo",
|
||||||
|
@ -670,5 +673,6 @@
|
||||||
"fiat_api": "API da Fiat",
|
"fiat_api": "API da Fiat",
|
||||||
"disabled": "Desabilitado",
|
"disabled": "Desabilitado",
|
||||||
"enabled": "Habilitado",
|
"enabled": "Habilitado",
|
||||||
"tor_only": "Tor apenas"
|
"tor_only": "Tor apenas",
|
||||||
|
"unmatched_currencies": "A moeda da sua carteira atual não corresponde à do QR digitalizado"
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,7 +369,7 @@
|
||||||
"trade_for_not_created" : "Сделка для ${title} не создана.",
|
"trade_for_not_created" : "Сделка для ${title} не создана.",
|
||||||
"trade_not_created" : "Сделка не создана",
|
"trade_not_created" : "Сделка не создана",
|
||||||
"trade_id_not_found" : "Сделка ${tradeId} ${title} не найдена.",
|
"trade_id_not_found" : "Сделка ${tradeId} ${title} не найдена.",
|
||||||
"trade_not_found" : "Trade not found.",
|
"trade_not_found" : "Торговля не найдена.",
|
||||||
|
|
||||||
|
|
||||||
"trade_state_pending" : "Ожидание",
|
"trade_state_pending" : "Ожидание",
|
||||||
|
@ -663,6 +663,9 @@
|
||||||
"privacy": "Конфиденциальность",
|
"privacy": "Конфиденциальность",
|
||||||
"display_settings": "Настройки отображения",
|
"display_settings": "Настройки отображения",
|
||||||
"other_settings": "Другие настройки",
|
"other_settings": "Другие настройки",
|
||||||
|
"require_pin_after": "Требовать ПИН после",
|
||||||
|
"always": "всегда",
|
||||||
|
"minutes_to_pin_code": "${minute} минут",
|
||||||
"disable_exchange": "Отключить обмен",
|
"disable_exchange": "Отключить обмен",
|
||||||
"advanced_privacy_settings": "Расширенные настройки конфиденциальности",
|
"advanced_privacy_settings": "Расширенные настройки конфиденциальности",
|
||||||
"settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения.",
|
"settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения.",
|
||||||
|
@ -671,5 +674,6 @@
|
||||||
"fiat_api": "Фиат API",
|
"fiat_api": "Фиат API",
|
||||||
"disabled": "Отключено",
|
"disabled": "Отключено",
|
||||||
"enabled": "Включено",
|
"enabled": "Включено",
|
||||||
"tor_only": "Только Tor"
|
"tor_only": "Только Tor",
|
||||||
|
"unmatched_currencies": "Валюта вашего текущего кошелька не соответствует валюте отсканированного QR-кода."
|
||||||
}
|
}
|
||||||
|
|
|
@ -662,6 +662,9 @@
|
||||||
"privacy": "Конфіденційність",
|
"privacy": "Конфіденційність",
|
||||||
"display_settings": "Налаштування дисплея",
|
"display_settings": "Налаштування дисплея",
|
||||||
"other_settings": "Інші налаштування",
|
"other_settings": "Інші налаштування",
|
||||||
|
"require_pin_after": "Вимагати PIN після",
|
||||||
|
"always": "Завжди",
|
||||||
|
"minutes_to_pin_code": "${minute} хвилин",
|
||||||
"disable_exchange": "Вимкнути exchange",
|
"disable_exchange": "Вимкнути exchange",
|
||||||
"advanced_privacy_settings": "Розширені налаштування конфіденційності",
|
"advanced_privacy_settings": "Розширені налаштування конфіденційності",
|
||||||
"settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми",
|
"settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми",
|
||||||
|
@ -670,5 +673,6 @@
|
||||||
"fiat_api": "Фіат API",
|
"fiat_api": "Фіат API",
|
||||||
"disabled": "Вимкнено",
|
"disabled": "Вимкнено",
|
||||||
"enabled": "Увімкнено",
|
"enabled": "Увімкнено",
|
||||||
"tor_only": "Тільки Tor"
|
"tor_only": "Тільки Tor",
|
||||||
|
"unmatched_currencies": "Валюта вашого гаманця не збігається з валютою сканованого QR-коду"
|
||||||
}
|
}
|
||||||
|
|
|
@ -661,6 +661,9 @@
|
||||||
"privacy":"隐私",
|
"privacy":"隐私",
|
||||||
"display_settings": "显示设置",
|
"display_settings": "显示设置",
|
||||||
"other_settings": "其他设置",
|
"other_settings": "其他设置",
|
||||||
|
"require_pin_after": "之后需要 PIN",
|
||||||
|
"always": "总是",
|
||||||
|
"minutes_to_pin_code": "${minute} 分钟",
|
||||||
"disable_exchange": "禁用交换",
|
"disable_exchange": "禁用交换",
|
||||||
"advanced_privacy_settings": "高级隐私设置",
|
"advanced_privacy_settings": "高级隐私设置",
|
||||||
"settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置",
|
"settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置",
|
||||||
|
@ -669,5 +672,6 @@
|
||||||
"fiat_api": "法币API",
|
"fiat_api": "法币API",
|
||||||
"disabled": "禁用",
|
"disabled": "禁用",
|
||||||
"enabled": "启用",
|
"enabled": "启用",
|
||||||
"tor_only": "仅限 Tor"
|
"tor_only": "仅限 Tor",
|
||||||
|
"unmatched_currencies": "您当前钱包的货币与扫描的 QR 的货币不匹配"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
||||||
APP_ANDROID_TYPE=$1
|
APP_ANDROID_TYPE=$1
|
||||||
|
|
||||||
MONERO_COM_NAME="Monero.com"
|
MONERO_COM_NAME="Monero.com"
|
||||||
MONERO_COM_VERSION="1.2.1"
|
MONERO_COM_VERSION="1.2.2"
|
||||||
MONERO_COM_BUILD_NUMBER=32
|
MONERO_COM_BUILD_NUMBER=33
|
||||||
MONERO_COM_BUNDLE_ID="com.monero.app"
|
MONERO_COM_BUNDLE_ID="com.monero.app"
|
||||||
MONERO_COM_PACKAGE="com.monero.app"
|
MONERO_COM_PACKAGE="com.monero.app"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="4.5.1"
|
CAKEWALLET_VERSION="4.5.3"
|
||||||
CAKEWALLET_BUILD_NUMBER=136
|
CAKEWALLET_BUILD_NUMBER=138
|
||||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
||||||
APP_IOS_TYPE=$1
|
APP_IOS_TYPE=$1
|
||||||
|
|
||||||
MONERO_COM_NAME="Monero.com"
|
MONERO_COM_NAME="Monero.com"
|
||||||
MONERO_COM_VERSION="1.2.1"
|
MONERO_COM_VERSION="1.2.2"
|
||||||
MONERO_COM_BUILD_NUMBER=29
|
MONERO_COM_BUILD_NUMBER=30
|
||||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="4.5.1"
|
CAKEWALLET_VERSION="4.5.3"
|
||||||
CAKEWALLET_BUILD_NUMBER=133
|
CAKEWALLET_BUILD_NUMBER=135
|
||||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||||
|
|
||||||
HAVEN_NAME="Haven"
|
HAVEN_NAME="Haven"
|
||||||
|
|
Loading…
Reference in a new issue