mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
b4fcec3a01
9 changed files with 277 additions and 335 deletions
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
|
@ -11,3 +11,4 @@ Please include a summary of the changes and which issue is fixed / feature is ad
|
||||||
- [ ] Format code
|
- [ ] Format code
|
||||||
- [ ] Look for code duplication
|
- [ ] Look for code duplication
|
||||||
- [ ] Clear naming for variables and methods
|
- [ ] Clear naming for variables and methods
|
||||||
|
- [ ] Manual tests in accessibility mode (TalkBack on Android) passed
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
import 'package:cake_wallet/entities/get_encryption_key.dart';
|
import 'package:cake_wallet/entities/get_encryption_key.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||||
|
@ -164,6 +163,31 @@ class $BackupService {
|
||||||
}
|
}
|
||||||
|
|
||||||
final data = json.decode(preferencesFile.readAsStringSync()) as Map<String, dynamic>;
|
final data = json.decode(preferencesFile.readAsStringSync()) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
try { // shouldn't throw an error but just in case, so it doesn't stop the backup restore
|
||||||
|
for (var entry in data.entries) {
|
||||||
|
String key = entry.key;
|
||||||
|
dynamic value = entry.value;
|
||||||
|
|
||||||
|
// Check the type of the value and save accordingly
|
||||||
|
if (value is String) {
|
||||||
|
await sharedPreferences.setString(key, value);
|
||||||
|
} else if (value is int) {
|
||||||
|
await sharedPreferences.setInt(key, value);
|
||||||
|
} else if (value is double) {
|
||||||
|
await sharedPreferences.setDouble(key, value);
|
||||||
|
} else if (value is bool) {
|
||||||
|
await sharedPreferences.setBool(key, value);
|
||||||
|
} else if (value is List<String>) {
|
||||||
|
await sharedPreferences.setStringList(key, value);
|
||||||
|
} else {
|
||||||
|
if (kDebugMode) {
|
||||||
|
printV('Skipping individual save for key "$key": Unsupported type (${value.runtimeType}). Value: $value');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
String currentWalletName = data[PreferencesKey.currentWalletName] as String;
|
String currentWalletName = data[PreferencesKey.currentWalletName] as String;
|
||||||
int currentWalletType = data[PreferencesKey.currentWalletType] as int;
|
int currentWalletType = data[PreferencesKey.currentWalletType] as int;
|
||||||
|
|
||||||
|
@ -175,151 +199,10 @@ class $BackupService {
|
||||||
currentWalletType = serializeToInt(correctWallets.first.type);
|
currentWalletType = serializeToInt(correctWallets.first.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
final currentNodeId = data[PreferencesKey.currentNodeIdKey] as int?;
|
if (DeviceInfo.instance.isDesktop) {
|
||||||
final currentBalanceDisplayMode = data[PreferencesKey.currentBalanceDisplayModeKey] as int?;
|
|
||||||
final currentFiatCurrency = data[PreferencesKey.currentFiatCurrencyKey] as String?;
|
|
||||||
final shouldSaveRecipientAddress = data[PreferencesKey.shouldSaveRecipientAddressKey] as bool?;
|
|
||||||
final isAppSecure = data[PreferencesKey.isAppSecureKey] as bool?;
|
|
||||||
final disableTradeOption = data[PreferencesKey.disableTradeOption] as bool?;
|
|
||||||
final currentTransactionPriorityKeyLegacy =
|
|
||||||
data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int?;
|
|
||||||
final currentBitcoinElectrumSererId =
|
|
||||||
data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?;
|
|
||||||
final currentLanguageCode = data[PreferencesKey.currentLanguageCode] as String?;
|
|
||||||
final displayActionListMode = data[PreferencesKey.displayActionListModeKey] as int?;
|
|
||||||
final fiatApiMode = data[PreferencesKey.currentFiatApiModeKey] as int?;
|
|
||||||
final currentTheme = data[PreferencesKey.currentTheme] as int?;
|
|
||||||
final exchangeStatus = data[PreferencesKey.exchangeStatusKey] as int?;
|
|
||||||
final currentDefaultSettingsMigrationVersion =
|
|
||||||
data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?;
|
|
||||||
final moneroTransactionPriority = data[PreferencesKey.moneroTransactionPriority] as int?;
|
|
||||||
final bitcoinTransactionPriority = data[PreferencesKey.bitcoinTransactionPriority] as int?;
|
|
||||||
final sortBalanceTokensBy = data[PreferencesKey.sortBalanceBy] as int?;
|
|
||||||
final pinNativeTokenAtTop = data[PreferencesKey.pinNativeTokenAtTop] as bool?;
|
|
||||||
final useEtherscan = data[PreferencesKey.useEtherscan] as bool?;
|
|
||||||
final defaultNanoRep = data[PreferencesKey.defaultNanoRep] as String?;
|
|
||||||
final defaultBananoRep = data[PreferencesKey.defaultBananoRep] as String?;
|
|
||||||
final lookupsTwitter = data[PreferencesKey.lookupsTwitter] as bool?;
|
|
||||||
final lookupsMastodon = data[PreferencesKey.lookupsMastodon] as bool?;
|
|
||||||
final lookupsYatService = data[PreferencesKey.lookupsYatService] as bool?;
|
|
||||||
final lookupsUnstoppableDomains = data[PreferencesKey.lookupsUnstoppableDomains] as bool?;
|
|
||||||
final lookupsOpenAlias = data[PreferencesKey.lookupsOpenAlias] as bool?;
|
|
||||||
final lookupsENS = data[PreferencesKey.lookupsENS] as bool?;
|
|
||||||
final lookupsWellKnown = data[PreferencesKey.lookupsWellKnown] as bool?;
|
|
||||||
final syncAll = data[PreferencesKey.syncAllKey] as bool?;
|
|
||||||
final syncMode = data[PreferencesKey.syncModeKey] as int?;
|
|
||||||
final autoGenerateSubaddressStatus =
|
|
||||||
data[PreferencesKey.autoGenerateSubaddressStatusKey] as int?;
|
|
||||||
|
|
||||||
await sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName);
|
|
||||||
|
|
||||||
if (currentNodeId != null)
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, currentNodeId);
|
|
||||||
|
|
||||||
if (currentBalanceDisplayMode != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.currentBalanceDisplayModeKey, currentBalanceDisplayMode);
|
|
||||||
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentWalletType, currentWalletType);
|
|
||||||
|
|
||||||
if (currentFiatCurrency != null)
|
|
||||||
await sharedPreferences.setString(
|
|
||||||
PreferencesKey.currentFiatCurrencyKey, currentFiatCurrency);
|
|
||||||
|
|
||||||
if (shouldSaveRecipientAddress != null)
|
|
||||||
await sharedPreferences.setBool(
|
|
||||||
PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress);
|
|
||||||
|
|
||||||
if (isAppSecure != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
|
|
||||||
|
|
||||||
if (disableTradeOption != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.disableTradeOption, disableTradeOption);
|
|
||||||
|
|
||||||
if (currentTransactionPriorityKeyLegacy != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.currentTransactionPriorityKeyLegacy, currentTransactionPriorityKeyLegacy);
|
|
||||||
|
|
||||||
if (currentBitcoinElectrumSererId != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.currentBitcoinElectrumSererIdKey, currentBitcoinElectrumSererId);
|
|
||||||
|
|
||||||
if (currentLanguageCode != null)
|
|
||||||
await sharedPreferences.setString(PreferencesKey.currentLanguageCode, currentLanguageCode);
|
|
||||||
|
|
||||||
if (displayActionListMode != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.displayActionListModeKey, displayActionListMode);
|
|
||||||
|
|
||||||
if (fiatApiMode != null)
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, fiatApiMode);
|
|
||||||
if (autoGenerateSubaddressStatus != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.autoGenerateSubaddressStatusKey, autoGenerateSubaddressStatus);
|
|
||||||
|
|
||||||
if (currentTheme != null && DeviceInfo.instance.isMobile) {
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentTheme, currentTheme);
|
|
||||||
// enforce dark theme on desktop platforms until the design is ready:
|
|
||||||
} else if (DeviceInfo.instance.isDesktop) {
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentTheme, ThemeList.darkTheme.raw);
|
await sharedPreferences.setInt(PreferencesKey.currentTheme, ThemeList.darkTheme.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exchangeStatus != null)
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, exchangeStatus);
|
|
||||||
|
|
||||||
if (currentDefaultSettingsMigrationVersion != null)
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion,
|
|
||||||
currentDefaultSettingsMigrationVersion);
|
|
||||||
|
|
||||||
if (moneroTransactionPriority != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.moneroTransactionPriority, moneroTransactionPriority);
|
|
||||||
|
|
||||||
if (bitcoinTransactionPriority != null)
|
|
||||||
await sharedPreferences.setInt(
|
|
||||||
PreferencesKey.bitcoinTransactionPriority, bitcoinTransactionPriority);
|
|
||||||
|
|
||||||
if (sortBalanceTokensBy != null)
|
|
||||||
await sharedPreferences.setInt(PreferencesKey.sortBalanceBy, sortBalanceTokensBy);
|
|
||||||
|
|
||||||
if (pinNativeTokenAtTop != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.pinNativeTokenAtTop, pinNativeTokenAtTop);
|
|
||||||
|
|
||||||
if (useEtherscan != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
|
|
||||||
|
|
||||||
if (defaultNanoRep != null)
|
|
||||||
await sharedPreferences.setString(PreferencesKey.defaultNanoRep, defaultNanoRep);
|
|
||||||
|
|
||||||
if (defaultBananoRep != null)
|
|
||||||
await sharedPreferences.setString(PreferencesKey.defaultBananoRep, defaultBananoRep);
|
|
||||||
|
|
||||||
if (syncAll != null) await sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
|
||||||
if (lookupsTwitter != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.lookupsTwitter, lookupsTwitter);
|
|
||||||
|
|
||||||
if (lookupsMastodon != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.lookupsMastodon, lookupsMastodon);
|
|
||||||
|
|
||||||
if (lookupsYatService != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.lookupsYatService, lookupsYatService);
|
|
||||||
|
|
||||||
if (lookupsUnstoppableDomains != null)
|
|
||||||
await sharedPreferences.setBool(
|
|
||||||
PreferencesKey.lookupsUnstoppableDomains, lookupsUnstoppableDomains);
|
|
||||||
|
|
||||||
if (lookupsOpenAlias != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, lookupsOpenAlias);
|
|
||||||
|
|
||||||
if (lookupsENS != null) await sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS);
|
|
||||||
|
|
||||||
if (lookupsWellKnown != null)
|
|
||||||
await sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, lookupsWellKnown);
|
|
||||||
|
|
||||||
if (syncAll != null) await sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
|
||||||
|
|
||||||
if (syncMode != null) await sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode);
|
|
||||||
|
|
||||||
await preferencesFile.delete();
|
await preferencesFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,83 +261,45 @@ class $BackupService {
|
||||||
await keyService.saveWalletPassword(walletName: name, password: password);
|
await keyService.saveWalletPassword(walletName: name, password: password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated('Use v2 instead')
|
|
||||||
Future<Uint8List> _exportKeychainDumpV1(String password,
|
|
||||||
{required String nonce, String keychainSalt = secrets.backupKeychainSalt}) async =>
|
|
||||||
throw Exception('Deprecated');
|
|
||||||
|
|
||||||
Future<Uint8List> exportKeychainDumpV2(String password,
|
Future<Uint8List> exportKeychainDumpV2(String password,
|
||||||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
|
final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
|
||||||
return {
|
try {
|
||||||
'name': walletInfo.name,
|
return {
|
||||||
'type': walletInfo.type.toString(),
|
'name': walletInfo.name,
|
||||||
'password': await keyService.getWalletPassword(walletName: walletInfo.name)
|
'type': walletInfo.type.toString(),
|
||||||
};
|
'password': await keyService.getWalletPassword(walletName: walletInfo.name)
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
'name': walletInfo.name,
|
||||||
|
'type': walletInfo.type.toString(),
|
||||||
|
'password': ''
|
||||||
|
};
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||||
final backupPassword = await _secureStorage.read(key: backupPasswordKey);
|
final backupPassword = await _secureStorage.read(key: backupPasswordKey);
|
||||||
final data = utf8.encode(
|
final data = utf8.encode(
|
||||||
json.encode({'wallets': wallets, backupPasswordKey: backupPassword}));
|
json.encode({'wallets': wallets, backupPasswordKey: backupPassword, '_all': await _secureStorage.readAll()}));
|
||||||
final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
|
final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
|
||||||
|
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const List<String> _excludedPrefsKeys = [
|
||||||
|
PreferencesKey.currentPinLength,
|
||||||
|
PreferencesKey.showCameraConsent,
|
||||||
|
PreferencesKey.lastSeenAppVersion,
|
||||||
|
PreferencesKey.failedTotpTokenTrials,
|
||||||
|
];
|
||||||
|
|
||||||
Future<String> exportPreferencesJSON() async {
|
Future<String> exportPreferencesJSON() async {
|
||||||
final preferences = <String, dynamic>{
|
final preferences = <String, dynamic>{};
|
||||||
PreferencesKey.currentWalletName:
|
sharedPreferences.getKeys().forEach((key) => preferences[key] = sharedPreferences.get(key));
|
||||||
sharedPreferences.getString(PreferencesKey.currentWalletName),
|
|
||||||
PreferencesKey.currentNodeIdKey: sharedPreferences.getInt(PreferencesKey.currentNodeIdKey),
|
_excludedPrefsKeys.forEach((key) => preferences.remove(key));
|
||||||
PreferencesKey.currentBalanceDisplayModeKey:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey),
|
|
||||||
PreferencesKey.currentWalletType: sharedPreferences.getInt(PreferencesKey.currentWalletType),
|
|
||||||
PreferencesKey.currentFiatCurrencyKey:
|
|
||||||
sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey),
|
|
||||||
PreferencesKey.shouldSaveRecipientAddressKey:
|
|
||||||
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
|
|
||||||
PreferencesKey.disableTradeOption: sharedPreferences.getBool(PreferencesKey.disableTradeOption),
|
|
||||||
PreferencesKey.currentTransactionPriorityKeyLegacy:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy),
|
|
||||||
PreferencesKey.currentBitcoinElectrumSererIdKey:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey),
|
|
||||||
PreferencesKey.currentLanguageCode:
|
|
||||||
sharedPreferences.getString(PreferencesKey.currentLanguageCode),
|
|
||||||
PreferencesKey.displayActionListModeKey:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
|
|
||||||
PreferencesKey.currentTheme: sharedPreferences.getInt(PreferencesKey.currentTheme),
|
|
||||||
PreferencesKey.exchangeStatusKey: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey),
|
|
||||||
PreferencesKey.currentDefaultSettingsMigrationVersion:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion),
|
|
||||||
PreferencesKey.bitcoinTransactionPriority:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority),
|
|
||||||
PreferencesKey.moneroTransactionPriority:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority),
|
|
||||||
PreferencesKey.currentFiatApiModeKey:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey),
|
|
||||||
PreferencesKey.sortBalanceBy: sharedPreferences.getInt(PreferencesKey.sortBalanceBy),
|
|
||||||
PreferencesKey.pinNativeTokenAtTop:
|
|
||||||
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
|
|
||||||
PreferencesKey.useEtherscan: sharedPreferences.getBool(PreferencesKey.useEtherscan),
|
|
||||||
PreferencesKey.defaultNanoRep: sharedPreferences.getString(PreferencesKey.defaultNanoRep),
|
|
||||||
PreferencesKey.defaultBananoRep:
|
|
||||||
sharedPreferences.getString(PreferencesKey.defaultBananoRep),
|
|
||||||
PreferencesKey.lookupsTwitter: sharedPreferences.getBool(PreferencesKey.lookupsTwitter),
|
|
||||||
PreferencesKey.lookupsMastodon: sharedPreferences.getBool(PreferencesKey.lookupsMastodon),
|
|
||||||
PreferencesKey.lookupsYatService:
|
|
||||||
sharedPreferences.getBool(PreferencesKey.lookupsYatService),
|
|
||||||
PreferencesKey.lookupsUnstoppableDomains:
|
|
||||||
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains),
|
|
||||||
PreferencesKey.lookupsOpenAlias: sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias),
|
|
||||||
PreferencesKey.lookupsENS: sharedPreferences.getBool(PreferencesKey.lookupsENS),
|
|
||||||
PreferencesKey.lookupsWellKnown:
|
|
||||||
sharedPreferences.getBool(PreferencesKey.lookupsWellKnown),
|
|
||||||
PreferencesKey.syncModeKey: sharedPreferences.getInt(PreferencesKey.syncModeKey),
|
|
||||||
PreferencesKey.syncAllKey: sharedPreferences.getBool(PreferencesKey.syncAllKey),
|
|
||||||
PreferencesKey.autoGenerateSubaddressStatusKey:
|
|
||||||
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey),
|
|
||||||
};
|
|
||||||
|
|
||||||
return json.encode(preferences);
|
return json.encode(preferences);
|
||||||
}
|
}
|
||||||
|
@ -466,10 +311,6 @@ class $BackupService {
|
||||||
return Uint8List.fromList(bytes);
|
return Uint8List.fromList(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated('Use v2 instead')
|
|
||||||
Future<Uint8List> _encryptV1(Uint8List data, String secretKeySource, String nonceBase64) async =>
|
|
||||||
throw Exception('Deprecated');
|
|
||||||
|
|
||||||
Future<Uint8List> _decryptV1(Uint8List data, String secretKeySource, String nonceBase64,
|
Future<Uint8List> _decryptV1(Uint8List data, String secretKeySource, String nonceBase64,
|
||||||
{int macLength = 16}) async {
|
{int macLength = 16}) async {
|
||||||
final secretKeyHash = await Cryptography.instance.sha256().hash(utf8.encode(secretKeySource));
|
final secretKeyHash = await Cryptography.instance.sha256().hash(utf8.encode(secretKeySource));
|
||||||
|
|
|
@ -490,11 +490,19 @@ class BuySellPage extends BasePage {
|
||||||
return DesktopExchangeCardsSection(
|
return DesktopExchangeCardsSection(
|
||||||
firstExchangeCard: fiatExchangeCard,
|
firstExchangeCard: fiatExchangeCard,
|
||||||
secondExchangeCard: cryptoExchangeCard,
|
secondExchangeCard: cryptoExchangeCard,
|
||||||
|
onBuyTap: () => null,
|
||||||
|
onSellTap: () =>
|
||||||
|
buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
|
||||||
|
isBuySellOption: true,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return DesktopExchangeCardsSection(
|
return DesktopExchangeCardsSection(
|
||||||
firstExchangeCard: cryptoExchangeCard,
|
firstExchangeCard: cryptoExchangeCard,
|
||||||
secondExchangeCard: fiatExchangeCard,
|
secondExchangeCard: fiatExchangeCard,
|
||||||
|
onBuyTap: () =>
|
||||||
|
!buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
|
||||||
|
onSellTap: () => null,
|
||||||
|
isBuySellOption: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,123 +1,178 @@
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
|
||||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart';
|
|
||||||
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
|
|
||||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
|
|
||||||
class FilterWidget extends StatelessWidget {
|
class FilterWidget extends StatefulWidget {
|
||||||
FilterWidget({required this.filterItems});
|
const FilterWidget({required this.filterItems, this.onClose, Key? key}) : super(key: key);
|
||||||
|
|
||||||
final Map<String, List<FilterItem>> filterItems;
|
final Map<String, List<FilterItem>> filterItems;
|
||||||
|
final Function()? onClose;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FilterWidgetState createState() => _FilterWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FilterWidgetState extends State<FilterWidget> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const sectionDivider = const HorizontalSectionDivider();
|
return AlertBackground(
|
||||||
return PickerWrapperWidget(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
const Expanded(child: SizedBox()),
|
||||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
Expanded(
|
||||||
child: ClipRRect(
|
flex: responsiveLayoutUtil.shouldRenderTabletUI ? 16 : 8,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
child: LayoutBuilder(
|
||||||
child: Container(
|
builder: (context, constraints) {
|
||||||
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
|
double availableHeight = constraints.maxHeight;
|
||||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
return _buildFilterContent(context, availableHeight);
|
||||||
Padding(
|
},
|
||||||
padding: EdgeInsets.all(24.0),
|
),
|
||||||
child: Text(
|
),
|
||||||
S.of(context).filter_by,
|
Expanded(
|
||||||
style: TextStyle(
|
child: AlertCloseButton(
|
||||||
color:
|
key: const ValueKey('filter_wrapper_close_button_key'),
|
||||||
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
isPositioned: false,
|
||||||
fontSize: 16,
|
onTap: widget.onClose,
|
||||||
fontFamily: 'Lato',
|
),
|
||||||
decoration: TextDecoration.none,
|
),
|
||||||
),
|
const SizedBox(height: 24),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
sectionDivider,
|
);
|
||||||
ListView.separated(
|
}
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
shrinkWrap: true,
|
Widget _buildFilterContent(BuildContext context, double availableHeight) {
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
const sectionDivider = HorizontalSectionDivider();
|
||||||
itemCount: filterItems.length,
|
|
||||||
separatorBuilder: (context, _) => sectionDivider,
|
const double totalHeaderHeight = 73;
|
||||||
itemBuilder: (_, index1) {
|
const double filterTileMinHeight = 40;
|
||||||
final title = filterItems.keys.elementAt(index1);
|
double availableHeightForItems = availableHeight - totalHeaderHeight;
|
||||||
final section = filterItems.values.elementAt(index1);
|
|
||||||
return Column(
|
return Center(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: <Widget>[
|
mainAxisSize: MainAxisSize.min,
|
||||||
Padding(
|
children: [
|
||||||
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
|
Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||||
title,
|
child: ClipRRect(
|
||||||
style: TextStyle(
|
borderRadius: BorderRadius.circular(24),
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
child: Container(
|
||||||
fontSize: 16,
|
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
|
||||||
fontFamily: 'Lato',
|
child: Column(
|
||||||
fontWeight: FontWeight.bold,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
decoration: TextDecoration.none),
|
children: [
|
||||||
),
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: Text(
|
||||||
|
S.of(context).filter_by,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<TransactionTradeTheme>()!
|
||||||
|
.detailsTitlesColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
decoration: TextDecoration.none,
|
||||||
),
|
),
|
||||||
ListView.builder(
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 28.0),
|
),
|
||||||
shrinkWrap: true,
|
sectionDivider,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: widget.filterItems.length,
|
||||||
|
separatorBuilder: (context, _) => sectionDivider,
|
||||||
|
itemBuilder: (_, index1) {
|
||||||
|
final title = widget.filterItems.keys.elementAt(index1);
|
||||||
|
final section = widget.filterItems.values.elementAt(index1);
|
||||||
|
|
||||||
|
final double itemHeight =
|
||||||
|
availableHeightForItems / widget.filterItems.length;
|
||||||
|
|
||||||
|
final isSectionScrollable =
|
||||||
|
(itemHeight < (section.length * filterTileMinHeight));
|
||||||
|
|
||||||
|
final Widget sectionListView = ListView.builder(
|
||||||
|
controller: isSectionScrollable ? _scrollController : null,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 28.0),
|
||||||
|
shrinkWrap: isSectionScrollable ? false : true,
|
||||||
|
physics: isSectionScrollable
|
||||||
|
? const BouncingScrollPhysics()
|
||||||
|
: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: section.length,
|
itemCount: section.length,
|
||||||
itemBuilder: (_, index2) {
|
itemBuilder: (_, index2) {
|
||||||
final item = section[index2];
|
final item = section[index2];
|
||||||
|
|
||||||
if (item is DropdownFilterItem) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(8, 0, 8, 16),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
width: 1.0,
|
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: DropdownFilterList(
|
|
||||||
items: item.items,
|
|
||||||
caption: item.caption,
|
|
||||||
selectedItem: item.selectedItem,
|
|
||||||
onItemSelected: item.onItemSelected,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final content = Observer(
|
final content = Observer(
|
||||||
builder: (_) => StandardCheckbox(
|
builder: (_) => StandardCheckbox(
|
||||||
value: item.value(),
|
value: item.value(),
|
||||||
caption: item.caption,
|
caption: item.caption,
|
||||||
gradientBackground: true,
|
gradientBackground: true,
|
||||||
borderColor: Theme.of(context).dividerColor,
|
borderColor: Theme.of(context).dividerColor,
|
||||||
iconColor: Colors.white,
|
iconColor: Colors.white,
|
||||||
onChanged: (value) => item.onChanged(),
|
onChanged: (value) => item.onChanged(),
|
||||||
));
|
),
|
||||||
return FilterTile(child: content);
|
);
|
||||||
|
return FilterTile(
|
||||||
|
child: content,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
],
|
|
||||||
);
|
return Column(
|
||||||
},
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 20, left: 24, right: 24),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: isSectionScrollable ? itemHeight - totalHeaderHeight : null,
|
||||||
|
child: isSectionScrollable
|
||||||
|
? Scrollbar(
|
||||||
|
controller: _scrollController,
|
||||||
|
thumbVisibility: true,
|
||||||
|
child: sectionListView,
|
||||||
|
)
|
||||||
|
: sectionListView,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
]),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
|
import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DesktopExchangeCardsSection extends StatelessWidget {
|
class DesktopExchangeCardsSection extends StatelessWidget {
|
||||||
final Widget firstExchangeCard;
|
|
||||||
final Widget secondExchangeCard;
|
|
||||||
|
|
||||||
const DesktopExchangeCardsSection({
|
const DesktopExchangeCardsSection({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.firstExchangeCard,
|
required this.firstExchangeCard,
|
||||||
required this.secondExchangeCard,
|
required this.secondExchangeCard,
|
||||||
|
this.isBuySellOption = false,
|
||||||
|
this.onBuyTap,
|
||||||
|
this.onSellTap,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget firstExchangeCard;
|
||||||
|
final Widget secondExchangeCard;
|
||||||
|
final bool isBuySellOption;
|
||||||
|
final VoidCallback? onBuyTap;
|
||||||
|
final VoidCallback? onSellTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FocusTraversalGroup(
|
return FocusTraversalGroup(
|
||||||
|
@ -18,7 +25,18 @@ class DesktopExchangeCardsSection extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 55, left: 24, right: 24),
|
padding: EdgeInsets.only(top: 55, left: 24, right: 24),
|
||||||
child: firstExchangeCard,
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (isBuySellOption)
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
BuySellOptionButtons(onBuyTap: onBuyTap, onSellTap: onSellTap),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
firstExchangeCard,
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 29, left: 24, right: 24),
|
padding: EdgeInsets.only(top: 29, left: 24, right: 24),
|
||||||
|
|
|
@ -38,6 +38,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
static const fourPinLength = 4;
|
static const fourPinLength = 4;
|
||||||
final _gridViewKey = GlobalKey();
|
final _gridViewKey = GlobalKey();
|
||||||
final _key = GlobalKey<ScaffoldState>();
|
final _key = GlobalKey<ScaffoldState>();
|
||||||
|
late final FocusNode _focusNode;
|
||||||
|
|
||||||
int pinLength;
|
int pinLength;
|
||||||
String pin;
|
String pin;
|
||||||
|
@ -54,7 +55,17 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
pin = '';
|
pin = '';
|
||||||
title = S.current.enter_your_pin;
|
title = S.current.enter_your_pin;
|
||||||
_aspectRatio = 0;
|
_aspectRatio = 0;
|
||||||
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
|
_focusNode = FocusNode();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_focusNode.requestFocus();
|
||||||
|
_afterLayout(_);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTitle(String title) => setState(() => this.title = title);
|
void setTitle(String title) => setState(() => this.title = title);
|
||||||
|
@ -120,8 +131,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
return KeyboardListener(
|
return KeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: _focusNode,
|
||||||
autofocus: true,
|
autofocus: false,
|
||||||
onKeyEvent: (keyEvent) {
|
onKeyEvent: (keyEvent) {
|
||||||
if (keyEvent is KeyDownEvent) {
|
if (keyEvent is KeyDownEvent) {
|
||||||
if (keyEvent.logicalKey.keyLabel == "Backspace") {
|
if (keyEvent.logicalKey.keyLabel == "Backspace") {
|
||||||
|
@ -144,8 +155,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color:
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
||||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
|
||||||
Spacer(flex: 8),
|
Spacer(flex: 8),
|
||||||
Container(
|
Container(
|
||||||
width: 180,
|
width: 180,
|
||||||
|
@ -162,7 +172,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: isFilled
|
color: isFilled
|
||||||
? Theme.of(context).extension<CakeTextTheme>()!.titleColor
|
? Theme.of(context).extension<CakeTextTheme>()!.titleColor
|
||||||
: Theme.of(context).extension<PinCodeTheme>()!.indicatorsColor
|
: Theme.of(context)
|
||||||
|
.extension<PinCodeTheme>()!
|
||||||
|
.indicatorsColor
|
||||||
.withOpacity(0.25),
|
.withOpacity(0.25),
|
||||||
));
|
));
|
||||||
}),
|
}),
|
||||||
|
@ -225,7 +237,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () => _pop(),
|
onPressed: () => _pop(),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.background,
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
),
|
),
|
||||||
child: deleteIconImage,
|
child: deleteIconImage,
|
||||||
|
@ -250,7 +263,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 25.0,
|
fontSize: 25.0,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,6 +7,7 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
this.image,
|
this.image,
|
||||||
this.bottom,
|
this.bottom,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.isPositioned = true,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
|
|
||||||
final Image? image;
|
final Image? image;
|
||||||
final double? bottom;
|
final double? bottom;
|
||||||
|
final bool isPositioned;
|
||||||
|
|
||||||
final closeButton = Image.asset(
|
final closeButton = Image.asset(
|
||||||
'assets/images/close.png',
|
'assets/images/close.png',
|
||||||
|
@ -22,24 +24,18 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Positioned(
|
final button = GestureDetector(
|
||||||
bottom: bottom ?? 60,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: onTap ?? () => Navigator.of(context).pop(),
|
onTap: onTap ?? () => Navigator.of(context).pop(),
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
label: S.of(context).close,
|
label: S.of(context).close,
|
||||||
button: true,
|
button: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 42,
|
height: 42,
|
||||||
width: 42,
|
width: 42,
|
||||||
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
||||||
child: Center(
|
child: Center(child: image ?? closeButton))));
|
||||||
child: image ?? closeButton,
|
|
||||||
),
|
return isPositioned ? Positioned(bottom: bottom ?? 60, child: button) : button;
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
||||||
state = FailureState('This is not a valid backup file, please make sure you selected the correct backup file');
|
state = FailureState('This is not a valid backup file, please make sure you selected the correct backup file');
|
||||||
} else {
|
} else {
|
||||||
state = FailureState('Failed to restore backup, please try again');
|
state = FailureState('Failed to restore backup, please try again');
|
||||||
ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s, silent: true));
|
ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1629,6 +1629,7 @@ abstract class SecureStorage {
|
||||||
Future<void> delete({required String key});
|
Future<void> delete({required String key});
|
||||||
// Legacy
|
// Legacy
|
||||||
Future<String?> readNoIOptions({required String key});
|
Future<String?> readNoIOptions({required String key});
|
||||||
|
Future<Map<String, String>> readAll();
|
||||||
}""";
|
}""";
|
||||||
const defaultSecureStorage = """
|
const defaultSecureStorage = """
|
||||||
class DefaultSecureStorage extends SecureStorage {
|
class DefaultSecureStorage extends SecureStorage {
|
||||||
|
@ -1667,6 +1668,11 @@ class DefaultSecureStorage extends SecureStorage {
|
||||||
iOptions: useNoIOptions ? IOSOptions() : null,
|
iOptions: useNoIOptions ? IOSOptions() : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Map<String, String>> readAll() async {
|
||||||
|
return await _secureStorage.readAll();
|
||||||
|
}
|
||||||
}""";
|
}""";
|
||||||
const fakeSecureStorage = """
|
const fakeSecureStorage = """
|
||||||
class FakeSecureStorage extends SecureStorage {
|
class FakeSecureStorage extends SecureStorage {
|
||||||
|
@ -1678,6 +1684,8 @@ class FakeSecureStorage extends SecureStorage {
|
||||||
Future<void> delete({required String key}) async {}
|
Future<void> delete({required String key}) async {}
|
||||||
@override
|
@override
|
||||||
Future<String?> readNoIOptions({required String key}) async => null;
|
Future<String?> readNoIOptions({required String key}) async => null;
|
||||||
|
@override
|
||||||
|
Future<Map<String, String>> readAll() async => {};
|
||||||
}""";
|
}""";
|
||||||
final outputFile = File(secureStoragePath);
|
final outputFile = File(secureStoragePath);
|
||||||
final header = hasFlutterSecureStorage
|
final header = hasFlutterSecureStorage
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue