import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/models/contact.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(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!'); } return Contact.fromJson(Map.from(json)); } List get contacts { final keys = List.from( DB.instance.keys(boxName: DB.boxNameAddressBook)); final _contacts = keys .map((id) => Contact.fromJson(Map.from(DB.instance .get(boxName: DB.boxNameAddressBook, key: id) as Map))) .toList(growable: false); _contacts .sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase())); return _contacts; } Future>? _addressBookEntries; Future> get addressBookEntries => _addressBookEntries ??= _fetchAddressBookEntries(); // Load address book contact entries Future> _fetchAddressBookEntries() async { return contacts; } /// search address book entries //TODO optimize address book search? Future> search(String text) async { if (text.isEmpty) return addressBookEntries; var results = (await addressBookEntries).toList(); results.retainWhere((contact) => matches(text, contact)); return results; } bool matches(String term, Contact contact) { if (term.isEmpty) { return true; } final text = term.toLowerCase(); if (contact.name.toLowerCase().contains(text)) { return true; } for (int i = 0; i < contact.addresses.length; i++) { if (contact.addresses[i].label.toLowerCase().contains(text) || contact.addresses[i].coin.name.toLowerCase().contains(text) || contact.addresses[i].coin.prettyName.toLowerCase().contains(text) || contact.addresses[i].coin.ticker.toLowerCase().contains(text) || contact.addresses[i].address.toLowerCase().contains(text)) { return true; } } return false; } /// add contact /// /// returns false if it provided [contact]'s id already exists in the database /// other true if the [contact] was saved Future addContact(Contact contact) async { if (DB.instance.containsKey( boxName: DB.boxNameAddressBook, key: contact.id)) { return false; } await DB.instance.put( 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 editContact(Contact editedContact) async { // over write the contact with edited version await DB.instance.put( boxName: DB.boxNameAddressBook, key: editedContact.id, value: editedContact.toMap()); Logging.instance.log("edit address book entry saved", level: LogLevel.Info); await _refreshAddressBookEntries(); return true; } /// Remove address book contact entry from db if it exists Future removeContact(String id) async { await DB.instance.delete(key: id, boxName: DB.boxNameAddressBook); await _refreshAddressBookEntries(); } Future _refreshAddressBookEntries() async { final newAddressBookEntries = await _fetchAddressBookEntries(); _addressBookEntries = Future(() => newAddressBookEntries); notifyListeners(); } }