diff --git a/lib/globals.dart b/lib/globals.dart index ac34913..641c106 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -23,8 +23,8 @@ late Box contactsBox; // late Box keystoreBox; late Directory imageDirectory; -// String cesiumPod = "https://g1.data.le-sou.org"; -String cesiumPod = "https://g1.data.presles.fr"; +String cesiumPod = "https://g1.data.le-sou.org"; +// String cesiumPod = "https://g1.data.presles.fr"; // String cesiumPod = "https://g1.data.e-is.pro"; // Responsive ratios diff --git a/lib/models/g1_wallets_list.dart b/lib/models/g1_wallets_list.dart index 3fce1b3..3fe0695 100644 --- a/lib/models/g1_wallets_list.dart +++ b/lib/models/g1_wallets_list.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; part 'g1_wallets_list.g.dart'; @@ -15,22 +14,18 @@ class G1WalletsList { Id? id; @HiveField(3) - Image? avatar; - - @HiveField(4) String? username; - @HiveField(5) + @HiveField(4) String? csName; - @HiveField(6) + @HiveField(5) bool? isMembre; G1WalletsList({ required this.address, this.balance, this.id, - this.avatar, this.username, this.csName, this.isMembre, diff --git a/lib/models/g1_wallets_list.g.dart b/lib/models/g1_wallets_list.g.dart index 8b84c23..9a800f8 100644 --- a/lib/models/g1_wallets_list.g.dart +++ b/lib/models/g1_wallets_list.g.dart @@ -20,17 +20,16 @@ class G1WalletsListAdapter extends TypeAdapter { address: fields[0] as String, balance: fields[1] as double?, id: fields[2] as Id?, - avatar: fields[3] as Image?, - username: fields[4] as String?, - csName: fields[5] as String?, - isMembre: fields[6] as bool?, + username: fields[3] as String?, + csName: fields[4] as String?, + isMembre: fields[5] as bool?, ); } @override void write(BinaryWriter writer, G1WalletsList obj) { writer - ..writeByte(7) + ..writeByte(6) ..writeByte(0) ..write(obj.address) ..writeByte(1) @@ -38,12 +37,10 @@ class G1WalletsListAdapter extends TypeAdapter { ..writeByte(2) ..write(obj.id) ..writeByte(3) - ..write(obj.avatar) - ..writeByte(4) ..write(obj.username) - ..writeByte(5) + ..writeByte(4) ..write(obj.csName) - ..writeByte(6) + ..writeByte(5) ..write(obj.isMembre); } diff --git a/lib/providers/cesium_plus.dart b/lib/providers/cesium_plus.dart index bfc630b..4a798f0 100644 --- a/lib/providers/cesium_plus.dart +++ b/lib/providers/cesium_plus.dart @@ -3,7 +3,9 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:provider/provider.dart'; // import 'package:http/http.dart' as http; class CesiumPlusProvider with ChangeNotifier { @@ -11,18 +13,18 @@ class CesiumPlusProvider with ChangeNotifier { CancelToken avatarCancelToken = CancelToken(); - Future _buildQuery(pubkey) async { + Future _buildQuery(String address) async { var queryGetAvatar = json.encode({ "query": { "bool": { "should": [ { "match": { - '_id': {"query": pubkey, "boost": 2} + '_id': {"query": address, "boost": 2} } }, { - "prefix": {'_id': pubkey} + "prefix": {'_id': address} } ] } @@ -58,14 +60,14 @@ class CesiumPlusProvider with ChangeNotifier { return [podRequest, queryGetAvatar, headers]; } - Future getName(String? pubkey) async { + Future getName(String address) async { String? name; - if (g1WalletsBox.get(pubkey)?.csName != null) { - return g1WalletsBox.get(pubkey)!.csName!; + if (g1WalletsBox.get(address)?.csName != null) { + return g1WalletsBox.get(address)!.csName!; } - List queryOptions = await _buildQuery(pubkey); + List queryOptions = await _buildQuery(address); var dio = Dio(); late Response response; @@ -96,20 +98,22 @@ class CesiumPlusProvider with ChangeNotifier { name = response.data['hits']['hits'][0]['_source']['title']; name ??= ''; - g1WalletsBox.get(pubkey)!.csName = name; + g1WalletsBox.get(address)!.csName = name; return name; } - Future getAvatar(String? pubkey, double size) async { - if (g1WalletsBox.get(pubkey)?.avatar != null) { - return g1WalletsBox.get(pubkey)!.avatar; + Future getAvatar(String address, double size) async { + final sub = Provider.of(homeContext, listen: false); + if (await isAvatarExist(address)) { + return await getAvatarLocal(address, size); } + + final pubkeyV1 = await sub.addressToPubkeyB58(address); + var dio = Dio(); - // log.d(_pubkey); - - List queryOptions = await _buildQuery(pubkey); + List queryOptions = await _buildQuery(pubkeyV1); late Response response; try { @@ -139,9 +143,7 @@ class CesiumPlusProvider with ChangeNotifier { final avatar = response.data['hits']['hits'][0]['_source']['avatar']['_content']; - var avatarFile = - File('${(await getTemporaryDirectory()).path}/avatar_$pubkey.png'); - await avatarFile.writeAsBytes(base64.decode(avatar)); + final avatarFile = await saveAvatar(address, avatar); final finalAvatar = Image.file( avatarFile, @@ -149,10 +151,45 @@ class CesiumPlusProvider with ChangeNotifier { fit: BoxFit.fitWidth, ); - g1WalletsBox.get(pubkey)!.avatar = finalAvatar; - return finalAvatar; } + + Future getLocalPath() async { + final directory = await getApplicationDocumentsDirectory(); + return directory.path; + } + + Future saveAvatar(String address, String data) async { + final path = await getLocalPath(); + final avatarFolder = Directory('$path/avatars/'); + if (!await avatarFolder.exists()) { + await avatarFolder.create(); + } + final file = File('$path/avatars/$address'); + return await file.writeAsBytes(base64.decode(data)); + } + + Future getAvatarLocal(String address, double size) async { + final path = await getLocalPath(); + final avatarFile = File('$path/avatars/$address'); + return Image.file( + avatarFile, + height: size, + fit: BoxFit.fitWidth, + ); + } + + Future isAvatarExist(String address) async { + final path = await getLocalPath(); + final avatarFile = File('$path/avatars/$address'); + return avatarFile.exists(); + } + + Future deleteAvatarFolder() async { + final path = await getLocalPath(); + final avatarFolder = Directory('$path/avatars/'); + await avatarFolder.delete(recursive: true); + } } Image defaultAvatar(double size) => diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index 0ff0835..0c1f558 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -449,6 +449,10 @@ class SubstrateSdk with ChangeNotifier { return pubkeyByte; } + Future addressToPubkeyB58(String address) async { + return Base58Encode(await addressToPubkey(address)); + } + // Future pubkeyToAddress(String pubkey) async { // await sdk.api.account.encodeAddress([pubkey]); // } diff --git a/lib/screens/activity.dart b/lib/screens/activity.dart index 9435d87..2831b91 100644 --- a/lib/screens/activity.dart +++ b/lib/screens/activity.dart @@ -13,11 +13,10 @@ import 'package:provider/provider.dart'; class ActivityScreen extends StatefulWidget { const ActivityScreen( - {required this.address, required this.avatar, this.username}) + {required this.address, this.username}) : super(key: keyActivityScreen); final String address; final String? username; - final Image avatar; @override State createState() => _ActivityScreenState(); diff --git a/lib/screens/home.dart b/lib/screens/home.dart index df22b2e..489e07a 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -6,6 +6,7 @@ import 'package:gecko/globals.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/widgets_keys.dart'; +import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/chest_provider.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/home.dart'; @@ -41,6 +42,8 @@ class _HomeScreenState extends State { Provider.of(context, listen: false); final myWalletProvider = Provider.of(context, listen: false); + final csProvider = + Provider.of(context, listen: false); final bool isWalletsExists = myWalletProvider.checkIfWalletExist(); @@ -66,6 +69,7 @@ class _HomeScreenState extends State { if (sub.sdkReady && !sub.nodeConnected) { walletBox = await Hive.openBox("walletBox"); await Hive.deleteBoxFromDisk('g1WalletsBox'); + await csProvider.deleteAvatarFolder(); g1WalletsBox = await Hive.openBox("g1WalletsBox"); contactsBox = await Hive.openBox("contactsBox"); diff --git a/lib/screens/myWallets/wallet_options.dart b/lib/screens/myWallets/wallet_options.dart index 50a83dd..e9eabab 100644 --- a/lib/screens/myWallets/wallet_options.dart +++ b/lib/screens/myWallets/wallet_options.dart @@ -448,17 +448,7 @@ class WalletOptions extends StatelessWidget { Navigator.push( context, PageNoTransit(builder: (context) { - return ActivityScreen( - address: walletProvider.address.text, - avatar: wallet.imageCustomPath == null - ? Image.asset( - 'assets/avatars/${wallet.imageDefaultPath}', - width: 110, - ) - : Image.asset( - wallet.imageCustomPath!, - width: 110, - )); + return ActivityScreen(address: walletProvider.address.text); }), ); }, diff --git a/lib/screens/my_contacts.dart b/lib/screens/my_contacts.dart index 75872bb..a42456c 100644 --- a/lib/screens/my_contacts.dart +++ b/lib/screens/my_contacts.dart @@ -14,7 +14,6 @@ class ContactsScreen extends StatelessWidget { @override Widget build(BuildContext context) { Provider.of(context, listen: true); - double avatarSize = 55; final myContacts = contactsBox.toMap().values.toList(); // Order contacts by username @@ -37,7 +36,7 @@ class ContactsScreen extends StatelessWidget { bottomNavigationBar: const GeckoBottomAppBar(), body: SafeArea( child: Stack(children: [ - ContactsList(myContacts: myContacts, avatarSize: avatarSize), + ContactsList(myContacts: myContacts), const OfflineInfo(), ]), ), diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart index 83571cc..17b8314 100644 --- a/lib/screens/wallet_view.dart +++ b/lib/screens/wallet_view.dart @@ -6,7 +6,6 @@ import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/widgets_keys.dart'; -import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/my_wallets.dart'; @@ -29,11 +28,10 @@ const double buttonFontSize = 18; class WalletViewScreen extends StatelessWidget { const WalletViewScreen( - {required this.address, required this.username, this.avatar, Key? key}) + {required this.address, required this.username, Key? key}) : super(key: key); final String address; final String? username; - final Image? avatar; @override Widget build(BuildContext context) { @@ -136,9 +134,7 @@ class WalletViewScreen extends StatelessWidget { Navigator.push( context, PageNoTransit(builder: (context) { - return ActivityScreen( - address: address, - avatar: defaultAvatar(50)); + return ActivityScreen(address: address); }), ); }), diff --git a/lib/widgets/cesium_avatar.dart b/lib/widgets/cesium_avatar.dart new file mode 100644 index 0000000..4290189 --- /dev/null +++ b/lib/widgets/cesium_avatar.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/providers/cesium_plus.dart'; +import 'package:gecko/widgets/commons/loading.dart'; +import 'package:provider/provider.dart'; + +class CesiumAvatar extends StatelessWidget { + const CesiumAvatar({Key? key, required this.address, this.size = 15}) + : super(key: key); + final String address; + final double size; + + @override + Widget build(BuildContext context) { + final csProvider = Provider.of(context, listen: false); + log.d('tatata'); + + return ClipOval( + child: FutureBuilder( + future: csProvider.getAvatar(address, size), + builder: ((context, AsyncSnapshot avatar) { + if (avatar.hasError) { + log.e(avatar.error); + return (Icon(Icons.close_outlined, + color: Colors.red, size: size)); + } else if (avatar.connectionState != ConnectionState.done) { + return SizedBox( + width: size, + height: size, + child: const FractionallySizedBox( + widthFactor: 0.6, heightFactor: 0.6, child: Loading())); + } + return avatar.data!; + })), + ); + } +} diff --git a/lib/widgets/commons/loading.dart b/lib/widgets/commons/loading.dart new file mode 100644 index 0000000..b969606 --- /dev/null +++ b/lib/widgets/commons/loading.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; + +class Loading extends StatelessWidget { + const Loading({ + Key? key, + this.size = 15, + this.stroke = 2, + }) : super(key: key); + + final double size; + final double stroke; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: size, + width: size, + child: CircularProgressIndicator( + color: orangeC, + strokeWidth: stroke, + ), + ); + } +} diff --git a/lib/widgets/contacts_list.dart b/lib/widgets/contacts_list.dart index 2dd8aab..128ed94 100644 --- a/lib/widgets/contacts_list.dart +++ b/lib/widgets/contacts_list.dart @@ -1,15 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/widgets_keys.dart'; -import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/wallet_view.dart'; import 'package:gecko/widgets/balance.dart'; +import 'package:gecko/widgets/cesium_avatar.dart'; import 'package:gecko/widgets/name_by_address.dart'; import 'package:provider/provider.dart'; @@ -17,11 +16,9 @@ class ContactsList extends StatelessWidget { const ContactsList({ Key? key, required this.myContacts, - required this.avatarSize, }) : super(key: key); final List myContacts; - final double avatarSize; @override Widget build(BuildContext context) { @@ -47,7 +44,8 @@ class ContactsList extends StatelessWidget { key: keySearchResult('keyID++'), horizontalTitleGap: 40, contentPadding: const EdgeInsets.all(5), - leading: defaultAvatar(avatarSize), + leading: + CesiumAvatar(address: g1Wallet.address, size: 55), title: Row(children: [ Text(getShortPubkey(g1Wallet.address), style: const TextStyle( @@ -87,13 +85,9 @@ class ContactsList extends StatelessWidget { MaterialPageRoute(builder: (context) { walletsProfilesClass.address = g1Wallet.address; return WalletViewScreen( - address: g1Wallet.address, - username: duniterIndexer - .walletNameIndexer[g1Wallet.address], - avatar: g1WalletsBox - .get(g1Wallet.address) - ?.avatar, - ); + address: g1Wallet.address, + username: duniterIndexer + .walletNameIndexer[g1Wallet.address]); }), ); }), diff --git a/lib/widgets/header_profile.dart b/lib/widgets/header_profile.dart index 1337e2d..d852e54 100644 --- a/lib/widgets/header_profile.dart +++ b/lib/widgets/header_profile.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/widgets_keys.dart'; -import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallet_options.dart'; @@ -10,6 +9,7 @@ import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/certifications.dart'; import 'package:gecko/widgets/balance.dart'; import 'package:gecko/widgets/certifications.dart'; +import 'package:gecko/widgets/cesium_avatar.dart'; import 'package:gecko/widgets/commons/offline_info.dart'; import 'package:gecko/widgets/idty_status.dart'; import 'package:gecko/widgets/page_route_no_transition.dart'; @@ -50,7 +50,7 @@ class HeaderProfile extends StatelessWidget { )); }), Padding( - padding: const EdgeInsets.only(left: 30, right: 40), + padding: const EdgeInsets.only(left: 30, right: 30), child: Row(children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -107,9 +107,7 @@ class HeaderProfile extends StatelessWidget { ]), const Spacer(), Column(children: [ - ClipOval( - child: defaultAvatar(avatarSize), - ), + CesiumAvatar(address: address, size: avatarSize), ]), ]), ), diff --git a/lib/widgets/search_identity_query.dart b/lib/widgets/search_identity_query.dart index 8e6ddb8..2a2a351 100644 --- a/lib/widgets/search_identity_query.dart +++ b/lib/widgets/search_identity_query.dart @@ -4,13 +4,13 @@ import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/queries_indexer.dart'; import 'package:gecko/models/widgets_keys.dart'; -import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/search.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/wallet_view.dart'; import 'package:gecko/widgets/balance.dart'; +import 'package:gecko/widgets/cesium_avatar.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; @@ -86,7 +86,8 @@ class SearchIdentityQuery extends StatelessWidget { key: keySearchResult(profile['pubkey']), horizontalTitleGap: 40, contentPadding: const EdgeInsets.all(5), - leading: defaultAvatar(avatarSize), + leading: CesiumAvatar( + address: profile['pubkey'], size: avatarSize), title: Row(children: [ Text(getShortPubkey(profile['pubkey']), style: const TextStyle( @@ -125,8 +126,6 @@ class SearchIdentityQuery extends StatelessWidget { return WalletViewScreen( address: profile['pubkey'], username: profile['name'], - avatar: - g1WalletsBox.get(profile['pubkey'])?.avatar, ); }), ); diff --git a/lib/widgets/search_result_list.dart b/lib/widgets/search_result_list.dart index 9a09db8..6c701a3 100644 --- a/lib/widgets/search_result_list.dart +++ b/lib/widgets/search_result_list.dart @@ -3,13 +3,13 @@ import 'package:gecko/globals.dart'; import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/widgets_keys.dart'; -import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/search.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/wallet_view.dart'; import 'package:gecko/widgets/balance.dart'; +import 'package:gecko/widgets/cesium_avatar.dart'; import 'package:gecko/widgets/name_by_address.dart'; import 'package:gecko/widgets/search_identity_query.dart'; @@ -65,7 +65,7 @@ class SearchResult extends StatelessWidget { key: keySearchResult(g1Wallet.address), horizontalTitleGap: 40, contentPadding: const EdgeInsets.all(5), - leading: defaultAvatar(avatarSize), + leading: CesiumAvatar(address: g1Wallet.address, size: avatarSize), title: Row(children: [ Text(getShortPubkey(g1Wallet.address), style: const TextStyle( @@ -101,7 +101,6 @@ class SearchResult extends StatelessWidget { return WalletViewScreen( address: g1Wallet.address, username: g1Wallet.username, - avatar: g1Wallet.avatar, ); }), ); diff --git a/pubspec.lock b/pubspec.lock index b52e77f..64b91f1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -711,6 +711,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + hive_generator: + dependency: "direct dev" + description: + name: hive_generator + sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" + url: "https://pub.dev" + source: hosted + version: "2.0.1" html: dependency: transitive description: @@ -1411,6 +1419,22 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 13347ff..532f288 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,6 +65,7 @@ dev_dependencies: # flutter_launcher_icons_maker: ^^0.10.2 icons_launcher: ^2.0.6 build_runner: ^2.1.2 + hive_generator: ^2.0.1 flutter_lints: ^3.0.1 flutter_test: sdk: flutter