From 9d7ac05c27576e5ed38bcbf2299657549da8efd7 Mon Sep 17 00:00:00 2001 From: vjrj <vjrj@comunes.org> Date: Tue, 28 Mar 2023 01:11:58 +0200 Subject: [PATCH] Use hive to store cached contacts --- lib/main.dart | 8 +++++ lib/ui/contacts_cache.dart | 71 ++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index dbe44ab7..8497aa7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:ginkgo/ui/contacts_cache.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:introduction_screen/introduction_screen.dart'; @@ -234,9 +235,16 @@ class _GinkgoAppState extends State<GinkgoApp> { @override void initState() { super.initState(); + ContactsCache().init(); NodeManager().loadFromCubit(context.read<NodeListCubit>()); } + @override + void dispose() { + ContactsCache().dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return BlocBuilder<NodeListCubit, NodeListState>( diff --git a/lib/ui/contacts_cache.dart b/lib/ui/contacts_cache.dart index ba833410..578a7a54 100644 --- a/lib/ui/contacts_cache.dart +++ b/lib/ui/contacts_cache.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:html'; import 'package:flutter/foundation.dart'; +import 'package:hive/hive.dart'; import '../data/models/contact.dart'; import '../g1/api.dart'; @@ -16,18 +16,32 @@ class ContactsCache { ContactsCache._internal(); + Box<dynamic>? _box; + + Future<void> init() async { + _box = await Hive.openBox(_boxName); + } + + Future<void> dispose() async { + await _box?.close(); + } + static ContactsCache? _instance; final Map<String, List<Completer<Contact>>> _pendingRequests = <String, List<Completer<Contact>>>{}; static Duration duration = kReleaseMode ? const Duration(days: 3) : const Duration(hours: 5); - Future<Contact> getContact(String pubKey) async { - final String cacheKey = _key(pubKey); + final String _boxName = 'contacts_cache'; + + Box<dynamic> _openBox() { + return _box!; + } + Future<Contact> getContact(String pubKey) async { Contact? cachedContact; try { - cachedContact = _retrieveContact(pubKey); + cachedContact = await _retrieveContact(pubKey); } catch (e) { logger('Error while retrieving contact from cache: $e, $pubKey'); } @@ -53,12 +67,7 @@ class ContactsCache { _pendingRequests[pubKey] = <Completer<Contact>>[completer]; try { cachedContact = await getProfile(pubKey); - - final String encodedValue = json.encode(<String, dynamic>{ - 'timestamp': DateTime.now().toIso8601String(), - 'data': cachedContact.toJson(), - }); - window.localStorage[cacheKey] = encodedValue; + storeContact(cachedContact); if (!kReleaseMode) { // logger('Returning non cached contact $contact'); } @@ -80,11 +89,9 @@ class ContactsCache { } } - String _key(String pubKey) => 'contact-$pubKey'; - - void addContact(Contact contact) { + Future<void> addContact(Contact contact) async { // Get the cached version of the contact, if it exists - Contact? cachedContact = _retrieveContact(contact.pubKey); + Contact? cachedContact = await _retrieveContact(contact.pubKey); // Merge the new contact with the cached contact if (cachedContact != null) { @@ -96,31 +103,35 @@ class ContactsCache { } // Cache the merged contact - final String encodedValue = json.encode(<String, dynamic>{ + // Cache the merged contact + await storeContact(cachedContact); + + // logger('Added contact $cachedContact to cache'); + } + + Future<void> storeContact(Contact contact) async { + final Box<dynamic> box = _openBox(); + await box.put(contact.pubKey, <String, dynamic>{ 'timestamp': DateTime.now().toIso8601String(), - 'data': cachedContact.toJson(), + 'data': json.encode(contact.toJson()), }); - window.localStorage[_key(contact.pubKey)] = encodedValue; - // logger('Added contact $cachedContact to cache'); } - Contact? _retrieveContact(String pubKey) { - final String? cachedValue = window.localStorage[_key(pubKey)]; - if (cachedValue != null) { - final Map<String, dynamic> decodedValue = - json.decode(cachedValue) as Map<String, dynamic>; + Future<Contact?> _retrieveContact(String pubKey) async { + final Box<dynamic> box = _openBox(); + final dynamic record = box.get(pubKey); + + if (record != null) { + final Map<String, dynamic> typedRecord = + Map<String, dynamic>.from(record as Map); final DateTime timestamp = - DateTime.parse(decodedValue['timestamp'] as String); + DateTime.parse(typedRecord['timestamp'] as String); final bool before = DateTime.now().isBefore(timestamp.add(duration)); if (before) { - final Contact contact = - Contact.fromJson(decodedValue['data'] as Map<String, dynamic>); - if (!kReleaseMode) { - logger('Returning cached contact $contact'); - } + final Contact contact = Contact.fromJson( + json.decode(typedRecord['data'] as String) as Map<String, dynamic>); return contact; } - // logger('Cached contact $pubKey is expired'); } return null; } -- GitLab