diff --git a/lib/globals.dart b/lib/globals.dart index ebb2b4392b8466deed95ed82fc45ebc41dd4319e..4e4046c3afe3bcf2b020aa65d2f37c359c76450a 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -4,11 +4,13 @@ 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:gecko/models/wallet_header_data.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:logger/logger.dart'; // Version of box data const int dataVersion = 10; +const int walletHeaderDataVersion = 1; late String appVersion; const int pinLength = 4; @@ -20,6 +22,7 @@ late Box<ChestData> chestBox; late Box configBox; late Box<G1WalletsList> g1WalletsBox; late Box<G1WalletsList> contactsBox; +late Box<WalletHeaderData> walletHeaderDataBox; // late Box keystoreBox; late Directory avatarsDirectory; late Directory avatarsCacheDirectory; diff --git a/lib/models/certification_data.dart b/lib/models/certification_data.dart new file mode 100644 index 0000000000000000000000000000000000000000..e94fb763d62c16a3c7c322af5292e521d56d3ed0 --- /dev/null +++ b/lib/models/certification_data.dart @@ -0,0 +1,22 @@ +// Add a class to store certification data +import 'package:hive_flutter/hive_flutter.dart'; + +part 'certification_data.g.dart'; + +@HiveType(typeId: 8) +class CertificationData { + @HiveField(0) + final int receivedCount; + + @HiveField(1) + final int sentCount; + + CertificationData({required this.receivedCount, required this.sentCount}); + + bool equals(CertificationData? other) { + if (other == null) return false; + return receivedCount == other.receivedCount && sentCount == other.sentCount; + } + + bool get isEmpty => receivedCount == 0 && sentCount == 0; +} diff --git a/lib/models/certification_data.g.dart b/lib/models/certification_data.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..bf15b4011b7199b1efe62ecb787e766213f7c97c --- /dev/null +++ b/lib/models/certification_data.g.dart @@ -0,0 +1,44 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'certification_data.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class CertificationDataAdapter extends TypeAdapter<CertificationData> { + @override + final int typeId = 8; + + @override + CertificationData read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = <int, dynamic>{ + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return CertificationData( + receivedCount: fields[0] as int, + sentCount: fields[1] as int, + ); + } + + @override + void write(BinaryWriter writer, CertificationData obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.receivedCount) + ..writeByte(1) + ..write(obj.sentCount); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CertificationDataAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/models/wallet_header_data.dart b/lib/models/wallet_header_data.dart index e9ee920cafb57a9866acc3ae985abfa915783b4d..90fa439da8fb0c677d8e523dea85d4211f0a22fe 100644 --- a/lib/models/wallet_header_data.dart +++ b/lib/models/wallet_header_data.dart @@ -1,4 +1,4 @@ - +import 'package:gecko/models/certification_data.dart'; import 'package:hive_flutter/hive_flutter.dart'; part 'wallet_header_data.g.dart'; @@ -33,7 +33,7 @@ class WalletHeaderData { final BigInt balance; @HiveField(4) - final List<int> certCount; + final CertificationData certCount; WalletHeaderData({ required this.hasIdentity, @@ -52,7 +52,7 @@ class WalletHeaderData { isOwner == other.isOwner && walletName == other.walletName && balance == other.balance && - certCount[0] == other.certCount[0] && - certCount[1] == other.certCount[1]; + certCount.receivedCount == other.certCount.receivedCount && + certCount.sentCount == other.certCount.sentCount; } } diff --git a/lib/models/wallet_header_data.g.dart b/lib/models/wallet_header_data.g.dart index cdc79d6c8e6128706ca69e8a6c61387834d67681..7532b2536353fe4abf353ddebc9e208e6c5daa71 100644 --- a/lib/models/wallet_header_data.g.dart +++ b/lib/models/wallet_header_data.g.dart @@ -21,7 +21,7 @@ class WalletHeaderDataAdapter extends TypeAdapter<WalletHeaderData> { isOwner: fields[1] as bool, walletName: fields[2] as String?, balance: fields[3] as BigInt, - certCount: (fields[4] as List).cast<int>(), + certCount: fields[4] as CertificationData, ); } diff --git a/lib/providers/home.dart b/lib/providers/home.dart index 2509abd44e7040dfad3c8b9155b3b4ee3951d2e8..5810785fb83e8f615ff96f8585d9d886644bcaf5 100644 --- a/lib/providers/home.dart +++ b/lib/providers/home.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:async'; import 'package:gecko/globals.dart'; +import 'package:gecko/models/certification_data.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallet_options.dart'; import 'package:hive_flutter/hive_flutter.dart'; @@ -17,7 +18,6 @@ import 'package:provider/provider.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:gecko/widgets/wallet_header.dart'; import 'package:gecko/models/wallet_header_data.dart'; import 'package:gecko/services/network_config_service.dart'; @@ -70,13 +70,19 @@ class HomeProvider with ChangeNotifier { Hive.registerAdapter(G1WalletsListAdapter()); Hive.registerAdapter(IdAdapter()); Hive.registerAdapter(IdtyStatusAdapter()); + Hive.registerAdapter(CertificationDataAdapter()); // Open required boxes synchronously chestBox = await Hive.openBox<ChestData>("chestBox"); configBox = await Hive.openBox("configBox"); - // Initialize other boxes asynchronously - unawaited(WalletHeader.initializeBox()); + // Check if walletHeaderDataVersion non compatible, drop wallet_header_cache + if (configBox.get('walletHeaderDataVersion') == null || configBox.get('walletHeaderDataVersion') < walletHeaderDataVersion) { + await Hive.deleteBoxFromDisk('wallet_header_cache'); + configBox.put('walletHeaderDataVersion', walletHeaderDataVersion); + } + + walletHeaderDataBox = await Hive.openBox<WalletHeaderData>("wallet_header_cache"); } Future changeCurrencyUnit(BuildContext context) async { diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index 2ab96c7fbbc71c93f3a66909c70963894a7ff2aa..70ed58a291d06edbedc1b381d65353bcc5cfbd08 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -6,6 +6,7 @@ import 'package:fast_base58/fast_base58.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/models/certification_data.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/membership_status.dart'; import 'package:gecko/models/migrate_wallet_checks.dart'; @@ -30,7 +31,6 @@ import 'package:provider/provider.dart'; import 'package:pointycastle/pointycastle.dart' as pc; import "package:hex/hex.dart"; import 'package:uuid/uuid.dart' show Uuid; -import 'package:gecko/widgets/certifications.dart'; class SubstrateSdk with ChangeNotifier { final WalletSDK sdk = WalletSDK(); diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 76aebc703469204ccb701cda67bbec3e31fcb558..aa597c72622242906bd0ecb022b15fac21edf66a 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/widgets_keys.dart'; import 'package:gecko/models/g1_wallets_list.dart'; -import 'package:gecko/models/wallet_header_data.dart'; import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/home.dart'; import 'package:gecko/providers/my_wallets.dart'; @@ -163,8 +162,7 @@ class _SettingsScreenState extends State<SettingsScreen> { if (confirm) { // Clear WalletHeaderData cache - final walletHeaderBox = await Hive.openBox<WalletHeaderData>('wallet_header_cache'); - await walletHeaderBox.clear(); + await walletHeaderDataBox.clear(); // Clear G1WalletsList cache final g1WalletsBox = await Hive.openBox<G1WalletsList>('g1_wallets_list'); diff --git a/lib/widgets/certifications.dart b/lib/widgets/certifications.dart index 1822f14c76a9b3fe9c2a77fbcb0748a976676180..2fddd2d4c47a2b85c18b97dc1595d19e05b8a989 100644 --- a/lib/widgets/certifications.dart +++ b/lib/widgets/certifications.dart @@ -3,19 +3,6 @@ import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:provider/provider.dart'; -// Add a class to store certification data -class CertificationData { - final int receivedCount; - final int sentCount; - - CertificationData({required this.receivedCount, required this.sentCount}); - - bool equals(CertificationData? other) { - if (other == null) return false; - return receivedCount == other.receivedCount && sentCount == other.sentCount; - } -} - class Certifications extends StatefulWidget { const Certifications({super.key, required this.address, required this.size, this.color = Colors.black}); final String address; diff --git a/lib/widgets/wallet_header.dart b/lib/widgets/wallet_header.dart index aee0b07fc76c654b80c8579589b1452ca49a73b4..b0d20356b1010920a6b656b6bf2a1e9410bc21ed 100644 --- a/lib/widgets/wallet_header.dart +++ b/lib/widgets/wallet_header.dart @@ -17,7 +17,6 @@ import 'package:gecko/widgets/certifications.dart'; import 'package:gecko/widgets/datapod_avatar.dart'; import 'package:gecko/widgets/idty_status.dart'; import 'package:gecko/widgets/page_route_no_transition.dart'; -import 'package:hive_flutter/hive_flutter.dart'; import 'package:provider/provider.dart'; import 'package:gecko/providers/wallet_options.dart'; import 'package:gecko/providers/substrate_sdk.dart'; @@ -35,31 +34,15 @@ class WalletHeader extends StatefulWidget { final String? customImagePath; final String? defaultImagePath; - static Future<void> initializeBox() => _WalletHeaderState.initializeBox(); - @override State<WalletHeader> createState() => _WalletHeaderState(); } class _WalletHeaderState extends State<WalletHeader> { late Future<WalletHeaderData> _loadData; - static const String _cacheBoxName = 'wallet_header_cache'; - static Box<WalletHeaderData>? _cacheBox; - static bool _isInitializing = false; - static Future<void>? _initFuture; bool _isPickerOpen = false; String _newCustomImagePath = ''; - static Future<void> initializeBox() async { - if (_isInitializing || _cacheBox != null) return _initFuture; - _isInitializing = true; - _initFuture = Hive.openBox<WalletHeaderData>(_cacheBoxName).then((box) { - _cacheBox = box; - _isInitializing = false; - }); - return _initFuture!; - } - @override void initState() { super.initState(); @@ -67,10 +50,8 @@ class _WalletHeaderState extends State<WalletHeader> { } Future<WalletHeaderData> _initializeData() async { - await initializeBox(); - // Check cache from Hive - final cached = _cacheBox?.get(widget.address); + final cached = walletHeaderDataBox.get(widget.address); if (cached != null) { // Refresh in background _refreshData(); @@ -93,11 +74,11 @@ class _WalletHeaderState extends State<WalletHeader> { isOwner: myWalletProvider.isOwner(widget.address), walletName: duniterIndexer.walletNameIndexer[widget.address], balance: BigInt.from(balance['transferableBalance'] ?? 0), - certCount: [certData.receivedCount, certData.sentCount], + certCount: certData, ); // Save to Hive cache - await _cacheBox?.put(widget.address, data); + await walletHeaderDataBox.put(widget.address, data); return data; } @@ -120,12 +101,12 @@ class _WalletHeaderState extends State<WalletHeader> { isOwner: myWalletProvider.isOwner(widget.address), walletName: duniterIndexer.walletNameIndexer[widget.address], balance: BigInt.from(balance['transferableBalance'] ?? 0), - certCount: [certData.receivedCount, certData.sentCount], + certCount: certData, ); - final existing = _cacheBox?.get(widget.address); + final existing = walletHeaderDataBox.get(widget.address); if (existing == null || !existing.equals(data)) { - await _cacheBox?.put(widget.address, data); + await walletHeaderDataBox.put(widget.address, data); if (mounted) { setState(() { _loadData = Future.value(data); @@ -470,7 +451,7 @@ class _WalletHeaderState extends State<WalletHeader> { final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false); // If data is in cache, show it immediately - final cached = _cacheBox?.get(widget.address); + final cached = walletHeaderDataBox.get(widget.address); if (cached != null) { return _buildContent( context, diff --git a/pubspec.yaml b/pubspec.yaml index f8d492160d1f003ac7902bfd58ac56c7534d00a0..d94af3f13242c9ae57476f180c92202d6678325c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: gecko description: Pay with G1. publish_to: "none" -version: 0.1.25+105 +version: 0.1.25+106 environment: sdk: ^3.5.3