Improve performance of history explorer

This commit is contained in:
poka 2021-12-02 07:23:12 +01:00
parent 46bfb61391
commit a0a5d02212
11 changed files with 263 additions and 195 deletions

View File

@ -35,6 +35,8 @@ import 'package:gecko/screens/home.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gecko/screens/myWallets/wallets_home.dart';
import 'package:gecko/screens/search.dart';
import 'package:gecko/screens/search_result.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart';
@ -139,55 +141,58 @@ class Gecko extends StatelessWidget {
// HistoryProvider _historyProvider = Provider.of<HistoryProvider>(context);
// HistoryProvider('').snackNode(context);
return MultiProvider(
providers: [
// Provider(create: (context) => HistoryProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => WalletsProfilesProvider('')),
ChangeNotifierProvider(create: (_) => MyWalletsProvider()),
ChangeNotifierProvider(create: (_) => ChestProvider()),
ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()),
ChangeNotifierProvider(create: (_) => WalletOptionsProvider()),
ChangeNotifierProvider(create: (_) => ChangePinProvider()),
ChangeNotifierProvider(create: (_) => SearchProvider()),
ChangeNotifierProvider(create: (_) => CesiumPlusProvider())
],
child: GraphQLProvider(
client: _client,
child: MaterialApp(
builder: (context, widget) => ResponsiveWrapper.builder(
BouncingScrollWrapper.builder(context, widget),
maxWidth: 1200,
minWidth: 480,
defaultScale: true,
breakpoints: [
const ResponsiveBreakpoint.resize(480, name: MOBILE),
const ResponsiveBreakpoint.autoScale(800, name: TABLET),
const ResponsiveBreakpoint.resize(1000, name: DESKTOP),
],
background: Container(color: backgroundColor)),
title: 'Ğecko',
theme: ThemeData(
appBarTheme: const AppBarTheme(
color: Color(0xffFFD58D),
foregroundColor: Color(0xFF000000),
),
primaryColor: const Color(0xffFFD58D),
textTheme: const TextTheme(
bodyText1: TextStyle(),
bodyText2: TextStyle(),
).apply(
bodyColor: const Color(0xFF000000),
),
colorScheme: ColorScheme.fromSwatch()
.copyWith(secondary: Colors.grey[850]),
providers: [
// Provider(create: (context) => HistoryProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => WalletsProfilesProvider('')),
ChangeNotifierProvider(create: (_) => MyWalletsProvider()),
ChangeNotifierProvider(create: (_) => ChestProvider()),
ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()),
ChangeNotifierProvider(create: (_) => WalletOptionsProvider()),
ChangeNotifierProvider(create: (_) => ChangePinProvider()),
ChangeNotifierProvider(create: (_) => SearchProvider()),
ChangeNotifierProvider(create: (_) => CesiumPlusProvider())
],
child: GraphQLProvider(
client: _client,
child: MaterialApp(
builder: (context, widget) => ResponsiveWrapper.builder(
BouncingScrollWrapper.builder(context, widget),
maxWidth: 1200,
minWidth: 480,
defaultScale: true,
breakpoints: [
const ResponsiveBreakpoint.resize(480, name: MOBILE),
const ResponsiveBreakpoint.autoScale(800, name: TABLET),
const ResponsiveBreakpoint.resize(1000, name: DESKTOP),
],
background: Container(color: backgroundColor)),
title: 'Ğecko',
theme: ThemeData(
appBarTheme: const AppBarTheme(
color: Color(0xffFFD58D),
foregroundColor: Color(0xFF000000),
),
home: const HomeScreen(),
initialRoute: "/",
routes: {
'/mywallets': (context) => WalletsHome(),
},
primaryColor: const Color(0xffFFD58D),
textTheme: const TextTheme(
bodyText1: TextStyle(),
bodyText2: TextStyle(),
).apply(
bodyColor: const Color(0xFF000000),
),
colorScheme:
ColorScheme.fromSwatch().copyWith(secondary: Colors.grey[850]),
),
));
home: const HomeScreen(),
initialRoute: "/",
routes: {
'/mywallets': (context) => WalletsHome(),
'/search': (context) => const SearchScreen(),
'/searchResult': (context) => const SearchResultScreen(),
},
),
),
);
}
}

View File

@ -1,16 +1,19 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
// import 'package:http/http.dart' as http;
class CesiumPlusProvider with ChangeNotifier {
TextEditingController cesiumName = TextEditingController();
Image defaultAvatar(double size) =>
Image.asset(('assets/icon_user.png'), height: size);
CancelToken avatarCancelToken = CancelToken();
Future<List> _buildQuery(_pubkey) async {
var queryGetAvatar = json.encode({
"query": {
@ -66,18 +69,34 @@ class CesiumPlusProvider with ChangeNotifier {
}
List queryOptions = await _buildQuery(_pubkey);
final response = await http.post((Uri.parse(queryOptions[0])),
body: queryOptions[1], headers: queryOptions[2]);
final responseJson = json.decode(response.body);
if (responseJson['hits']['hits'].toString() == '[]') {
var dio = Dio();
Response response;
try {
response = await dio.post(
queryOptions[0],
data: queryOptions[1],
options: Options(
headers: queryOptions[2],
sendTimeout: 3000,
receiveTimeout: 5000,
),
);
// response = await http.post((Uri.parse(queryOptions[0])),
// body: queryOptions[1], headers: queryOptions[2]);
} catch (e) {
log.e(e);
}
if (response.data['hits']['hits'].toString() == '[]') {
return '';
}
final bool _nameExist =
responseJson['hits']['hits'][0]['_source'].containsKey("title");
response.data['hits']['hits'][0]['_source'].containsKey("title");
if (!_nameExist) {
return '';
}
_name = responseJson['hits']['hits'][0]['_source']['title'];
_name = response.data['hits']['hits'][0]['_source']['title'];
g1WalletsBox.get(_pubkey).csName = _name;
@ -88,27 +107,39 @@ class CesiumPlusProvider with ChangeNotifier {
if (g1WalletsBox.get(_pubkey).avatar != null) {
return g1WalletsBox.get(_pubkey).avatar;
}
var dio = Dio();
log.d(_pubkey);
// log.d(_pubkey);
List queryOptions = await _buildQuery(_pubkey);
http.Response response;
Response response;
try {
response = await http.post((Uri.parse(queryOptions[0])),
body: queryOptions[1], headers: queryOptions[2]);
response = await dio
.post(queryOptions[0],
data: queryOptions[1],
options: Options(
headers: queryOptions[2],
sendTimeout: 4000,
receiveTimeout: 15000,
),
cancelToken: avatarCancelToken)
.timeout(
const Duration(seconds: 15),
);
// response = await http.post((Uri.parse(queryOptions[0])),
// body: queryOptions[1], headers: queryOptions[2]);
} catch (e) {
log.e(e);
}
final responseJson = json.decode(response.body);
if (responseJson['hits']['hits'].toString() == '[]' ||
!responseJson['hits']['hits'][0]['_source'].containsKey("avatar")) {
if (response.data['hits']['hits'].toString() == '[]' ||
!response.data['hits']['hits'][0]['_source'].containsKey("avatar")) {
return defaultAvatar(size);
}
final _avatar =
responseJson['hits']['hits'][0]['_source']['avatar']['_content'];
response.data['hits']['hits'][0]['_source']['avatar']['_content'];
var avatarFile =
File('${(await getTemporaryDirectory()).path}/avatar_$_pubkey.png');

View File

@ -1,9 +1,8 @@
import 'dart:convert';
import 'package:dio/dio.dart';
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();
@ -21,10 +20,26 @@ class SearchProvider with ChangeNotifier {
if (cacheTime + cacheDuring <= searchTime) {
g1WalletsBox.clear();
final url = Uri.parse('https://g1-stats.axiom-team.fr/data/forbes.json');
final response = await http.get(url);
// final url = Uri.parse('https://g1-stats.axiom-team.fr/data/forbes.json');
// final response = await http.get(url);
List<G1WalletsList> _listWallets = _parseG1Wallets(response.body);
var dio = Dio();
Response response;
try {
response = await dio.get(
'https://g1-stats.axiom-team.fr/data/forbes.json',
options: Options(
sendTimeout: 5000,
receiveTimeout: 10000,
),
);
// response = await http.post((Uri.parse(queryOptions[0])),
// body: queryOptions[1], headers: queryOptions[2]);
} catch (e) {
log.e(e);
}
List<G1WalletsList> _listWallets = _parseG1Wallets(response.data);
Map<String, G1WalletsList> _mapWallets = {
for (var e in _listWallets) e.pubkey: e
};
@ -49,8 +64,8 @@ class SearchProvider with ChangeNotifier {
}
}
List<G1WalletsList> _parseG1Wallets(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
List<G1WalletsList> _parseG1Wallets(var responseBody) {
final parsed = responseBody.cast<Map<String, dynamic>>();
return parsed
.map<G1WalletsList>((json) => G1WalletsList.fromJson(json))

View File

@ -30,6 +30,8 @@ class WalletsProfilesProvider with ChangeNotifier {
TextEditingController payAmount = TextEditingController();
TextEditingController payComment = TextEditingController();
num balance;
int nRepositories = 10;
int nPage = 1;
Future scan(context) async {
await Permission.camera.request();
@ -193,11 +195,21 @@ class WalletsProfilesProvider with ChangeNotifier {
(result.data['txsHistoryBc']['both']['edges'] as List<dynamic>);
pageInfo = result.data['txsHistoryBc']['both']['pageInfo'];
fetchMoreCursor = pageInfo['endCursor'];
if (fetchMoreCursor == null) nPage = 1;
if (nPage == 1) {
nRepositories = 30;
} else if (nPage == 2) {
nRepositories = 100;
}
log.d(nPage);
log.d(nRepositories);
nPage++;
if (fetchMoreCursor != null) {
opts = FetchMoreOptions(
variables: {'cursor': fetchMoreCursor},
variables: {'cursor': fetchMoreCursor, 'number': nRepositories},
updateQuery: (previousResultData, fetchMoreResultData) {
final List<dynamic> repos = [
...previousResultData['txsHistoryBc']['both']['edges']

View File

@ -1,7 +1,6 @@
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/cesium_plus.dart';
import 'package:gecko/models/home.dart';
import 'package:gecko/models/queries.dart';
import 'package:gecko/models/wallets_profiles.dart';
import 'package:flutter/material.dart';
@ -18,7 +17,6 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
HistoryScreen({@required this.pubkey, this.avatar, this.username, Key key})
: super(key: key);
final ScrollController scrollController = ScrollController();
final nRepositories = 20;
final double avatarsSize = 80;
final String pubkey;
final String username;
@ -53,14 +51,14 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
),
body: Column(children: <Widget>[
headerProfileView(context, _historyProvider, _cesiumPlusProvider),
historyQuery(context, _historyProvider, _cesiumPlusProvider),
historyQuery(context, _cesiumPlusProvider),
]));
}
Widget historyQuery(context, WalletsProfilesProvider _historyProvider2,
CesiumPlusProvider _cesiumPlusProvider) {
Widget historyQuery(context, CesiumPlusProvider _cesiumPlusProvider) {
WalletsProfilesProvider _historyProvider =
Provider.of<WalletsProfilesProvider>(context, listen: true);
return Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
@ -71,13 +69,11 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
document: gql(getHistory),
variables: <String, dynamic>{
'pubkey': pubkey,
'number': nRepositories,
'number': 10,
'cursor': null
},
),
builder: (QueryResult result, {fetchMore, refetch}) {
// log.d(result.data);
if (result.isLoading && result.data == null) {
return const Center(
child: CircularProgressIndicator(),
@ -110,7 +106,10 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
.removeDecimalZero(result.data['balance']['amount'] / 100);
}
opts = _historyProvider.checkQueryResult(result, opts, pubkey);
if (result.isNotLoading) {
// log.d(result.data);
opts = _historyProvider.checkQueryResult(result, opts, pubkey);
}
// Build history list
return NotificationListener(
@ -175,8 +174,6 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
Widget getTransactionTile(
BuildContext context, WalletsProfilesProvider _historyProvider) {
HomeProvider _homeProvider =
Provider.of<HomeProvider>(context, listen: false);
CesiumPlusProvider _cesiumPlusProvider =
Provider.of<CesiumPlusProvider>(context, listen: false);
int keyID = 0;
@ -358,15 +355,14 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
dense: false,
isThreeLine: false,
onTap: () {
if (_historyProvider.isPubkey(context, repository[2])) {
_homeProvider.currentIndex = 0;
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return WalletViewScreen(pubkey: repository[2]);
}),
);
}
_historyProvider.nPage = 1;
// _cesiumPlusProvider.avatarCancelToken.cancel('cancelled');
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return WalletViewScreen(pubkey: repository[2]);
}),
);
// Navigator.pop(context);
}),
),

View File

@ -235,7 +235,7 @@ Widget geckHome(context) {
),
const SizedBox(height: 12),
const Text(
"Rechercher un\nportfeuille",
"Rechercher un\nportefeuille",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
@ -473,7 +473,7 @@ Widget welcomeHome(context) {
);
},
child: const Text(
'Créer un portfeuille',
'Créer un portefeuille',
style:
TextStyle(fontSize: 24, fontWeight: FontWeight.w600),
),

View File

@ -113,13 +113,16 @@ class _ChooseChestState extends State<ChooseChest> {
WalletData defaultWallet =
_myWalletProvider.getDefaultWallet(currentChest);
_myWalletProvider.rebuildWidget();
Navigator.pushAndRemoveUntil(context,
MaterialPageRoute(builder: (context) {
return UnlockingWallet(
wallet: defaultWallet,
action: "mywallets",
);
}), ModalRoute.withName('/'));
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) {
return UnlockingWallet(
wallet: defaultWallet,
action: "mywallets",
);
}),
ModalRoute.withName('/'),
);
},
child: Text(
'Ouvrir ce coffre',

View File

@ -46,13 +46,10 @@ class OnboardingStepFiveteen extends StatelessWidget {
onPrimary: Colors.white, // foreground
),
onPressed: () {
Navigator.popUntil(
context,
ModalRoute.withName('/'),
);
Navigator.pushNamed(
Navigator.pushNamedAndRemoveUntil(
context,
'/mywallets',
ModalRoute.withName('/'),
);
},
child: const Text("Accéder à mes portefeuilles",

View File

@ -65,9 +65,9 @@ class WalletViewScreen extends StatelessWidget {
page: HistoryScreen(
pubkey: pubkey,
username: username ??
g1WalletsBox.get(pubkey).username,
g1WalletsBox.get(pubkey)?.username,
avatar: avatar ??
g1WalletsBox.get(pubkey).avatar,
g1WalletsBox.get(pubkey)?.avatar,
),
isFast: false),
);
@ -98,8 +98,7 @@ class WalletViewScreen extends StatelessWidget {
image: AssetImage('assets/copy_key.png'),
height: 90)),
onTap: () {
Clipboard.setData(
ClipboardData(text: _historyProvider.pubkey));
Clipboard.setData(ClipboardData(text: pubkey));
_historyProvider.snackCopyKey(context);
}),
),
@ -201,101 +200,103 @@ class WalletViewScreen extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 40),
child: Row(children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start, children: <
Widget>[
Row(children: [
GestureDetector(
key: const Key('copyPubkey'),
onTap: () {
Clipboard.setData(ClipboardData(text: pubkey));
_historyProvider.snackCopyKey(context);
},
child: Text(
_historyProvider.getShortPubkey(pubkey),
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.w800,
),
),
),
]),
const SizedBox(height: 10),
if (username == null && g1WalletsBox.get(pubkey).username == null)
Query(
options: QueryOptions(
document: gql(getId),
variables: {
'pubkey': _historyProvider.pubkey,
},
),
builder: (QueryResult result,
{VoidCallback refetch, FetchMore fetchMore}) {
if (result.isLoading || result.hasException) {
return const Text('...');
} else if (result.data['idty'] == null ||
result.data['idty']['username'] == null) {
g1WalletsBox.get(pubkey).username = '';
return const Text('');
} else {
g1WalletsBox.get(pubkey).username =
result?.data['idty']['username'] ?? '';
return SizedBox(
width: 230,
child: Text(
result?.data['idty']['username'] ?? '',
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(children: [
GestureDetector(
key: const Key('copyPubkey'),
onTap: () {
Clipboard.setData(ClipboardData(text: pubkey));
_historyProvider.snackCopyKey(context);
},
child: Text(
_historyProvider.getShortPubkey(pubkey),
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.w800,
),
);
}
},
),
if (username == null && g1WalletsBox.get(pubkey).username != null)
SizedBox(
width: 230,
child: Text(
g1WalletsBox.get(pubkey).username,
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
),
),
),
),
if (username != null)
SizedBox(
width: 230,
child: Text(
username,
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
]),
const SizedBox(height: 10),
if (username == null &&
g1WalletsBox.get(pubkey)?.username == null)
Query(
options: QueryOptions(
document: gql(getId),
variables: {
'pubkey': pubkey,
},
),
builder: (QueryResult result,
{VoidCallback refetch, FetchMore fetchMore}) {
if (result.isLoading || result.hasException) {
return const Text('...');
} else if (result.data['idty'] == null ||
result.data['idty']['username'] == null) {
g1WalletsBox.get(pubkey)?.username = '';
return const Text('');
} else {
g1WalletsBox.get(pubkey)?.username =
result?.data['idty']['username'] ?? '';
return SizedBox(
width: 230,
child: Text(
result?.data['idty']['username'] ?? '',
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
),
),
);
}
},
),
),
),
const SizedBox(height: 25),
FutureBuilder(
future: _cesiumPlusProvider.getName(_historyProvider.pubkey),
initialData: '...',
builder: (context, snapshot) {
return SizedBox(
if (username == null &&
g1WalletsBox.get(pubkey)?.username != null)
SizedBox(
width: 230,
child: Text(
snapshot.data ?? '-',
style:
const TextStyle(fontSize: 18, color: Colors.black),
g1WalletsBox.get(pubkey)?.username,
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
),
),
);
}),
const SizedBox(height: 30),
]),
),
if (username != null)
SizedBox(
width: 230,
child: Text(
username,
style: const TextStyle(
fontSize: 27,
color: Color(0xff814C00),
),
),
),
const SizedBox(height: 25),
FutureBuilder(
future: _cesiumPlusProvider.getName(pubkey),
initialData: '...',
builder: (context, snapshot) {
return SizedBox(
width: 230,
child: Text(
snapshot.data ?? '-',
style: const TextStyle(
fontSize: 18, color: Colors.black),
),
);
}),
const SizedBox(height: 30),
]),
const Spacer(),
Column(children: <Widget>[
if (avatar == null)
FutureBuilder(
future: _cesiumPlusProvider.getAvatar(
_historyProvider.pubkey, _avatarSize),
future: _cesiumPlusProvider.getAvatar(pubkey, _avatarSize),
builder:
(BuildContext context, AsyncSnapshot<Image> _avatar) {
if (_avatar.connectionState != ConnectionState.done) {

View File

@ -267,6 +267,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.6"
dio:
dependency: "direct main"
description:
name: dio
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.4"
dubp:
dependency: "direct main"
description:

View File

@ -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+10
version: 0.0.3+12
environment:
sdk: ">=2.7.0 <3.0.0"
@ -57,6 +57,7 @@ dependencies:
unorm_dart: ^0.2.0
xml: ^5.3.0
pull_to_refresh: ^2.0.0
dio: ^4.0.4
flutter_icons:
android: "ic_launcher"