Merge branch 'dev'
This commit is contained in:
commit
6cb085851f
|
@ -165,6 +165,7 @@
|
||||||
"choiceOfSourceWallet": "Choose a source wallet",
|
"choiceOfSourceWallet": "Choose a source wallet",
|
||||||
"extrinsicInProgress": "{} in progress",
|
"extrinsicInProgress": "{} in progress",
|
||||||
"extrinsicValidated": "{} validated !",
|
"extrinsicValidated": "{} validated !",
|
||||||
|
"extrinsicFinalized": "{} finalized !",
|
||||||
"fromMinus": "from",
|
"fromMinus": "from",
|
||||||
"toMinus": "to",
|
"toMinus": "to",
|
||||||
"deleteThisWallet": "Delete this wallet",
|
"deleteThisWallet": "Delete this wallet",
|
||||||
|
@ -229,5 +230,10 @@
|
||||||
"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 !",
|
||||||
|
"identityMigrated": "Identity migrated"
|
||||||
}
|
}
|
|
@ -166,6 +166,7 @@
|
||||||
"choiceOfSourceWallet": "Elige un monedero de origen",
|
"choiceOfSourceWallet": "Elige un monedero de origen",
|
||||||
"extrinsicInProgress": "{} en progreso",
|
"extrinsicInProgress": "{} en progreso",
|
||||||
"extrinsicValidated": "¡ {} validado !",
|
"extrinsicValidated": "¡ {} validado !",
|
||||||
|
"extrinsicFinalized": "{} finalized !",
|
||||||
"fromMinus": "de",
|
"fromMinus": "de",
|
||||||
"toMinus": "a",
|
"toMinus": "a",
|
||||||
"deleteThisWallet": "Borrar este monedero",
|
"deleteThisWallet": "Borrar este monedero",
|
||||||
|
@ -230,5 +231,10 @@
|
||||||
"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 !",
|
||||||
|
"identityMigrated": "Identity migrated"
|
||||||
}
|
}
|
|
@ -165,6 +165,7 @@
|
||||||
"choiceOfSourceWallet": "Choix du portefeuille source",
|
"choiceOfSourceWallet": "Choix du portefeuille source",
|
||||||
"extrinsicInProgress": "{} en cours",
|
"extrinsicInProgress": "{} en cours",
|
||||||
"extrinsicValidated": "{} validée !",
|
"extrinsicValidated": "{} validée !",
|
||||||
|
"extrinsicFinalized": "{} finalisé !",
|
||||||
"fromMinus": "de",
|
"fromMinus": "de",
|
||||||
"toMinus": "vers",
|
"toMinus": "vers",
|
||||||
"deleteThisWallet": "Supprimer ce portefeuille",
|
"deleteThisWallet": "Supprimer ce portefeuille",
|
||||||
|
@ -229,5 +230,10 @@
|
||||||
"gotit": "J'ai compris",
|
"gotit": "J'ai compris",
|
||||||
"moreInfo": "Plus d'info",
|
"moreInfo": "Plus d'info",
|
||||||
"keepThisPaperSafe": "Gardez cette feuille précieusement, à l’abri des lézards indiscrets.\nElle vous permettra de restaurer tous vos portefeuilles à tout moment.",
|
"keepThisPaperSafe": "Gardez cette feuille précieusement, à l’abri 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é !",
|
||||||
|
"identityMigrated": "Identité migré"
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
[
|
[
|
||||||
"https://hasura.gdev.coinduf.eu"
|
"gdev-indexer.p2p.legal",
|
||||||
|
"gdev-hasura.cgeek.fr",
|
||||||
|
"hasura-gdev.pini.fr"
|
||||||
]
|
]
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ const cesiumPod = "https://g1.data.le-sou.org";
|
||||||
// String cesiumPod = "https://g1.data.presles.fr";
|
// String cesiumPod = "https://g1.data.presles.fr";
|
||||||
// String cesiumPod = "https://g1.data.e-is.pro";
|
// String cesiumPod = "https://g1.data.e-is.pro";
|
||||||
|
|
||||||
const datapodEndpoint = 'https://gdev-datapod.p2p.legal';
|
const datapodEndpoint = 'gdev-datapod.p2p.legal';
|
||||||
// const v2sDatapod = 'http://10.0.2.2:8080';
|
// const v2sDatapod = 'http://10.0.2.2:8080';
|
||||||
|
|
||||||
// Contexts
|
// Contexts
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ query ($name: String!) {
|
||||||
}
|
}
|
||||||
''';
|
''';
|
||||||
|
|
||||||
const String getHistoryByAddressQ = r'''
|
const String getHistoryByAddressRelayQ = r'''
|
||||||
query ($address: String!, $number: Int!, $cursor: String) {
|
query ($address: String!, $number: Int!, $cursor: String) {
|
||||||
transaction_connection(where:
|
transaction_connection(where:
|
||||||
{_or: [
|
{_or: [
|
||||||
|
@ -56,9 +56,36 @@ query ($address: String!, $number: Int!, $cursor: String) {
|
||||||
}
|
}
|
||||||
''';
|
''';
|
||||||
|
|
||||||
|
const String getHistoryByAddressQ = r'''
|
||||||
|
query ($address: String!, $number: Int!, $offset: Int!) {
|
||||||
|
transaction_aggregate(where: {_or: [{issuer_pubkey: {_eq: $address}}, {receiver_pubkey: {_eq: $address}}]}) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transaction(where: {_or: [{issuer_pubkey: {_eq: $address}}, {receiver_pubkey: {_eq: $address}}]}, order_by: {created_at: desc}, limit: $number, offset: $offset) {
|
||||||
|
amount
|
||||||
|
comment
|
||||||
|
created_at
|
||||||
|
issuer {
|
||||||
|
pubkey
|
||||||
|
identity {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
receiver {
|
||||||
|
pubkey
|
||||||
|
identity {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
||||||
const String getCertsReceived = r'''
|
const String getCertsReceived = r'''
|
||||||
query ($address: String!) {
|
query ($address: String!) {
|
||||||
certification(where: {receiver: {pubkey: {_eq: $address}}}) {
|
certification(where: {receiver: {pubkey: {_eq: $address}}}, order_by: {created_at: desc}) {
|
||||||
issuer {
|
issuer {
|
||||||
pubkey
|
pubkey
|
||||||
name
|
name
|
||||||
|
@ -70,7 +97,7 @@ query ($address: String!) {
|
||||||
|
|
||||||
const String getCertsSent = r'''
|
const String getCertsSent = r'''
|
||||||
query ($address: String!) {
|
query ($address: String!) {
|
||||||
certification(where: {issuer: {pubkey: {_eq: $address}}}) {
|
certification(where: {issuer: {pubkey: {_eq: $address}}}, order_by: {created_at: desc}) {
|
||||||
receiver {
|
receiver {
|
||||||
pubkey
|
pubkey
|
||||||
name
|
name
|
||||||
|
@ -96,3 +123,15 @@ query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
''';
|
''';
|
||||||
|
|
||||||
|
const String subscribeHistoryIssuedQ = r'''
|
||||||
|
subscription ($address: String!) {
|
||||||
|
account_by_pk(pubkey: $address) {
|
||||||
|
transactions_issued(limit: 1, order_by: {created_at: desc}) {
|
||||||
|
receiver_pubkey
|
||||||
|
amount
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:gecko/widgets/transaction_status.dart';
|
||||||
|
|
||||||
|
class TransactionContent {
|
||||||
|
final String transactionId;
|
||||||
|
TransactionStatus status;
|
||||||
|
final String from;
|
||||||
|
final String to;
|
||||||
|
final double amount;
|
||||||
|
String? error;
|
||||||
|
|
||||||
|
TransactionContent({
|
||||||
|
required this.transactionId,
|
||||||
|
required this.status,
|
||||||
|
required this.from,
|
||||||
|
required this.to,
|
||||||
|
required this.amount,
|
||||||
|
this.error,
|
||||||
|
});
|
||||||
|
}
|
|
@ -70,7 +70,7 @@ class WalletData extends HiveObject {
|
||||||
|
|
||||||
// creates the ':'-separated string from the WalletData
|
// creates the ':'-separated string from the WalletData
|
||||||
String inLine() {
|
String inLine() {
|
||||||
return "$chest:$number:$name:$derivation:$imageDefaultPath";
|
return "$chest:$number:$name:$derivation:$imageDefaultPath:$imageCustomPath:$identityStatus";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasIdentity() {
|
bool hasIdentity() {
|
||||||
|
@ -112,7 +112,7 @@ class WalletData extends HiveObject {
|
||||||
final datapod = Provider.of<V2sDatapodProvider>(homeContext, listen: false);
|
final datapod = Provider.of<V2sDatapodProvider>(homeContext, listen: false);
|
||||||
final avatarUuid = const Uuid().v4();
|
final avatarUuid = const Uuid().v4();
|
||||||
|
|
||||||
await datapod.getAvatar(address, saveOnDisk: true, uuid: avatarUuid);
|
await datapod.getRemoteAvatar(address, uuid: avatarUuid);
|
||||||
|
|
||||||
final avatarPath = '${avatarsDirectory.path}/$address-$avatarUuid';
|
final avatarPath = '${avatarsDirectory.path}/$address-$avatarUuid';
|
||||||
if (!await File(avatarPath).exists()) return;
|
if (!await File(avatarPath).exists()) return;
|
||||||
|
|
|
@ -11,11 +11,12 @@ import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
|
||||||
class DuniterIndexer with ChangeNotifier {
|
class DuniterIndexer with ChangeNotifier {
|
||||||
Map<String, String?> walletNameIndexer = {};
|
Map<String, String?> walletNameIndexer = {};
|
||||||
String? fetchMoreCursor;
|
|
||||||
Map? pageInfo;
|
|
||||||
List? transBC;
|
List? transBC;
|
||||||
List listIndexerEndpoints = [];
|
List listIndexerEndpoints = [];
|
||||||
bool isLoadingIndexer = false;
|
bool isLoadingIndexer = false;
|
||||||
|
bool hasNextPage = false;
|
||||||
|
Future<QueryResult<Object?>?> Function()? refetch;
|
||||||
|
late GraphQLClient indexerClient;
|
||||||
|
|
||||||
void reload() {
|
void reload() {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -27,10 +28,11 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
client.connectionTimeout = const Duration(milliseconds: 4000);
|
client.connectionTimeout = const Duration(milliseconds: 4000);
|
||||||
try {
|
try {
|
||||||
final request = await client.postUrl(Uri.parse('$endpoint/v1/graphql'));
|
final request =
|
||||||
|
await client.postUrl(Uri.parse('https://$endpoint/v1/graphql'));
|
||||||
final response = await request.close();
|
final response = await request.close();
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
log.w('INDEXER IS OFFLINE');
|
log.w('Indexer $endpoint is offline');
|
||||||
indexerEndpoint = '';
|
indexerEndpoint = '';
|
||||||
isLoadingIndexer = false;
|
isLoadingIndexer = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -46,7 +48,7 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.w('INDEXER IS OFFLINE');
|
log.w('Indexer $endpoint is offline');
|
||||||
indexerEndpoint = '';
|
indexerEndpoint = '';
|
||||||
isLoadingIndexer = false;
|
isLoadingIndexer = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -96,7 +98,7 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final endpointPath = '${listIndexerEndpoints[i]}/v1/graphql';
|
final endpointPath = 'https://${listIndexerEndpoints[i]}/v1/graphql';
|
||||||
|
|
||||||
final request = await client.postUrl(Uri.parse(endpointPath));
|
final request = await client.postUrl(Uri.parse(endpointPath));
|
||||||
final response = await request.close();
|
final response = await request.close();
|
||||||
|
@ -128,14 +130,13 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
return indexerEndpoint;
|
return indexerEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
List parseHistory(blockchainTX, pubkey) {
|
List parseHistory(List blockchainTX, String address) {
|
||||||
List transBC = [];
|
List transBC = [];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (final trans in blockchainTX) {
|
for (final transaction in blockchainTX) {
|
||||||
final transaction = trans['node'];
|
|
||||||
final direction =
|
final direction =
|
||||||
transaction['issuer_pubkey'] != pubkey ? 'RECEIVED' : 'SENT';
|
transaction['issuer']['pubkey'] != address ? 'RECEIVED' : 'SENT';
|
||||||
|
|
||||||
transBC.add(i);
|
transBC.add(i);
|
||||||
transBC[i] = [];
|
transBC[i] = [];
|
||||||
|
@ -143,10 +144,10 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
final amountBrut = transaction['amount'];
|
final amountBrut = transaction['amount'];
|
||||||
final amount = removeDecimalZero(amountBrut / 100);
|
final amount = removeDecimalZero(amountBrut / 100);
|
||||||
if (direction == "RECEIVED") {
|
if (direction == "RECEIVED") {
|
||||||
transBC[i].add(transaction['issuer_pubkey']);
|
transBC[i].add(transaction['issuer']['pubkey']);
|
||||||
transBC[i].add(transaction['issuer']['identity']?['name'] ?? '');
|
transBC[i].add(transaction['issuer']['identity']?['name'] ?? '');
|
||||||
} else if (direction == "SENT") {
|
} else if (direction == "SENT") {
|
||||||
transBC[i].add(transaction['receiver_pubkey']);
|
transBC[i].add(transaction['receiver']['pubkey']);
|
||||||
transBC[i].add(transaction['receiver']['identity']?['name'] ?? '');
|
transBC[i].add(transaction['receiver']['identity']?['name'] ?? '');
|
||||||
}
|
}
|
||||||
transBC[i].add(amount);
|
transBC[i].add(amount);
|
||||||
|
@ -157,38 +158,35 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
return transBC;
|
return transBC;
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchMoreOptions? mergeQueryResult(result, opts, pubkey, nRepositories) {
|
FetchMoreOptions? mergeQueryResult(
|
||||||
final List<dynamic>? blockchainTX =
|
{required List transactions,
|
||||||
(result.data['transaction_connection']['edges'] as List<dynamic>?);
|
required FetchMoreOptions? opts,
|
||||||
|
required String address,
|
||||||
|
required int nRepositories,
|
||||||
|
required int offset}) {
|
||||||
|
// pageInfo = result.data!['transaction_connection']['pageInfo'];
|
||||||
|
// fetchMoreCursor = pageInfo!['endCursor'];
|
||||||
|
// final hasNextPage = pageInfo!['hasNextPage'];
|
||||||
|
// final hasPreviousPage = pageInfo!['hasPreviousPage'];
|
||||||
|
// log.d('endCursor: $fetchMoreCursor $hasNextPage $hasPreviousPage');
|
||||||
|
|
||||||
pageInfo = result.data['transaction_connection']['pageInfo'];
|
// if (fetchMoreCursor != null) {
|
||||||
fetchMoreCursor = pageInfo!['endCursor'];
|
opts = FetchMoreOptions(
|
||||||
final hasNextPage = pageInfo!['hasNextPage'];
|
variables: {'offset': offset, 'number': nRepositories},
|
||||||
final hasPreviousPage = pageInfo!['hasPreviousPage'];
|
updateQuery: (previousResultData, fetchMoreResultData) {
|
||||||
log.d('endCursor: $fetchMoreCursor $hasNextPage $hasPreviousPage');
|
final List<dynamic> repos = [
|
||||||
|
...previousResultData!['transaction'] as List<dynamic>,
|
||||||
|
...fetchMoreResultData!['transaction'] as List<dynamic>
|
||||||
|
];
|
||||||
|
|
||||||
if (fetchMoreCursor != null) {
|
fetchMoreResultData['transaction'] = repos;
|
||||||
opts = FetchMoreOptions(
|
return fetchMoreResultData;
|
||||||
variables: {'cursor': fetchMoreCursor, 'number': nRepositories},
|
},
|
||||||
updateQuery: (previousResultData, fetchMoreResultData) {
|
);
|
||||||
final List<dynamic> repos = [
|
transBC = parseHistory(transactions, address);
|
||||||
...previousResultData!['transaction_connection']['edges']
|
// } else {
|
||||||
as List<dynamic>,
|
// log.d("Activity start of $address");
|
||||||
...fetchMoreResultData!['transaction_connection']['edges']
|
// }
|
||||||
as List<dynamic>
|
|
||||||
];
|
|
||||||
|
|
||||||
fetchMoreResultData['transaction_connection']['edges'] = repos;
|
|
||||||
return fetchMoreResultData;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fetchMoreCursor != null) {
|
|
||||||
transBC = parseHistory(blockchainTX, pubkey);
|
|
||||||
} else {
|
|
||||||
log.d("Activity start of $pubkey");
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
@ -197,113 +195,119 @@ class DuniterIndexer with ChangeNotifier {
|
||||||
String result = n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2);
|
String result = n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2);
|
||||||
return double.parse(result);
|
return double.parse(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//// Manuals queries
|
//// Manuals queries
|
||||||
|
|
||||||
Future<bool> isIdtyExist(String name) async {
|
Future<bool> isIdtyExist(String name) async {
|
||||||
final variables = <String, dynamic>{
|
final variables = <String, dynamic>{
|
||||||
'name': name,
|
'name': name,
|
||||||
};
|
};
|
||||||
final result = await _execQuery(isIdtyExistQ, variables);
|
final result = await _execQuery(isIdtyExistQ, variables);
|
||||||
return result.data!['identity']?.isNotEmpty ?? false;
|
return result.data!['identity']?.isNotEmpty ?? false;
|
||||||
}
|
|
||||||
|
|
||||||
Future<DateTime> getBlockStart() async {
|
|
||||||
final result = await _execQuery(getBlockchainStartQ, {});
|
|
||||||
if (!result.hasException) {
|
|
||||||
startBlockchainTime =
|
|
||||||
DateTime.parse(result.data!['block'][0]['created_at']);
|
|
||||||
startBlockchainInitialized = true;
|
|
||||||
return startBlockchainTime;
|
|
||||||
}
|
|
||||||
return DateTime(0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<QueryResult> _execQuery(
|
|
||||||
String query, Map<String, dynamic> variables) async {
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$indexerEndpoint/v1/graphql',
|
|
||||||
);
|
|
||||||
|
|
||||||
final GraphQLClient client = GraphQLClient(
|
|
||||||
cache: GraphQLCache(),
|
|
||||||
link: httpLink,
|
|
||||||
);
|
|
||||||
|
|
||||||
final QueryOptions options =
|
|
||||||
QueryOptions(document: gql(query), variables: variables);
|
|
||||||
|
|
||||||
return await client.query(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map computeHistoryView(repository, String address) {
|
|
||||||
final bool isUdUnit = configBox.get('isUdUnit') ?? false;
|
|
||||||
late double amount;
|
|
||||||
late String finalAmount;
|
|
||||||
final DateTime date = repository[0];
|
|
||||||
|
|
||||||
final dateForm = "${date.day} ${monthsInYear[date.month]!.substring(0, {
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
7,
|
|
||||||
9
|
|
||||||
}.contains(date.month) ? 4 : 3)}";
|
|
||||||
|
|
||||||
DateTime normalizeDate(DateTime inputDate) {
|
|
||||||
return DateTime(inputDate.year, inputDate.month, inputDate.day);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDateDelimiter() {
|
Future<DateTime> getBlockStart() async {
|
||||||
DateTime now = DateTime.now();
|
final result = await _execQuery(getBlockchainStartQ, {});
|
||||||
final transactionDate = normalizeDate(date.toLocal());
|
if (!result.hasException) {
|
||||||
final todayDate = normalizeDate(now);
|
startBlockchainTime =
|
||||||
final yesterdayDate = normalizeDate(now.subtract(const Duration(days: 1)));
|
DateTime.parse(result.data!['block'][0]['created_at']);
|
||||||
final isSameWeek = weekNumber(transactionDate) == weekNumber(now) &&
|
startBlockchainInitialized = true;
|
||||||
transactionDate.year == now.year;
|
return startBlockchainTime;
|
||||||
final isTodayOrYesterday =
|
|
||||||
transactionDate == todayDate || transactionDate == yesterdayDate;
|
|
||||||
|
|
||||||
if (transactionDate == todayDate) {
|
|
||||||
return "today".tr();
|
|
||||||
} else if (transactionDate == yesterdayDate) {
|
|
||||||
return "yesterday".tr();
|
|
||||||
} else if (isSameWeek && !isTodayOrYesterday) {
|
|
||||||
return "thisWeek".tr();
|
|
||||||
} else if (!isSameWeek && !isTodayOrYesterday) {
|
|
||||||
if (transactionDate.year == now.year) {
|
|
||||||
return monthsInYear[transactionDate.month]!;
|
|
||||||
} else {
|
|
||||||
return "${monthsInYear[transactionDate.month]} ${transactionDate.year}";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
return DateTime(0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final dateDelimiter = getDateDelimiter();
|
Future<QueryResult> _execQuery(
|
||||||
|
String query, Map<String, dynamic> variables) async {
|
||||||
|
final options = QueryOptions(document: gql(query), variables: variables);
|
||||||
|
|
||||||
amount = repository[4] == 'RECEIVED' ? repository[3] : repository[3] * -1;
|
// 5GMyvKsTNk9wDBy9jwKaX6mhSzmFFtpdK9KNnmrLoSTSuJHv
|
||||||
|
|
||||||
if (isUdUnit) {
|
return await indexerClient.query(options);
|
||||||
amount = round(amount / balanceRatio);
|
|
||||||
finalAmount = 'ud'.tr(args: ['$amount ']);
|
|
||||||
} else {
|
|
||||||
finalAmount = '$amount $currencyName';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isMigrationTime =
|
Stream<QueryResult> subscribeHistoryIssued(String address) {
|
||||||
startBlockchainInitialized && date.compareTo(startBlockchainTime) < 0;
|
final variables = <String, dynamic>{
|
||||||
|
'address': address,
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
final options = SubscriptionOptions(
|
||||||
'finalAmount': finalAmount,
|
document: gql(subscribeHistoryIssuedQ),
|
||||||
'isMigrationTime': isMigrationTime,
|
variables: variables,
|
||||||
'dateDelimiter': dateDelimiter,
|
);
|
||||||
'dateForm': dateForm,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
int weekNumber(DateTime date) {
|
return indexerClient.subscribe(options);
|
||||||
int dayOfYear = int.parse(DateFormat("D").format(date));
|
}
|
||||||
return ((dayOfYear - date.weekday + 10) / 7).floor();
|
|
||||||
|
Map computeHistoryView(repository, String address) {
|
||||||
|
final bool isUdUnit = configBox.get('isUdUnit') ?? false;
|
||||||
|
late double amount;
|
||||||
|
late String finalAmount;
|
||||||
|
final DateTime date = repository[0];
|
||||||
|
|
||||||
|
final dateForm = "${date.day} ${monthsInYear[date.month]!.substring(0, {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
7,
|
||||||
|
9
|
||||||
|
}.contains(date.month) ? 4 : 3)}";
|
||||||
|
|
||||||
|
DateTime normalizeDate(DateTime inputDate) {
|
||||||
|
return DateTime(inputDate.year, inputDate.month, inputDate.day);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDateDelimiter() {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
final transactionDate = normalizeDate(date.toLocal());
|
||||||
|
final todayDate = normalizeDate(now);
|
||||||
|
final yesterdayDate =
|
||||||
|
normalizeDate(now.subtract(const Duration(days: 1)));
|
||||||
|
final isSameWeek = weekNumber(transactionDate) == weekNumber(now) &&
|
||||||
|
transactionDate.year == now.year;
|
||||||
|
final isTodayOrYesterday =
|
||||||
|
transactionDate == todayDate || transactionDate == yesterdayDate;
|
||||||
|
|
||||||
|
if (transactionDate == todayDate) {
|
||||||
|
return "today".tr();
|
||||||
|
} else if (transactionDate == yesterdayDate) {
|
||||||
|
return "yesterday".tr();
|
||||||
|
} else if (isSameWeek && !isTodayOrYesterday) {
|
||||||
|
return "thisWeek".tr();
|
||||||
|
} else if (!isSameWeek && !isTodayOrYesterday) {
|
||||||
|
if (transactionDate.year == now.year) {
|
||||||
|
return monthsInYear[transactionDate.month]!;
|
||||||
|
} else {
|
||||||
|
return "${monthsInYear[transactionDate.month]} ${transactionDate.year}";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final dateDelimiter = getDateDelimiter();
|
||||||
|
|
||||||
|
amount = repository[4] == 'RECEIVED' ? repository[3] : repository[3] * -1;
|
||||||
|
|
||||||
|
if (isUdUnit) {
|
||||||
|
amount = round(amount / balanceRatio);
|
||||||
|
finalAmount = 'ud'.tr(args: ['$amount ']);
|
||||||
|
} else {
|
||||||
|
finalAmount = '$amount $currencyName';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMigrationTime =
|
||||||
|
startBlockchainInitialized && date.compareTo(startBlockchainTime) < 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
'finalAmount': finalAmount,
|
||||||
|
'isMigrationTime': isMigrationTime,
|
||||||
|
'dateDelimiter': dateDelimiter,
|
||||||
|
'dateForm': dateForm,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int weekNumber(DateTime date) {
|
||||||
|
int dayOfYear = int.parse(DateFormat("D").format(date));
|
||||||
|
return ((dayOfYear - date.weekday + 10) / 7).floor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = '';
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -6,12 +6,15 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/chest_data.dart';
|
import 'package:gecko/models/chest_data.dart';
|
||||||
import 'package:gecko/models/migrate_wallet_checks.dart';
|
import 'package:gecko/models/migrate_wallet_checks.dart';
|
||||||
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
import 'package:gecko/models/transaction_content.dart';
|
||||||
import 'package:gecko/models/wallet_data.dart';
|
import 'package:gecko/models/wallet_data.dart';
|
||||||
import 'package:gecko/providers/duniter_indexer.dart';
|
import 'package:gecko/providers/duniter_indexer.dart';
|
||||||
import 'package:gecko/providers/home.dart';
|
import 'package:gecko/providers/home.dart';
|
||||||
import 'package:gecko/providers/my_wallets.dart';
|
import 'package:gecko/providers/my_wallets.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/providers/wallets_profiles.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status.dart';
|
||||||
import 'package:pinenacl/ed25519.dart';
|
import 'package:pinenacl/ed25519.dart';
|
||||||
import 'package:polkawallet_sdk/api/apiKeyring.dart';
|
import 'package:polkawallet_sdk/api/apiKeyring.dart';
|
||||||
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
||||||
|
@ -36,8 +39,8 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
bool importIsLoading = false;
|
bool importIsLoading = false;
|
||||||
int blocNumber = 0;
|
int blocNumber = 0;
|
||||||
bool isLoadingEndpoint = false;
|
bool isLoadingEndpoint = false;
|
||||||
Map transactionStatus = {};
|
Map<String, TransactionContent> 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();
|
||||||
|
@ -53,21 +56,35 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
////////// 1: API METHODS ///////////
|
////////// 1: API METHODS ///////////
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
||||||
Future<String> _executeCall(String currentTransactionId, TxInfoData txInfo,
|
Map<String, TransactionStatus> statusMap = {
|
||||||
|
'sending': TransactionStatus.sending,
|
||||||
|
'Ready': TransactionStatus.propagation,
|
||||||
|
'Broadcast': TransactionStatus.validating,
|
||||||
|
'Finalized': TransactionStatus.finalized
|
||||||
|
};
|
||||||
|
|
||||||
|
Future _executeCall(TransactionContent transcationContent, TxInfoData txInfo,
|
||||||
txOptions, String password,
|
txOptions, String password,
|
||||||
[String? rawParams]) async {
|
[String? rawParams]) async {
|
||||||
final walletOptions =
|
final walletOptions =
|
||||||
Provider.of<WalletOptionsProvider>(homeContext, listen: false);
|
Provider.of<WalletOptionsProvider>(homeContext, listen: false);
|
||||||
final walletProfiles =
|
final walletProfiles =
|
||||||
Provider.of<WalletsProfilesProvider>(homeContext, listen: false);
|
Provider.of<WalletsProfilesProvider>(homeContext, listen: false);
|
||||||
transactionStatus.putIfAbsent(currentTransactionId, () => 'sending');
|
final currentTransactionId = transcationContent.transactionId;
|
||||||
|
transactionStatus.putIfAbsent(
|
||||||
|
currentTransactionId, () => transcationContent);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final hash = await sdk.api.tx.signAndSend(txInfo, txOptions, password,
|
final hash = await sdk.api.tx.signAndSend(txInfo, txOptions, password,
|
||||||
rawParam: rawParams, onStatusChange: (p0) {
|
rawParam: rawParams, onStatusChange: (newStatus) {
|
||||||
transactionStatus.update(currentTransactionId, (_) => p0,
|
transactionStatus.update(currentTransactionId, (trans) {
|
||||||
ifAbsent: () => p0);
|
trans.status = statusMap[newStatus]!;
|
||||||
|
return trans;
|
||||||
|
}, ifAbsent: () {
|
||||||
|
transcationContent.status = statusMap[newStatus]!;
|
||||||
|
return transcationContent;
|
||||||
|
});
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}).timeout(
|
}).timeout(
|
||||||
const Duration(seconds: 18),
|
const Duration(seconds: 18),
|
||||||
|
@ -76,25 +93,47 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
log.d(hash);
|
log.d(hash);
|
||||||
if (hash.isEmpty) {
|
if (hash.isEmpty) {
|
||||||
transactionStatus.update(
|
transactionStatus.update(
|
||||||
currentTransactionId, (_) => 'Exception: timeout');
|
currentTransactionId,
|
||||||
|
(trans) {
|
||||||
|
trans.status = TransactionStatus.timeout;
|
||||||
|
return trans;
|
||||||
|
},
|
||||||
|
ifAbsent: () {
|
||||||
|
transcationContent.status = TransactionStatus.timeout;
|
||||||
|
return transcationContent;
|
||||||
|
},
|
||||||
|
);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
return 'Exception: timeout';
|
|
||||||
} else {
|
} else {
|
||||||
// Success !
|
// Success !
|
||||||
transactionStatus.update(currentTransactionId, (_) => hash.toString(),
|
transactionStatus.update(currentTransactionId, (trans) {
|
||||||
ifAbsent: () => hash.toString());
|
trans.status = TransactionStatus.success;
|
||||||
|
return trans;
|
||||||
|
}, ifAbsent: () {
|
||||||
|
transcationContent.status = TransactionStatus.success;
|
||||||
|
return transcationContent;
|
||||||
|
});
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
walletOptions.reload();
|
walletOptions.reload();
|
||||||
walletProfiles.reload();
|
walletProfiles.reload();
|
||||||
return hash.toString();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
transactionStatus.update(currentTransactionId, (_) => e.toString(),
|
transactionStatus.update(
|
||||||
ifAbsent: () => e.toString());
|
currentTransactionId,
|
||||||
|
(trans) {
|
||||||
|
trans.status = TransactionStatus.failed;
|
||||||
|
trans.error = e.toString();
|
||||||
|
return trans;
|
||||||
|
},
|
||||||
|
ifAbsent: () {
|
||||||
|
transcationContent.status = TransactionStatus.failed;
|
||||||
|
transcationContent.error = e.toString();
|
||||||
|
return transcationContent;
|
||||||
|
},
|
||||||
|
);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return e.toString();
|
|
||||||
}
|
}
|
||||||
|
transactionStatus.remove(currentTransactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getStorage(String call) async {
|
Future _getStorage(String call) async {
|
||||||
|
@ -603,6 +642,8 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
final homeProvider = Provider.of<HomeProvider>(homeContext, listen: false);
|
final homeProvider = Provider.of<HomeProvider>(homeContext, listen: false);
|
||||||
final myWalletProvider =
|
final myWalletProvider =
|
||||||
Provider.of<MyWalletsProvider>(homeContext, listen: false);
|
Provider.of<MyWalletsProvider>(homeContext, listen: false);
|
||||||
|
final duniterIndexer =
|
||||||
|
Provider.of<DuniterIndexer>(homeContext, listen: false);
|
||||||
|
|
||||||
homeProvider.changeMessage("connectionPending".tr(), 0);
|
homeProvider.changeMessage("connectionPending".tr(), 0);
|
||||||
|
|
||||||
|
@ -647,7 +688,7 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
await initCurrencyParameters();
|
await initCurrencyParameters();
|
||||||
|
|
||||||
// Indexer Blockchain start
|
// Indexer Blockchain start
|
||||||
getBlockStart();
|
duniterIndexer.getBlockStart();
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
homeProvider.changeMessage(
|
homeProvider.changeMessage(
|
||||||
|
@ -889,7 +930,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 = '';
|
||||||
|
|
||||||
|
@ -907,7 +947,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) {
|
||||||
|
@ -920,14 +962,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,
|
||||||
);
|
);
|
||||||
|
@ -988,7 +1025,14 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
final transactionId = const Uuid().v4();
|
final transactionId = const Uuid().v4();
|
||||||
_executeCall(transactionId, txInfo, txOptions, password, rawParams);
|
final transactionContent = TransactionContent(
|
||||||
|
transactionId: transactionId,
|
||||||
|
status: TransactionStatus.sending,
|
||||||
|
from: fromAddress,
|
||||||
|
to: destAddress,
|
||||||
|
amount: amount,
|
||||||
|
);
|
||||||
|
_executeCall(transactionContent, txInfo, txOptions, password, rawParams);
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,7 +1100,14 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
|
|
||||||
log.d('Cert action: ${txInfo.call!}');
|
log.d('Cert action: ${txInfo.call!}');
|
||||||
final transactionId = const Uuid().v4();
|
final transactionId = const Uuid().v4();
|
||||||
_executeCall(transactionId, txInfo, txOptions, password, rawParams);
|
final transactionContent = TransactionContent(
|
||||||
|
transactionId: const Uuid().v4(),
|
||||||
|
status: TransactionStatus.sending,
|
||||||
|
from: fromAddress,
|
||||||
|
to: destAddress,
|
||||||
|
amount: -1,
|
||||||
|
);
|
||||||
|
_executeCall(transactionContent, txInfo, txOptions, password, rawParams);
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,8 +1123,14 @@ class SubstrateSdk with ChangeNotifier {
|
||||||
final txOptions = [name];
|
final txOptions = [name];
|
||||||
|
|
||||||
final transactionId = const Uuid().v4();
|
final transactionId = const Uuid().v4();
|
||||||
|
final transactionContent = TransactionContent(
|
||||||
_executeCall(transactionId, txInfo, txOptions, password);
|
transactionId: const Uuid().v4(),
|
||||||
|
status: TransactionStatus.sending,
|
||||||
|
from: fromAddress,
|
||||||
|
to: fromAddress,
|
||||||
|
amount: -1,
|
||||||
|
);
|
||||||
|
_executeCall(transactionContent, txInfo, txOptions, password);
|
||||||
|
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1200,15 @@ newKeySig: $newKeySigType""");
|
||||||
}
|
}
|
||||||
|
|
||||||
final transactionId = const Uuid().v4();
|
final transactionId = const Uuid().v4();
|
||||||
_executeCall(transactionId, txInfo, txOptions, fromPassword, rawParams);
|
final transactionContent = TransactionContent(
|
||||||
|
transactionId: const Uuid().v4(),
|
||||||
|
status: TransactionStatus.sending,
|
||||||
|
from: fromAddress,
|
||||||
|
to: fromAddress,
|
||||||
|
amount: -1,
|
||||||
|
);
|
||||||
|
_executeCall(
|
||||||
|
transactionContent, txInfo, txOptions, fromPassword, rawParams);
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,7 +1234,14 @@ newKeySig: $newKeySigType""");
|
||||||
|
|
||||||
final txOptions = [idtyIndex, address, revocationSigTyped];
|
final txOptions = [idtyIndex, address, revocationSigTyped];
|
||||||
final transactionId = const Uuid().v4();
|
final transactionId = const Uuid().v4();
|
||||||
_executeCall(transactionId, txInfo, txOptions, password);
|
final transactionContent = TransactionContent(
|
||||||
|
transactionId: const Uuid().v4(),
|
||||||
|
status: TransactionStatus.sending,
|
||||||
|
from: address,
|
||||||
|
to: address,
|
||||||
|
amount: -1,
|
||||||
|
);
|
||||||
|
_executeCall(transactionContent, txInfo, txOptions, password);
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,10 +1316,6 @@ newKeySig: $newKeySigType""");
|
||||||
void reload() {
|
void reload() {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetTransactionStatus() {
|
|
||||||
transactionStatus.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
|
@ -1267,7 +1335,7 @@ void snackNode(bool isConnected) {
|
||||||
final snackBar = SnackBar(
|
final snackBar = SnackBar(
|
||||||
backgroundColor: Colors.grey[900],
|
backgroundColor: Colors.grey[900],
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
content: Text(message, style: const TextStyle(fontSize: 16)),
|
content: Text(message, style: scaledTextStyle(fontSize: 14)),
|
||||||
duration: const Duration(seconds: 4));
|
duration: const Duration(seconds: 4));
|
||||||
ScaffoldMessenger.of(homeContext).showSnackBar(snackBar);
|
ScaffoldMessenger.of(homeContext).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,20 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/queries_datapod.dart';
|
import 'package:gecko/models/queries_datapod.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/providers/my_wallets.dart';
|
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class V2sDatapodProvider with ChangeNotifier {
|
class V2sDatapodProvider with ChangeNotifier {
|
||||||
|
late GraphQLClient datapodClient;
|
||||||
|
|
||||||
Future<QueryResult> _execQuery(
|
Future<QueryResult> _execQuery(
|
||||||
String query, Map<String, dynamic> variables) async {
|
String query, Map<String, dynamic> variables) async {
|
||||||
final httpLink = HttpLink('$datapodEndpoint/v1/graphql');
|
|
||||||
|
|
||||||
final GraphQLClient client = GraphQLClient(
|
|
||||||
cache: GraphQLCache(),
|
|
||||||
link: httpLink,
|
|
||||||
);
|
|
||||||
|
|
||||||
final QueryOptions options =
|
final QueryOptions options =
|
||||||
QueryOptions(document: gql(query), variables: variables);
|
QueryOptions(document: gql(query), variables: variables);
|
||||||
|
|
||||||
return await client.query(options);
|
return await datapodClient.query(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateProfile(
|
Future<bool> updateProfile(
|
||||||
|
@ -36,9 +30,6 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
List<Map<String, String>>? socials,
|
List<Map<String, String>>? socials,
|
||||||
Map<String, double>? geoloc}) async {
|
Map<String, double>? geoloc}) async {
|
||||||
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
|
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
|
||||||
final myWallets =
|
|
||||||
Provider.of<MyWalletsProvider>(homeContext, listen: false);
|
|
||||||
final walletData = myWallets.getWalletDataByAddress(address);
|
|
||||||
|
|
||||||
final messageToSign = jsonEncode({
|
final messageToSign = jsonEncode({
|
||||||
'address': address,
|
'address': address,
|
||||||
|
@ -70,9 +61,6 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log.d(result.data!['updateProfile']['message']);
|
log.d(result.data!['updateProfile']['message']);
|
||||||
walletData!.profileUpdatedTime = DateTime.now();
|
|
||||||
walletBox.put(address, walletData);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +133,8 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
return profileDate;
|
return profileDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Image> getAvatar(String address,
|
Future<Image> getRemoteAvatar(String address,
|
||||||
{double size = 20, bool saveOnDisk = false, String? uuid}) async {
|
{double size = 20, String? uuid}) async {
|
||||||
final variables = <String, dynamic>{
|
final variables = <String, dynamic>{
|
||||||
'address': address,
|
'address': address,
|
||||||
};
|
};
|
||||||
|
@ -164,12 +152,8 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
final sanitizedAvatar64 =
|
final sanitizedAvatar64 =
|
||||||
avatar64.replaceAll('\n', '').replaceAll('\r', '').replaceAll(' ', '');
|
avatar64.replaceAll('\n', '').replaceAll('\r', '').replaceAll(' ', '');
|
||||||
|
|
||||||
if (saveOnDisk) {
|
log.d('We save avatar for $address');
|
||||||
log.d('We save avatar for $address');
|
await saveAvatar(address, sanitizedAvatar64, uuid);
|
||||||
await saveAvatar(address, sanitizedAvatar64, uuid);
|
|
||||||
} else {
|
|
||||||
await cacheAvatar(address, sanitizedAvatar64);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Image.memory(
|
return Image.memory(
|
||||||
base64.decode(sanitizedAvatar64),
|
base64.decode(sanitizedAvatar64),
|
||||||
|
@ -185,16 +169,26 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File> cacheAvatar(String address, String data) async {
|
Future<File> cacheAvatar(String address, String data) async {
|
||||||
final file = File('${avatarsCacheDirectory.path}/$address');
|
final uuid = const Uuid().v4();
|
||||||
return await file.writeAsBytes(base64.decode(data));
|
final tempFile = File('${avatarsCacheDirectory.path}/$uuid$address');
|
||||||
|
final targetFile = File('${avatarsCacheDirectory.path}/$address');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write to a temporary file first to prevent data race
|
||||||
|
await tempFile.writeAsBytes(base64.decode(data));
|
||||||
|
log.d('Caching avatar of $address');
|
||||||
|
return await tempFile.rename(targetFile.path);
|
||||||
|
} catch (e) {
|
||||||
|
log.e("An error occurred while caching avatar: $e");
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image getAvatarLocal(String address, double size) {
|
Image getAvatarLocal(String address) {
|
||||||
final avatarFile = File('${avatarsCacheDirectory.path}/$address');
|
final avatarFile = File('${avatarsCacheDirectory.path}/$address');
|
||||||
return Image.file(
|
return Image.file(
|
||||||
avatarFile,
|
avatarFile,
|
||||||
height: size,
|
fit: BoxFit.cover,
|
||||||
fit: BoxFit.fitWidth,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,13 +201,12 @@ class V2sDatapodProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future deleteAvatarsDirectory() async {
|
Future deleteAvatarsDirectory() async {
|
||||||
if (await avatarsDirectory.exists()) {
|
if (await avatarsDirectory.exists()) {
|
||||||
await avatarsDirectory.delete(recursive: true);
|
await avatarsDirectory.delete(recursive: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import 'package:gecko/screens/transaction_in_progress.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:image_cropper/image_cropper.dart';
|
import 'package:image_cropper/image_cropper.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class WalletOptionsProvider with ChangeNotifier {
|
class WalletOptionsProvider with ChangeNotifier {
|
||||||
final address = TextEditingController();
|
final address = TextEditingController();
|
||||||
|
@ -116,15 +117,31 @@ class WalletOptionsProvider with ChangeNotifier {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final newPath = "${avatarsDirectory.path}/${address.text}";
|
final avatarUuid = const Uuid().v4();
|
||||||
|
final newPath = "${avatarsDirectory.path}/${address.text}-$avatarUuid";
|
||||||
|
|
||||||
if (croppedFile != null) {
|
if (croppedFile == null) {
|
||||||
await File(croppedFile.path).rename(newPath);
|
|
||||||
} else {
|
|
||||||
log.w('No image selected.');
|
log.w('No image selected.');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await File(croppedFile.path).rename(newPath);
|
||||||
|
|
||||||
|
final walletData =
|
||||||
|
MyWalletsProvider().getWalletDataByAddress(address.text);
|
||||||
|
|
||||||
|
if (walletData!.imageCustomPath != null) {
|
||||||
|
final avatarFile = File(walletData.imageCustomPath!);
|
||||||
|
await avatarFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
walletData.profileUpdatedTime = DateTime.now();
|
||||||
|
walletData.imageCustomPath = newPath;
|
||||||
|
|
||||||
|
await walletBox.put(address.text, walletData);
|
||||||
|
notifyListeners();
|
||||||
datapod.setAvatar(address.text, newPath);
|
datapod.setAvatar(address.text, newPath);
|
||||||
|
|
||||||
return newPath;
|
return newPath;
|
||||||
} else {
|
} else {
|
||||||
log.w('No image selected.');
|
log.w('No image selected.');
|
||||||
|
@ -139,6 +156,7 @@ class WalletOptionsProvider with ChangeNotifier {
|
||||||
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 duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
|
||||||
|
|
||||||
bool canValidate = false;
|
bool canValidate = false;
|
||||||
bool idtyExist = false;
|
bool idtyExist = false;
|
||||||
|
@ -151,7 +169,7 @@ class WalletOptionsProvider with ChangeNotifier {
|
||||||
title: Text(
|
title: Text(
|
||||||
'confirmYourIdentity'.tr(),
|
'confirmYourIdentity'.tr(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
|
@ -160,9 +178,9 @@ class WalletOptionsProvider with ChangeNotifier {
|
||||||
TextField(
|
TextField(
|
||||||
key: keyEnterIdentityUsername,
|
key: keyEnterIdentityUsername,
|
||||||
onChanged: (_) async {
|
onChanged: (_) async {
|
||||||
idtyExist = await isIdtyExist(idtyName.text);
|
idtyExist = await duniterIndexer.isIdtyExist(idtyName.text);
|
||||||
canValidate = !idtyExist &&
|
canValidate = !idtyExist &&
|
||||||
!await isIdtyExist(idtyName.text) &&
|
!await duniterIndexer.isIdtyExist(idtyName.text) &&
|
||||||
idtyName.text.length >= 2 &&
|
idtyName.text.length >= 2 &&
|
||||||
idtyName.text.length <= 32;
|
idtyName.text.length <= 32;
|
||||||
|
|
||||||
|
@ -176,7 +194,7 @@ class WalletOptionsProvider with ChangeNotifier {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
controller: idtyName,
|
controller: idtyName,
|
||||||
style: const TextStyle(fontSize: 19),
|
style: const TextStyle(fontSize: 17),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Consumer<WalletOptionsProvider>(builder: (context, wOptions, _) {
|
Consumer<WalletOptionsProvider>(builder: (context, wOptions, _) {
|
||||||
|
|
|
@ -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,24 +95,30 @@ 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,
|
||||||
{required String message, int duration = 2, double fontSize = 16}) {
|
{required String message, int duration = 2, double fontSize = 14}) {
|
||||||
final snackBar = SnackBar(
|
final snackBar = SnackBar(
|
||||||
backgroundColor: Colors.grey[900],
|
backgroundColor: Colors.grey[900],
|
||||||
padding: EdgeInsets.all(scaleSize(19)),
|
padding: EdgeInsets.all(scaleSize(19)),
|
||||||
|
@ -124,7 +132,7 @@ snackCopyKey(context) {
|
||||||
backgroundColor: Colors.grey[900],
|
backgroundColor: Colors.grey[900],
|
||||||
padding: EdgeInsets.all(scaleSize(19)),
|
padding: EdgeInsets.all(scaleSize(19)),
|
||||||
content: Text("thisAddressHasBeenCopiedToClipboard".tr(),
|
content: Text("thisAddressHasBeenCopiedToClipboard".tr(),
|
||||||
style: scaledTextStyle(fontSize: 16)),
|
style: scaledTextStyle(fontSize: 14)),
|
||||||
duration: const Duration(seconds: 2));
|
duration: const Duration(seconds: 2));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +142,7 @@ snackCopySeed(context) {
|
||||||
backgroundColor: Colors.grey[900],
|
backgroundColor: Colors.grey[900],
|
||||||
padding: EdgeInsets.all(scaleSize(19)),
|
padding: EdgeInsets.all(scaleSize(19)),
|
||||||
content: Text("thisMnemonicHasBeenCopiedToClipboard".tr(),
|
content: Text("thisMnemonicHasBeenCopiedToClipboard".tr(),
|
||||||
style: scaledTextStyle(fontSize: 16)),
|
style: scaledTextStyle(fontSize: 14)),
|
||||||
duration: const Duration(seconds: 4));
|
duration: const Duration(seconds: 4));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,7 @@ class _ActivityScreenState extends State<ActivityScreen> {
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvoked: (_) {
|
onPopInvoked: (_) {
|
||||||
duniterIndexer.fetchMoreCursor =
|
duniterIndexer.refetch = duniterIndexer.transBC = null;
|
||||||
duniterIndexer.pageInfo = duniterIndexer.transBC = null;
|
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -45,7 +44,7 @@ class _ActivityScreenState extends State<ActivityScreen> {
|
||||||
toolbarHeight: scaleSize(57),
|
toolbarHeight: scaleSize(57),
|
||||||
title: Text(
|
title: Text(
|
||||||
'accountActivity'.tr(),
|
'accountActivity'.tr(),
|
||||||
style: scaledTextStyle(fontSize: 20),
|
style: scaledTextStyle(fontSize: 18),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: const GeckoBottomAppBar(),
|
bottomNavigationBar: const GeckoBottomAppBar(),
|
||||||
|
|
|
@ -51,7 +51,7 @@ class CertificationsScreen extends StatelessWidget {
|
||||||
CertsCounter(address: address)
|
CertsCounter(address: address)
|
||||||
]),
|
]),
|
||||||
content: CertsList(
|
content: CertsList(
|
||||||
address: address, direction: CertDirection.sent),
|
address: address, direction: CertDirection.received),
|
||||||
contentHorizontalPadding: 0,
|
contentHorizontalPadding: 0,
|
||||||
contentBorderWidth: 1,
|
contentBorderWidth: 1,
|
||||||
),
|
),
|
||||||
|
|
|
@ -35,8 +35,8 @@ class DebugScreen extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 60,
|
height: 50,
|
||||||
width: 250,
|
width: 210,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
|
@ -47,7 +47,7 @@ class DebugScreen extends StatelessWidget {
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Spawn a bloc',
|
'Spawn a bloc',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.w600),
|
fontSize: 17, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -20,6 +20,7 @@ import 'package:gecko/screens/myWallets/restore_chest.dart';
|
||||||
import 'package:gecko/screens/onBoarding/1.dart';
|
import 'package:gecko/screens/onBoarding/1.dart';
|
||||||
import 'package:gecko/widgets/drawer.dart';
|
import 'package:gecko/widgets/drawer.dart';
|
||||||
import 'package:gecko/widgets/buttons/home_buttons.dart';
|
import 'package:gecko/widgets/buttons/home_buttons.dart';
|
||||||
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -76,7 +77,25 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
homeProvider.isWalletBoxInit = true;
|
homeProvider.isWalletBoxInit = true;
|
||||||
myWalletProvider.reload();
|
myWalletProvider.reload();
|
||||||
|
|
||||||
duniterIndexer.getValidIndexerEndpoint();
|
duniterIndexer.getValidIndexerEndpoint().then((validIndexerEndpoint) {
|
||||||
|
final wsLinkIndexer = WebSocketLink(
|
||||||
|
'wss://$validIndexerEndpoint/v1/graphql',
|
||||||
|
);
|
||||||
|
|
||||||
|
final wsLinkDatapod = WebSocketLink(
|
||||||
|
'wss://$datapodEndpoint/v1/graphql',
|
||||||
|
);
|
||||||
|
|
||||||
|
duniterIndexer.indexerClient = GraphQLClient(
|
||||||
|
cache: GraphQLCache(),
|
||||||
|
link: wsLinkIndexer,
|
||||||
|
);
|
||||||
|
|
||||||
|
datapod.datapodClient = GraphQLClient(
|
||||||
|
cache: GraphQLCache(),
|
||||||
|
link: wsLinkDatapod,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
await homeProvider.getValidEndpoints();
|
await homeProvider.getValidEndpoints();
|
||||||
if (configBox.get('isCacheChecked') == null) {
|
if (configBox.get('isCacheChecked') == null) {
|
||||||
|
@ -101,7 +120,6 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// _duniterIndexer.checkIndexerEndpointBackground();
|
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:durt/durt.dart';
|
import 'package:durt/durt.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
|
||||||
import 'package:gecko/models/wallet_data.dart';
|
import 'package:gecko/models/wallet_data.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/screens/myWallets/unlocking_wallet.dart';
|
import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
|
||||||
|
import 'package:gecko/widgets/commons/top_appbar.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ChangePinScreen extends StatefulWidget with ChangeNotifier {
|
class ChangePinScreen extends StatefulWidget with ChangeNotifier {
|
||||||
|
@ -45,11 +45,7 @@ class _ChangePinScreenState extends State<ChangePinScreen> {
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: GeckoAppBar(widget.walletName!),
|
||||||
elevation: 1,
|
|
||||||
toolbarHeight: scaleSize(57),
|
|
||||||
title: Text(widget.walletName!),
|
|
||||||
),
|
|
||||||
body: Center(
|
body: Center(
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Column(children: <Widget>[
|
child: Column(children: <Widget>[
|
||||||
|
|
|
@ -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]),
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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(),
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ class RestoreChest extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
'restoreThisChest'.tr(),
|
'restoreThisChest'.tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20,
|
fontSize: 19,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.white),
|
color: Colors.white),
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,7 +10,6 @@ import 'package:gecko/providers/duniter_indexer.dart';
|
||||||
import 'package:gecko/providers/my_wallets.dart';
|
import 'package:gecko/providers/my_wallets.dart';
|
||||||
import 'package:gecko/models/wallet_data.dart';
|
import 'package:gecko/models/wallet_data.dart';
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/providers/v2s_datapod.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/providers/wallets_profiles.dart';
|
||||||
import 'package:gecko/screens/certifications.dart';
|
import 'package:gecko/screens/certifications.dart';
|
||||||
|
@ -50,6 +49,24 @@ class WalletOptions extends StatelessWidget {
|
||||||
final isWalletNameIndexed =
|
final isWalletNameIndexed =
|
||||||
duniterIndexer.walletNameIndexer[walletOptions.address.text] != null;
|
duniterIndexer.walletNameIndexer[walletOptions.address.text] != null;
|
||||||
|
|
||||||
|
// StreamSubscription<QueryResult>? subscription;
|
||||||
|
// final stream = duniterIndexer.subscribeHistoryIssued(wallet.address);
|
||||||
|
|
||||||
|
// subscription = stream.listen((result) {
|
||||||
|
// if (result.hasException) {
|
||||||
|
// log.e(result.exception);
|
||||||
|
// } else {
|
||||||
|
// final Map transData =
|
||||||
|
// result.data?['account_by_pk']['transactions_issued'].first;
|
||||||
|
// final String receiver = transData['receiver_pubkey'];
|
||||||
|
// final double amount = transData['amount'] / 100;
|
||||||
|
// final createdAt = DateTime.parse(transData['created_at']);
|
||||||
|
// log.d('$receiver --- $amount --- $createdAt');
|
||||||
|
|
||||||
|
// subscription?.cancel();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvoked: (_) {
|
onPopInvoked: (_) {
|
||||||
walletOptions.isEditing = false;
|
walletOptions.isEditing = false;
|
||||||
|
@ -69,7 +86,7 @@ class WalletOptions extends StatelessWidget {
|
||||||
? duniterIndexer
|
? duniterIndexer
|
||||||
.walletNameIndexer[walletOptions.address.text]!
|
.walletNameIndexer[walletOptions.address.text]!
|
||||||
: wallet.name!,
|
: wallet.name!,
|
||||||
style: scaledTextStyle(fontSize: 20),
|
style: scaledTextStyle(fontSize: 19),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
actions: [
|
actions: [
|
||||||
|
@ -259,58 +276,48 @@ class WalletOptions extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget avatar(WalletOptionsProvider walletProvider) {
|
Widget avatar(WalletOptionsProvider walletProvider) {
|
||||||
return Consumer<V2sDatapodProvider>(builder: (context, datapod, _) {
|
return Stack(
|
||||||
return Stack(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
InkWell(
|
||||||
InkWell(
|
onTap: () async {
|
||||||
|
await (walletProvider.changeAvatar());
|
||||||
|
},
|
||||||
|
child: wallet.imageCustomPath == null || wallet.imageCustomPath == ''
|
||||||
|
? Image.asset(
|
||||||
|
'assets/avatars/${wallet.imageDefaultPath}',
|
||||||
|
width: scaleSize(122),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
width: scaleSize(122),
|
||||||
|
height: scaleSize(122),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.transparent,
|
||||||
|
image: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: FileImage(
|
||||||
|
File(wallet.imageCustomPath!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final newPath = await (walletProvider.changeAvatar());
|
wallet.imageCustomPath = await (walletProvider.changeAvatar());
|
||||||
if (newPath != '') {
|
|
||||||
wallet.imageCustomPath = newPath;
|
|
||||||
walletBox.put(wallet.key, wallet);
|
|
||||||
// Uncomment to enable Cs+ avatar storage
|
|
||||||
// CesiumPlusProvider().setAvatar(wallet.address, newPath);
|
|
||||||
}
|
|
||||||
walletProvider.reload();
|
walletProvider.reload();
|
||||||
},
|
},
|
||||||
child:
|
child: Image.asset(
|
||||||
wallet.imageCustomPath == null || wallet.imageCustomPath == ''
|
'assets/walletOptions/camera.png',
|
||||||
? Image.asset(
|
height: scaleSize(38),
|
||||||
'assets/avatars/${wallet.imageDefaultPath}',
|
|
||||||
width: scaleSize(122),
|
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
width: scaleSize(122),
|
|
||||||
height: scaleSize(122),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: Colors.transparent,
|
|
||||||
image: DecorationImage(
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
image: FileImage(
|
|
||||||
File(wallet.imageCustomPath!),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
wallet.imageCustomPath = await (walletProvider.changeAvatar());
|
|
||||||
walletProvider.reload();
|
|
||||||
},
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/walletOptions/camera.png',
|
|
||||||
height: scaleSize(38),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
],
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget confirmIdentityButton(WalletOptionsProvider walletProvider) {
|
Widget confirmIdentityButton(WalletOptionsProvider walletProvider) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ class _WalletsHomeState extends State<WalletsHome> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 1,
|
backgroundColor: yellowC,
|
||||||
toolbarHeight: scaleSize(57),
|
toolbarHeight: scaleSize(57),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -62,7 +62,6 @@ class _WalletsHomeState extends State<WalletsHome> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
backgroundColor: const Color(0xffFFD58D),
|
|
||||||
),
|
),
|
||||||
bottomNavigationBar:
|
bottomNavigationBar:
|
||||||
Consumer<MyWalletsProvider>(builder: (context, _, __) {
|
Consumer<MyWalletsProvider>(builder: (context, _, __) {
|
||||||
|
@ -161,7 +160,7 @@ class _WalletsHomeState extends State<WalletsHome> {
|
||||||
'explainDraggableWallet'.tr(),
|
'explainDraggableWallet'.tr(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.w500),
|
fontSize: 17, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
|
|
|
@ -83,7 +83,7 @@ class OnboardingStepTen extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
"youHaveToBeConnectedToValidateChest".tr(),
|
"youHaveToBeConnectedToValidateChest".tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20,
|
fontSize: 17,
|
||||||
color: Colors.redAccent,
|
color: Colors.redAccent,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
|
|
|
@ -63,7 +63,7 @@ class _QrCodeFullscreenState extends State<QrCodeFullscreen> {
|
||||||
}),
|
}),
|
||||||
title: Text(
|
title: Text(
|
||||||
'QR Code de ${getShortPubkey(widget.address)}',
|
'QR Code de ${getShortPubkey(widget.address)}',
|
||||||
style: scaledTextStyle(color: orangeC, fontSize: 20),
|
style: scaledTextStyle(color: orangeC, fontSize: 18),
|
||||||
)),
|
)),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: SizedBox.expand(
|
child: SizedBox.expand(
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:gecko/providers/settings_provider.dart';
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/widgets/commons/loading.dart';
|
import 'package:gecko/widgets/commons/loading.dart';
|
||||||
|
import 'package:gecko/widgets/commons/top_appbar.dart';
|
||||||
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -21,17 +22,12 @@ class SettingsScreen extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
appBar: AppBar(
|
appBar: GeckoAppBar('parameters'.tr()),
|
||||||
toolbarHeight: scaleSize(57),
|
|
||||||
title: Text(
|
|
||||||
'parameters'.tr(),
|
|
||||||
style: scaledTextStyle(fontSize: 21),
|
|
||||||
)),
|
|
||||||
body: Column(children: <Widget>[
|
body: Column(children: <Widget>[
|
||||||
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),
|
||||||
|
@ -40,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),
|
||||||
|
@ -60,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,
|
||||||
),
|
),
|
||||||
|
@ -87,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),
|
||||||
|
@ -145,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(),
|
||||||
|
@ -165,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
|
||||||
|
@ -233,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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -297,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),
|
||||||
|
@ -307,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:
|
||||||
|
@ -370,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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
import 'package:gecko/widgets/commons/top_appbar.dart';
|
||||||
|
|
||||||
class TemplateScreen extends StatelessWidget {
|
class TemplateScreen extends StatelessWidget {
|
||||||
const TemplateScreen({Key? key}) : super(key: key);
|
const TemplateScreen({Key? key}) : super(key: key);
|
||||||
|
@ -11,13 +12,12 @@ class TemplateScreen extends StatelessWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
appBar: AppBar(
|
appBar: const GeckoAppBar('Template screen'),
|
||||||
toolbarHeight: scaleSize(57), title: const Text('Template screen')),
|
body: SafeArea(
|
||||||
body: const SafeArea(
|
|
||||||
child: Column(children: <Widget>[
|
child: Column(children: <Widget>[
|
||||||
SizedBox(height: 20),
|
ScaledSizedBox(height: 20),
|
||||||
Text('data'),
|
const Text('data'),
|
||||||
SizedBox(height: 20),
|
ScaledSizedBox(height: 20),
|
||||||
]),
|
]),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
import 'package:gecko/models/transaction_content.dart';
|
||||||
import 'package:gecko/models/widgets_keys.dart';
|
import 'package:gecko/models/widgets_keys.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/wallets_profiles.dart';
|
import 'package:gecko/providers/wallets_profiles.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status_icon.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
class TransactionInProgress extends StatelessWidget {
|
class TransactionInProgress extends StatefulWidget {
|
||||||
final String transactionId;
|
final String transactionId;
|
||||||
final String transType;
|
final String transType;
|
||||||
final String? fromAddress, toAddress, toUsername;
|
final String? fromAddress, toAddress, toUsername;
|
||||||
|
@ -22,56 +25,69 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
this.toUsername,
|
this.toUsername,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TransactionInProgress> createState() => _TransactionInProgressState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TransactionInProgressState extends State<TransactionInProgress> {
|
||||||
|
String resultText = '';
|
||||||
|
late String fromAddressFormat;
|
||||||
|
late String toAddressFormat;
|
||||||
|
late String toUsernameFormat;
|
||||||
|
late String amount;
|
||||||
|
late bool isUdUnit;
|
||||||
|
late TransactionContent txContent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final walletProfiles =
|
||||||
|
Provider.of<WalletsProfilesProvider>(homeContext, listen: false);
|
||||||
|
final myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(homeContext, listen: false);
|
||||||
|
|
||||||
|
String defaultWalletAddress = myWalletProvider.getDefaultWallet().address;
|
||||||
|
String defaultWalletName = myWalletProvider.getDefaultWallet().name!;
|
||||||
|
String? walletDataName =
|
||||||
|
myWalletProvider.getWalletDataByAddress(widget.toAddress ?? '')?.name;
|
||||||
|
|
||||||
|
fromAddressFormat = widget.fromAddress ??
|
||||||
|
g1WalletsBox.get(defaultWalletAddress)?.username ??
|
||||||
|
defaultWalletName;
|
||||||
|
toAddressFormat = widget.toAddress ?? walletProfiles.address;
|
||||||
|
toUsernameFormat =
|
||||||
|
widget.toUsername ?? walletDataName ?? getShortPubkey(toAddressFormat);
|
||||||
|
|
||||||
|
amount = walletProfiles.payAmount.text;
|
||||||
|
isUdUnit = configBox.get('isUdUnit') ?? false;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final sub = Provider.of<SubstrateSdk>(context, listen: true);
|
final sub = Provider.of<SubstrateSdk>(context, listen: true);
|
||||||
|
|
||||||
final transactionDetails = TransactionDetails(
|
if (sub.transactionStatus.containsKey(widget.transactionId)) {
|
||||||
transactionId: transactionId,
|
txContent = sub.transactionStatus[widget.transactionId]!;
|
||||||
fromAddress: fromAddress,
|
|
||||||
toAddress: toAddress,
|
|
||||||
toUsername: toUsername,
|
|
||||||
sub: sub,
|
|
||||||
transType: transType,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget getTransactionStatusIcon(TransactionDetails details) {
|
|
||||||
switch (details.txStatus) {
|
|
||||||
case TransactionStatus.loading:
|
|
||||||
return ScaledSizedBox(
|
|
||||||
height: 17,
|
|
||||||
width: 17,
|
|
||||||
child: const CircularProgressIndicator(
|
|
||||||
color: orangeC,
|
|
||||||
strokeWidth: 2,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
case TransactionStatus.success:
|
|
||||||
return Icon(
|
|
||||||
Icons.done_all,
|
|
||||||
size: scaleSize(32),
|
|
||||||
color: Colors.greenAccent,
|
|
||||||
);
|
|
||||||
case TransactionStatus.failed:
|
|
||||||
return Icon(
|
|
||||||
Icons.close,
|
|
||||||
size: scaleSize(32),
|
|
||||||
color: Colors.redAccent,
|
|
||||||
);
|
|
||||||
case TransactionStatus.none:
|
|
||||||
default:
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildTransactionStatus(TransactionDetails details) {
|
if (txContent.status == TransactionStatus.success) {
|
||||||
|
resultText = 'extrinsicValidated'
|
||||||
|
.tr(args: [actionMap[widget.transType] ?? 'strangeTransaction'.tr()]);
|
||||||
|
} else if (txContent.status == TransactionStatus.failed) {
|
||||||
|
resultText = errorTransactionMap[txContent.error] ?? txContent.error!;
|
||||||
|
} else {
|
||||||
|
resultText = statusStatusMap[txContent.status] ??
|
||||||
|
'Unknown status: ${txContent.status}';
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTransactionStatus() {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
getTransactionStatusIcon(details),
|
TransactionStatusIcon(txContent.status),
|
||||||
ScaledSizedBox(height: 7),
|
ScaledSizedBox(height: 7),
|
||||||
if (details.txStatus != TransactionStatus.none)
|
if (txContent.status != TransactionStatus.none)
|
||||||
Text(
|
Text(
|
||||||
transactionDetails.resultText,
|
resultText,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(fontSize: 17),
|
style: scaledTextStyle(fontSize: 17),
|
||||||
)
|
)
|
||||||
|
@ -80,9 +96,6 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvoked: (_) {
|
|
||||||
sub.resetTransactionStatus();
|
|
||||||
},
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -94,8 +107,7 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
'extrinsicInProgress'.tr(args: [
|
'extrinsicInProgress'.tr(args: [
|
||||||
transactionDetails.actionMap[transType] ??
|
actionMap[widget.transType] ?? 'strangeTransaction'.tr()
|
||||||
'strangeTransaction'.tr()
|
|
||||||
]),
|
]),
|
||||||
style: scaledTextStyle(fontSize: 20),
|
style: scaledTextStyle(fontSize: 20),
|
||||||
)
|
)
|
||||||
|
@ -117,30 +129,29 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
)),
|
)),
|
||||||
child: Column(children: <Widget>[
|
child: Column(children: <Widget>[
|
||||||
ScaledSizedBox(height: 10),
|
ScaledSizedBox(height: 10),
|
||||||
if (transType == 'pay')
|
if (widget.transType == 'pay')
|
||||||
Text(
|
Text(
|
||||||
transactionDetails.isUdUnit
|
isUdUnit
|
||||||
? 'ud'.tr(args: ['${transactionDetails.amount} '])
|
? 'ud'.tr(args: ['$amount '])
|
||||||
: '${transactionDetails.amount} $currencyName',
|
: '$amount $currencyName',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 17, fontWeight: FontWeight.w500),
|
fontSize: 17, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
if (transType == 'pay') ScaledSizedBox(height: 10),
|
if (widget.transType == 'pay') ScaledSizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
'fromMinus'.tr(),
|
'fromMinus'.tr(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(fontSize: 16),
|
style: scaledTextStyle(fontSize: 16),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
transactionDetails.fromAddress!,
|
fromAddressFormat,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 17, fontWeight: FontWeight.w500),
|
fontSize: 17, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: transactionDetails.fromAddress !=
|
visible: fromAddressFormat != toAddressFormat,
|
||||||
transactionDetails.toAddress,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
ScaledSizedBox(height: 10),
|
ScaledSizedBox(height: 10),
|
||||||
|
@ -150,7 +161,7 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
style: scaledTextStyle(fontSize: 16),
|
style: scaledTextStyle(fontSize: 16),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
transactionDetails.toUsername!,
|
toUsernameFormat,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 17, fontWeight: FontWeight.w500),
|
fontSize: 17, fontWeight: FontWeight.w500),
|
||||||
|
@ -162,7 +173,7 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
buildTransactionStatus(transactionDetails),
|
buildTransactionStatus(),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Align(
|
child: Align(
|
||||||
|
@ -178,13 +189,12 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
backgroundColor: orangeC,
|
backgroundColor: orangeC,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
sub.resetTransactionStatus();
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'close'.tr(),
|
'close'.tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.w600),
|
fontSize: 19, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -198,84 +208,3 @@ class TransactionInProgress extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TransactionStatus { loading, failed, success, none }
|
|
||||||
|
|
||||||
class TransactionDetails {
|
|
||||||
String? fromAddress, toAddress, toUsername, amount;
|
|
||||||
bool isUdUnit = false;
|
|
||||||
String resultText = '';
|
|
||||||
TransactionStatus txStatus = TransactionStatus.none;
|
|
||||||
|
|
||||||
TransactionDetails({
|
|
||||||
required transactionId,
|
|
||||||
required this.fromAddress,
|
|
||||||
required this.toAddress,
|
|
||||||
required this.toUsername,
|
|
||||||
required SubstrateSdk sub,
|
|
||||||
required String transType,
|
|
||||||
}) {
|
|
||||||
final walletProfiles =
|
|
||||||
Provider.of<WalletsProfilesProvider>(homeContext, listen: false);
|
|
||||||
final myWalletProvider =
|
|
||||||
Provider.of<MyWalletsProvider>(homeContext, listen: false);
|
|
||||||
String defaultWalletAddress = myWalletProvider.getDefaultWallet().address;
|
|
||||||
String defaultWalletName = myWalletProvider.getDefaultWallet().name!;
|
|
||||||
String? walletDataName =
|
|
||||||
myWalletProvider.getWalletDataByAddress(toAddress ?? '')?.name;
|
|
||||||
|
|
||||||
fromAddress = fromAddress ??
|
|
||||||
g1WalletsBox.get(defaultWalletAddress)?.username ??
|
|
||||||
defaultWalletName;
|
|
||||||
toAddress = toAddress ?? walletProfiles.address;
|
|
||||||
toUsername = toUsername ?? walletDataName ?? getShortPubkey(toAddress!);
|
|
||||||
|
|
||||||
amount = walletProfiles.payAmount.text;
|
|
||||||
isUdUnit = configBox.get('isUdUnit') ?? false;
|
|
||||||
|
|
||||||
if (sub.transactionStatus.containsKey(transactionId)) {
|
|
||||||
calculateTransactionStatus(
|
|
||||||
sub.transactionStatus[transactionId], transType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void calculateTransactionStatus(String? result, String transType) {
|
|
||||||
if (result == null) {
|
|
||||||
txStatus = TransactionStatus.none;
|
|
||||||
} else if (result.contains('blockHash: ')) {
|
|
||||||
txStatus = TransactionStatus.success;
|
|
||||||
resultText = 'extrinsicValidated'
|
|
||||||
.tr(args: [actionMap[transType] ?? 'strangeTransaction'.tr()]);
|
|
||||||
} else if (result.contains('Exception: ')) {
|
|
||||||
txStatus = TransactionStatus.failed;
|
|
||||||
String exception = result.split('Exception: ')[1];
|
|
||||||
resultText = resultMap[exception] ?? exception;
|
|
||||||
} else {
|
|
||||||
txStatus = TransactionStatus.loading;
|
|
||||||
resultText = resultMap[result] ?? 'Unknown status: $result';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> actionMap = {
|
|
||||||
'pay': 'transaction'.tr(),
|
|
||||||
'cert': 'certification'.tr(),
|
|
||||||
'comfirmIdty': 'identityConfirm'.tr(),
|
|
||||||
'revokeIdty': 'revokeAdhesion'.tr(),
|
|
||||||
'identityMigration': 'identityMigration'.tr(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<String, String> resultMap = {
|
|
||||||
'sending': 'sending'.tr(),
|
|
||||||
'Ready': 'propagating'.tr(),
|
|
||||||
'Broadcast': 'validating'.tr(),
|
|
||||||
'cert.NotRespectCertPeriod': '24hbetweenCerts'.tr(),
|
|
||||||
'identity.CreatorNotAllowedToCreateIdty': '24hbetweenCerts'.tr(),
|
|
||||||
'cert.CannotCertifySelf': 'canNotCertifySelf'.tr(),
|
|
||||||
'identity.IdtyNameAlreadyExist': 'nameAlreadyExist'.tr(),
|
|
||||||
'balances.KeepAlive': '2GDtoKeepAlive'.tr(),
|
|
||||||
'1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low':
|
|
||||||
'youHaveToFeedThisAccountBeforeUsing'.tr(),
|
|
||||||
'Token.FundsUnavailable': 'fundsUnavailable'.tr(),
|
|
||||||
'Exception: timeout': 'execTimeoutOver'.tr(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -104,16 +104,15 @@ class GeckoBottomAppBar extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (myWalletProvider.pinCode == '') return;
|
|
||||||
Navigator.popUntil(
|
|
||||||
context, ModalRoute.withName('/'));
|
|
||||||
//FIXME: Should not have to wait 300 milliseconds when /mywallets exist in navigator...
|
|
||||||
sleep(const Duration(milliseconds: 300));
|
|
||||||
Navigator.pushNamed(context, '/mywallets');
|
|
||||||
// Navigator.pushNamedAndRemoveUntil(
|
|
||||||
// context, '/mywallets', ModalRoute.withName('/'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (myWalletProvider.pinCode == '') return;
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||||
|
//FIXME: Should not have to wait 300 milliseconds when /mywallets exist in navigator...
|
||||||
|
sleep(const Duration(milliseconds: 300));
|
||||||
|
Navigator.pushNamed(context, '/mywallets');
|
||||||
|
// Navigator.pushNamedAndRemoveUntil(
|
||||||
|
// context, '/mywallets', ModalRoute.withName('/'));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -79,7 +79,7 @@ class ChestOptionsButtons extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ScaledSizedBox(height: 20),
|
// ScaledSizedBox(height: 20),
|
||||||
// InkWell(
|
// InkWell(
|
||||||
// key: keyChangeChest,
|
// key: keyChangeChest,
|
||||||
// onTap: () {
|
// onTap: () {
|
||||||
|
|
|
@ -3,8 +3,8 @@ import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/models/widgets_keys.dart';
|
import 'package:gecko/models/widgets_keys.dart';
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/providers/v2s_datapod.dart';
|
|
||||||
import 'package:gecko/screens/wallet_view.dart';
|
import 'package:gecko/screens/wallet_view.dart';
|
||||||
|
import 'package:gecko/widgets/datapod_avatar.dart';
|
||||||
|
|
||||||
class CertTile extends StatelessWidget {
|
class CertTile extends StatelessWidget {
|
||||||
const CertTile({
|
const CertTile({
|
||||||
|
@ -28,9 +28,8 @@ class CertTile extends StatelessWidget {
|
||||||
key: keyTransaction(keyID++),
|
key: keyTransaction(keyID++),
|
||||||
contentPadding: EdgeInsets.only(
|
contentPadding: EdgeInsets.only(
|
||||||
left: 10, right: 0, top: scaleSize(3), bottom: scaleSize(3)),
|
left: 10, right: 0, top: scaleSize(3), bottom: scaleSize(3)),
|
||||||
leading: ClipOval(
|
leading: DatapodAvatar(
|
||||||
child: V2sDatapodProvider().defaultAvatar(avatarSize),
|
address: repository['address'], size: avatarSize),
|
||||||
),
|
|
||||||
title: Padding(
|
title: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 2),
|
padding: const EdgeInsets.only(bottom: 2),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -4,8 +4,10 @@ import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/queries_indexer.dart';
|
import 'package:gecko/models/queries_indexer.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.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/widgets/cert_tile.dart';
|
import 'package:gecko/widgets/cert_tile.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class CertsList extends StatelessWidget {
|
class CertsList extends StatelessWidget {
|
||||||
const CertsList(
|
const CertsList(
|
||||||
|
@ -18,14 +20,11 @@ class CertsList extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final indexerProvider = Provider.of<DuniterIndexer>(context, listen: false);
|
||||||
final screenHeight = MediaQuery.of(context).size.height;
|
final screenHeight = MediaQuery.of(context).size.height;
|
||||||
final appBarHeight = AppBar().preferredSize.height;
|
final appBarHeight = AppBar().preferredSize.height;
|
||||||
final windowHeight = screenHeight - appBarHeight - (isTall ? 170 : 140);
|
final windowHeight = screenHeight - appBarHeight - (isTall ? 170 : 140);
|
||||||
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$indexerEndpoint/v1/graphql',
|
|
||||||
);
|
|
||||||
|
|
||||||
late String gertCertsReq;
|
late String gertCertsReq;
|
||||||
late String certFrom;
|
late String certFrom;
|
||||||
|
|
||||||
|
@ -37,14 +36,8 @@ class CertsList extends StatelessWidget {
|
||||||
certFrom = 'receiver';
|
certFrom = 'receiver';
|
||||||
}
|
}
|
||||||
|
|
||||||
final client = ValueNotifier(
|
|
||||||
GraphQLClient(
|
|
||||||
cache: GraphQLCache(store: HiveStore()),
|
|
||||||
link: httpLink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return GraphQLProvider(
|
return GraphQLProvider(
|
||||||
client: client,
|
client: ValueNotifier(indexerProvider.indexerClient),
|
||||||
child: Query(
|
child: Query(
|
||||||
options: QueryOptions(
|
options: QueryOptions(
|
||||||
document: gql(gertCertsReq),
|
document: gql(gertCertsReq),
|
||||||
|
@ -53,7 +46,7 @@ class CertsList extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
builder: (QueryResult result, {fetchMore, refetch}) {
|
builder: (QueryResult result, {fetchMore, refetch}) {
|
||||||
if (result.isLoading && result.data == null) {
|
if (result.isLoading || result.data == null) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
);
|
);
|
||||||
|
@ -87,31 +80,39 @@ class CertsList extends StatelessWidget {
|
||||||
final date = DateTime.parse(cert['created_at']);
|
final date = DateTime.parse(cert['created_at']);
|
||||||
final dp = DateTime(date.year, date.month, date.day);
|
final dp = DateTime(date.year, date.month, date.day);
|
||||||
final dateForm = '${dp.day}-${dp.month}-${dp.year}';
|
final dateForm = '${dp.day}-${dp.month}-${dp.year}';
|
||||||
listCerts.add({
|
|
||||||
'address': issuerAddress,
|
// Check if we have a more recent certification, we skip
|
||||||
'name': issuerName,
|
if (!listCerts.any((cert) => cert['address'] == issuerAddress)) {
|
||||||
'date': dateForm
|
listCerts.add({
|
||||||
});
|
'address': issuerAddress,
|
||||||
|
'name': issuerName,
|
||||||
|
'date': dateForm
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build history list
|
// Build history list
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: windowHeight,
|
height: windowHeight,
|
||||||
child: ListView(
|
child: RefreshIndicator(
|
||||||
key: keyListTransactions,
|
color: orangeC,
|
||||||
children: <Widget>[
|
onRefresh: () async => refetch!.call(),
|
||||||
result.data == null
|
child: ListView(
|
||||||
? Column(children: <Widget>[
|
key: keyListTransactions,
|
||||||
ScaledSizedBox(height: 50),
|
children: <Widget>[
|
||||||
Text(
|
result.data == null
|
||||||
"noTransactionToDisplay".tr(),
|
? Column(children: <Widget>[
|
||||||
style: scaledTextStyle(fontSize: 18),
|
ScaledSizedBox(height: 50),
|
||||||
)
|
Text(
|
||||||
])
|
"noTransactionToDisplay".tr(),
|
||||||
: Column(children: <Widget>[
|
style: scaledTextStyle(fontSize: 18),
|
||||||
CertTile(listCerts: listCerts),
|
)
|
||||||
])
|
])
|
||||||
],
|
: Column(children: <Widget>[
|
||||||
|
CertTile(listCerts: listCerts),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -112,7 +112,7 @@ Future<bool?> confirmPopupCertification(BuildContext context, String question1,
|
||||||
child: Text(
|
child: Text(
|
||||||
"yes".tr(),
|
"yes".tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20,
|
fontSize: 19,
|
||||||
color: const Color(0xffD80000),
|
color: const Color(0xffD80000),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -124,7 +124,7 @@ Future<bool?> confirmPopupCertification(BuildContext context, String question1,
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(
|
child: Text(
|
||||||
"no".tr(),
|
"no".tr(),
|
||||||
style: scaledTextStyle(fontSize: 20),
|
style: scaledTextStyle(fontSize: 19),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context, false);
|
Navigator.pop(context, false);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gecko/globals.dart';
|
import 'package:gecko/globals.dart';
|
||||||
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
|
||||||
class Loading extends StatelessWidget {
|
class Loading extends StatelessWidget {
|
||||||
const Loading({
|
const Loading({
|
||||||
|
@ -13,7 +14,7 @@ class Loading extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return ScaledSizedBox(
|
||||||
height: size,
|
height: size,
|
||||||
width: size,
|
width: size,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
|
|
|
@ -48,7 +48,7 @@ class ContactsList extends StatelessWidget {
|
||||||
contentPadding: const EdgeInsets.all(5),
|
contentPadding: const EdgeInsets.all(5),
|
||||||
dense: !isTall,
|
dense: !isTall,
|
||||||
leading: DatapodAvatar(
|
leading: DatapodAvatar(
|
||||||
address: g1Wallet.address, size: scaleSize(50)),
|
address: g1Wallet.address, size: 47),
|
||||||
title: Row(children: <Widget>[
|
title: Row(children: <Widget>[
|
||||||
Text(getShortPubkey(g1Wallet.address),
|
Text(getShortPubkey(g1Wallet.address),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:gecko/globals.dart';
|
||||||
import 'package:gecko/models/queries_datapod.dart';
|
import 'package:gecko/models/queries_datapod.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/providers/v2s_datapod.dart';
|
import 'package:gecko/providers/v2s_datapod.dart';
|
||||||
import 'package:gecko/widgets/commons/loading.dart';
|
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -24,27 +23,17 @@ class DatapodAvatar extends StatelessWidget {
|
||||||
if (cachedImage.existsSync()) {
|
if (cachedImage.existsSync()) {
|
||||||
return ScaledSizedBox(
|
return ScaledSizedBox(
|
||||||
width: size,
|
width: size,
|
||||||
|
height: size,
|
||||||
child: ClipOval(
|
child: ClipOval(
|
||||||
child: datapod.getAvatarLocal(address, size),
|
child: datapod.getAvatarLocal(address),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$datapodEndpoint/v1/graphql',
|
|
||||||
);
|
|
||||||
|
|
||||||
final client = ValueNotifier(
|
|
||||||
GraphQLClient(
|
|
||||||
cache: GraphQLCache(store: HiveStore()),
|
|
||||||
link: httpLink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return ScaledSizedBox(
|
return ScaledSizedBox(
|
||||||
width: size,
|
width: size,
|
||||||
child: GraphQLProvider(
|
child: GraphQLProvider(
|
||||||
client: client,
|
client: ValueNotifier(datapod.datapodClient),
|
||||||
child: Query(
|
child: Query(
|
||||||
options: QueryOptions(
|
options: QueryOptions(
|
||||||
document: gql(getAvatarQ),
|
document: gql(getAvatarQ),
|
||||||
|
@ -53,9 +42,9 @@ class DatapodAvatar extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
builder: (QueryResult result, {fetchMore, refetch}) {
|
builder: (QueryResult result, {fetchMore, refetch}) {
|
||||||
if (result.isLoading) {
|
if (result.isLoading || result.data == null) {
|
||||||
return const Center(
|
return Center(
|
||||||
child: Loading(),
|
child: ClipOval(child: datapod.defaultAvatar(size)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final String? avatar64 =
|
final String? avatar64 =
|
||||||
|
@ -75,8 +64,7 @@ class DatapodAvatar extends StatelessWidget {
|
||||||
return ClipOval(
|
return ClipOval(
|
||||||
child: Image.memory(
|
child: Image.memory(
|
||||||
base64.decode(sanitizedAvatar64),
|
base64.decode(sanitizedAvatar64),
|
||||||
height: size,
|
fit: BoxFit.cover,
|
||||||
fit: BoxFit.fitWidth,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -28,7 +28,7 @@ class HeaderProfile extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final avatarSize = scaleSize(110);
|
const double avatarSize = 110;
|
||||||
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
|
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
|
||||||
final walletOptions =
|
final walletOptions =
|
||||||
Provider.of<WalletOptionsProvider>(context, listen: false);
|
Provider.of<WalletOptionsProvider>(context, listen: false);
|
||||||
|
@ -79,30 +79,37 @@ class HeaderProfile extends StatelessWidget {
|
||||||
]),
|
]),
|
||||||
ScaledSizedBox(height: 15),
|
ScaledSizedBox(height: 15),
|
||||||
Balance(address: address, size: 20),
|
Balance(address: address, size: 20),
|
||||||
ScaledSizedBox(height: 5),
|
ScaledSizedBox(
|
||||||
InkWell(
|
height: 60,
|
||||||
onTap: () => sub.certsCounterCache[address] != null
|
|
||||||
? {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
PageNoTransit(builder: (context) {
|
|
||||||
return CertificationsScreen(
|
|
||||||
address: address,
|
|
||||||
username: duniterIndexer
|
|
||||||
.walletNameIndexer[address] ??
|
|
||||||
'');
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
IdentityStatus(
|
ScaledSizedBox(height: 5),
|
||||||
address: address,
|
InkWell(
|
||||||
isOwner: false,
|
onTap: () => sub.certsCounterCache[address] != null
|
||||||
color: Colors.black),
|
? {
|
||||||
Certifications(address: address, size: 18)
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
PageNoTransit(builder: (context) {
|
||||||
|
return CertificationsScreen(
|
||||||
|
address: address,
|
||||||
|
username: duniterIndexer
|
||||||
|
.walletNameIndexer[address] ??
|
||||||
|
'');
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
IdentityStatus(
|
||||||
|
address: address,
|
||||||
|
isOwner: false,
|
||||||
|
color: Colors.black),
|
||||||
|
Certifications(address: address, size: 18)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,7 +5,9 @@ import 'package:gecko/models/queries_indexer.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.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/substrate_sdk.dart';
|
||||||
import 'package:gecko/widgets/history_view.dart';
|
import 'package:gecko/widgets/history_view.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_in_progress_tile.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -16,11 +18,11 @@ class HistoryQuery extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
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 ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
FetchMoreOptions? opts;
|
FetchMoreOptions? opts;
|
||||||
|
|
||||||
int nPage = 1;
|
|
||||||
int nRepositories = 20;
|
int nRepositories = 20;
|
||||||
|
|
||||||
if (indexerEndpoint == '') {
|
if (indexerEndpoint == '') {
|
||||||
|
@ -34,19 +36,8 @@ class HistoryQuery extends StatelessWidget {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$indexerEndpoint/v1beta1/relay',
|
|
||||||
);
|
|
||||||
|
|
||||||
final client = ValueNotifier(
|
|
||||||
GraphQLClient(
|
|
||||||
cache: GraphQLCache(),
|
|
||||||
link: httpLink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return GraphQLProvider(
|
return GraphQLProvider(
|
||||||
client: client,
|
client: ValueNotifier(duniterIndexer.indexerClient),
|
||||||
child: Expanded(
|
child: Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
@ -57,11 +48,12 @@ class HistoryQuery extends StatelessWidget {
|
||||||
document: gql(getHistoryByAddressQ),
|
document: gql(getHistoryByAddressQ),
|
||||||
variables: <String, dynamic>{
|
variables: <String, dynamic>{
|
||||||
'address': address,
|
'address': address,
|
||||||
'number': 20,
|
'number': nRepositories,
|
||||||
'cursor': null
|
'offset': 0
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
builder: (QueryResult result, {fetchMore, refetch}) {
|
builder: (QueryResult result, {fetchMore, refetch}) {
|
||||||
|
duniterIndexer.refetch = refetch;
|
||||||
if (result.isLoading && result.data == null) {
|
if (result.isLoading && result.data == null) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
|
@ -69,6 +61,7 @@ class HistoryQuery extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final List transactions = result.data?["transaction"];
|
||||||
|
|
||||||
if (result.hasException) {
|
if (result.hasException) {
|
||||||
log.e('Error Indexer: ${result.exception}');
|
log.e('Error Indexer: ${result.exception}');
|
||||||
|
@ -80,8 +73,7 @@ class HistoryQuery extends StatelessWidget {
|
||||||
style: scaledTextStyle(fontSize: 18),
|
style: scaledTextStyle(fontSize: 18),
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
} else if (result
|
} else if (transactions.isEmpty) {
|
||||||
.data?['transaction_connection']?['edges'].isEmpty) {
|
|
||||||
return Column(children: <Widget>[
|
return Column(children: <Widget>[
|
||||||
ScaledSizedBox(height: 50),
|
ScaledSizedBox(height: 50),
|
||||||
Text(
|
Text(
|
||||||
|
@ -91,47 +83,57 @@ class HistoryQuery extends StatelessWidget {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.isNotLoading) {
|
final int totalTransactions =
|
||||||
if (duniterIndexer.fetchMoreCursor == null) nPage = 1;
|
result.data!["transaction_aggregate"]["aggregate"]["count"];
|
||||||
|
duniterIndexer.hasNextPage =
|
||||||
|
!(transactions.length == totalTransactions);
|
||||||
|
|
||||||
if (nPage <= 3) {
|
opts = duniterIndexer.mergeQueryResult(
|
||||||
nRepositories = 20;
|
transactions: transactions,
|
||||||
} else if (nPage <= 6) {
|
opts: opts,
|
||||||
nRepositories = 40;
|
address: address,
|
||||||
} else if (nPage <= 12) {
|
nRepositories: nRepositories,
|
||||||
nRepositories = 80;
|
offset: transactions.length,
|
||||||
} else {
|
);
|
||||||
nRepositories = 120;
|
|
||||||
|
// Get transaction in progress if exist
|
||||||
|
String? transactionId;
|
||||||
|
for (final entry in sub.transactionStatus.entries) {
|
||||||
|
if (entry.value.from == address) {
|
||||||
|
transactionId = entry.key;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
nPage++;
|
|
||||||
opts = duniterIndexer.mergeQueryResult(
|
|
||||||
result, opts, address, nRepositories);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build history list
|
// Build history list
|
||||||
return NotificationListener(
|
return NotificationListener(
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => Expanded(
|
builder: (context) => Expanded(
|
||||||
child: ListView(
|
child: RefreshIndicator(
|
||||||
key: keyListTransactions,
|
color: orangeC,
|
||||||
controller: scrollController,
|
onRefresh: () async => refetch!.call(),
|
||||||
children: <Widget>[
|
child: ListView(
|
||||||
HistoryView(
|
key: keyListTransactions,
|
||||||
result: result,
|
controller: scrollController,
|
||||||
address: address,
|
children: <Widget>[
|
||||||
)
|
if (transactionId != null)
|
||||||
],
|
TransactionInProgressTule(
|
||||||
|
address: address,
|
||||||
|
transactionId: transactionId),
|
||||||
|
HistoryView(
|
||||||
|
result: result,
|
||||||
|
address: address,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onNotification: (dynamic t) {
|
onNotification: (dynamic t) {
|
||||||
if (duniterIndexer.pageInfo == null) {
|
|
||||||
duniterIndexer.reload();
|
|
||||||
}
|
|
||||||
if (t is ScrollEndNotification &&
|
if (t is ScrollEndNotification &&
|
||||||
scrollController.position.pixels >=
|
scrollController.position.pixels >=
|
||||||
scrollController.position.maxScrollExtent * 0.7 &&
|
scrollController.position.maxScrollExtent * 0.7 &&
|
||||||
duniterIndexer.pageInfo!['hasNextPage'] &&
|
duniterIndexer.hasNextPage &&
|
||||||
result.isNotLoading) {
|
result.isNotLoading) {
|
||||||
fetchMore!(opts!);
|
fetchMore!(opts!);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/providers/duniter_indexer.dart';
|
import 'package:gecko/providers/duniter_indexer.dart';
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/screens/wallet_view.dart';
|
import 'package:gecko/screens/wallet_view.dart';
|
||||||
|
import 'package:gecko/widgets/commons/loading.dart';
|
||||||
import 'package:gecko/widgets/page_route_no_transition.dart';
|
import 'package:gecko/widgets/page_route_no_transition.dart';
|
||||||
import 'package:gecko/widgets/transaction_tile.dart';
|
import 'package:gecko/widgets/transaction_tile.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
@ -34,13 +35,14 @@ class HistoryView extends StatelessWidget {
|
||||||
ScaledSizedBox(height: 50),
|
ScaledSizedBox(height: 50),
|
||||||
Text(
|
Text(
|
||||||
"noTransactionToDisplay".tr(),
|
"noTransactionToDisplay".tr(),
|
||||||
style: scaledTextStyle(fontSize: 18),
|
style: scaledTextStyle(fontSize: 17),
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
: Column(children: <Widget>[
|
: Column(children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
children: duniterIndexer.transBC!.map((repository) {
|
children: duniterIndexer.transBC!.map((repository) {
|
||||||
final answer = computeHistoryView(repository, address);
|
final answer =
|
||||||
|
duniterIndexer.computeHistoryView(repository, address);
|
||||||
pastDelimiters.add(answer['dateDelimiter']);
|
pastDelimiters.add(answer['dateDelimiter']);
|
||||||
|
|
||||||
bool isMigrationTime = false;
|
bool isMigrationTime = false;
|
||||||
|
@ -52,23 +54,24 @@ class HistoryView extends StatelessWidget {
|
||||||
return Column(children: <Widget>[
|
return Column(children: <Widget>[
|
||||||
if (isMigrationTime)
|
if (isMigrationTime)
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: scaleSize(23)),
|
padding: EdgeInsets.only(
|
||||||
|
top: scaleSize(25), bottom: scaleSize(15)),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Image(
|
Image(
|
||||||
image: const AssetImage('assets/party.png'),
|
image: const AssetImage('assets/party.png'),
|
||||||
height: scaleSize(32)),
|
height: scaleSize(31)),
|
||||||
Text(
|
Text(
|
||||||
'blockchainStart'.tr(),
|
'blockchainStart'.tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: Colors.blueAccent,
|
color: Colors.blueAccent,
|
||||||
fontWeight: FontWeight.w500),
|
fontWeight: FontWeight.w400),
|
||||||
),
|
),
|
||||||
Image(
|
Image(
|
||||||
image: const AssetImage('assets/party.png'),
|
image: const AssetImage('assets/party.png'),
|
||||||
height: scaleSize(32)),
|
height: scaleSize(31)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -96,14 +99,14 @@ class HistoryView extends StatelessWidget {
|
||||||
context: context),
|
context: context),
|
||||||
]);
|
]);
|
||||||
}).toList()),
|
}).toList()),
|
||||||
if (result.isLoading && duniterIndexer.pageInfo!['hasPreviousPage'])
|
if (result.isLoading && duniterIndexer.hasNextPage)
|
||||||
const Row(
|
const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
CircularProgressIndicator(),
|
Loading(size: 30, stroke: 3),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (!duniterIndexer.pageInfo!['hasNextPage'] &&
|
if (!duniterIndexer.hasNextPage &&
|
||||||
sub.oldOwnerKeys[address]?[0] != null)
|
sub.oldOwnerKeys[address]?[0] != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 30),
|
padding: const EdgeInsets.symmetric(vertical: 30),
|
||||||
|
@ -127,7 +130,7 @@ class HistoryView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Column(children: [
|
Column(children: [
|
||||||
Text(
|
Text(
|
||||||
'Identité migré:'.tr(),
|
'identityMigrated'.tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: Colors.green[700],
|
color: Colors.green[700],
|
||||||
|
@ -149,14 +152,22 @@ class HistoryView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!duniterIndexer.pageInfo!['hasNextPage'])
|
if (!duniterIndexer.hasNextPage)
|
||||||
Column(
|
Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ScaledSizedBox(height: 15),
|
ScaledSizedBox(height: 15),
|
||||||
Text("historyStart".tr(),
|
Row(
|
||||||
textAlign: TextAlign.center,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
style: scaledTextStyle(fontSize: 20)),
|
children: [
|
||||||
ScaledSizedBox(height: 15)
|
Icon(Icons.blur_on_outlined, size: scaleSize(31)),
|
||||||
|
Text("historyStart".tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: scaledTextStyle(
|
||||||
|
fontSize: 20, fontWeight: FontWeight.w300)),
|
||||||
|
Icon(Icons.blur_on_outlined, size: scaleSize(31)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ScaledSizedBox(height: 30)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/models/wallet_data.dart';
|
import 'package:gecko/models/wallet_data.dart';
|
||||||
import 'package:gecko/providers/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/widgets/commons/animated_text.dart';
|
import 'package:gecko/widgets/commons/animated_text.dart';
|
||||||
|
import 'package:gecko/widgets/commons/loading.dart';
|
||||||
import 'package:gecko/widgets/name_by_address.dart';
|
import 'package:gecko/widgets/name_by_address.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -28,6 +29,13 @@ class IdentityStatus extends StatelessWidget {
|
||||||
future: sub.idtyStatus([address]),
|
future: sub.idtyStatus([address]),
|
||||||
initialData: [walletData.identityStatus],
|
initialData: [walletData.identityStatus],
|
||||||
builder: (context, AsyncSnapshot<List<IdtyStatus>> snapshot) {
|
builder: (context, AsyncSnapshot<List<IdtyStatus>> snapshot) {
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) {
|
||||||
|
return const Loading(size: 18);
|
||||||
|
} else if (snapshot.hasError || snapshot.data == null) {
|
||||||
|
log.e(snapshot.error);
|
||||||
|
return const Icon(Icons.close, color: Colors.red);
|
||||||
|
}
|
||||||
|
|
||||||
final resStatus = snapshot.data!.first;
|
final resStatus = snapshot.data!.first;
|
||||||
walletData.identityStatus = resStatus;
|
walletData.identityStatus = resStatus;
|
||||||
walletBox.put(address, walletData);
|
walletBox.put(address, walletData);
|
||||||
|
@ -51,7 +59,7 @@ class IdentityStatus extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<IdtyStatus, String> statusText = {
|
final Map<IdtyStatus, String> statusText = {
|
||||||
IdtyStatus.none: 'noIdentity'.tr(),
|
IdtyStatus.none: '',
|
||||||
IdtyStatus.created: 'identityCreated'.tr(),
|
IdtyStatus.created: 'identityCreated'.tr(),
|
||||||
IdtyStatus.confirmed: 'identityConfirmed'.tr(),
|
IdtyStatus.confirmed: 'identityConfirmed'.tr(),
|
||||||
IdtyStatus.validated: 'memberValidated'.tr(),
|
IdtyStatus.validated: 'memberValidated'.tr(),
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:gecko/models/queries_indexer.dart';
|
||||||
import 'package:gecko/models/scale_functions.dart';
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
import 'package:gecko/models/wallet_data.dart';
|
import 'package:gecko/models/wallet_data.dart';
|
||||||
import 'package:gecko/providers/duniter_indexer.dart';
|
import 'package:gecko/providers/duniter_indexer.dart';
|
||||||
|
import 'package:gecko/widgets/commons/loading.dart';
|
||||||
import 'package:gecko/widgets/wallet_name.dart';
|
import 'package:gecko/widgets/wallet_name.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -34,22 +35,8 @@ class NameByAddress extends StatelessWidget {
|
||||||
return WalletName(wallet: wallet, size: size, color: color);
|
return WalletName(wallet: wallet, size: size, color: color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (g1WalletsBox.get(wallet.address)?.username != null) {
|
|
||||||
// return Text(g1WalletsBox.get(wallet.address)!.username!);
|
|
||||||
// }
|
|
||||||
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$indexerEndpoint/v1/graphql',
|
|
||||||
);
|
|
||||||
|
|
||||||
final client = ValueNotifier(
|
|
||||||
GraphQLClient(
|
|
||||||
cache: GraphQLCache(store: HiveStore()),
|
|
||||||
link: httpLink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return GraphQLProvider(
|
return GraphQLProvider(
|
||||||
client: client,
|
client: ValueNotifier(duniterIndexer.indexerClient),
|
||||||
child: Query(
|
child: Query(
|
||||||
options: QueryOptions(
|
options: QueryOptions(
|
||||||
document: gql(getNameByAddressQ),
|
document: gql(getNameByAddressQ),
|
||||||
|
@ -66,7 +53,7 @@ class NameByAddress extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.isLoading) {
|
if (result.isLoading) {
|
||||||
return const Text('Loading');
|
return const Loading();
|
||||||
}
|
}
|
||||||
|
|
||||||
duniterIndexer.walletNameIndexer[wallet.address] =
|
duniterIndexer.walletNameIndexer[wallet.address] =
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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/providers/wallets_profiles.dart';
|
||||||
|
import 'package:gecko/screens/activity.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/balance.dart';
|
import 'package:gecko/widgets/balance.dart';
|
||||||
|
@ -54,13 +55,17 @@ void paymentPopup(BuildContext context, String toAddress, String? username) {
|
||||||
destAddress: toAddress,
|
destAddress: toAddress,
|
||||||
amount: double.parse(walletViewProvider.payAmount.text),
|
amount: double.parse(walletViewProvider.payAmount.text),
|
||||||
password: myWalletProvider.pinCode);
|
password: myWalletProvider.pinCode);
|
||||||
|
|
||||||
|
const legacyMonitor = false;
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) {
|
MaterialPageRoute(builder: (context) {
|
||||||
return TransactionInProgress(
|
return legacyMonitor
|
||||||
transactionId: transactionId,
|
? TransactionInProgress(
|
||||||
toAddress: toAddress,
|
transactionId: transactionId,
|
||||||
toUsername: username);
|
toAddress: toAddress,
|
||||||
|
toUsername: username)
|
||||||
|
: ActivityScreen(address: acc.address!);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +136,7 @@ void paymentPopup(BuildContext context, String toAddress, String? username) {
|
||||||
Text(
|
Text(
|
||||||
'executeATransfer'.tr(),
|
'executeATransfer'.tr(),
|
||||||
style: scaledTextStyle(
|
style: scaledTextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.w700),
|
fontSize: 19, fontWeight: FontWeight.w700),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
key: keyPopButton,
|
key: keyPopButton,
|
||||||
|
|
|
@ -29,19 +29,8 @@ class SearchIdentityQuery extends StatelessWidget {
|
||||||
return Text('noResult'.tr());
|
return Text('noResult'.tr());
|
||||||
}
|
}
|
||||||
|
|
||||||
final httpLink = HttpLink(
|
|
||||||
'$indexerEndpoint/v1/graphql',
|
|
||||||
);
|
|
||||||
|
|
||||||
final client = ValueNotifier(
|
|
||||||
GraphQLClient(
|
|
||||||
cache: GraphQLCache(
|
|
||||||
store: HiveStore()), // GraphQLCache(store: HiveStore())
|
|
||||||
link: httpLink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return GraphQLProvider(
|
return GraphQLProvider(
|
||||||
client: client,
|
client: ValueNotifier(duniterIndexer.indexerClient),
|
||||||
child: Query(
|
child: Query(
|
||||||
options: QueryOptions(
|
options: QueryOptions(
|
||||||
document: gql(searchAddressByNameQ),
|
document: gql(searchAddressByNameQ),
|
||||||
|
@ -74,7 +63,7 @@ class SearchIdentityQuery extends StatelessWidget {
|
||||||
|
|
||||||
searchProvider.resultLenght = identities.length;
|
searchProvider.resultLenght = identities.length;
|
||||||
|
|
||||||
final avatarSize = scaleSize(45);
|
const double avatarSize = 45;
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: ListView(children: <Widget>[
|
child: ListView(children: <Widget>[
|
||||||
for (Map profile in identities)
|
for (Map profile in identities)
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gecko/globals.dart';
|
||||||
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
import 'package:gecko/models/transaction_content.dart';
|
||||||
|
import 'package:gecko/providers/duniter_indexer.dart';
|
||||||
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
|
import 'package:gecko/widgets/datapod_avatar.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status_icon.dart';
|
||||||
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:fade_and_translate/fade_and_translate.dart';
|
||||||
|
|
||||||
|
class TransactionInProgressTule extends StatefulWidget {
|
||||||
|
const TransactionInProgressTule(
|
||||||
|
{Key? key, required this.address, this.transactionId})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
final String? transactionId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TransactionInProgressTule> createState() =>
|
||||||
|
_TransactionInProgressTuleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TransactionInProgressTuleState extends State<TransactionInProgressTule> {
|
||||||
|
late bool isVisible;
|
||||||
|
late TransactionContent txContent;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
isVisible = true;
|
||||||
|
StreamSubscription<QueryResult>? subscription;
|
||||||
|
final sub = Provider.of<SubstrateSdk>(context, listen: false);
|
||||||
|
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
|
||||||
|
final stream = duniterIndexer.subscribeHistoryIssued(widget.address);
|
||||||
|
txContent = sub.transactionStatus[widget.transactionId]!;
|
||||||
|
|
||||||
|
subscription = stream.listen((result) {
|
||||||
|
if (result.hasException) {
|
||||||
|
log.e(result.exception);
|
||||||
|
isVisible = true;
|
||||||
|
} else {
|
||||||
|
final Map transData =
|
||||||
|
result.data?['account_by_pk']['transactions_issued'].first;
|
||||||
|
final String receiver = transData['receiver_pubkey'];
|
||||||
|
final double amount = transData['amount'] / 100;
|
||||||
|
final createdAt = DateTime.parse(transData['created_at']);
|
||||||
|
final difference = createdAt.difference(DateTime.now());
|
||||||
|
|
||||||
|
if (receiver == txContent.to &&
|
||||||
|
amount == txContent.amount &&
|
||||||
|
difference.inSeconds.abs() < 30) {
|
||||||
|
isVisible = false;
|
||||||
|
txContent.status = TransactionStatus.finalized;
|
||||||
|
sub.reload();
|
||||||
|
subscription?.cancel();
|
||||||
|
} else {
|
||||||
|
isVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
|
||||||
|
return Consumer<SubstrateSdk>(builder: (context, sub, _) {
|
||||||
|
final statusIcon =
|
||||||
|
TransactionStatusIcon(txContent.status, size: 21, stroke: 2);
|
||||||
|
String humanStatus = '';
|
||||||
|
final finalAmount = txContent.amount * -1;
|
||||||
|
|
||||||
|
if (txContent.status == TransactionStatus.success) {
|
||||||
|
humanStatus = 'extrinsicValidated'.tr(args: [actionMap['pay']!]);
|
||||||
|
} else if (txContent.status == TransactionStatus.failed) {
|
||||||
|
humanStatus = errorTransactionMap[txContent.error] ?? txContent.error!;
|
||||||
|
} else {
|
||||||
|
humanStatus = statusStatusMap[txContent.status] ??
|
||||||
|
'Unknown status: ${txContent.status}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return FadeAndTranslate(
|
||||||
|
visible: isVisible,
|
||||||
|
translate: const Offset(0, -40),
|
||||||
|
delay: const Duration(seconds: 2),
|
||||||
|
duration: const Duration(milliseconds: 700),
|
||||||
|
onCompleted: () async => duniterIndexer.refetch?.call(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
color: orangeC,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
'Transaction en cours',
|
||||||
|
style: scaledTextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
key: const Key('transactionInProgress'),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 5, vertical: 15),
|
||||||
|
leading: DatapodAvatar(address: txContent.to, size: 50),
|
||||||
|
title: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 5),
|
||||||
|
child: Text(getShortPubkey(txContent.to),
|
||||||
|
style: scaledTextStyle(
|
||||||
|
fontSize: 17, fontFamily: 'Monospace')),
|
||||||
|
),
|
||||||
|
subtitle: Row(
|
||||||
|
children: [
|
||||||
|
statusIcon,
|
||||||
|
ScaledSizedBox(width: 10),
|
||||||
|
ScaledSizedBox(
|
||||||
|
width: 160,
|
||||||
|
child: Text(
|
||||||
|
humanStatus,
|
||||||
|
style: scaledTextStyle(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleLarge!
|
||||||
|
.color,
|
||||||
|
fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
trailing: Text("$finalAmount $currencyName",
|
||||||
|
style: scaledTextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.blue[700]),
|
||||||
|
textAlign: TextAlign.justify),
|
||||||
|
dense: !isTall,
|
||||||
|
isThreeLine: false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
|
enum TransactionStatus {
|
||||||
|
sending,
|
||||||
|
propagation,
|
||||||
|
validating,
|
||||||
|
failed,
|
||||||
|
success,
|
||||||
|
timeout,
|
||||||
|
finalized,
|
||||||
|
none
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> actionMap = {
|
||||||
|
'pay': 'transaction'.tr(),
|
||||||
|
'cert': 'certification'.tr(),
|
||||||
|
'comfirmIdty': 'identityConfirm'.tr(),
|
||||||
|
'revokeIdty': 'revokeAdhesion'.tr(),
|
||||||
|
'identityMigration': 'identityMigration'.tr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<TransactionStatus, String> statusStatusMap = {
|
||||||
|
TransactionStatus.none: 'noTransaction'.tr(),
|
||||||
|
TransactionStatus.sending: 'sending'.tr(),
|
||||||
|
TransactionStatus.propagation: 'propagating'.tr(),
|
||||||
|
TransactionStatus.validating: 'validating'.tr(),
|
||||||
|
TransactionStatus.success: 'extrinsicValidated'.tr(args: [actionMap['pay']!]),
|
||||||
|
TransactionStatus.finalized:
|
||||||
|
'extrinsicFinalized'.tr(args: [actionMap['pay']!]),
|
||||||
|
TransactionStatus.timeout: 'execTimeoutOver'.tr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, String> errorTransactionMap = {
|
||||||
|
'cert.NotRespectCertPeriod': '24hbetweenCerts'.tr(),
|
||||||
|
'identity.CreatorNotAllowedToCreateIdty': '24hbetweenCerts'.tr(),
|
||||||
|
'cert.CannotCertifySelf': 'canNotCertifySelf'.tr(),
|
||||||
|
'identity.IdtyNameAlreadyExist': 'nameAlreadyExist'.tr(),
|
||||||
|
'balances.KeepAlive': '2GDtoKeepAlive'.tr(),
|
||||||
|
'1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low':
|
||||||
|
'youHaveToFeedThisAccountBeforeUsing'.tr(),
|
||||||
|
'Token.FundsUnavailable': 'fundsUnavailable'.tr(),
|
||||||
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gecko/models/scale_functions.dart';
|
||||||
|
import 'package:gecko/widgets/commons/loading.dart';
|
||||||
|
import 'package:gecko/widgets/transaction_status.dart';
|
||||||
|
|
||||||
|
class TransactionStatusIcon extends StatelessWidget {
|
||||||
|
const TransactionStatusIcon(this.status,
|
||||||
|
{Key? key, this.size = 32, this.stroke = 3})
|
||||||
|
: super(key: key);
|
||||||
|
final TransactionStatus status;
|
||||||
|
final double size;
|
||||||
|
final double stroke;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
switch (status) {
|
||||||
|
case TransactionStatus.sending:
|
||||||
|
case TransactionStatus.propagation:
|
||||||
|
case TransactionStatus.validating:
|
||||||
|
return Loading(size: size, stroke: stroke);
|
||||||
|
case TransactionStatus.success:
|
||||||
|
return Icon(
|
||||||
|
Icons.done,
|
||||||
|
size: scaleSize(size),
|
||||||
|
color: Colors.green,
|
||||||
|
);
|
||||||
|
case TransactionStatus.finalized:
|
||||||
|
return Icon(
|
||||||
|
Icons.done_all,
|
||||||
|
size: scaleSize(size),
|
||||||
|
color: Colors.green,
|
||||||
|
);
|
||||||
|
case TransactionStatus.failed:
|
||||||
|
case TransactionStatus.timeout:
|
||||||
|
return Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: scaleSize(size),
|
||||||
|
color: Colors.red,
|
||||||
|
);
|
||||||
|
case TransactionStatus.none:
|
||||||
|
default:
|
||||||
|
return ScaledSizedBox(height: size, width: size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import 'package:gecko/models/scale_functions.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/substrate_sdk.dart';
|
import 'package:gecko/providers/substrate_sdk.dart';
|
||||||
import 'package:gecko/providers/v2s_datapod.dart';
|
|
||||||
import 'package:gecko/screens/wallet_view.dart';
|
import 'package:gecko/screens/wallet_view.dart';
|
||||||
|
import 'package:gecko/widgets/datapod_avatar.dart';
|
||||||
import 'package:gecko/widgets/page_route_no_transition.dart';
|
import 'package:gecko/widgets/page_route_no_transition.dart';
|
||||||
|
|
||||||
class TransactionTile extends StatelessWidget {
|
class TransactionTile extends StatelessWidget {
|
||||||
|
@ -39,9 +39,7 @@ class TransactionTile extends StatelessWidget {
|
||||||
key: keyTransaction(newKey),
|
key: keyTransaction(newKey),
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
|
const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
|
||||||
leading: ClipOval(
|
leading: DatapodAvatar(address: repository[1], size: avatarSize),
|
||||||
child: V2sDatapodProvider().defaultAvatar(avatarSize),
|
|
||||||
),
|
|
||||||
title: Padding(
|
title: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 5),
|
padding: const EdgeInsets.only(bottom: 5),
|
||||||
child: Text(getShortPubkey(repository[1]),
|
child: Text(getShortPubkey(repository[1]),
|
||||||
|
|
|
@ -417,6 +417,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.1+3"
|
version: "0.0.1+3"
|
||||||
|
fade_and_translate:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fade_and_translate
|
||||||
|
sha256: d5ebb7279e00cbef6da9391e15976f0348d3deceb2aee0ed172c23a736fa5dd4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -5,7 +5,7 @@ description: Pay with G1.
|
||||||
# pub.dev using `pub publish`. This is preferred for private packages.
|
# pub.dev using `pub publish`. This is preferred for private packages.
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 0.1.3+63
|
version: 0.1.4+66
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.12.0 <3.0.0"
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
@ -59,6 +59,7 @@ dependencies:
|
||||||
crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
screen_brightness: ^0.2.2+1
|
screen_brightness: ^0.2.2+1
|
||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
|
fade_and_translate: ^0.1.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
# flutter_launcher_icons: ^0.9.2
|
# flutter_launcher_icons: ^0.9.2
|
||||||
|
|
Loading…
Reference in New Issue