mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-29 04:49:51 +00:00
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
This commit is contained in:
commit
860d882c41
8 changed files with 130 additions and 339 deletions
|
@ -162,7 +162,8 @@ class $BackupService {
|
|||
|
||||
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
|
||||
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;
|
||||
|
@ -180,7 +181,8 @@ class $BackupService {
|
|||
await sharedPreferences.setStringList(key, value);
|
||||
} else {
|
||||
if (kDebugMode) {
|
||||
printV('Skipping individual save for key "$key": Unsupported type (${value.runtimeType}). Value: $value');
|
||||
printV(
|
||||
'Skipping individual save for key "$key": Unsupported type (${value.runtimeType}). Value: $value');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,15 +265,23 @@ class $BackupService {
|
|||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
|
||||
try {
|
||||
return {
|
||||
'name': 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 backupPassword = await _secureStorage.read(key: backupPasswordKey);
|
||||
final data = utf8.encode(json.encode({'wallets': wallets, backupPasswordKey: backupPassword}));
|
||||
final data = utf8.encode(json.encode({
|
||||
'wallets': wallets,
|
||||
backupPasswordKey: backupPassword,
|
||||
'_all': await _secureStorage.readAll()
|
||||
}));
|
||||
final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
|
||||
|
||||
return encrypted;
|
||||
|
|
|
@ -33,6 +33,7 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
|||
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/haven/cw_haven.dart';
|
||||
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
|
||||
import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/background_sync_page.dart';
|
||||
|
@ -1144,8 +1145,9 @@ Future<void> setup({
|
|||
return zano!.createZanoWalletService(_walletInfoSource);
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
return HavenWalletService(_walletInfoSource);
|
||||
case WalletType.none:
|
||||
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -41,8 +41,8 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
|
||||
static const sending = TradeState(raw: 'sending', title: 'Sending');
|
||||
static const success = TradeState(raw: 'success', title: 'Success');
|
||||
static TradeState deserialize({required String raw}) {
|
||||
|
||||
static TradeState deserialize({required String raw}) {
|
||||
switch (raw) {
|
||||
case '1':
|
||||
return unpaid;
|
||||
|
@ -138,7 +138,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
case 'awaiting':
|
||||
return awaiting;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw in TradeState deserialize');
|
||||
return TradeState(raw: raw, title: raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,348 +1,78 @@
|
|||
part of 'haven.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class CWHavenAccountList extends HavenAccountList {
|
||||
CWHavenAccountList(this._wallet);
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
final Object _wallet;
|
||||
class HavenWalletService extends WalletService {
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
||||
HavenWalletService(this.walletInfoSource);
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Account> get accounts {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final accounts = havenWallet.walletAddresses.accountList.accounts
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
return ObservableList<Account>.of(accounts);
|
||||
WalletType getType() => WalletType.haven;
|
||||
|
||||
@override
|
||||
Future<void> remove(String wallet) async {
|
||||
final path = await pathForWalletDir(name: wallet, type: WalletType.haven);
|
||||
|
||||
final file = Directory(path);
|
||||
final isExist = file.existsSync();
|
||||
|
||||
if (isExist) {
|
||||
await file.delete(recursive: true);
|
||||
}
|
||||
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
void update(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.update();
|
||||
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> create(
|
||||
WalletCredentials credentials,
|
||||
{bool? isTestnet}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void refresh(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.refresh();
|
||||
Future<bool> isWalletExit(String name) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Account> getAll(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses.accountList
|
||||
.getAll()
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> openWallet(
|
||||
String name, String password) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
Future<void> rename(String currentName, String password, String newName) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList
|
||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
CWHavenSubaddressList(this._wallet);
|
||||
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Subaddress> get subaddresses {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final subAddresses = havenWallet.walletAddresses.subaddressList.subaddresses
|
||||
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
|
||||
.toList();
|
||||
return ObservableList<Subaddress>.of(subAddresses);
|
||||
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
|
||||
restoreFromHardwareWallet(WalletCredentials credentials) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void update(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
||||
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
|
||||
restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void refresh(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Subaddress> getAll(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses.subaddressList
|
||||
.getAll()
|
||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addSubaddress(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.addSubaddress(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelSubaddress(Object wallet,
|
||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
|
||||
restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class CWHavenWalletDetails extends HavenWalletDetails {
|
||||
CWHavenWalletDetails(this._wallet);
|
||||
|
||||
final Object _wallet;
|
||||
|
||||
@computed
|
||||
@override
|
||||
Account get account {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
|
||||
@computed
|
||||
@override
|
||||
HavenBalance get balance {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final balance = havenWallet.balance;
|
||||
throw Exception('Unimplemented');
|
||||
//return HavenBalance(
|
||||
// fullBalance: balance.fullBalance,
|
||||
// unlockedBalance: balance.unlockedBalance);
|
||||
}
|
||||
}
|
||||
|
||||
class CWHaven extends Haven {
|
||||
@override
|
||||
HavenAccountList getAccountList(Object wallet) {
|
||||
return CWHavenAccountList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
||||
return CWHavenSubaddressList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.transactionHistory;
|
||||
}
|
||||
|
||||
@override
|
||||
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
|
||||
return CWHavenWalletDetails(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
int getHeightByDate({required DateTime date}) => getHavenHeightByDate(date: date);
|
||||
|
||||
@override
|
||||
Future<int> getCurrentHeight() => getHavenCurrentHeight();
|
||||
|
||||
@override
|
||||
TransactionPriority getDefaultTransactionPriority() {
|
||||
return MoneroTransactionPriority.automatic;
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
||||
}
|
||||
|
||||
@override
|
||||
List<TransactionPriority> getTransactionPriorities() {
|
||||
return MoneroTransactionPriority.all;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getMoneroWordList(String language) {
|
||||
switch (language.toLowerCase()) {
|
||||
case 'english':
|
||||
return EnglishMnemonics.words;
|
||||
case 'chinese (simplified)':
|
||||
return ChineseSimplifiedMnemonics.words;
|
||||
case 'dutch':
|
||||
return DutchMnemonics.words;
|
||||
case 'german':
|
||||
return GermanMnemonics.words;
|
||||
case 'japanese':
|
||||
return JapaneseMnemonics.words;
|
||||
case 'portuguese':
|
||||
return PortugueseMnemonics.words;
|
||||
case 'russian':
|
||||
return RussianMnemonics.words;
|
||||
case 'spanish':
|
||||
return SpanishMnemonics.words;
|
||||
case 'french':
|
||||
return FrenchMnemonics.words;
|
||||
case 'italian':
|
||||
return ItalianMnemonics.words;
|
||||
default:
|
||||
return EnglishMnemonics.words;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromKeysCredentials(
|
||||
{required String name,
|
||||
required String spendKey,
|
||||
required String viewKey,
|
||||
required String address,
|
||||
required String password,
|
||||
required String language,
|
||||
required int height}) {
|
||||
return HavenRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
spendKey: spendKey,
|
||||
viewKey: viewKey,
|
||||
address: address,
|
||||
password: password,
|
||||
language: language,
|
||||
height: height);
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required int height,
|
||||
required String mnemonic}) {
|
||||
return HavenRestoreWalletFromSeedCredentials(
|
||||
name: name, password: password, height: height, mnemonic: mnemonic);
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenNewWalletCredentials(
|
||||
{required String name, required String language, String? password}) {
|
||||
return HavenNewWalletCredentials(name: name, password: password, language: language);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> getKeys(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final keys = havenWallet.keys;
|
||||
return <String, String>{
|
||||
'privateSpendKey': keys.privateSpendKey,
|
||||
'privateViewKey': keys.privateViewKey,
|
||||
'publicSpendKey': keys.publicSpendKey,
|
||||
'publicViewKey': keys.publicViewKey
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Object createHavenTransactionCreationCredentials(
|
||||
{required List<Output> outputs,
|
||||
required TransactionPriority priority,
|
||||
required String assetType}) {
|
||||
return HavenTransactionCreationCredentials(
|
||||
outputs: outputs
|
||||
.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
cryptoAmount: out.cryptoAmount,
|
||||
address: out.address,
|
||||
note: out.note,
|
||||
sendAll: out.sendAll,
|
||||
extractedAddress: out.extractedAddress,
|
||||
isParsedAddress: out.isParsedAddress,
|
||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||
.toList(),
|
||||
priority: priority as MoneroTransactionPriority,
|
||||
assetType: assetType);
|
||||
}
|
||||
|
||||
@override
|
||||
String formatterMoneroAmountToString({required int amount}) {
|
||||
return moneroAmountToString(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
double formatterMoneroAmountToDouble({required int amount}) {
|
||||
return moneroAmountToDouble(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
int formatterMoneroParseAmount({required String amount}) {
|
||||
return moneroParseAmount(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
Account getCurrentAccount(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
|
||||
@override
|
||||
void setCurrentAccount(Object wallet, int id, String label) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
void onStartup() {
|
||||
monero_wallet_api.onStartup();
|
||||
}
|
||||
|
||||
@override
|
||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
||||
final havenTransactionInfo = tx as HavenTransactionInfo;
|
||||
return havenTransactionInfo.accountIndex;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
|
||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final wallets = walletInfoSource.values
|
||||
.where((element) => element.type == WalletType.haven);
|
||||
for (var w in wallets) {
|
||||
final walletService = HavenWalletService(walletInfoSource);
|
||||
final flutterSecureStorage = secureStorageShared;
|
||||
final keyService = KeyService(flutterSecureStorage);
|
||||
final password = await keyService.getWalletPassword(walletName: w.name);
|
||||
final wallet = await walletService.openWallet(w.name, password);
|
||||
await havenSeedStore.add(HavenSeedStore(id: wallet.id, seed: wallet.seed));
|
||||
wallet.close();
|
||||
}
|
||||
await havenSeedStore.flush();
|
||||
}
|
||||
|
||||
@override
|
||||
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
|
||||
return HavenWalletService(walletInfoSource);
|
||||
}
|
||||
|
||||
@override
|
||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
||||
final transaction = tx as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
||||
return asset;
|
||||
}
|
||||
|
||||
@override
|
||||
List<AssetRate> getAssetRate() =>
|
||||
getRate().map((rate) => AssetRate(rate.getAssetType(), rate.getRate())).toList();
|
||||
}
|
||||
|
|
|
@ -490,11 +490,19 @@ class BuySellPage extends BasePage {
|
|||
return DesktopExchangeCardsSection(
|
||||
firstExchangeCard: fiatExchangeCard,
|
||||
secondExchangeCard: cryptoExchangeCard,
|
||||
onBuyTap: () => null,
|
||||
onSellTap: () =>
|
||||
buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
|
||||
isBuySellOption: true,
|
||||
);
|
||||
} else {
|
||||
return DesktopExchangeCardsSection(
|
||||
firstExchangeCard: cryptoExchangeCard,
|
||||
secondExchangeCard: fiatExchangeCard,
|
||||
onBuyTap: () =>
|
||||
!buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
|
||||
onSellTap: () => null,
|
||||
isBuySellOption: true,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DesktopExchangeCardsSection extends StatelessWidget {
|
||||
final Widget firstExchangeCard;
|
||||
final Widget secondExchangeCard;
|
||||
|
||||
const DesktopExchangeCardsSection({
|
||||
Key? key,
|
||||
required this.firstExchangeCard,
|
||||
required this.secondExchangeCard,
|
||||
this.isBuySellOption = false,
|
||||
this.onBuyTap,
|
||||
this.onSellTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget firstExchangeCard;
|
||||
final Widget secondExchangeCard;
|
||||
final bool isBuySellOption;
|
||||
final VoidCallback? onBuyTap;
|
||||
final VoidCallback? onSellTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FocusTraversalGroup(
|
||||
|
@ -18,7 +25,18 @@ class DesktopExchangeCardsSection extends StatelessWidget {
|
|||
children: <Widget>[
|
||||
Padding(
|
||||
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: EdgeInsets.only(top: 29, left: 24, right: 24),
|
||||
|
|
|
@ -38,6 +38,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
static const fourPinLength = 4;
|
||||
final _gridViewKey = GlobalKey();
|
||||
final _key = GlobalKey<ScaffoldState>();
|
||||
late final FocusNode _focusNode;
|
||||
|
||||
int pinLength;
|
||||
String pin;
|
||||
|
@ -54,7 +55,17 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
pin = '';
|
||||
title = S.current.enter_your_pin;
|
||||
_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);
|
||||
|
@ -120,8 +131,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
);
|
||||
|
||||
return KeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
autofocus: true,
|
||||
focusNode: _focusNode,
|
||||
autofocus: false,
|
||||
onKeyEvent: (keyEvent) {
|
||||
if (keyEvent is KeyDownEvent) {
|
||||
if (keyEvent.logicalKey.keyLabel == "Backspace") {
|
||||
|
@ -144,8 +155,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
||||
Spacer(flex: 8),
|
||||
Container(
|
||||
width: 180,
|
||||
|
@ -162,7 +172,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
shape: BoxShape.circle,
|
||||
color: isFilled
|
||||
? Theme.of(context).extension<CakeTextTheme>()!.titleColor
|
||||
: Theme.of(context).extension<PinCodeTheme>()!.indicatorsColor
|
||||
: Theme.of(context)
|
||||
.extension<PinCodeTheme>()!
|
||||
.indicatorsColor
|
||||
.withOpacity(0.25),
|
||||
));
|
||||
}),
|
||||
|
@ -225,7 +237,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
child: TextButton(
|
||||
onPressed: () => _pop(),
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.background,
|
||||
shape: CircleBorder(),
|
||||
),
|
||||
child: deleteIconImage,
|
||||
|
@ -250,7 +263,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
style: TextStyle(
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
||||
color: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.titleColor)),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
|
|
@ -1680,6 +1680,7 @@ abstract class SecureStorage {
|
|||
Future<void> delete({required String key});
|
||||
// Legacy
|
||||
Future<String?> readNoIOptions({required String key});
|
||||
Future<Map<String, String>> readAll();
|
||||
}""";
|
||||
const defaultSecureStorage = """
|
||||
class DefaultSecureStorage extends SecureStorage {
|
||||
|
@ -1718,6 +1719,11 @@ class DefaultSecureStorage extends SecureStorage {
|
|||
iOptions: useNoIOptions ? IOSOptions() : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, String>> readAll() async {
|
||||
return await _secureStorage.readAll();
|
||||
}
|
||||
}""";
|
||||
const fakeSecureStorage = """
|
||||
class FakeSecureStorage extends SecureStorage {
|
||||
|
@ -1729,6 +1735,8 @@ class FakeSecureStorage extends SecureStorage {
|
|||
Future<void> delete({required String key}) async {}
|
||||
@override
|
||||
Future<String?> readNoIOptions({required String key}) async => null;
|
||||
@override
|
||||
Future<Map<String, String>> readAll() async => {};
|
||||
}""";
|
||||
final outputFile = File(secureStoragePath);
|
||||
final header = hasFlutterSecureStorage
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue