mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
feat: move address books to isar
This commit is contained in:
parent
b2c365797c
commit
524f4c5514
5 changed files with 1404 additions and 46 deletions
|
@ -3,6 +3,7 @@ import 'package:flutter_native_splash/cli_commands.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:stackwallet/exceptions/main_db/main_db_exception.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/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/models/isar_models.dart';
|
||||||
import 'package:stackwallet/models/isar/stack_theme.dart';
|
import 'package:stackwallet/models/isar/stack_theme.dart';
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
|
@ -37,6 +38,7 @@ class MainDB {
|
||||||
EthContractSchema,
|
EthContractSchema,
|
||||||
TransactionBlockExplorerSchema,
|
TransactionBlockExplorerSchema,
|
||||||
StackThemeSchema,
|
StackThemeSchema,
|
||||||
|
ContactEntrySchema,
|
||||||
],
|
],
|
||||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||||
// inspector: kDebugMode,
|
// inspector: kDebugMode,
|
||||||
|
@ -47,6 +49,45 @@ class MainDB {
|
||||||
return true;
|
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
|
// tx block explorers
|
||||||
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
|
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
|
||||||
return isar.transactionBlockExplorers
|
return isar.transactionBlockExplorers
|
||||||
|
|
24
lib/models/isar/models/contact_entry.dart
Normal file
24
lib/models/isar/models/contact_entry.dart
Normal 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;
|
||||||
|
}
|
1253
lib/models/isar/models/contact_entry.g.dart
Normal file
1253
lib/models/isar/models/contact_entry.g.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -102,8 +102,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType");
|
debugPrint("BUILD: $runtimeType");
|
||||||
final contacts =
|
final contacts = ref.watch(addressBookServiceProvider.select((value) => value.contacts));
|
||||||
ref.watch(addressBookServiceProvider.select((value) => value.contacts));
|
|
||||||
|
|
||||||
final isDesktop = Util.isDesktop;
|
final isDesktop = Util.isDesktop;
|
||||||
return ConditionalParent(
|
return ConditionalParent(
|
||||||
|
|
|
@ -1,40 +1,92 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.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.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/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
class AddressBookService extends ChangeNotifier {
|
class AddressBookService extends ChangeNotifier {
|
||||||
Contact getContactById(String id) {
|
|
||||||
final json = DB.instance
|
ContactEntry turnContactToEntry({required Contact contact}) {
|
||||||
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map?;
|
String? emojiChar = contact.emojiChar;
|
||||||
if (json == null) {
|
String name = contact.name;
|
||||||
Logging.instance
|
List<String> addresses = [];
|
||||||
.log("Attempted to get non existing contact", level: LogLevel.Fatal);
|
bool isFavorite = contact.isFavorite;
|
||||||
throw Exception('Contact ID "$id" not found!');
|
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 {
|
List<Contact> get contacts {
|
||||||
final keys = List<String>.from(
|
List<ContactEntry> contactEntries = MainDB.instance.getContactEntries();
|
||||||
DB.instance.keys<dynamic>(boxName: DB.boxNameAddressBook));
|
List<Contact> contactsList = [];
|
||||||
final _contacts = keys
|
for (ContactEntry contactEntry in contactEntries) {
|
||||||
.map((id) => Contact.fromJson(Map<String, dynamic>.from(DB.instance
|
contactsList.add(turnEntryToContact(contactEntry: contactEntry));
|
||||||
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map)))
|
}
|
||||||
.toList(growable: false);
|
return contactsList;
|
||||||
_contacts
|
|
||||||
.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
|
|
||||||
return _contacts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Contact>>? _addressBookEntries;
|
List<Contact>? _addressBookEntries;
|
||||||
Future<List<Contact>> get addressBookEntries =>
|
List<Contact> get addressBookEntries =>
|
||||||
_addressBookEntries ??= _fetchAddressBookEntries();
|
_addressBookEntries ??= _fetchAddressBookEntries();
|
||||||
|
|
||||||
// Load address book contact entries
|
// Load address book contact entries
|
||||||
Future<List<Contact>> _fetchAddressBookEntries() async {
|
List<Contact> _fetchAddressBookEntries() {
|
||||||
return contacts;
|
return contacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,43 +126,32 @@ class AddressBookService extends ChangeNotifier {
|
||||||
/// returns false if it provided [contact]'s id already exists in the database
|
/// returns false if it provided [contact]'s id already exists in the database
|
||||||
/// other true if the [contact] was saved
|
/// other true if the [contact] was saved
|
||||||
Future<bool> addContact(Contact contact) async {
|
Future<bool> addContact(Contact contact) async {
|
||||||
if (DB.instance.containsKey<dynamic>(
|
if (await MainDB.instance.isContactEntryExists(id: contact.id)) {
|
||||||
boxName: DB.boxNameAddressBook, key: contact.id)) {
|
|
||||||
return false;
|
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
|
/// Edit contact
|
||||||
Future<bool> editContact(Contact editedContact) async {
|
Future<bool> editContact(Contact editedContact) async {
|
||||||
// over write the contact with edited version
|
// over write the contact with edited version
|
||||||
await DB.instance.put<dynamic>(
|
await MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: editedContact));
|
||||||
boxName: DB.boxNameAddressBook,
|
_refreshAddressBookEntries();
|
||||||
key: editedContact.id,
|
|
||||||
value: editedContact.toMap());
|
|
||||||
|
|
||||||
Logging.instance.log("edit address book entry saved", level: LogLevel.Info);
|
|
||||||
await _refreshAddressBookEntries();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove address book contact entry from db if it exists
|
/// Remove address book contact entry from db if it exists
|
||||||
Future<void> removeContact(String id) async {
|
Future<void> removeContact(String id) async {
|
||||||
await DB.instance.delete<dynamic>(key: id, boxName: DB.boxNameAddressBook);
|
await MainDB.instance.deleteContactEntry(id: id);
|
||||||
await _refreshAddressBookEntries();
|
_refreshAddressBookEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _refreshAddressBookEntries() async {
|
void _refreshAddressBookEntries() {
|
||||||
final newAddressBookEntries = await _fetchAddressBookEntries();
|
final newAddressBookEntries = _fetchAddressBookEntries();
|
||||||
_addressBookEntries = Future(() => newAddressBookEntries);
|
_addressBookEntries = newAddressBookEntries;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue