From 524f4c55148a41b6877f1137fac9530d81ece5f0 Mon Sep 17 00:00:00 2001 From: detherminal <76167420+detherminal@users.noreply.github.com> Date: Sun, 14 May 2023 18:06:47 +0300 Subject: [PATCH] feat: move address books to isar --- lib/db/isar/main_db.dart | 41 + lib/models/isar/models/contact_entry.dart | 24 + lib/models/isar/models/contact_entry.g.dart | 1253 +++++++++++++++++ .../address_book_views/address_book_view.dart | 3 +- lib/services/address_book_service.dart | 129 +- 5 files changed, 1404 insertions(+), 46 deletions(-) create mode 100644 lib/models/isar/models/contact_entry.dart create mode 100644 lib/models/isar/models/contact_entry.g.dart diff --git a/lib/db/isar/main_db.dart b/lib/db/isar/main_db.dart index 0e9d9efc4..b9841de02 100644 --- a/lib/db/isar/main_db.dart +++ b/lib/db/isar/main_db.dart @@ -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 getContactEntries(){ + return isar.contactEntrys.where().findAllSync(); + } + + Future 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 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 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 diff --git a/lib/models/isar/models/contact_entry.dart b/lib/models/isar/models/contact_entry.dart new file mode 100644 index 000000000..fac725ac9 --- /dev/null +++ b/lib/models/isar/models/contact_entry.dart @@ -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 addresses; + late final bool isFavorite; + + @Index(unique: true, replace: true) + late final String customId; +} \ No newline at end of file diff --git a/lib/models/isar/models/contact_entry.g.dart b/lib/models/isar/models/contact_entry.g.dart new file mode 100644 index 000000000..0b1d63faf --- /dev/null +++ b/lib/models/isar/models/contact_entry.g.dart @@ -0,0 +1,1253 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'contact_entry.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters + +extension GetContactEntryCollection on Isar { + IsarCollection get contactEntrys => this.collection(); +} + +const ContactEntrySchema = CollectionSchema( + name: r'ContactEntry', + id: -3248212280610531288, + properties: { + r'addresses': PropertySchema( + id: 0, + name: r'addresses', + type: IsarType.stringList, + ), + r'customId': PropertySchema( + id: 1, + name: r'customId', + type: IsarType.string, + ), + r'emojiChar': PropertySchema( + id: 2, + name: r'emojiChar', + type: IsarType.string, + ), + r'isFavorite': PropertySchema( + id: 3, + name: r'isFavorite', + type: IsarType.bool, + ), + r'name': PropertySchema( + id: 4, + name: r'name', + type: IsarType.string, + ) + }, + estimateSize: _contactEntryEstimateSize, + serialize: _contactEntrySerialize, + deserialize: _contactEntryDeserialize, + deserializeProp: _contactEntryDeserializeProp, + idName: r'id', + indexes: { + r'customId': IndexSchema( + id: -7523974382886476007, + name: r'customId', + unique: true, + replace: true, + properties: [ + IndexPropertySchema( + name: r'customId', + type: IndexType.hash, + caseSensitive: true, + ) + ], + ) + }, + links: {}, + embeddedSchemas: {}, + getId: _contactEntryGetId, + getLinks: _contactEntryGetLinks, + attach: _contactEntryAttach, + version: '3.0.5', +); + +int _contactEntryEstimateSize( + ContactEntry object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + bytesCount += 3 + object.addresses.length * 3; + { + for (var i = 0; i < object.addresses.length; i++) { + final value = object.addresses[i]; + bytesCount += value.length * 3; + } + } + bytesCount += 3 + object.customId.length * 3; + { + final value = object.emojiChar; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } + bytesCount += 3 + object.name.length * 3; + return bytesCount; +} + +void _contactEntrySerialize( + ContactEntry object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeStringList(offsets[0], object.addresses); + writer.writeString(offsets[1], object.customId); + writer.writeString(offsets[2], object.emojiChar); + writer.writeBool(offsets[3], object.isFavorite); + writer.writeString(offsets[4], object.name); +} + +ContactEntry _contactEntryDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = ContactEntry( + addresses: reader.readStringList(offsets[0]) ?? [], + customId: reader.readString(offsets[1]), + emojiChar: reader.readStringOrNull(offsets[2]), + isFavorite: reader.readBool(offsets[3]), + name: reader.readString(offsets[4]), + ); + object.id = id; + return object; +} + +P _contactEntryDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readStringList(offset) ?? []) as P; + case 1: + return (reader.readString(offset)) as P; + case 2: + return (reader.readStringOrNull(offset)) as P; + case 3: + return (reader.readBool(offset)) as P; + case 4: + return (reader.readString(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +Id _contactEntryGetId(ContactEntry object) { + return object.id; +} + +List> _contactEntryGetLinks(ContactEntry object) { + return []; +} + +void _contactEntryAttach( + IsarCollection col, Id id, ContactEntry object) { + object.id = id; +} + +extension ContactEntryByIndex on IsarCollection { + Future getByCustomId(String customId) { + return getByIndex(r'customId', [customId]); + } + + ContactEntry? getByCustomIdSync(String customId) { + return getByIndexSync(r'customId', [customId]); + } + + Future deleteByCustomId(String customId) { + return deleteByIndex(r'customId', [customId]); + } + + bool deleteByCustomIdSync(String customId) { + return deleteByIndexSync(r'customId', [customId]); + } + + Future> getAllByCustomId(List customIdValues) { + final values = customIdValues.map((e) => [e]).toList(); + return getAllByIndex(r'customId', values); + } + + List getAllByCustomIdSync(List customIdValues) { + final values = customIdValues.map((e) => [e]).toList(); + return getAllByIndexSync(r'customId', values); + } + + Future deleteAllByCustomId(List customIdValues) { + final values = customIdValues.map((e) => [e]).toList(); + return deleteAllByIndex(r'customId', values); + } + + int deleteAllByCustomIdSync(List customIdValues) { + final values = customIdValues.map((e) => [e]).toList(); + return deleteAllByIndexSync(r'customId', values); + } + + Future putByCustomId(ContactEntry object) { + return putByIndex(r'customId', object); + } + + Id putByCustomIdSync(ContactEntry object, {bool saveLinks = true}) { + return putByIndexSync(r'customId', object, saveLinks: saveLinks); + } + + Future> putAllByCustomId(List objects) { + return putAllByIndex(r'customId', objects); + } + + List putAllByCustomIdSync(List objects, + {bool saveLinks = true}) { + return putAllByIndexSync(r'customId', objects, saveLinks: saveLinks); + } +} + +extension ContactEntryQueryWhereSort + on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension ContactEntryQueryWhere + on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo( + Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan( + Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder customIdEqualTo( + String customId) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.equalTo( + indexName: r'customId', + value: [customId], + )); + }); + } + + QueryBuilder + customIdNotEqualTo(String customId) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'customId', + lower: [], + upper: [customId], + includeUpper: false, + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'customId', + lower: [customId], + includeLower: false, + upper: [], + )); + } else { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'customId', + lower: [customId], + includeLower: false, + upper: [], + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'customId', + lower: [], + upper: [customId], + includeUpper: false, + )); + } + }); + } +} + +extension ContactEntryQueryFilter + on QueryBuilder { + QueryBuilder + addressesElementEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'addresses', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'addresses', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'addresses', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + addressesElementIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'addresses', + value: '', + )); + }); + } + + QueryBuilder + addressesElementIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'addresses', + value: '', + )); + }); + } + + QueryBuilder + addressesLengthEqualTo(int length) { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + length, + true, + length, + true, + ); + }); + } + + QueryBuilder + addressesIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + 0, + true, + 0, + true, + ); + }); + } + + QueryBuilder + addressesIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + 0, + false, + 999999, + true, + ); + }); + } + + QueryBuilder + addressesLengthLessThan( + int length, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + 0, + true, + length, + include, + ); + }); + } + + QueryBuilder + addressesLengthGreaterThan( + int length, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + length, + include, + 999999, + true, + ); + }); + } + + QueryBuilder + addressesLengthBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.listLength( + r'addresses', + lower, + includeLower, + upper, + includeUpper, + ); + }); + } + + QueryBuilder + customIdEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'customId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'customId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'customId', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + customIdIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'customId', + value: '', + )); + }); + } + + QueryBuilder + customIdIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'customId', + value: '', + )); + }); + } + + QueryBuilder + emojiCharIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'emojiChar', + )); + }); + } + + QueryBuilder + emojiCharIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'emojiChar', + )); + }); + } + + QueryBuilder + emojiCharEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'emojiChar', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'emojiChar', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'emojiChar', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + emojiCharIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'emojiChar', + value: '', + )); + }); + } + + QueryBuilder + emojiCharIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'emojiChar', + value: '', + )); + }); + } + + QueryBuilder idEqualTo( + Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder + isFavoriteEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isFavorite', + value: value, + )); + }); + } + + QueryBuilder nameEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + nameGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder + nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'name', + value: '', + )); + }); + } +} + +extension ContactEntryQueryObject + on QueryBuilder {} + +extension ContactEntryQueryLinks + on QueryBuilder {} + +extension ContactEntryQuerySortBy + on QueryBuilder { + QueryBuilder sortByCustomId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'customId', Sort.asc); + }); + } + + QueryBuilder sortByCustomIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'customId', Sort.desc); + }); + } + + QueryBuilder sortByEmojiChar() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'emojiChar', Sort.asc); + }); + } + + QueryBuilder sortByEmojiCharDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'emojiChar', Sort.desc); + }); + } + + QueryBuilder sortByIsFavorite() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavorite', Sort.asc); + }); + } + + QueryBuilder + sortByIsFavoriteDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavorite', Sort.desc); + }); + } + + QueryBuilder sortByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder sortByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension ContactEntryQuerySortThenBy + on QueryBuilder { + QueryBuilder thenByCustomId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'customId', Sort.asc); + }); + } + + QueryBuilder thenByCustomIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'customId', Sort.desc); + }); + } + + QueryBuilder thenByEmojiChar() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'emojiChar', Sort.asc); + }); + } + + QueryBuilder thenByEmojiCharDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'emojiChar', Sort.desc); + }); + } + + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByIsFavorite() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavorite', Sort.asc); + }); + } + + QueryBuilder + thenByIsFavoriteDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavorite', Sort.desc); + }); + } + + QueryBuilder thenByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder thenByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension ContactEntryQueryWhereDistinct + on QueryBuilder { + QueryBuilder distinctByAddresses() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'addresses'); + }); + } + + QueryBuilder distinctByCustomId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'customId', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByEmojiChar( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'emojiChar', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByIsFavorite() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isFavorite'); + }); + } + + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'name', caseSensitive: caseSensitive); + }); + } +} + +extension ContactEntryQueryProperty + on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder, QQueryOperations> + addressesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'addresses'); + }); + } + + QueryBuilder customIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'customId'); + }); + } + + QueryBuilder emojiCharProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'emojiChar'); + }); + } + + QueryBuilder isFavoriteProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isFavorite'); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'name'); + }); + } +} diff --git a/lib/pages/address_book_views/address_book_view.dart b/lib/pages/address_book_views/address_book_view.dart index 8e3ef0629..81b7af4ca 100644 --- a/lib/pages/address_book_views/address_book_view.dart +++ b/lib/pages/address_book_views/address_book_view.dart @@ -102,8 +102,7 @@ class _AddressBookViewState extends ConsumerState { @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( diff --git a/lib/services/address_book_service.dart b/lib/services/address_book_service.dart index e92c0b00b..6889edf6c 100644 --- a/lib/services/address_book_service.dart +++ b/lib/services/address_book_service.dart @@ -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(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 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 addresses = []; + bool isFavorite = contactEntry.isFavorite; + String id = contactEntry.customId; + for (String addressEntry in contactEntry.addresses) { + List 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.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; + List contactEntries = MainDB.instance.getContactEntries(); + List contactsList = []; + for (ContactEntry contactEntry in contactEntries) { + contactsList.add(turnEntryToContact(contactEntry: contactEntry)); + } + return contactsList; } - Future>? _addressBookEntries; - Future> get addressBookEntries => + List? _addressBookEntries; + List get addressBookEntries => _addressBookEntries ??= _fetchAddressBookEntries(); // Load address book contact entries - Future> _fetchAddressBookEntries() async { + List _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 addContact(Contact contact) async { - if (DB.instance.containsKey( - 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( - 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(); + await MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: editedContact)); + _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(); + await MainDB.instance.deleteContactEntry(id: id); + _refreshAddressBookEntries(); } - Future _refreshAddressBookEntries() async { - final newAddressBookEntries = await _fetchAddressBookEntries(); - _addressBookEntries = Future(() => newAddressBookEntries); + void _refreshAddressBookEntries() { + final newAddressBookEntries = _fetchAddressBookEntries(); + _addressBookEntries = newAddressBookEntries; notifyListeners(); } }