feat: can migrate identity to external address

This commit is contained in:
poka 2024-01-05 19:16:09 +01:00
parent 20590a944c
commit 93c9b377ba
13 changed files with 319 additions and 208 deletions

View File

@ -229,5 +229,9 @@
"gotit": "Got it", "gotit": "Got it",
"moreInfo": "More information", "moreInfo": "More information",
"keepThisPaperSafe": "Keep this sheet safe from prying lizards.\nIt will allow you to restore all your wallets at any time.", "keepThisPaperSafe": "Keep this sheet safe from prying lizards.\nIt will allow you to restore all your wallets at any time.",
"fundsUnavailable": "Insufficient funds" "fundsUnavailable": "Insufficient funds",
"addressNotBelongToMnemonic": "The address you provided does not belong to this recovery sentence",
"enterYourNewMnemonic": "Enter your new recovery sentence",
"enterYourNewAddress": "Enter your new address {}",
"youCanMigrateThisIdentity": "You can migrate this identity !"
} }

View File

@ -230,5 +230,9 @@
"gotit": "Got it", "gotit": "Got it",
"moreInfo": "More information", "moreInfo": "More information",
"keepThisPaperSafe": "Keep this sheet safe from prying lizards.\nIt will allow you to restore all your wallets at any time.", "keepThisPaperSafe": "Keep this sheet safe from prying lizards.\nIt will allow you to restore all your wallets at any time.",
"fundsUnavailable": "Insufficient funds" "fundsUnavailable": "Insufficient funds",
"addressNotBelongToMnemonic": "The address you provided does not belong to this recovery sentence",
"enterYourNewMnemonic": "Enter your new recovery sentence",
"enterYourNewAddress": "Enter your new address {}",
"youCanMigrateThisIdentity": "You can migrate this identity !"
} }

View File

@ -229,5 +229,9 @@
"gotit": "J'ai compris", "gotit": "J'ai compris",
"moreInfo": "Plus d'info", "moreInfo": "Plus d'info",
"keepThisPaperSafe": "Gardez cette feuille précieusement, à labri des lézards indiscrets.\nElle vous permettra de restaurer tous vos portefeuilles à tout moment.", "keepThisPaperSafe": "Gardez cette feuille précieusement, à labri des lézards indiscrets.\nElle vous permettra de restaurer tous vos portefeuilles à tout moment.",
"fundsUnavailable": "Fonds insuffisants" "fundsUnavailable": "Fonds insuffisants",
"addressNotBelongToMnemonic": "L'adresse que vous avez fournit n'appartient pas à cette phrase de restauration",
"enterYourNewMnemonic": "Entrez votre nouvelle phrase de restauration",
"enterYourNewAddress": "Entrez votre nouvelle adresse {}",
"youCanMigrateThisIdentity": "Vous pouvez migrer vers cette identité !"
} }

View File

@ -1,5 +1,5 @@
{ {
"initial_monetary_mass": 50100, "initial_monetary_mass": 60100,
"identities": { "identities": {
"test1": { "test1": {
"index": 0, "index": 0,
@ -49,7 +49,7 @@
}, },
"owner_pubkey": "5LqbvutJtRTHvnforyndwPbkC4Kf5cJtdRQaDcHoMi8S" "owner_pubkey": "5LqbvutJtRTHvnforyndwPbkC4Kf5cJtdRQaDcHoMi8S"
}, },
"testCesium1": { "test5": {
"index": 4, "index": 4,
"balance": 10000, "balance": 10000,
"membership_expire_on": 1705509948, "membership_expire_on": 1705509948,
@ -59,6 +59,18 @@
"test2": 1727758466, "test2": 1727758466,
"test3": 1727758466 "test3": 1727758466
}, },
"owner_pubkey": "6FgzG8NwatTWHo7rM7sPP6P4Q95R2ZQNqYiHCs38RT21"
},
"testCesium1": {
"index": 5,
"balance": 10000,
"membership_expire_on": 1705509948,
"next_cert_issuable_on": 1668347505,
"certs_received": {
"test1": 1727758466,
"test2": 1727758466,
"test3": 1727758466
},
"owner_pubkey": "DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr" "owner_pubkey": "DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr"
} }
} }

View File

@ -3,14 +3,30 @@ import 'package:gecko/models/wallet_data.dart';
class MigrateWalletChecks { class MigrateWalletChecks {
final Map balance; final Map balance;
final IdtyStatus idtyStatus; final IdtyStatus idtyStatus;
final bool isSmith;
final String validationStatus; final String validationStatus;
final bool canValidate; final bool canValidate;
const MigrateWalletChecks( const MigrateWalletChecks({
{required this.balance, required this.balance,
required this.idtyStatus, required this.idtyStatus,
required this.isSmith, required this.validationStatus,
required this.validationStatus, required this.canValidate,
required this.canValidate}); });
const MigrateWalletChecks.defaultValues({
this.balance = const {'transferableBalance': 0},
this.idtyStatus = IdtyStatus.none,
this.validationStatus = '',
this.canValidate = false,
});
@override
String toString() {
return {
'balance': balance,
'idtyStatus': idtyStatus,
'validationStatus': validationStatus,
'canValidate': canValidate,
}.toString();
}
} }

View File

@ -119,6 +119,7 @@ class MyWalletsProvider with ChangeNotifier {
final avatarFolder = Directory('${directory.path}/avatars/'); final avatarFolder = Directory('${directory.path}/avatars/');
if (await avatarFolder.exists()) { if (await avatarFolder.exists()) {
await avatarFolder.delete(recursive: true); await avatarFolder.delete(recursive: true);
await avatarFolder.create();
} }
myWalletProvider.pinCode = ''; myWalletProvider.pinCode = '';

View File

@ -12,7 +12,7 @@ class SearchProvider with ChangeNotifier {
} }
Future<List<G1WalletsList>> searchAddress() async { Future<List<G1WalletsList>> searchAddress() async {
if (isAddress(searchController.text)) { if (await isAddress(searchController.text)) {
G1WalletsList wallet = G1WalletsList(address: searchController.text); G1WalletsList wallet = G1WalletsList(address: searchController.text);
return [wallet]; return [wallet];
} else { } else {

View File

@ -38,7 +38,7 @@ class SubstrateSdk with ChangeNotifier {
int blocNumber = 0; int blocNumber = 0;
bool isLoadingEndpoint = false; bool isLoadingEndpoint = false;
Map transactionStatus = {}; Map transactionStatus = {};
static const int initSs58 = 42; final int initSs58 = 42;
Map<String, int> currencyParameters = {}; Map<String, int> currencyParameters = {};
final csSalt = TextEditingController(); final csSalt = TextEditingController();
final csPassword = TextEditingController(); final csPassword = TextEditingController();
@ -890,7 +890,6 @@ class SubstrateSdk with ChangeNotifier {
Future<MigrateWalletChecks> getBalanceAndIdtyStatus( Future<MigrateWalletChecks> getBalanceAndIdtyStatus(
String fromAddress, String toAddress) async { String fromAddress, String toAddress) async {
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
bool canValidate = false; bool canValidate = false;
String validationStatus = ''; String validationStatus = '';
@ -908,7 +907,9 @@ class SubstrateSdk with ChangeNotifier {
final isSmithData = await isSmith(fromAddress); final isSmithData = await isSmith(fromAddress);
// Check conditions to set 'canValidate' and 'validationStatus' // Check conditions to set 'canValidate' and 'validationStatus'
if (transferableBalance != 0 && !fromHasConsumer) { if (transferableBalance != 0 &&
!fromHasConsumer &&
await isAddress(toAddress)) {
canValidate = true; canValidate = true;
} else if (toIdtyStatus != IdtyStatus.none && } else if (toIdtyStatus != IdtyStatus.none &&
fromIdtyStatus != IdtyStatus.none) { fromIdtyStatus != IdtyStatus.none) {
@ -921,14 +922,9 @@ class SubstrateSdk with ChangeNotifier {
validationStatus = 'thisAccountIsEmpty'.tr(); validationStatus = 'thisAccountIsEmpty'.tr();
} }
if (sub.g1V1NewAddress == '') {
validationStatus = '';
}
return MigrateWalletChecks( return MigrateWalletChecks(
balance: fromBalance, balance: fromBalance,
idtyStatus: toIdtyStatus, idtyStatus: toIdtyStatus,
isSmith: isSmithData,
validationStatus: validationStatus, validationStatus: validationStatus,
canValidate: canValidate, canValidate: canValidate,
); );

View File

@ -6,10 +6,12 @@ import 'package:flutter/material.dart';
import 'package:gecko/globals.dart'; import 'package:gecko/globals.dart';
import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/scale_functions.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/screens/wallet_view.dart'; import 'package:gecko/screens/wallet_view.dart';
import 'package:jdenticon_dart/jdenticon_dart.dart'; import 'package:jdenticon_dart/jdenticon_dart.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:provider/provider.dart';
class WalletsProfilesProvider with ChangeNotifier { class WalletsProfilesProvider with ChangeNotifier {
WalletsProfilesProvider(this.address); WalletsProfilesProvider(this.address);
@ -35,7 +37,7 @@ class WalletsProfilesProvider with ChangeNotifier {
log.e("BarcodeScanner ERR: $e"); log.e("BarcodeScanner ERR: $e");
return 'false'; return 'false';
} }
if (isAddress(barcode.rawContent)) { if (await isAddress(barcode.rawContent)) {
address = barcode.rawContent; address = barcode.rawContent;
Navigator.popUntil( Navigator.popUntil(
context, context,
@ -93,20 +95,26 @@ class WalletsProfilesProvider with ChangeNotifier {
} }
} }
bool isAddress(address) { // bool isAddress(address) {
final RegExp regExp = RegExp( // final RegExp regExp = RegExp(
r'^[a-zA-Z0-9]+$', // r'^[a-zA-Z0-9]+$',
caseSensitive: false, // caseSensitive: false,
multiLine: false, // multiLine: false,
); // );
if (regExp.hasMatch(address) == true && // if (regExp.hasMatch(address) == true &&
address.length > 45 && // address.length > 45 &&
address.length < 52) { // address.length < 52) {
return true; // return true;
} else { // } else {
return false; // return false;
} // }
// }
Future<bool> isAddress(String address) async {
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
return await sub.sdk.api.account.checkAddressFormat(address, sub.initSs58) ??
false;
} }
snackMessage(context, snackMessage(context,

View File

@ -91,9 +91,10 @@ class ImportG1v1 extends StatelessWidget {
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: sub.csSalt, controller: sub.csSalt,
obscureText: !sub.isCesiumIDVisible, obscureText: !sub.isCesiumIDVisible,
style: scaledTextStyle(fontSize: 16), style: scaledTextStyle(fontSize: 14),
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'enterCesiumId'.tr(), hintText: 'enterCesiumId'.tr(),
hintStyle: scaledTextStyle(fontSize: 14),
suffixIcon: IconButton( suffixIcon: IconButton(
key: keyCesiumIdVisible, key: keyCesiumIdVisible,
icon: Icon( icon: Icon(
@ -132,9 +133,10 @@ class ImportG1v1 extends StatelessWidget {
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: sub.csPassword, controller: sub.csPassword,
obscureText: !sub.isCesiumIDVisible, obscureText: !sub.isCesiumIDVisible,
style: scaledTextStyle(fontSize: 16), style: scaledTextStyle(fontSize: 14),
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'enterCesiumPassword'.tr(), hintText: 'enterCesiumPassword'.tr(),
hintStyle: scaledTextStyle(fontSize: 14),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
sub.isCesiumIDVisible sub.isCesiumIDVisible
@ -167,7 +169,7 @@ class ImportG1v1 extends StatelessWidget {
child: Text( child: Text(
'v1: ${getShortPubkey(sub.g1V1OldPubkey)}', 'v1: ${getShortPubkey(sub.g1V1OldPubkey)}',
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 17, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontFamily: 'Monospace'), fontFamily: 'Monospace'),
), ),
@ -183,7 +185,7 @@ class ImportG1v1 extends StatelessWidget {
child: Text( child: Text(
'v2: ${getShortPubkey(sub.g1V1NewAddress)}', 'v2: ${getShortPubkey(sub.g1V1NewAddress)}',
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 17, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontFamily: 'Monospace'), fontFamily: 'Monospace'),
), ),
@ -212,7 +214,7 @@ class ImportG1v1 extends StatelessWidget {
ScaledSizedBox(height: 20), ScaledSizedBox(height: 20),
Text( Text(
'migrateToThisWallet'.tr(), 'migrateToThisWallet'.tr(),
style: scaledTextStyle(fontSize: 17), style: scaledTextStyle(fontSize: 16),
), ),
ScaledSizedBox(height: 5), ScaledSizedBox(height: 5),
DropdownButtonHideUnderline( DropdownButtonHideUnderline(
@ -226,7 +228,7 @@ class ImportG1v1 extends StatelessWidget {
value: wallet, value: wallet,
child: Text( child: Text(
wallet.name!, wallet.name!,
style: scaledTextStyle(fontSize: 17), style: scaledTextStyle(fontSize: 16),
), ),
); );
}).toList(), }).toList(),
@ -292,7 +294,7 @@ class ImportG1v1 extends StatelessWidget {
child: Text( child: Text(
'migrateAccount'.tr(), 'migrateAccount'.tr(),
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 20, fontWeight: FontWeight.w600), fontSize: 19, fontWeight: FontWeight.w600),
), ),
), ),
), ),
@ -301,7 +303,7 @@ class ImportG1v1 extends StatelessWidget {
statusData.validationStatus, statusData.validationStatus,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 14, color: Colors.grey[600]), fontSize: 12, color: Colors.grey[600]),
) )
]); ]);
}); });

View File

@ -9,12 +9,15 @@ import 'package:gecko/models/scale_functions.dart';
import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart'; import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart'; import 'package:gecko/providers/wallet_options.dart';
import 'package:gecko/providers/wallets_profiles.dart';
import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
import 'package:gecko/screens/transaction_in_progress.dart'; import 'package:gecko/screens/transaction_in_progress.dart';
import 'package:gecko/widgets/commons/top_appbar.dart'; import 'package:gecko/widgets/commons/top_appbar.dart';
import 'package:polkawallet_sdk/api/apiKeyring.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class MigrateIdentityScreen extends StatelessWidget { class MigrateIdentityScreen extends StatelessWidget {
@ -22,190 +25,251 @@ class MigrateIdentityScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// final _homeProvider = Provider.of<HomeProvider>(context);
final walletOptions = final walletOptions =
Provider.of<WalletOptionsProvider>(context, listen: false); Provider.of<WalletOptionsProvider>(context, listen: false);
final myWalletProvider = final myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false); Provider.of<MyWalletsProvider>(context, listen: false);
final generatedWalletsProvider =
Provider.of<GenerateWalletsProvider>(context, listen: false);
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false); final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
final sub = Provider.of<SubstrateSdk>(context, listen: false);
final fromAddress = walletOptions.address.text; final fromAddress = walletOptions.address.text;
final defaultWallet = myWalletProvider.getDefaultWallet(); final newMnemonicSentence = TextEditingController();
final walletsList = myWalletProvider.listWallets.toList(); final newWalletAddress = TextEditingController();
late WalletData selectedWallet;
if (fromAddress == defaultWallet.address) {
selectedWallet =
walletsList[fromAddress == walletsList[0].address ? 1 : 0];
} else {
selectedWallet = defaultWallet;
}
final mdStyle = MarkdownStyleSheet( final mdStyle = MarkdownStyleSheet(
p: scaledTextStyle(fontSize: 17, color: Colors.black, letterSpacing: 0.3), p: scaledTextStyle(fontSize: 16, color: Colors.black, letterSpacing: 0.3),
textAlign: WrapAlignment.center, textAlign: WrapAlignment.center,
); );
final bool isUdUnit = configBox.get('isUdUnit') ?? false;
final unit = isUdUnit ? 'ud'.tr(args: ['']) : currencyName;
if (walletsList.length < 2) { var statusData = const MigrateWalletChecks.defaultValues();
return Column( var mnemonicIsValid = false;
children: [ int? matchDerivationNbr;
ScaledSizedBox(height: 80), String matchInfo = '';
Row(
mainAxisAlignment: MainAxisAlignment.center, Future scanDerivations() async {
children: [ if (!await isAddress(newWalletAddress.text) ||
Text( !await sub.isMnemonicValid(newMnemonicSentence.text) ||
'Vous devez avoir au moins 2 portefeuilles\npour effecter cette opération', !statusData.canValidate) {
style: scaledTextStyle(fontSize: 17), mnemonicIsValid = false;
) matchInfo = '';
], walletOptions.reload();
) return;
], }
log.d('Scan derivations to find a match');
//Scan root wallet
final addressData = await sub.sdk.api.keyring.addressFromMnemonic(
sub.currencyParameters['ss58']!,
cryptoType: CryptoType.sr25519,
mnemonic: newMnemonicSentence.text,
); );
if (addressData.address == newWalletAddress.text) {
matchDerivationNbr = -1;
mnemonicIsValid = true;
walletOptions.reload();
return;
}
//Scan derivations
for (int derivationNbr in [
for (var i = 0; i < generatedWalletsProvider.numberScan; i += 1) i
]) {
final addressData = await sub.sdk.api.keyring.addressFromMnemonic(
sub.currencyParameters['ss58']!,
cryptoType: CryptoType.sr25519,
mnemonic: newMnemonicSentence.text,
derivePath: '//$derivationNbr');
if (addressData.address == newWalletAddress.text) {
matchDerivationNbr = derivationNbr;
mnemonicIsValid = true;
matchInfo = "youCanMigrateThisIdentity".tr();
break;
} else {
mnemonicIsValid = false;
}
}
if (!mnemonicIsValid) {
matchInfo = "addressNotBelongToMnemonic".tr();
}
walletOptions.reload();
} }
return Scaffold( return Scaffold(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
appBar: GeckoAppBar('migrateIdentity'.tr()), appBar: GeckoAppBar('migrateIdentity'.tr()),
body: SafeArea( body: SafeArea(
child: Consumer<SubstrateSdk>(builder: (context, sub, _) { child: Column(children: <Widget>[
return FutureBuilder( const Row(children: []),
future: sub.getBalanceAndIdtyStatus( ScaledSizedBox(height: 18),
fromAddress, selectedWallet.address), ScaledSizedBox(
builder: (BuildContext context, width: 320,
AsyncSnapshot<MigrateWalletChecks> status) { child: MarkdownBody(
if (status.data == null) { data: 'areYouSureMigrateIdentity'.tr(args: [
return Column(children: [ duniterIndexer.walletNameIndexer[fromAddress] ?? '???',
ScaledSizedBox(height: 80), '${walletOptions.balanceCache[fromAddress]} $unit'
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ ]),
ScaledSizedBox( styleSheet: mdStyle),
height: scaleSize(32), ),
width: scaleSize(32), ScaledSizedBox(height: 55),
child: CircularProgressIndicator( Text('migrateToThisWallet'.tr(),
color: orangeC, style: scaledTextStyle(fontSize: 16)),
strokeWidth: scaleSize(4), ScaledSizedBox(height: 5),
), ScaledSizedBox(
), width: 320,
]), child: TextField(
]); controller: newMnemonicSentence,
autofocus: true,
minLines: 2,
maxLines: 2,
style: scaledTextStyle(fontSize: 14),
decoration: InputDecoration(
icon: Image.asset(
'assets/onBoarding/phrase_de_restauration_flou.png',
width: scaleSize(30),
),
hintText: 'enterYourNewMnemonic'.tr(),
hintStyle: scaledTextStyle(fontSize: 14),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: orangeC),
),
),
onChanged: (newMnemonic) async {
await scanDerivations();
},
),
),
ScaledSizedBox(height: 5),
ScaledSizedBox(
width: 320,
child: TextField(
controller: newWalletAddress,
style: scaledTextStyle(fontSize: 14),
decoration: InputDecoration(
icon: Image.asset(
'assets/walletOptions/key.png',
height: scaleSize(30),
),
hintText: 'enterYourNewAddress'.tr(args: [currencyName]),
hintStyle: scaledTextStyle(fontSize: 14),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: orangeC),
),
),
onChanged: (newAddress) async {
if (await isAddress(newAddress)) {
statusData = await sub.getBalanceAndIdtyStatus(
fromAddress, newAddress);
await scanDerivations();
} else {
statusData = const MigrateWalletChecks.defaultValues();
matchInfo = '';
walletOptions.reload();
} }
},
),
),
const Spacer(flex: 2),
Consumer<WalletOptionsProvider>(builder: (context, _, __) {
return ScaledSizedBox(
width: 320,
height: 55,
child: ElevatedButton(
key: keyConfirm,
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
elevation: 4,
backgroundColor: orangeC,
),
onPressed: statusData.canValidate && mnemonicIsValid
? () async {
WalletData? defaultWallet =
myWalletProvider.getDefaultWallet();
final statusData = status.data!; String? pin;
final walletsList = myWalletProvider.listWallets.toList(); if (myWalletProvider.pinCode == '') {
pin = await Navigator.push(
context,
MaterialPageRoute(
builder: (homeContext) {
return UnlockingWallet(wallet: defaultWallet);
},
),
);
}
if (myWalletProvider.pinCode == '') return;
walletsList await sub.importAccount(
.removeWhere((element) => element.address == fromAddress); mnemonic: newMnemonicSentence.text,
derivePath: matchDerivationNbr == -1
? ''
: "//$matchDerivationNbr",
password: 'password');
final bool isUdUnit = configBox.get('isUdUnit') ?? false; final transactionId = await sub.migrateIdentity(
final unit = isUdUnit ? 'ud'.tr(args: ['']) : currencyName; fromAddress: fromAddress,
destAddress: newWalletAddress.text,
fromPassword: pin ?? myWalletProvider.pinCode,
destPassword: 'password',
withBalance: true,
fromBalance: statusData.balance);
return Column(children: <Widget>[ sub.deleteAccounts([newWalletAddress.text]);
const Row(children: []), Navigator.pop(context);
ScaledSizedBox(height: 18), Navigator.push(
ScaledSizedBox( context,
width: 320, MaterialPageRoute(builder: (context) {
child: MarkdownBody( return TransactionInProgress(
data: 'areYouSureMigrateIdentity'.tr(args: [ transactionId: transactionId,
duniterIndexer.walletNameIndexer[fromAddress] ?? transType: 'identityMigration',
'???', fromAddress: getShortPubkey(fromAddress),
'${statusData.balance['transferableBalance']} $unit' toAddress:
]), getShortPubkey(newWalletAddress.text));
styleSheet: mdStyle), }),
),
ScaledSizedBox(height: 55),
Text('migrateToThisWallet'.tr(),
style: scaledTextStyle(fontSize: 17)),
ScaledSizedBox(height: 5),
DropdownButtonHideUnderline(
key: keySelectWallet,
child: DropdownButton(
value: selectedWallet,
icon: const Icon(Icons.keyboard_arrow_down),
items: walletsList.map((wallet) {
return DropdownMenuItem(
key: keySelectThisWallet(wallet.address),
value: wallet,
child: Text(
wallet.name!,
style: scaledTextStyle(fontSize: 17),
),
); );
}).toList(), }
onChanged: (WalletData? newSelectedWallet) { : null,
selectedWallet = newSelectedWallet!; child: Text(
sub.reload(); 'migrateIdentity'.tr(),
}, style: scaledTextStyle(
), fontSize: 19,
), fontWeight: FontWeight.w600,
const Spacer(flex: 2), color: Colors.white),
ScaledSizedBox( ),
width: 320, ),
height: 55, );
child: ElevatedButton( }),
key: keyConfirm, Consumer<WalletOptionsProvider>(builder: (context, _, __) {
style: ElevatedButton.styleFrom( return ScaledSizedBox(
foregroundColor: Colors.white, width: 320,
elevation: 4, child: Column(
backgroundColor: orangeC, children: [
),
onPressed: statusData.canValidate
? () async {
WalletData? defaultWallet =
myWalletProvider.getDefaultWallet();
String? pin;
if (myWalletProvider.pinCode == '') {
pin = await Navigator.push(
context,
MaterialPageRoute(
builder: (homeContext) {
return UnlockingWallet(
wallet: defaultWallet);
},
),
);
}
if (myWalletProvider.pinCode == '') return;
final transactionId = await sub.migrateIdentity(
fromAddress: fromAddress,
destAddress: selectedWallet.address,
fromPassword: pin ?? myWalletProvider.pinCode,
destPassword: pin ?? myWalletProvider.pinCode,
withBalance: true,
fromBalance: statusData.balance);
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return TransactionInProgress(
transactionId: transactionId,
transType: 'identityMigration',
fromAddress: getShortPubkey(fromAddress),
toAddress: getShortPubkey(
selectedWallet.address));
}),
);
}
: null,
child: Text(
'migrateIdentity'.tr(),
style: scaledTextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white),
),
),
),
ScaledSizedBox(height: 10), ScaledSizedBox(height: 10),
Text( Text(
statusData.validationStatus, statusData.validationStatus,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: style:
scaledTextStyle(fontSize: 15, color: Colors.grey[600]), scaledTextStyle(fontSize: 12, color: Colors.grey[600]),
), ),
const Spacer(), ScaledSizedBox(height: 5),
]); Text(
}); matchInfo,
}), textAlign: TextAlign.center,
style:
scaledTextStyle(fontSize: 12, color: Colors.grey[600]),
),
],
),
);
}),
const Spacer(),
]),
), ),
); );
} }

View File

@ -32,7 +32,7 @@ class _SearchScreenState extends State<SearchScreen> {
final searchProvider = Provider.of<SearchProvider>(context, listen: false); final searchProvider = Provider.of<SearchProvider>(context, listen: false);
final clipboard = await Clipboard.getData('text/plain'); final clipboard = await Clipboard.getData('text/plain');
pastedAddress = clipboard?.text ?? ''; pastedAddress = clipboard?.text ?? '';
canPasteAddress = isAddress(pastedAddress); canPasteAddress = await isAddress(pastedAddress);
searchProvider.reload(); searchProvider.reload();
} }

View File

@ -27,7 +27,7 @@ class SettingsScreen extends StatelessWidget {
ScaledSizedBox(height: 30), ScaledSizedBox(height: 30),
Text( Text(
'networkSettings'.tr(), 'networkSettings'.tr(),
style: scaledTextStyle(color: Colors.grey[500]!, fontSize: 20), style: scaledTextStyle(color: Colors.grey[500]!, fontSize: 19),
), ),
ScaledSizedBox(height: 20), ScaledSizedBox(height: 20),
duniterEndpointSelection(context), duniterEndpointSelection(context),
@ -36,7 +36,7 @@ class SettingsScreen extends StatelessWidget {
ScaledSizedBox(height: 35), ScaledSizedBox(height: 35),
Text( Text(
'displaySettings'.tr(), 'displaySettings'.tr(),
style: scaledTextStyle(color: Colors.grey[500]!, fontSize: 20), style: scaledTextStyle(color: Colors.grey[500]!, fontSize: 19),
), ),
ScaledSizedBox(height: 20), ScaledSizedBox(height: 20),
chooseCurrencyUnit(context), chooseCurrencyUnit(context),
@ -56,7 +56,7 @@ class SettingsScreen extends StatelessWidget {
child: Text( child: Text(
'forgetAllMyChests'.tr(), 'forgetAllMyChests'.tr(),
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 18, fontSize: 17,
color: const Color(0xffD80000), color: const Color(0xffD80000),
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@ -83,14 +83,14 @@ class SettingsScreen extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
ScaledSizedBox(width: 12), ScaledSizedBox(width: 12),
Text('showUdAmounts'.tr(), style: scaledTextStyle(fontSize: 16)), Text('showUdAmounts'.tr(), style: scaledTextStyle(fontSize: 15)),
const Spacer(), const Spacer(),
Consumer<HomeProvider>(builder: (context, homeProvider, _) { Consumer<HomeProvider>(builder: (context, homeProvider, _) {
final bool isUdUnit = configBox.get('isUdUnit') ?? false; final bool isUdUnit = configBox.get('isUdUnit') ?? false;
return Icon( return Icon(
isUdUnit ? Icons.check_box : Icons.check_box_outline_blank, isUdUnit ? Icons.check_box : Icons.check_box_outline_blank,
color: orangeC, color: orangeC,
size: scaleSize(30), size: scaleSize(27),
); );
}), }),
ScaledSizedBox(width: 30), ScaledSizedBox(width: 30),
@ -141,7 +141,7 @@ class SettingsScreen extends StatelessWidget {
width: 55, width: 55,
child: Text( child: Text(
'currencyNode'.tr(), 'currencyNode'.tr(),
style: scaledTextStyle(fontSize: 16), style: scaledTextStyle(fontSize: 15),
), ),
), ),
const Spacer(), const Spacer(),
@ -161,7 +161,7 @@ class SettingsScreen extends StatelessWidget {
return DropdownButtonHideUnderline( return DropdownButtonHideUnderline(
key: keySelectDuniterNodeDropDown, key: keySelectDuniterNodeDropDown,
child: DropdownButton( child: DropdownButton(
style: scaledTextStyle(fontSize: 16, color: Colors.black), style: scaledTextStyle(fontSize: 15, color: Colors.black),
value: selectedDuniterEndpoint, value: selectedDuniterEndpoint,
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
items: duniterBootstrapNodes items: duniterBootstrapNodes
@ -229,7 +229,7 @@ class SettingsScreen extends StatelessWidget {
key: keyCustomDuniterEndpoint, key: keyCustomDuniterEndpoint,
controller: endpointController, controller: endpointController,
autocorrect: false, autocorrect: false,
style: scaledTextStyle(fontSize: 16), style: scaledTextStyle(fontSize: 15),
), ),
), ),
); );
@ -293,7 +293,7 @@ class SettingsScreen extends StatelessWidget {
ScaledSizedBox(width: 5), ScaledSizedBox(width: 5),
ScaledSizedBox( ScaledSizedBox(
width: 55, width: 55,
child: Text('Indexer', style: scaledTextStyle(fontSize: 16)), child: Text('Indexer', style: scaledTextStyle(fontSize: 15)),
), ),
const Spacer(), const Spacer(),
Icon(indexerEndpoint != '' ? Icons.check : Icons.close), Icon(indexerEndpoint != '' ? Icons.check : Icons.close),
@ -303,7 +303,7 @@ class SettingsScreen extends StatelessWidget {
child: Consumer<SettingsProvider>(builder: (context, set, _) { child: Consumer<SettingsProvider>(builder: (context, set, _) {
return DropdownButtonHideUnderline( return DropdownButtonHideUnderline(
child: DropdownButton( child: DropdownButton(
style: scaledTextStyle(fontSize: 16, color: Colors.black), style: scaledTextStyle(fontSize: 15, color: Colors.black),
value: selectedIndexerEndpoint, value: selectedIndexerEndpoint,
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
items: items:
@ -366,7 +366,7 @@ class SettingsScreen extends StatelessWidget {
child: TextField( child: TextField(
controller: indexerEndpointController, controller: indexerEndpointController,
autocorrect: false, autocorrect: false,
style: scaledTextStyle(fontSize: 16), style: scaledTextStyle(fontSize: 15),
), ),
), ),
); );