mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
172 lines
5 KiB
Dart
172 lines
5 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:cake_wallet/entities/parsed_address.dart';
|
|
import 'package:cw_core/crypto_currency.dart';
|
|
import 'package:cw_core/hive_type_ids.dart';
|
|
import 'package:cw_core/keyable.dart';
|
|
import 'package:hive/hive.dart';
|
|
|
|
part 'contact.g.dart';
|
|
|
|
@HiveType(typeId: Contact.typeId)
|
|
class Contact extends HiveObject with Keyable {
|
|
Contact({
|
|
required this.name,
|
|
this.address = '',
|
|
CryptoCurrency? type,
|
|
Map<String, Map<int, Map<String, String>>> parsedByHandle = const {},
|
|
Map<int, Map<String, String>> manualAddresses = const {},
|
|
Map<String, String> extraBlobs = const {},
|
|
AddressSource source = AddressSource.notParsed,
|
|
this.handle = '',
|
|
this.imagePath = '',
|
|
this.profileName = '',
|
|
this.description = '',
|
|
DateTime? lastChange,
|
|
}) : raw = type?.raw ?? 0,
|
|
_parsedJson = _encode(parsedByHandle),
|
|
_manualJson = _encode(manualAddresses),
|
|
extraJsonBlobs = extraBlobs,
|
|
sourceRaw = source.raw,
|
|
lastChange = lastChange ?? DateTime.now();
|
|
|
|
static const typeId = CONTACT_TYPE_ID;
|
|
static const boxName = 'Contacts';
|
|
|
|
@HiveField(0, defaultValue: '')
|
|
String name;
|
|
|
|
@HiveField(1, defaultValue: '')
|
|
String address;
|
|
|
|
@HiveField(2, defaultValue: 0)
|
|
int raw;
|
|
|
|
@HiveField(3)
|
|
DateTime lastChange;
|
|
|
|
@HiveField(4, defaultValue: '')
|
|
String _parsedJson;
|
|
|
|
@HiveField(5, defaultValue: '')
|
|
String _manualJson;
|
|
|
|
@HiveField(6, defaultValue: '')
|
|
String handle;
|
|
|
|
@HiveField(7, defaultValue: '')
|
|
String imagePath;
|
|
|
|
@HiveField(8, defaultValue: '')
|
|
String profileName;
|
|
|
|
@HiveField(9, defaultValue: '')
|
|
String description;
|
|
|
|
@HiveField(10, defaultValue: 0)
|
|
int sourceRaw;
|
|
|
|
@HiveField(11, defaultValue: {})
|
|
Map<String, String> extraJsonBlobs;
|
|
|
|
AddressSource get source => AddressSourceIndex.fromRaw(sourceRaw);
|
|
|
|
set source(AddressSource v) => sourceRaw = v.raw;
|
|
|
|
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
|
|
|
|
set type(CryptoCurrency v) => raw = v.raw;
|
|
|
|
Map<String, Map<int, Map<String, String>>> get parsedByHandle => _decodeParsed(_parsedJson);
|
|
|
|
set parsedByHandle(Map<String, Map<int, Map<String, String>>> v) => _parsedJson = _encode(v);
|
|
|
|
Map<int, Map<String, String>> get manualAddresses => _decodeManual(_manualJson);
|
|
|
|
set manualAddresses(Map<int, Map<String, String>> v) => _manualJson = _encode(v);
|
|
|
|
Map<CryptoCurrency, Map<String, String>> get manualByCurrency => manualAddresses.map(
|
|
(k, v) => MapEntry(CryptoCurrency.deserialize(raw: k), v),
|
|
);
|
|
|
|
Map<CryptoCurrency, Map<String, String>> get parsedByCurrency {
|
|
final out = <CryptoCurrency, Map<String, String>>{};
|
|
for (final block in parsedByHandle.values) {
|
|
block.forEach((curRaw, lblMap) {
|
|
final cur = CryptoCurrency.deserialize(raw: curRaw);
|
|
out.putIfAbsent(cur, () => {})..addAll(lblMap);
|
|
});
|
|
}
|
|
return out;
|
|
}
|
|
|
|
@override
|
|
dynamic get keyIndex => key;
|
|
|
|
@override
|
|
bool operator ==(Object o) => o is Contact && o.key == key;
|
|
|
|
@override
|
|
int get hashCode => key.hashCode;
|
|
|
|
static String _encode(Object value) => jsonEncode(_stringifyKeys(value));
|
|
|
|
static dynamic _stringifyKeys(dynamic obj) {
|
|
if (obj is Map) {
|
|
return obj.map(
|
|
(k, v) => MapEntry(k.toString(), _stringifyKeys(v)),
|
|
);
|
|
}
|
|
if (obj is Iterable) return obj.map(_stringifyKeys).toList();
|
|
return obj;
|
|
}
|
|
|
|
static Map<String, Map<int, Map<String, String>>> _decodeParsed(String s) {
|
|
if (s.isEmpty) return {};
|
|
final Map<String, dynamic> data = jsonDecode(s) as Map<String, dynamic>;
|
|
return data.map((handle, byCur) {
|
|
final inner = (byCur as Map<String, dynamic>).map((curRaw, lblMap) {
|
|
final int cur = int.parse(curRaw);
|
|
final labels = (lblMap as Map).cast<String, String>();
|
|
return MapEntry(cur, labels);
|
|
});
|
|
return MapEntry(handle, inner);
|
|
});
|
|
}
|
|
|
|
static Map<int, Map<String, String>> _decodeManual(String s) {
|
|
if (s.isEmpty) return {};
|
|
final Map<String, dynamic> data = jsonDecode(s) as Map<String, dynamic>;
|
|
return data.map((curRaw, lblMap) {
|
|
final int cur = int.parse(curRaw);
|
|
final labels = (lblMap as Map).cast<String, String>();
|
|
return MapEntry(cur, labels);
|
|
});
|
|
}
|
|
|
|
factory Contact.fromParsed(ParsedAddress p, {String? localImage}) {
|
|
final manual = <int, Map<String, String>>{};
|
|
p.manualAddressByCurrencyMap?.forEach(
|
|
(cur, addr) => manual[cur.raw] = {cur.title: addr},
|
|
);
|
|
|
|
final parsed = <String, Map<int, Map<String, String>>>{};
|
|
if (p.parsedAddressByCurrencyMap.isNotEmpty) {
|
|
final hKey = '${p.addressSource.label}-${p.handle}';
|
|
parsed[hKey] = {
|
|
for (final e in p.parsedAddressByCurrencyMap.entries) e.key.raw: {e.key.title: e.value}
|
|
};
|
|
}
|
|
|
|
return Contact(
|
|
name: p.profileName.isNotEmpty ? p.profileName : p.handle,
|
|
profileName: p.profileName,
|
|
handle: p.handle,
|
|
description: p.description,
|
|
source: p.addressSource,
|
|
imagePath: localImage ?? '',
|
|
manualAddresses: manual,
|
|
parsedByHandle: parsed,
|
|
);
|
|
}
|
|
}
|