feat: move address books to isar

This commit is contained in:
detherminal 2023-05-14 18:06:47 +03:00
parent b2c365797c
commit 524f4c5514
5 changed files with 1404 additions and 46 deletions

View file

@ -3,6 +3,7 @@ import 'package:flutter_native_splash/cli_commands.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/exceptions/main_db/main_db_exception.dart';
import 'package:stackwallet/models/isar/models/block_explorer.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
@ -37,6 +38,7 @@ class MainDB {
EthContractSchema,
TransactionBlockExplorerSchema,
StackThemeSchema,
ContactEntrySchema,
],
directory: (await StackFileSystem.applicationIsarDirectory()).path,
// inspector: kDebugMode,
@ -47,6 +49,45 @@ class MainDB {
return true;
}
// contact entries
List<ContactEntry> getContactEntries(){
return isar.contactEntrys.where().findAllSync();
}
Future<bool> deleteContactEntry({required String id}) {
try {
return isar.writeTxn(() async {
await isar.contactEntrys.deleteByCustomId(id);
return true;
});
} catch (e) {
throw MainDBException("failed deleteContactEntry: $id", e);
}
}
Future<bool> isContactEntryExists({required String id}) async {
return isar.contactEntrys
.where()
.customIdEqualTo(id)
.count()
.then((value) => value > 0);
}
ContactEntry? getContactEntry({required String id}) {
return isar.contactEntrys.where().customIdEqualTo(id).findFirstSync();
}
Future<bool> putContactEntry({required ContactEntry contactEntry}) async {
try {
return await isar.writeTxn(() async {
await isar.contactEntrys.put(contactEntry);
return true;
});
} catch (e) {
throw MainDBException("failed putContactEntry: $contactEntry", e);
}
}
// tx block explorers
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
return isar.transactionBlockExplorers

View file

@ -0,0 +1,24 @@
import 'package:isar/isar.dart';
part 'contact_entry.g.dart';
@collection
class ContactEntry {
ContactEntry({
this.emojiChar,
required this.name,
required this.addresses,
required this.isFavorite,
required this.customId,
});
Id id = Isar.autoIncrement;
late final String? emojiChar;
late final String name;
late final List<String> addresses;
late final bool isFavorite;
@Index(unique: true, replace: true)
late final String customId;
}

File diff suppressed because it is too large Load diff

View file

@ -102,8 +102,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final contacts =
ref.watch(addressBookServiceProvider.select((value) => value.contacts));
final contacts = ref.watch(addressBookServiceProvider.select((value) => value.contacts));
final isDesktop = Util.isDesktop;
return ConditionalParent(

View file

@ -1,40 +1,92 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
class AddressBookService extends ChangeNotifier {
Contact getContactById(String id) {
final json = DB.instance
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map?;
if (json == null) {
Logging.instance
.log("Attempted to get non existing contact", level: LogLevel.Fatal);
throw Exception('Contact ID "$id" not found!');
ContactEntry turnContactToEntry({required Contact contact}) {
String? emojiChar = contact.emojiChar;
String name = contact.name;
List<String> addresses = [];
bool isFavorite = contact.isFavorite;
String customId = contact.id;
for (ContactAddressEntry contactAddressEntry in contact.addresses) {
String coin = contactAddressEntry.coin.ticker;
String address = contactAddressEntry.address;
String label = contactAddressEntry.label;
String? other = contactAddressEntry.other;
addresses.add("$coin,$address,$label,$other");
}
return ContactEntry(
emojiChar: emojiChar,
name: name,
addresses: addresses,
isFavorite: isFavorite,
customId: customId,
);
}
Contact turnEntryToContact({required ContactEntry contactEntry}) {
String? emojiChar = contactEntry.emojiChar;
String name = contactEntry.name;
List<ContactAddressEntry> addresses = [];
bool isFavorite = contactEntry.isFavorite;
String id = contactEntry.customId;
for (String addressEntry in contactEntry.addresses) {
List<String> addressEntrySplit = addressEntry.split(",");
Coin coin = coinFromTickerCaseInsensitive(addressEntrySplit[0]);
String address = addressEntrySplit[1];
String label = addressEntrySplit[2];
String? other = addressEntrySplit[3];
addresses.add(ContactAddressEntry(
coin: coin,
address: address,
label: label,
other: other,
));
}
return Contact(
emojiChar: emojiChar,
name: name,
addresses: addresses,
isFavorite: isFavorite,
id: id,
);
}
Contact getContactById(String id) {
ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id);
if (contactEntry == null) {
return Contact(
name: "Contact not found",
addresses: [],
isFavorite: false,
);
} else {
return turnEntryToContact(contactEntry: contactEntry);
}
return Contact.fromJson(Map<String, dynamic>.from(json));
}
List<Contact> get contacts {
final keys = List<String>.from(
DB.instance.keys<dynamic>(boxName: DB.boxNameAddressBook));
final _contacts = keys
.map((id) => Contact.fromJson(Map<String, dynamic>.from(DB.instance
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map)))
.toList(growable: false);
_contacts
.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
return _contacts;
List<ContactEntry> contactEntries = MainDB.instance.getContactEntries();
List<Contact> contactsList = [];
for (ContactEntry contactEntry in contactEntries) {
contactsList.add(turnEntryToContact(contactEntry: contactEntry));
}
return contactsList;
}
Future<List<Contact>>? _addressBookEntries;
Future<List<Contact>> get addressBookEntries =>
List<Contact>? _addressBookEntries;
List<Contact> get addressBookEntries =>
_addressBookEntries ??= _fetchAddressBookEntries();
// Load address book contact entries
Future<List<Contact>> _fetchAddressBookEntries() async {
List<Contact> _fetchAddressBookEntries() {
return contacts;
}
@ -74,43 +126,32 @@ class AddressBookService extends ChangeNotifier {
/// returns false if it provided [contact]'s id already exists in the database
/// other true if the [contact] was saved
Future<bool> addContact(Contact contact) async {
if (DB.instance.containsKey<dynamic>(
boxName: DB.boxNameAddressBook, key: contact.id)) {
if (await MainDB.instance.isContactEntryExists(id: contact.id)) {
return false;
} else {
await MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: contact));
_refreshAddressBookEntries();
return true;
}
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: contact.id,
value: contact.toMap());
Logging.instance.log("add address book entry saved", level: LogLevel.Info);
await _refreshAddressBookEntries();
return true;
}
/// Edit contact
Future<bool> editContact(Contact editedContact) async {
// over write the contact with edited version
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: editedContact.id,
value: editedContact.toMap());
Logging.instance.log("edit address book entry saved", level: LogLevel.Info);
await _refreshAddressBookEntries();
await MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: editedContact));
_refreshAddressBookEntries();
return true;
}
/// Remove address book contact entry from db if it exists
Future<void> removeContact(String id) async {
await DB.instance.delete<dynamic>(key: id, boxName: DB.boxNameAddressBook);
await _refreshAddressBookEntries();
await MainDB.instance.deleteContactEntry(id: id);
_refreshAddressBookEntries();
}
Future<void> _refreshAddressBookEntries() async {
final newAddressBookEntries = await _fetchAddressBookEntries();
_addressBookEntries = Future(() => newAddressBookEntries);
void _refreshAddressBookEntries() {
final newAddressBookEntries = _fetchAddressBookEntries();
_addressBookEntries = newAddressBookEntries;
notifyListeners();
}
}