Skip to content
Snippets Groups Projects
Commit b43a5fcd authored by poka's avatar poka
Browse files

feat: check indexer and node sync

parent 0e38099f
No related branches found
No related tags found
No related merge requests found
Pipeline #38189 waiting for manual action
const String getNameByAddressQ = r''' const getNameByAddressQ = r'''
query ($address: String!) { query ($address: String!) {
identityConnection( identityConnection(
where: { accountId: { _eq: $address } } where: { accountId: { _eq: $address } }
...@@ -14,7 +14,7 @@ query ($address: String!) { ...@@ -14,7 +14,7 @@ query ($address: String!) {
} }
'''; ''';
const String searchAddressByNameQ = r''' const searchAddressByNameQ = r'''
query ($name: String!) { query ($name: String!) {
identityConnection( identityConnection(
where: { name: { _ilike: $name } } where: { name: { _ilike: $name } }
...@@ -30,7 +30,7 @@ query ($name: String!) { ...@@ -30,7 +30,7 @@ query ($name: String!) {
} }
'''; ''';
const String getHistoryByAddressRelayQ = r''' const getHistoryByAddressRelayQ = r'''
query ($address: String!, $first: Int!, $after: String) { query ($address: String!, $first: Int!, $after: String) {
transferConnection( transferConnection(
after: $after after: $after
...@@ -64,7 +64,7 @@ query ($address: String!, $first: Int!, $after: String) { ...@@ -64,7 +64,7 @@ query ($address: String!, $first: Int!, $after: String) {
} }
'''; ''';
const String getCertsReceived = r''' const getCertsReceived = r'''
query ($address: String!) { query ($address: String!) {
certConnection( certConnection(
where: {receiver: {accountId: {_eq: $address}}} where: {receiver: {accountId: {_eq: $address}}}
...@@ -88,7 +88,7 @@ query ($address: String!) { ...@@ -88,7 +88,7 @@ query ($address: String!) {
} }
'''; ''';
const String getCertsSent = r''' const getCertsSent = r'''
query ($address: String!) { query ($address: String!) {
certConnection( certConnection(
where: {issuer: {accountId: {_eq: $address}}} where: {issuer: {accountId: {_eq: $address}}}
...@@ -112,7 +112,7 @@ query ($address: String!) { ...@@ -112,7 +112,7 @@ query ($address: String!) {
} }
'''; ''';
const String isIdtyExistQ = r''' const isIdtyExistQ = r'''
query ($name: String!) { query ($name: String!) {
identityConnection(where: {name: {_eq: ""}}) { identityConnection(where: {name: {_eq: ""}}) {
edges { edges {
...@@ -124,7 +124,7 @@ query ($name: String!) { ...@@ -124,7 +124,7 @@ query ($name: String!) {
} }
'''; ''';
const String getBlockchainStartQ = r''' const getBlockchainStartQ = r'''
query { query {
blockConnection(first: 1) { blockConnection(first: 1) {
edges { edges {
...@@ -137,7 +137,7 @@ query { ...@@ -137,7 +137,7 @@ query {
} }
'''; ''';
const String subscribeHistoryIssuedQ = r''' const subscribeHistoryIssuedQ = r'''
subscription ($address: String!) { subscription ($address: String!) {
accountConnection( accountConnection(
where: {id: {_eq: $address}} where: {id: {_eq: $address}}
...@@ -155,3 +155,11 @@ subscription ($address: String!) { ...@@ -155,3 +155,11 @@ subscription ($address: String!) {
} }
} }
'''; ''';
const getBlockByHash = r'''
query ($hash: bytea!) {
block(where: {hash: {_eq: $hash}}) {
height
}
}
''';
...@@ -8,6 +8,7 @@ import 'package:gecko/globals.dart'; ...@@ -8,6 +8,7 @@ import 'package:gecko/globals.dart';
import 'package:gecko/models/queries_indexer.dart'; import 'package:gecko/models/queries_indexer.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';
class DuniterIndexer with ChangeNotifier { class DuniterIndexer with ChangeNotifier {
Map<String, String?> walletNameIndexer = {}; Map<String, String?> walletNameIndexer = {};
...@@ -29,8 +30,7 @@ class DuniterIndexer with ChangeNotifier { ...@@ -29,8 +30,7 @@ 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 = final request = await client.postUrl(Uri.parse('https://$endpoint/v1beta1/relay'));
await client.postUrl(Uri.parse('https://$endpoint/v1beta1/relay'));
final response = await request.close(); final response = await request.close();
if (response.statusCode != 200) { if (response.statusCode != 200) {
log.w('Indexer $endpoint is offline'); log.w('Indexer $endpoint is offline');
...@@ -39,6 +39,12 @@ class DuniterIndexer with ChangeNotifier { ...@@ -39,6 +39,12 @@ class DuniterIndexer with ChangeNotifier {
notifyListeners(); notifyListeners();
return false; return false;
} else { } else {
final isSynced = await isIndexerSynced('https://$endpoint/v1/graphql');
if (!isSynced) {
log.e('This endpoint is not synced, next');
return false;
}
indexerEndpoint = endpoint; indexerEndpoint = endpoint;
await configBox.put('indexerEndpoint', endpoint); await configBox.put('indexerEndpoint', endpoint);
// await configBox.put('customEndpoint', endpoint); // await configBox.put('customEndpoint', endpoint);
...@@ -60,9 +66,7 @@ class DuniterIndexer with ChangeNotifier { ...@@ -60,9 +66,7 @@ class DuniterIndexer with ChangeNotifier {
Future<String> getValidIndexerEndpoint() async { Future<String> getValidIndexerEndpoint() async {
// await configBox.delete('indexerEndpoint'); // await configBox.delete('indexerEndpoint');
listIndexerEndpoints = await rootBundle listIndexerEndpoints = await rootBundle.loadString('config/indexer_endpoints.json').then((jsonStr) => jsonDecode(jsonStr));
.loadString('config/indexer_endpoints.json')
.then((jsonStr) => jsonDecode(jsonStr));
// _listEndpoints.shuffle(); // _listEndpoints.shuffle();
listIndexerEndpoints.add('Personnalisé'); listIndexerEndpoints.add('Personnalisé');
...@@ -71,8 +75,7 @@ class DuniterIndexer with ChangeNotifier { ...@@ -71,8 +75,7 @@ class DuniterIndexer with ChangeNotifier {
return configBox.get('customIndexer'); return configBox.get('customIndexer');
} }
if (configBox.containsKey('indexerEndpoint') && if (configBox.containsKey('indexerEndpoint') && listIndexerEndpoints.contains(configBox.get('indexerEndpoint'))) {
listIndexerEndpoints.contains(configBox.get('indexerEndpoint'))) {
if (await checkIndexerEndpoint(configBox.get('indexerEndpoint'))) { if (await checkIndexerEndpoint(configBox.get('indexerEndpoint'))) {
return configBox.get('indexerEndpoint'); return configBox.get('indexerEndpoint');
} }
...@@ -104,6 +107,15 @@ class DuniterIndexer with ChangeNotifier { ...@@ -104,6 +107,15 @@ class DuniterIndexer with ChangeNotifier {
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();
final isSynced = await isIndexerSynced('https://${listIndexerEndpoints[i]}/v1/graphql');
if (!isSynced) {
log.e('This endpoint is not synced, next');
statusCode = 40;
i++;
continue;
}
indexerEndpoint = listIndexerEndpoints[i]; indexerEndpoint = listIndexerEndpoints[i];
await configBox.put('indexerEndpoint', listIndexerEndpoints[i]); await configBox.put('indexerEndpoint', listIndexerEndpoints[i]);
...@@ -131,6 +143,37 @@ class DuniterIndexer with ChangeNotifier { ...@@ -131,6 +143,37 @@ class DuniterIndexer with ChangeNotifier {
return indexerEndpoint; return indexerEndpoint;
} }
Future<bool> isIndexerSynced(String endpoint) async {
try {
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
var duniterFinilizedHash = await sub.getLastFinilizedHash();
final duniterFinilizedNumber = await sub.getBlockNumberByHash(duniterFinilizedHash);
duniterFinilizedHash = "\\x${duniterFinilizedHash.substring(2)}";
final indexerLink = HttpLink(endpoint);
final iClient = GraphQLClient(
cache: GraphQLCache(),
link: indexerLink,
);
final result = await iClient.query(QueryOptions(document: gql(getBlockByHash), variables: <String, dynamic>{'hash': duniterFinilizedHash}));
if (result.hasException || result.data == null || result.data!['block'].isEmpty) {
log.e('Indexer is not synced: ${result.exception} -- ${result.data}');
return false;
}
final indexerFinilizedNumber = result.data!['block'][0]['height'] as int;
if (duniterFinilizedNumber != indexerFinilizedNumber) {
log.e('Indexer is not synced');
return false;
}
return true;
} catch (e) {
log.e('An error occured while checking indexer sync: $e');
return false;
}
}
List parseHistory(List blockchainTX, String address) { List parseHistory(List blockchainTX, String address) {
List transBC = []; List transBC = [];
int i = 0; int i = 0;
...@@ -159,10 +202,8 @@ class DuniterIndexer with ChangeNotifier { ...@@ -159,10 +202,8 @@ class DuniterIndexer with ChangeNotifier {
return transBC; return transBC;
} }
FetchMoreOptions? mergeQueryResult(QueryResult result, FetchMoreOptions? opts, FetchMoreOptions? mergeQueryResult(QueryResult result, FetchMoreOptions? opts, String address, int nRepositories) {
String address, int nRepositories) { final List<dynamic> blockchainTX = (result.data!['transferConnection']['edges'] as List<dynamic>);
final List<dynamic> blockchainTX =
(result.data!['transferConnection']['edges'] as List<dynamic>);
pageInfo = result.data!['transferConnection']['pageInfo']; pageInfo = result.data!['transferConnection']['pageInfo'];
fetchMoreCursor = pageInfo!['endCursor']; fetchMoreCursor = pageInfo!['endCursor'];
...@@ -174,10 +215,8 @@ class DuniterIndexer with ChangeNotifier { ...@@ -174,10 +215,8 @@ class DuniterIndexer with ChangeNotifier {
variables: {'after': fetchMoreCursor, 'first': nRepositories}, variables: {'after': fetchMoreCursor, 'first': nRepositories},
updateQuery: (previousResultData, fetchMoreResultData) { updateQuery: (previousResultData, fetchMoreResultData) {
final List<dynamic> repos = [ final List<dynamic> repos = [
...previousResultData!['transferConnection']['edges'] ...previousResultData!['transferConnection']['edges'] as List<dynamic>,
as List<dynamic>, ...fetchMoreResultData!['transferConnection']['edges'] as List<dynamic>
...fetchMoreResultData!['transferConnection']['edges']
as List<dynamic>
]; ];
fetchMoreResultData['transferConnection']['edges'] = repos; fetchMoreResultData['transferConnection']['edges'] = repos;
...@@ -213,16 +252,14 @@ class DuniterIndexer with ChangeNotifier { ...@@ -213,16 +252,14 @@ class DuniterIndexer with ChangeNotifier {
Future<DateTime> getBlockStart() async { Future<DateTime> getBlockStart() async {
final result = await _execQuery(getBlockchainStartQ, {}); final result = await _execQuery(getBlockchainStartQ, {});
if (!result.hasException) { if (!result.hasException) {
startBlockchainTime = DateTime.parse( startBlockchainTime = DateTime.parse(result.data!['blockConnection']['edges'][0]['node']['timestamp']);
result.data!['blockConnection']['edges'][0]['node']['timestamp']);
startBlockchainInitialized = true; startBlockchainInitialized = true;
return startBlockchainTime; return startBlockchainTime;
} }
return DateTime(0, 0, 0, 0, 0); return DateTime(0, 0, 0, 0, 0);
} }
Future<QueryResult> _execQuery( Future<QueryResult> _execQuery(String query, Map<String, dynamic> variables) async {
String query, Map<String, dynamic> variables) async {
final options = QueryOptions(document: gql(query), variables: variables); final options = QueryOptions(document: gql(query), variables: variables);
// 5GMyvKsTNk9wDBy9jwKaX6mhSzmFFtpdK9KNnmrLoSTSuJHv // 5GMyvKsTNk9wDBy9jwKaX6mhSzmFFtpdK9KNnmrLoSTSuJHv
...@@ -249,12 +286,7 @@ class DuniterIndexer with ChangeNotifier { ...@@ -249,12 +286,7 @@ class DuniterIndexer with ChangeNotifier {
late String finalAmount; late String finalAmount;
final DateTime date = repository[0]; final DateTime date = repository[0];
final dateForm = "${date.day} ${monthsInYear[date.month]!.substring(0, { final dateForm = "${date.day} ${monthsInYear[date.month]!.substring(0, {1, 2, 7, 9}.contains(date.month) ? 4 : 3)}";
1,
2,
7,
9
}.contains(date.month) ? 4 : 3)}";
DateTime normalizeDate(DateTime inputDate) { DateTime normalizeDate(DateTime inputDate) {
return DateTime(inputDate.year, inputDate.month, inputDate.day); return DateTime(inputDate.year, inputDate.month, inputDate.day);
...@@ -264,12 +296,9 @@ class DuniterIndexer with ChangeNotifier { ...@@ -264,12 +296,9 @@ class DuniterIndexer with ChangeNotifier {
DateTime now = DateTime.now(); DateTime now = DateTime.now();
final transactionDate = normalizeDate(date.toLocal()); final transactionDate = normalizeDate(date.toLocal());
final todayDate = normalizeDate(now); final todayDate = normalizeDate(now);
final yesterdayDate = final yesterdayDate = normalizeDate(now.subtract(const Duration(days: 1)));
normalizeDate(now.subtract(const Duration(days: 1))); final isSameWeek = weekNumber(transactionDate) == weekNumber(now) && transactionDate.year == now.year;
final isSameWeek = weekNumber(transactionDate) == weekNumber(now) && final isTodayOrYesterday = transactionDate == todayDate || transactionDate == yesterdayDate;
transactionDate.year == now.year;
final isTodayOrYesterday =
transactionDate == todayDate || transactionDate == yesterdayDate;
if (transactionDate == todayDate) { if (transactionDate == todayDate) {
return "today".tr(); return "today".tr();
...@@ -299,8 +328,7 @@ class DuniterIndexer with ChangeNotifier { ...@@ -299,8 +328,7 @@ class DuniterIndexer with ChangeNotifier {
finalAmount = '$amount $currencyName'; finalAmount = '$amount $currencyName';
} }
bool isMigrationTime = bool isMigrationTime = startBlockchainInitialized && date.compareTo(startBlockchainTime) < 0;
startBlockchainInitialized && date.compareTo(startBlockchainTime) < 0;
return { return {
'finalAmount': finalAmount, 'finalAmount': finalAmount,
......
...@@ -6,6 +6,8 @@ class SearchProvider with ChangeNotifier { ...@@ -6,6 +6,8 @@ class SearchProvider with ChangeNotifier {
final searchController = TextEditingController(); final searchController = TextEditingController();
List searchResult = []; List searchResult = [];
int resultLenght = 0; int resultLenght = 0;
bool canPasteAddress = false;
String pastedAddress = '';
void reload() { void reload() {
notifyListeners(); notifyListeners();
......
This diff is collapsed.
...@@ -37,10 +37,8 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -37,10 +37,8 @@ class _HomeScreenState extends State<HomeScreen> {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
final homeProvider = Provider.of<HomeProvider>(context, listen: false); final homeProvider = Provider.of<HomeProvider>(context, listen: false);
final sub = Provider.of<SubstrateSdk>(context, listen: false); final sub = Provider.of<SubstrateSdk>(context, listen: false);
final duniterIndexer = final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
Provider.of<DuniterIndexer>(context, listen: false); final myWalletProvider = Provider.of<MyWalletsProvider>(context, listen: false);
final myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false);
final datapod = Provider.of<V2sDatapodProvider>(context, listen: false); final datapod = Provider.of<V2sDatapodProvider>(context, listen: false);
final bool isWalletsExists = myWalletProvider.isWalletsExists(); final bool isWalletsExists = myWalletProvider.isWalletsExists();
...@@ -77,35 +75,12 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -77,35 +75,12 @@ class _HomeScreenState extends State<HomeScreen> {
homeProvider.isWalletBoxInit = true; homeProvider.isWalletBoxInit = true;
myWalletProvider.reload(); myWalletProvider.reload();
duniterIndexer.getValidIndexerEndpoint().then((validIndexerEndpoint) {
final wsLinkIndexer = WebSocketLink(
'wss://$validIndexerEndpoint/v1beta1/relay',
);
// const headerWebsocket =
// datapodEndpoint == '10.0.2.2:8080' ? 'ws' : 'wss';
// final wsLinkDatapod = WebSocketLink(
// '$headerWebsocket://$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) {
configBox.put('isCacheChecked', false); configBox.put('isCacheChecked', false);
} }
Future<void> updateConnectionStatus( Future<void> updateConnectionStatus(List<ConnectivityResult> result) async {
List<ConnectivityResult> result) async {
log.i('Network changed: $result'); log.i('Network changed: $result');
if (result.contains(ConnectivityResult.none)) { if (result.contains(ConnectivityResult.none)) {
sub.nodeConnected = false; sub.nodeConnected = false;
...@@ -117,6 +92,22 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -117,6 +92,22 @@ class _HomeScreenState extends State<HomeScreen> {
var connectivityResult = await (Connectivity().checkConnectivity()); var connectivityResult = await (Connectivity().checkConnectivity());
if (!connectivityResult.contains(ConnectivityResult.none)) { if (!connectivityResult.contains(ConnectivityResult.none)) {
await sub.connectNode(); await sub.connectNode();
//Connect to Indexer
final validIndexerEndpoint = await duniterIndexer.getValidIndexerEndpoint();
final wsLinkIndexer = WebSocketLink(
'wss://$validIndexerEndpoint/v1beta1/relay',
);
duniterIndexer.indexerClient = GraphQLClient(
cache: GraphQLCache(),
link: wsLinkIndexer,
);
// Indexer Blockchain start
duniterIndexer.getBlockStart();
homeProvider.changeMessage("Node and indexer synced !".tr(), 5);
} }
} }
} }
...@@ -135,9 +126,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -135,9 +126,7 @@ class _HomeScreenState extends State<HomeScreen> {
Provider.of<ChestProvider>(context); Provider.of<ChestProvider>(context);
final isWalletsExists = myWalletProvider.isWalletsExists(); final isWalletsExists = myWalletProvider.isWalletsExists();
isTall = (MediaQuery.of(context).size.height / isTall = (MediaQuery.of(context).size.height / MediaQuery.of(context).size.width) > 1.75;
MediaQuery.of(context).size.width) >
1.75;
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
...@@ -158,8 +147,7 @@ Widget geckHome(context) { ...@@ -158,8 +147,7 @@ Widget geckHome(context) {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
child: child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
Stack(children: <Widget>[ Stack(children: <Widget>[
Positioned( Positioned(
top: statusBarHeight + scaleSize(10), top: statusBarHeight + scaleSize(10),
...@@ -177,15 +165,12 @@ Widget geckHome(context) { ...@@ -177,15 +165,12 @@ Widget geckHome(context) {
), ),
), ),
Align( Align(
child: Image( child: Image(image: const AssetImage('assets/home/header.png'), height: scaleSize(165)),
image: const AssetImage('assets/home/header.png'),
height: scaleSize(165)),
), ),
]), ]),
Padding( Padding(
padding: const EdgeInsets.only(top: 15), padding: const EdgeInsets.only(top: 15),
child: child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
DefaultTextStyle( DefaultTextStyle(
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: scaledTextStyle( style: scaledTextStyle(
...@@ -246,8 +231,7 @@ Widget welcomeHome(context) { ...@@ -246,8 +231,7 @@ Widget welcomeHome(context) {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
child: child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
Stack(children: <Widget>[ Stack(children: <Widget>[
Positioned( Positioned(
top: statusBarHeight + scaleSize(10), top: statusBarHeight + scaleSize(10),
...@@ -265,15 +249,12 @@ Widget welcomeHome(context) { ...@@ -265,15 +249,12 @@ Widget welcomeHome(context) {
), ),
), ),
Align( Align(
child: Image( child: Image(image: const AssetImage('assets/home/header.png'), height: scaleSize(165)),
image: const AssetImage('assets/home/header.png'),
height: scaleSize(165)),
), ),
]), ]),
Padding( Padding(
padding: const EdgeInsets.only(top: 1), padding: const EdgeInsets.only(top: 1),
child: child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Text( Text(
"fastAppDescription".tr(args: [currencyName]), "fastAppDescription".tr(args: [currencyName]),
textAlign: TextAlign.center, textAlign: TextAlign.center,
...@@ -321,8 +302,7 @@ Widget welcomeHome(context) { ...@@ -321,8 +302,7 @@ Widget welcomeHome(context) {
Padding( Padding(
padding: EdgeInsets.only(top: scaleSize(55)), padding: EdgeInsets.only(top: scaleSize(55)),
child: Image( child: Image(
image: const AssetImage( image: const AssetImage('assets/home/gecko-bienvenue.png'),
'assets/home/gecko-bienvenue.png'),
height: scaleSize(180), height: scaleSize(180),
), ),
), ),
...@@ -356,10 +336,7 @@ Widget welcomeHome(context) { ...@@ -356,10 +336,7 @@ Widget welcomeHome(context) {
}, },
child: Text( child: Text(
'createWallet'.tr(), 'createWallet'.tr(),
style: scaledTextStyle( style: scaledTextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Colors.white),
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white),
), ),
), ),
), ),
...@@ -369,8 +346,7 @@ Widget welcomeHome(context) { ...@@ -369,8 +346,7 @@ Widget welcomeHome(context) {
height: 60, height: 60,
child: OutlinedButton( child: OutlinedButton(
key: keyRestoreChest, key: keyRestoreChest,
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(side: BorderSide(width: scaleSize(4), color: orangeC)),
side: BorderSide(width: scaleSize(4), color: orangeC)),
onPressed: () { onPressed: () {
Navigator.push( Navigator.push(
context, context,
...@@ -383,10 +359,7 @@ Widget welcomeHome(context) { ...@@ -383,10 +359,7 @@ Widget welcomeHome(context) {
}, },
child: Text( child: Text(
"restoreWallet".tr(), "restoreWallet".tr(),
style: scaledTextStyle( style: scaledTextStyle(fontSize: 20, color: orangeC, fontWeight: FontWeight.w600),
fontSize: 20,
color: orangeC,
fontWeight: FontWeight.w600),
), ),
), ),
), ),
......
...@@ -2,16 +2,15 @@ ...@@ -2,16 +2,15 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
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/models/widgets_keys.dart'; import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/search.dart'; import 'package:gecko/providers/search.dart';
import 'package:gecko/providers/wallets_profiles.dart';
import 'package:gecko/screens/my_contacts.dart'; import 'package:gecko/screens/my_contacts.dart';
import 'package:gecko/screens/search_result.dart'; import 'package:gecko/screens/search_result.dart';
import 'package:gecko/screens/wallet_view.dart'; import 'package:gecko/screens/wallet_view.dart';
import 'package:gecko/widgets/clipboard_monitor.dart';
import 'package:gecko/widgets/commons/offline_info.dart'; import 'package:gecko/widgets/commons/offline_info.dart';
import 'package:gecko/widgets/commons/top_appbar.dart'; import 'package:gecko/widgets/commons/top_appbar.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
...@@ -26,47 +25,13 @@ class SearchScreen extends StatefulWidget { ...@@ -26,47 +25,13 @@ class SearchScreen extends StatefulWidget {
class _SearchScreenState extends State<SearchScreen> { class _SearchScreenState extends State<SearchScreen> {
Timer? debounce; Timer? debounce;
final int debouneTime = 50; final int debouneTime = 50;
bool canPasteAddress = false;
String pastedAddress = '';
Timer? clipboardPollingTimer;
void getClipBoard() {
final searchProvider = Provider.of<SearchProvider>(context, listen: false);
// Function to check clipboard and update if necessary
Future<void> checkAndUpdateClipboard() async {
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
if (clipboardData?.text?.isEmpty ?? true) return;
if (clipboardData!.text != pastedAddress) {
canPasteAddress = await isAddress(clipboardData.text!);
if (!canPasteAddress) return;
pastedAddress = clipboardData.text!;
searchProvider.reload();
}
}
// Check clipboard immediately
checkAndUpdateClipboard();
// Set up the periodic clipboard checking
clipboardPollingTimer =
Timer.periodic(const Duration(milliseconds: 500), (_) async {
await checkAndUpdateClipboard();
});
}
@override @override
void initState() { void initState() {
getClipBoard(); ClipboardMonitor().startMonitoring();
super.initState(); super.initState();
} }
@override
void dispose() {
clipboardPollingTimer?.cancel();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final searchProvider = Provider.of<SearchProvider>(context); final searchProvider = Provider.of<SearchProvider>(context);
...@@ -139,13 +104,9 @@ class _SearchScreenState extends State<SearchScreen> { ...@@ -139,13 +104,9 @@ class _SearchScreenState extends State<SearchScreen> {
height: scaleSize(10), height: scaleSize(10),
), ),
), ),
border: OutlineInputBorder( border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey[500]!, width: 2), borderRadius: BorderRadius.circular(8)),
borderSide:
BorderSide(color: Colors.grey[500]!, width: 2),
borderRadius: BorderRadius.circular(8)),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: borderSide: BorderSide(color: Colors.grey[500]!, width: 2.5),
BorderSide(color: Colors.grey[500]!, width: 2.5),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
contentPadding: const EdgeInsets.all(13), contentPadding: const EdgeInsets.all(13),
...@@ -177,13 +138,12 @@ class _SearchScreenState extends State<SearchScreen> { ...@@ -177,13 +138,12 @@ class _SearchScreenState extends State<SearchScreen> {
}), }),
); );
} }
: canPasteAddress : searchProvider.canPasteAddress
? () async { ? () async {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(builder: (context) {
return WalletViewScreen( return WalletViewScreen(address: searchProvider.pastedAddress, username: null);
address: pastedAddress, username: null);
}), }),
); );
} }
...@@ -191,14 +151,11 @@ class _SearchScreenState extends State<SearchScreen> { ...@@ -191,14 +151,11 @@ class _SearchScreenState extends State<SearchScreen> {
child: Text( child: Text(
canValidate canValidate
? 'search'.tr() ? 'search'.tr()
: canPasteAddress : searchProvider.canPasteAddress
? 'pasteAddress'.tr() ? 'pasteAddress'.tr()
: 'search'.tr(), : 'search'.tr(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: scaledTextStyle( style: scaledTextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.white),
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white),
), ),
), ),
), ),
......
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/providers/search.dart';
import 'package:gecko/providers/wallets_profiles.dart';
import 'package:provider/provider.dart';
class ClipboardMonitor extends ChangeNotifier {
String? _lastClipboardContent;
Timer? _debounceTimer;
final searchProvider = Provider.of<SearchProvider>(homeContext, listen: false);
void startMonitoring() {
_checkClipboard();
}
void _checkClipboard() async {
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
final newContent = clipboardData?.text;
if (newContent != null && newContent != _lastClipboardContent) {
_lastClipboardContent = newContent;
_debounceTimer?.cancel();
_debounceTimer = Timer(const Duration(milliseconds: 300), () async {
if (await isAddress(newContent)) {
searchProvider.pastedAddress = newContent;
searchProvider.canPasteAddress = true;
searchProvider.reload();
} else {
searchProvider.pastedAddress = '';
searchProvider.canPasteAddress = false;
searchProvider.reload();
}
});
}
Future.delayed(const Duration(seconds: 1), _checkClipboard);
}
@override
void dispose() {
_debounceTimer?.cancel();
searchProvider.canPasteAddress = false;
super.dispose();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment