From 616801e6fe8da4bc0e13e40746921eb027a61aa0 Mon Sep 17 00:00:00 2001 From: poka Date: Fri, 26 Nov 2021 08:56:20 +0100 Subject: [PATCH] Search is working (WIP performance improvements) --- lib/globals.dart | 6 +- lib/main.dart | 4 + lib/models/g1_wallets_list.dart | 53 +++++++++++ lib/models/g1_wallets_list.g.dart | 72 ++++++++++++++ lib/models/search.dart | 51 +++++++++- lib/screens/common_elements.dart | 17 ++-- lib/screens/history.dart | 153 +++++++++++++++--------------- lib/screens/search_result.dart | 124 +++++++++++++++++++++--- pubspec.yaml | 4 +- 9 files changed, 382 insertions(+), 102 deletions(-) create mode 100644 lib/models/g1_wallets_list.dart create mode 100644 lib/models/g1_wallets_list.g.dart diff --git a/lib/globals.dart b/lib/globals.dart index 115be3d..70cd2ae 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:gecko/models/chest_data.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:hive/hive.dart'; import 'package:logger/logger.dart'; @@ -16,9 +17,10 @@ int ramSys; Box walletBox; Box chestBox; Box configBox; +Box g1WalletsBox; -// String cesiumPod = "https://g1.data.le-sou.org"; -String cesiumPod = "https://g1.data.e-is.pro"; +String cesiumPod = "https://g1.data.le-sou.org"; +// String cesiumPod = "https://g1.data.e-is.pro"; // Responsive ratios bool isTall; diff --git a/lib/main.dart b/lib/main.dart index a04f5aa..b187bfb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,6 +23,7 @@ import 'package:gecko/models/cesium_plus.dart'; import 'package:gecko/models/change_pin.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/chest_provider.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/generate_wallets.dart'; import 'package:gecko/models/history.dart'; import 'package:gecko/models/home.dart'; @@ -58,9 +59,12 @@ Future main() async { await Hive.initFlutter(appPath.path); Hive.registerAdapter(WalletDataAdapter()); Hive.registerAdapter(ChestDataAdapter()); + Hive.registerAdapter(G1WalletsListAdapter()); + Hive.registerAdapter(IdAdapter()); walletBox = await Hive.openBox("walletBox"); chestBox = await Hive.openBox("chestBox"); configBox = await Hive.openBox("configBox"); + g1WalletsBox = await Hive.openBox("g1WalletsBox"); // final HiveStore _store = // await HiveStore.open(path: '${appPath.path}/gqlCache'); diff --git a/lib/models/g1_wallets_list.dart b/lib/models/g1_wallets_list.dart new file mode 100644 index 0000000..286e98e --- /dev/null +++ b/lib/models/g1_wallets_list.dart @@ -0,0 +1,53 @@ +import 'package:hive_flutter/hive_flutter.dart'; + +part 'g1_wallets_list.g.dart'; + +@HiveType(typeId: 2) +class G1WalletsList { + @HiveField(0) + String pubkey; + + @HiveField(1) + double balance; + + @HiveField(3) + Id id; + + G1WalletsList({this.pubkey, this.balance, this.id}); + + G1WalletsList.fromJson(Map json) { + pubkey = json['pubkey']; + balance = json['balance']; + id = json['id'] != null ? Id.fromJson(json['id']) : null; + } + + Map toJson() { + final Map data = {}; + data['pubkey'] = pubkey; + data['balance'] = balance; + if (id != null) { + data['id'] = id.toJson(); + } + return data; + } +} + +@HiveType(typeId: 3) +class Id { + bool isMember; + String username; + + Id({this.isMember, this.username}); + + Id.fromJson(Map json) { + isMember = json['isMember']; + username = json['username']; + } + + Map toJson() { + final Map data = {}; + data['isMember'] = isMember; + data['username'] = username; + return data; + } +} diff --git a/lib/models/g1_wallets_list.g.dart b/lib/models/g1_wallets_list.g.dart new file mode 100644 index 0000000..31b83c6 --- /dev/null +++ b/lib/models/g1_wallets_list.g.dart @@ -0,0 +1,72 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'g1_wallets_list.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class G1WalletsListAdapter extends TypeAdapter { + @override + final int typeId = 2; + + @override + G1WalletsList read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return G1WalletsList( + pubkey: fields[0] as String, + balance: fields[1] as double, + id: fields[3] as Id, + ); + } + + @override + void write(BinaryWriter writer, G1WalletsList obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.pubkey) + ..writeByte(1) + ..write(obj.balance) + ..writeByte(3) + ..write(obj.id); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is G1WalletsListAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class IdAdapter extends TypeAdapter { + @override + final int typeId = 3; + + @override + Id read(BinaryReader reader) { + return Id(); + } + + @override + void write(BinaryWriter writer, Id obj) { + writer.writeByte(0); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is IdAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/models/search.dart b/lib/models/search.dart index eaa1beb..ef31a6e 100644 --- a/lib/models/search.dart +++ b/lib/models/search.dart @@ -1,12 +1,61 @@ +import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; +import 'package:http/http.dart' as http; class SearchProvider with ChangeNotifier { TextEditingController searchController = TextEditingController(); + List searchResult = []; + final cacheDuring = 60 * 60 * 1000; //First number is minutes + int cacheTime = 0; void rebuildWidget() { notifyListeners(); } - void searchPubkey() {} + Future searchBlockchain() async { + searchResult.clear(); + int searchTime = DateTime.now().millisecondsSinceEpoch; + + if (cacheTime + cacheDuring <= searchTime) { + var url = Uri.parse('https://g1-stats.axiom-team.fr/data/forbes.json'); + var response = await http.get(url); + // print('Response body: ${response.body}'); + List _listWallets = + await compute(_parseG1Wallets, response.body); + + for (G1WalletsList element in _listWallets) { + await g1WalletsBox.put(element.pubkey, element); + } + cacheTime = DateTime.now().millisecondsSinceEpoch; + } + + g1WalletsBox.toMap().forEach((key, value) { + if ((value.id != null && + value.id.username != null && + value.id.username.contains(searchController.text)) || + value.pubkey.contains(searchController.text)) { + searchResult.add(value); + return; + } + }); + + return searchResult; + + // notifyListeners(); + + // log.i(g1WalletsBox + // .get('1N18iwCfzLYd7u6DTKafVrzs9bPyeYTGHoc5SsLMcfv') + // .balance); + } +} + +List _parseG1Wallets(String responseBody) { + final parsed = jsonDecode(responseBody).cast>(); + + return parsed + .map((json) => G1WalletsList.fromJson(json)) + .toList(); } diff --git a/lib/screens/common_elements.dart b/lib/screens/common_elements.dart index b9f2654..bb36379 100644 --- a/lib/screens/common_elements.dart +++ b/lib/screens/common_elements.dart @@ -34,14 +34,15 @@ class CommonElements { margin: const BubbleEdges.fromLTRB(10, 0, 20, 10), // nip: BubbleNip.leftTop, child: RichText( - key: textKey, - text: TextSpan( - style: const TextStyle( - fontSize: 18.0, - color: Colors.black, - ), - children: text, - )), + key: textKey, + text: TextSpan( + style: const TextStyle( + fontSize: 18.0, + color: Colors.black, + ), + children: text, + ), + ), ); } diff --git a/lib/screens/history.dart b/lib/screens/history.dart index da0dc4c..a47c6f7 100644 --- a/lib/screens/history.dart +++ b/lib/screens/history.dart @@ -187,47 +187,48 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { children: [ if (_isFirstExec) Container( - padding: const EdgeInsets.fromLTRB( - 20, 0, 30, 0), - child: FutureBuilder( - future: - _cesiumPlusProvider.getAvatar( - _historyProvider.pubkey), - initialData: [ - File(appPath.path + - '/default_avatar.png') - ], - builder: (BuildContext context, - AsyncSnapshot _avatar) { - cesiumData = _avatar.data; - // _cesiumPlusProvider.isComplete = true; - if (_avatar.connectionState != - ConnectionState.done) { - return Image.file( - File(appPath.path + - '/default_avatar.png'), - height: avatarsSize); - } - if (_avatar.hasError) { - return Image.file( - File(appPath.path + - '/default_avatar.png'), - height: avatarsSize); - } - if (_avatar.hasData) { - return SingleChildScrollView( - padding: - const EdgeInsets.all( - 0.0), - child: Image.file( - _avatar.data[0], - height: avatarsSize)); - } + padding: const EdgeInsets.fromLTRB( + 20, 0, 30, 0), + child: FutureBuilder( + future: + _cesiumPlusProvider.getAvatar( + _historyProvider.pubkey), + initialData: [ + File(appPath.path + + '/default_avatar.png') + ], + builder: (BuildContext context, + AsyncSnapshot _avatar) { + cesiumData = _avatar.data; + // _cesiumPlusProvider.isComplete = true; + if (_avatar.connectionState != + ConnectionState.done) { return Image.file( File(appPath.path + '/default_avatar.png'), height: avatarsSize); - })), + } + if (_avatar.hasError) { + return Image.file( + File(appPath.path + + '/default_avatar.png'), + height: avatarsSize); + } + if (_avatar.hasData) { + return SingleChildScrollView( + padding: + const EdgeInsets.all( + 0.0), + child: Image.file( + _avatar.data[0], + height: avatarsSize)); + } + return Image.file( + File(appPath.path + + '/default_avatar.png'), + height: avatarsSize); + }), + ), GestureDetector( key: const Key('copyPubkey'), onTap: () { @@ -270,18 +271,19 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( - padding: const EdgeInsets.fromLTRB( - 0, 0, 0, 0), - // padding: const EdgeInsets., - child: FutureBuilder( - future: _cesiumPlusProvider.getName( - _historyProvider.pubkey), - initialData: '...', - builder: (context, snapshot) { - return Text(snapshot.data ?? '-', - style: const TextStyle( - fontSize: 20)); - })) + padding: + const EdgeInsets.fromLTRB(0, 0, 0, 0), + // padding: const EdgeInsets., + child: FutureBuilder( + future: _cesiumPlusProvider + .getName(_historyProvider.pubkey), + initialData: '...', + builder: (context, snapshot) { + return Text(snapshot.data ?? '-', + style: const TextStyle( + fontSize: 20)); + }), + ) ]), const SizedBox(height: 18), if (_isFirstExec) @@ -420,32 +422,33 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { : Column(children: [ for (var repository in _historyProvider.transBC) Padding( - padding: const EdgeInsets.symmetric(horizontal: 5.0), - child: ListTile( - key: Key('transaction${keyID++}'), - contentPadding: const EdgeInsets.all(5.0), - leading: Text(repository[1].toString(), - style: TextStyle( - fontSize: 12, - color: Colors.grey[800], - fontWeight: FontWeight.w700), - textAlign: TextAlign.center), - title: Text(repository[3], - style: const TextStyle( - fontSize: 15.0, fontFamily: 'Monospace'), - textAlign: TextAlign.center), - subtitle: Text(repository[6] != '' ? repository[6] : '-', - style: const TextStyle(fontSize: 12.0), - textAlign: TextAlign.center), - trailing: Text("${repository[4]} Ğ1", - style: const TextStyle(fontSize: 14.0), - textAlign: TextAlign.justify), - dense: true, - isThreeLine: false, - onTap: () { - // this._outputPubkey.text = repository[2]; - _historyProvider.isPubkey(context, repository[2]); - })), + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: ListTile( + key: Key('transaction${keyID++}'), + contentPadding: const EdgeInsets.all(5.0), + leading: Text(repository[1].toString(), + style: TextStyle( + fontSize: 12, + color: Colors.grey[800], + fontWeight: FontWeight.w700), + textAlign: TextAlign.center), + title: Text(repository[3], + style: const TextStyle( + fontSize: 15.0, fontFamily: 'Monospace'), + textAlign: TextAlign.center), + subtitle: Text(repository[6] != '' ? repository[6] : '-', + style: const TextStyle(fontSize: 12.0), + textAlign: TextAlign.center), + trailing: Text("${repository[4]} Ğ1", + style: const TextStyle(fontSize: 14.0), + textAlign: TextAlign.justify), + dense: true, + isThreeLine: false, + onTap: () { + // this._outputPubkey.text = repository[2]; + _historyProvider.isPubkey(context, repository[2]); + }), + ), if (result.isLoading) Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/screens/search_result.dart b/lib/screens/search_result.dart index 5c39998..8971fdf 100644 --- a/lib/screens/search_result.dart +++ b/lib/screens/search_result.dart @@ -1,6 +1,11 @@ +import 'dart:io'; + import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; +import 'package:gecko/models/cesium_plus.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; +import 'package:gecko/models/history.dart'; import 'package:gecko/models/search.dart'; import 'package:provider/provider.dart'; @@ -11,7 +16,16 @@ class SearchResultScreen extends StatelessWidget { Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SearchProvider _searchProvider = Provider.of(context); - int nbrResult = 0; + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context); + HistoryProvider _historyClass = + Provider.of(context, listen: false); + + // int nbrResult = 0; + int keyID = 0; + const double avatarsSize = 50; + + // _searchProvider.searchPubkey(); return Scaffold( appBar: AppBar( @@ -24,20 +38,102 @@ class SearchResultScreen extends StatelessWidget { body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 30), - Text( - '$nbrResult résultats pour "${_searchProvider.searchController.text}"', - style: TextStyle(fontSize: 18, color: Colors.grey[700]), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: < + Widget>[ + const SizedBox(height: 30), + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 18, + color: Colors.grey[700], ), - const SizedBox(height: 40), - const Text( - 'Dans la blockchain Ğ1', - style: TextStyle(fontSize: 20), - ) - ]), + children: [ + const TextSpan( + text: "Résultats pour ", + ), + TextSpan( + text: '"${_searchProvider.searchController.text}"', + style: const TextStyle(fontStyle: FontStyle.italic), + ), + ], + ), + ), + const SizedBox(height: 40), + const Text( + 'Dans la blockchain Ğ1', + style: TextStyle(fontSize: 20), + ), + const SizedBox(height: 20), + FutureBuilder( + future: _searchProvider.searchBlockchain(), + initialData: const [], + builder: (context, snapshot) { + return Expanded( + child: ListView(children: [ + for (G1WalletsList g1Wallet in snapshot.data) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: ListTile( + key: Key('searchResult${keyID++}'), + contentPadding: const EdgeInsets.all(5), + leading: FutureBuilder( + future: _cesiumPlusProvider + .getAvatar(g1Wallet.pubkey), + initialData: [ + File(appPath.path + '/default_avatar.png') + ], + builder: (BuildContext context, + AsyncSnapshot _avatar) { + if (_avatar.connectionState != + ConnectionState.done) { + return Image.file( + File(appPath.path + + '/default_avatar.png'), + height: avatarsSize); + } + if (_avatar.hasError) { + return Image.file( + File(appPath.path + + '/default_avatar.png'), + height: avatarsSize); + } + if (_avatar.hasData) { + return SingleChildScrollView( + padding: const EdgeInsets.all(0.0), + child: Image.file(_avatar.data.single, + height: avatarsSize)); + } + return Image.file( + File(appPath.path + + '/default_avatar.png'), + height: avatarsSize); + }), + title: Text( + _historyClass.getShortPubkey(g1Wallet.pubkey), + style: const TextStyle( + fontSize: 15.0, fontFamily: 'Monospace'), + textAlign: TextAlign.center), + subtitle: Text(g1Wallet?.id?.username ?? '', + style: const TextStyle(fontSize: 12.0), + textAlign: TextAlign.center), + trailing: Text("${g1Wallet.balance} Ğ1", + style: const TextStyle(fontSize: 14.0), + textAlign: TextAlign.justify), + dense: false, + isThreeLine: false, + onTap: () { + _historyClass.isPubkey( + context, g1Wallet.pubkey); + }), + ), + ]), + ); + }), + // Text( + // _searchProvider.searchResult.toString(), + // ) + ]), ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index f9fa4f1..ff1e3c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: Pay with G1. # 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 -version: 0.0.3+3 +version: 0.0.3+5 environment: sdk: ">=2.7.0 <3.0.0" @@ -26,7 +26,7 @@ dependencies: graphql_flutter: ^5.0.0 hive: ^2.0.4 hive_flutter: ^1.1.0 - http: ^0.13.0 + http: ^0.13.4 image_gallery_saver: ^1.6.9 image_picker: ^0.8.4 intl: ^0.17.0