commit
3dd1bdabcc
@ -1,6 +1,6 @@
|
|||||||
#Fri Jun 23 08:50:38 CEST 2017
|
#Mon Apr 19 18:19:26 EEST 2021
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'bitcoin_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class BitcoinWalletAddresses = BitcoinWalletAddressesBase
|
||||||
|
with _$BitcoinWalletAddresses;
|
||||||
|
|
||||||
|
abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||||
|
with Store {
|
||||||
|
BitcoinWalletAddressesBase(
|
||||||
|
WalletInfo walletInfo,
|
||||||
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
|
int accountIndex = 0,
|
||||||
|
@required bitcoin.HDWallet hd,
|
||||||
|
@required this.networkType})
|
||||||
|
: super(
|
||||||
|
walletInfo,
|
||||||
|
initialAddresses: initialAddresses,
|
||||||
|
accountIndex: accountIndex,
|
||||||
|
hd: hd);
|
||||||
|
|
||||||
|
bitcoin.NetworkType networkType;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||||
|
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_addresses.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'electrum_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class ElectrumWalletAddresses = ElectrumWalletAddressesBase
|
||||||
|
with _$ElectrumWalletAddresses;
|
||||||
|
|
||||||
|
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
ElectrumWalletAddressesBase(WalletInfo walletInfo,
|
||||||
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
|
int accountIndex = 0,
|
||||||
|
@required bitcoin.HDWallet hd})
|
||||||
|
: super(walletInfo) {
|
||||||
|
this.hd = hd;
|
||||||
|
this.accountIndex = accountIndex;
|
||||||
|
addresses = ObservableList<BitcoinAddressRecord>.of(
|
||||||
|
(initialAddresses ?? []).toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
String address;
|
||||||
|
|
||||||
|
bitcoin.HDWallet hd;
|
||||||
|
|
||||||
|
ObservableList<BitcoinAddressRecord> addresses;
|
||||||
|
|
||||||
|
int accountIndex;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> init() async {
|
||||||
|
await generateAddresses();
|
||||||
|
address = addresses[accountIndex].address;
|
||||||
|
await updateAddressesInBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> nextAddress() async {
|
||||||
|
accountIndex += 1;
|
||||||
|
|
||||||
|
if (accountIndex >= addresses.length) {
|
||||||
|
accountIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = addresses[accountIndex].address;
|
||||||
|
|
||||||
|
await updateAddressesInBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> generateAddresses() async {
|
||||||
|
if (addresses.length < 33) {
|
||||||
|
final addressesCount = 33 - addresses.length;
|
||||||
|
await generateNewAddresses(addressesCount,
|
||||||
|
startIndex: addresses.length, hd: hd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<BitcoinAddressRecord> generateNewAddress(
|
||||||
|
{bool isHidden = false, bitcoin.HDWallet hd}) async {
|
||||||
|
accountIndex += 1;
|
||||||
|
final _hd = hd ?? this.hd;
|
||||||
|
final address = BitcoinAddressRecord(
|
||||||
|
getAddress(index: accountIndex, hd: _hd),
|
||||||
|
index: accountIndex,
|
||||||
|
isHidden: isHidden);
|
||||||
|
addresses.add(address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BitcoinAddressRecord>> generateNewAddresses(int count,
|
||||||
|
{int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async {
|
||||||
|
final list = <BitcoinAddressRecord>[];
|
||||||
|
|
||||||
|
for (var i = startIndex; i < count + startIndex; i++) {
|
||||||
|
final address = BitcoinAddressRecord(getAddress(index: i, hd: hd),
|
||||||
|
index: i, isHidden: isHidden);
|
||||||
|
list.add(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses.addAll(list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Future<void> updateAddress(String address) async {
|
||||||
|
for (final addr in addresses) {
|
||||||
|
if (addr.address == address) {
|
||||||
|
await save();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateAddressesInBox() async {
|
||||||
|
try {
|
||||||
|
addressesMap.clear();
|
||||||
|
addressesMap[address] = '';
|
||||||
|
|
||||||
|
await saveAddressesInBox();
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'litecoin_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class LitecoinWalletAddresses = LitecoinWalletAddressesBase
|
||||||
|
with _$LitecoinWalletAddresses;
|
||||||
|
|
||||||
|
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||||
|
with Store {
|
||||||
|
LitecoinWalletAddressesBase(
|
||||||
|
WalletInfo walletInfo,
|
||||||
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
|
int accountIndex = 0,
|
||||||
|
@required bitcoin.HDWallet hd,
|
||||||
|
@required this.networkType,
|
||||||
|
@required this.mnemonic})
|
||||||
|
: super(
|
||||||
|
walletInfo,
|
||||||
|
initialAddresses: initialAddresses,
|
||||||
|
accountIndex: accountIndex,
|
||||||
|
hd: hd);
|
||||||
|
|
||||||
|
bitcoin.NetworkType networkType;
|
||||||
|
|
||||||
|
final String mnemonic;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||||
|
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> generateAddresses() async {
|
||||||
|
if (addresses.length < 33) {
|
||||||
|
final addressesCount = 22 - addresses.length;
|
||||||
|
await generateNewAddresses(addressesCount,
|
||||||
|
hd: hd, startIndex: addresses.length);
|
||||||
|
|
||||||
|
final changeRoot = bitcoin.HDWallet.fromSeed(
|
||||||
|
mnemonicToSeedBytes(mnemonic),
|
||||||
|
network: networkType)
|
||||||
|
.derivePath("m/0'/1");
|
||||||
|
|
||||||
|
await generateNewAddresses(11,
|
||||||
|
startIndex: 0, hd: changeRoot, isHidden: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||||
|
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||||
|
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||||
|
|
||||||
|
const topLevelDomain = 'crypto';
|
||||||
|
|
||||||
|
Future<ParsedAddress> parseAddressFromDomain(
|
||||||
|
String domain, String ticker) async {
|
||||||
|
try {
|
||||||
|
final formattedName = OpenaliasRecord.formatDomainName(domain);
|
||||||
|
final domainParts = formattedName.split('.');
|
||||||
|
final name = domainParts.last;
|
||||||
|
|
||||||
|
if (domainParts.length <= 1 || domainParts.first.isEmpty || name.isEmpty) {
|
||||||
|
return ParsedAddress(address: domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.contains(topLevelDomain)) {
|
||||||
|
final address =
|
||||||
|
await fetchUnstoppableDomainAddress(domain, ticker);
|
||||||
|
|
||||||
|
if (address?.isEmpty ?? true) {
|
||||||
|
return ParsedAddress(address: domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParsedAddress(
|
||||||
|
address: address,
|
||||||
|
name: domain,
|
||||||
|
parseFrom: ParseFrom.unstoppableDomains);
|
||||||
|
}
|
||||||
|
|
||||||
|
final record = await OpenaliasRecord.fetchAddressAndName(formattedName);
|
||||||
|
|
||||||
|
if (record == null || record.address.contains(formattedName)) {
|
||||||
|
return ParsedAddress(address: domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParsedAddress(
|
||||||
|
address: record.address,
|
||||||
|
name: record.name,
|
||||||
|
parseFrom: ParseFrom.openAlias);
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParsedAddress(address: domain);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
enum ParseFrom {unstoppableDomains, openAlias, notParsed}
|
||||||
|
|
||||||
|
class ParsedAddress {
|
||||||
|
ParsedAddress({
|
||||||
|
this.address = '',
|
||||||
|
this.name = '',
|
||||||
|
this.parseFrom = ParseFrom.notParsed});
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
final String name;
|
||||||
|
final ParseFrom parseFrom;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
const channel = MethodChannel('com.cake_wallet/native_utils');
|
||||||
|
|
||||||
|
Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async {
|
||||||
|
var address = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = await channel.invokeMethod(
|
||||||
|
'getUnstoppableDomainAddress',
|
||||||
|
<String, String> {
|
||||||
|
'domain' : domain,
|
||||||
|
'ticker' : ticker
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print('Unstoppable domain error: ${e.toString()}');
|
||||||
|
address = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||||
|
|
||||||
|
abstract class WalletAddresses {
|
||||||
|
WalletAddresses(this.walletInfo) {
|
||||||
|
addressesMap = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
final WalletInfo walletInfo;
|
||||||
|
|
||||||
|
String get address;
|
||||||
|
|
||||||
|
set address(String address);
|
||||||
|
|
||||||
|
Map<String, String> addressesMap;
|
||||||
|
|
||||||
|
Future<void> init();
|
||||||
|
|
||||||
|
Future<void> updateAddressesInBox();
|
||||||
|
|
||||||
|
Future<void> saveAddressesInBox() async {
|
||||||
|
try {
|
||||||
|
if (walletInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
walletInfo.address = address;
|
||||||
|
walletInfo.addresses = addressesMap;
|
||||||
|
|
||||||
|
if (walletInfo.isInBox) {
|
||||||
|
await walletInfo.save();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
import 'package:cake_wallet/entities/wallet_addresses.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||||
|
import 'package:cake_wallet/monero/account.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero_account_list.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero_subaddress_list.dart';
|
||||||
|
import 'package:cake_wallet/monero/subaddress.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'monero_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class MoneroWalletAddresses = MoneroWalletAddressesBase
|
||||||
|
with _$MoneroWalletAddresses;
|
||||||
|
|
||||||
|
abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
MoneroWalletAddressesBase(WalletInfo walletInfo) : super(walletInfo) {
|
||||||
|
accountList = MoneroAccountList();
|
||||||
|
subaddressList = MoneroSubaddressList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
String address;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
Account account;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
Subaddress subaddress;
|
||||||
|
|
||||||
|
MoneroSubaddressList subaddressList;
|
||||||
|
|
||||||
|
MoneroAccountList accountList;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> init() async {
|
||||||
|
accountList.update();
|
||||||
|
account = accountList.accounts.first;
|
||||||
|
updateSubaddressList(accountIndex: account.id ?? 0);
|
||||||
|
await updateAddressesInBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateAddressesInBox() async {
|
||||||
|
try {
|
||||||
|
final _subaddressList = MoneroSubaddressList();
|
||||||
|
|
||||||
|
addressesMap.clear();
|
||||||
|
|
||||||
|
accountList.accounts.forEach((account) {
|
||||||
|
_subaddressList.update(accountIndex: account.id);
|
||||||
|
_subaddressList.subaddresses.forEach((subaddress) {
|
||||||
|
addressesMap[subaddress.address] = subaddress.label;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await saveAddressesInBox();
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validate() {
|
||||||
|
accountList.update();
|
||||||
|
final accountListLength = accountList.accounts?.length ?? 0;
|
||||||
|
|
||||||
|
if (accountListLength <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
subaddressList.update(accountIndex: accountList.accounts.first.id);
|
||||||
|
final subaddressListLength = subaddressList.subaddresses?.length ?? 0;
|
||||||
|
|
||||||
|
if (subaddressListLength <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSubaddressList({int accountIndex}) {
|
||||||
|
subaddressList.update(accountIndex: accountIndex);
|
||||||
|
subaddress = subaddressList.subaddresses.first;
|
||||||
|
address = subaddress.address;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:cake_wallet/entities/pathForWallet.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||||
|
|
||||||
|
String backupFileName(String originalPath) {
|
||||||
|
final pathParts = originalPath.split('/');
|
||||||
|
final newName = '#_${pathParts.last}';
|
||||||
|
pathParts.removeLast();
|
||||||
|
pathParts.add(newName);
|
||||||
|
return pathParts.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> backupWalletFiles(String name) async {
|
||||||
|
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||||
|
final cacheFile = File(path);
|
||||||
|
final keysFile = File('$path.keys');
|
||||||
|
final addressListFile = File('$path.address.txt');
|
||||||
|
final newCacheFilePath = backupFileName(cacheFile.path);
|
||||||
|
final newKeysFilePath = backupFileName(keysFile.path);
|
||||||
|
final newAddressListFilePath = backupFileName(addressListFile.path);
|
||||||
|
|
||||||
|
if (cacheFile.existsSync()) {
|
||||||
|
await cacheFile.copy(newCacheFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keysFile.existsSync()) {
|
||||||
|
await keysFile.copy(newKeysFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressListFile.existsSync()) {
|
||||||
|
await addressListFile.copy(newAddressListFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> restoreWalletFiles(String name) async {
|
||||||
|
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
|
||||||
|
final cacheFilePath = '$walletDirPath/$name';
|
||||||
|
final keysFilePath = '$walletDirPath/$name.keys';
|
||||||
|
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||||
|
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||||
|
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||||
|
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||||
|
|
||||||
|
if (backupCacheFile.existsSync()) {
|
||||||
|
await backupCacheFile.copy(cacheFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupKeysFile.existsSync()) {
|
||||||
|
await backupKeysFile.copy(keysFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupAddressListFile.existsSync()) {
|
||||||
|
await backupAddressListFile.copy(addressListFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> backupWalletFilesExists(String name) async {
|
||||||
|
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
|
||||||
|
final cacheFilePath = '$walletDirPath/$name';
|
||||||
|
final keysFilePath = '$walletDirPath/$name.keys';
|
||||||
|
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||||
|
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||||
|
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||||
|
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||||
|
|
||||||
|
return backupCacheFile.existsSync()
|
||||||
|
&& backupKeysFile.existsSync()
|
||||||
|
&& backupAddressListFile.existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeCache(String name) async {
|
||||||
|
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||||
|
final cacheFile = File(path);
|
||||||
|
|
||||||
|
if (cacheFile.existsSync()) {
|
||||||
|
cacheFile.deleteSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> restoreOrResetWalletFiles(String name) async {
|
||||||
|
final backupsExists = await backupWalletFilesExists(name);
|
||||||
|
|
||||||
|
if (backupsExists) {
|
||||||
|
await restoreWalletFiles(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCache(name);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
|
void showAddressAlert(BuildContext context, String title, String content) async {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: title,
|
||||||
|
alertContent: content,
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in new issue