Skip to content
Snippets Groups Projects
Commit 1b723a1c authored by vjrj's avatar vjrj
Browse files

Improved contact cache. Contact serialization fix

parent bf426462
No related branches found
No related tags found
No related merge requests found
...@@ -5,6 +5,7 @@ import 'package:equatable/equatable.dart'; ...@@ -5,6 +5,7 @@ import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'is_json_serializable.dart'; import 'is_json_serializable.dart';
import 'model_utils.dart';
part 'contact.g.dart'; part 'contact.g.dart';
...@@ -13,7 +14,7 @@ part 'contact.g.dart'; ...@@ -13,7 +14,7 @@ part 'contact.g.dart';
class Contact extends Equatable implements IsJsonSerializable<Contact> { class Contact extends Equatable implements IsJsonSerializable<Contact> {
const Contact({ const Contact({
this.nick, this.nick,
required this.pubkey, required this.pubKey,
this.avatar, this.avatar,
this.notes, this.notes,
this.name, this.name,
...@@ -23,14 +24,14 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> { ...@@ -23,14 +24,14 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> {
_$ContactFromJson(json); _$ContactFromJson(json);
final String? nick; final String? nick;
final String pubkey; final String pubKey;
@JsonKey(fromJson: _fromList, toJson: _toList) @JsonKey(fromJson: uIntFromList, toJson: uIntToList)
final Uint8List? avatar; final Uint8List? avatar;
final String? notes; final String? notes;
final String? name; final String? name;
@override @override
List<Object?> get props => <dynamic>[nick, pubkey, avatar, notes, name]; List<Object?> get props => <dynamic>[nick, pubKey, avatar, notes, name];
@override @override
Map<String, dynamic> toJson() => _$ContactToJson(this); Map<String, dynamic> toJson() => _$ContactToJson(this);
...@@ -38,13 +39,8 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> { ...@@ -38,13 +39,8 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> {
@override @override
Contact fromJson(Map<String, dynamic> json) => Contact.fromJson(json); Contact fromJson(Map<String, dynamic> json) => Contact.fromJson(json);
static Uint8List _fromList(List<int> list) => Uint8List.fromList(list);
static List<int> _toList(Uint8List? uint8List) =>
uint8List != null ? uint8List.toList() : <int>[];
@override @override
String toString() { String toString() {
return 'Contact $pubkey, hasAvatar: ${avatar != null}, nick: $nick, name: $name'; return 'Contact $pubKey, hasAvatar: ${avatar != null}, nick: $nick, name: $name';
} }
} }
...@@ -9,7 +9,7 @@ part of 'contact.dart'; ...@@ -9,7 +9,7 @@ part of 'contact.dart';
abstract class _$ContactCWProxy { abstract class _$ContactCWProxy {
Contact nick(String? nick); Contact nick(String? nick);
Contact pubkey(String pubkey); Contact pubKey(String pubKey);
Contact avatar(Uint8List? avatar); Contact avatar(Uint8List? avatar);
...@@ -25,7 +25,7 @@ abstract class _$ContactCWProxy { ...@@ -25,7 +25,7 @@ abstract class _$ContactCWProxy {
/// ```` /// ````
Contact call({ Contact call({
String? nick, String? nick,
String? pubkey, String? pubKey,
Uint8List? avatar, Uint8List? avatar,
String? notes, String? notes,
String? name, String? name,
...@@ -42,7 +42,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy { ...@@ -42,7 +42,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
Contact nick(String? nick) => this(nick: nick); Contact nick(String? nick) => this(nick: nick);
@override @override
Contact pubkey(String pubkey) => this(pubkey: pubkey); Contact pubKey(String pubKey) => this(pubKey: pubKey);
@override @override
Contact avatar(Uint8List? avatar) => this(avatar: avatar); Contact avatar(Uint8List? avatar) => this(avatar: avatar);
...@@ -63,7 +63,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy { ...@@ -63,7 +63,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
/// ```` /// ````
Contact call({ Contact call({
Object? nick = const $CopyWithPlaceholder(), Object? nick = const $CopyWithPlaceholder(),
Object? pubkey = const $CopyWithPlaceholder(), Object? pubKey = const $CopyWithPlaceholder(),
Object? avatar = const $CopyWithPlaceholder(), Object? avatar = const $CopyWithPlaceholder(),
Object? notes = const $CopyWithPlaceholder(), Object? notes = const $CopyWithPlaceholder(),
Object? name = const $CopyWithPlaceholder(), Object? name = const $CopyWithPlaceholder(),
...@@ -73,10 +73,10 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy { ...@@ -73,10 +73,10 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
? _value.nick ? _value.nick
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: nick as String?, : nick as String?,
pubkey: pubkey == const $CopyWithPlaceholder() || pubkey == null pubKey: pubKey == const $CopyWithPlaceholder() || pubKey == null
? _value.pubkey ? _value.pubKey
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: pubkey as String, : pubKey as String,
avatar: avatar == const $CopyWithPlaceholder() avatar: avatar == const $CopyWithPlaceholder()
? _value.avatar ? _value.avatar
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
...@@ -105,16 +105,16 @@ extension $ContactCopyWith on Contact { ...@@ -105,16 +105,16 @@ extension $ContactCopyWith on Contact {
Contact _$ContactFromJson(Map<String, dynamic> json) => Contact( Contact _$ContactFromJson(Map<String, dynamic> json) => Contact(
nick: json['nick'] as String?, nick: json['nick'] as String?,
pubkey: json['pubkey'] as String, pubKey: json['pubKey'] as String,
avatar: Contact._fromList(json['avatar'] as List<int>), avatar: uIntFromList(json['avatar']),
notes: json['notes'] as String?, notes: json['notes'] as String?,
name: json['name'] as String?, name: json['name'] as String?,
); );
Map<String, dynamic> _$ContactToJson(Contact instance) => <String, dynamic>{ Map<String, dynamic> _$ContactToJson(Contact instance) => <String, dynamic>{
'nick': instance.nick, 'nick': instance.nick,
'pubkey': instance.pubkey, 'pubKey': instance.pubKey,
'avatar': Contact._toList(instance.avatar), 'avatar': uIntToList(instance.avatar),
'notes': instance.notes, 'notes': instance.notes,
'name': instance.name, 'name': instance.name,
}; };
...@@ -9,7 +9,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> { ...@@ -9,7 +9,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
Contact? _find(Contact contact) { Contact? _find(Contact contact) {
try { try {
return state.contacts return state.contacts
.firstWhere((Contact c) => c.pubkey == contact.pubkey); .firstWhere((Contact c) => c.pubKey == contact.pubKey);
} catch (e) { } catch (e) {
return null; return null;
} }
...@@ -24,10 +24,10 @@ class ContactsCubit extends HydratedCubit<ContactsState> { ...@@ -24,10 +24,10 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
void removeContact(Contact contact) { void removeContact(Contact contact) {
final List<Contact> contactsTruncated = state.contacts final List<Contact> contactsTruncated = state.contacts
.where((Contact c) => c.pubkey != contact.pubkey) .where((Contact c) => c.pubKey != contact.pubKey)
.toList(); .toList();
final List<Contact> filteredContactsTruncated = state.filteredContacts final List<Contact> filteredContactsTruncated = state.filteredContacts
.where((Contact c) => c.pubkey != contact.pubkey) .where((Contact c) => c.pubKey != contact.pubKey)
.toList(); .toList();
emit(state.copyWith( emit(state.copyWith(
contacts: contactsTruncated, contacts: contactsTruncated,
...@@ -36,7 +36,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> { ...@@ -36,7 +36,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
void updateContact(Contact contact) { void updateContact(Contact contact) {
final List<Contact> contacts = state.contacts.map((Contact c) { final List<Contact> contacts = state.contacts.map((Contact c) {
if (c.pubkey == contact.pubkey) { if (c.pubKey == contact.pubKey) {
return contact; return contact;
} }
return c; return c;
...@@ -50,7 +50,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> { ...@@ -50,7 +50,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
void filterContacts(String query) { void filterContacts(String query) {
final List<Contact> contacts = state.contacts.where((Contact c) { final List<Contact> contacts = state.contacts.where((Contact c) {
if (c.pubkey.contains(query)) { if (c.pubKey.contains(query)) {
return true; return true;
} }
if (c.nick != null && c.nick!.contains(query)) { if (c.nick != null && c.nick!.contains(query)) {
...@@ -91,5 +91,5 @@ class ContactsCubit extends HydratedCubit<ContactsState> { ...@@ -91,5 +91,5 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
String get id => 'contacts'; String get id => 'contacts';
bool isContact(String pubKey) => bool isContact(String pubKey) =>
state.contacts.any((Contact c) => c.pubkey == pubKey); state.contacts.any((Contact c) => c.pubKey == pubKey);
} }
import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
Uint8List uIntFromList(List<int> list) => Uint8List.fromList(list); Uint8List? uIntFromList(dynamic value) {
if (value is List<int> && value.isNotEmpty) {
return Uint8List.fromList(value);
} else if (value is String && value.isNotEmpty) {
return base64Decode(value);
} else {
return null;
}
}
List<int> uIntToList(Uint8List? uInt8List) => List<int> uIntToList(Uint8List? uInt8List) =>
uInt8List != null ? uInt8List.toList() : <int>[]; uInt8List != null ? uInt8List.toList() : <int>[];
...@@ -9,7 +9,7 @@ part of 'payment_state.dart'; ...@@ -9,7 +9,7 @@ part of 'payment_state.dart';
PaymentState _$PaymentStateFromJson(Map<String, dynamic> json) => PaymentState( PaymentState _$PaymentStateFromJson(Map<String, dynamic> json) => PaymentState(
publicKey: json['publicKey'] as String, publicKey: json['publicKey'] as String,
nick: json['nick'] as String?, nick: json['nick'] as String?,
avatar: uIntFromList(json['avatar'] as List<int>), avatar: uIntFromList(json['avatar']),
comment: json['comment'] as String? ?? '', comment: json['comment'] as String? ?? '',
amount: (json['amount'] as num?)?.toDouble(), amount: (json['amount'] as num?)?.toDouble(),
status: $enumDecodeNullable(_$PaymentStatusEnumMap, json['status']) ?? status: $enumDecodeNullable(_$PaymentStatusEnumMap, json['status']) ??
......
...@@ -242,9 +242,9 @@ Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction( ...@@ -242,9 +242,9 @@ Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction(
amount: (json['amount'] as num).toDouble(), amount: (json['amount'] as num).toDouble(),
comment: json['comment'] as String, comment: json['comment'] as String,
time: DateTime.parse(json['time'] as String), time: DateTime.parse(json['time'] as String),
toAvatar: uIntFromList(json['toAvatar'] as List<int>), toAvatar: uIntFromList(json['toAvatar']),
toNick: json['toNick'] as String?, toNick: json['toNick'] as String?,
fromAvatar: uIntFromList(json['fromAvatar'] as List<int>), fromAvatar: uIntFromList(json['fromAvatar']),
fromNick: json['fromNick'] as String?, fromNick: json['fromNick'] as String?,
); );
......
...@@ -56,7 +56,7 @@ Future<Contact> getProfile(String pubKey) async { ...@@ -56,7 +56,7 @@ Future<Contact> getProfile(String pubKey) async {
final Map<String, dynamic> result = final Map<String, dynamic> result =
const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>; const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>;
if (result['found'] == false) { if (result['found'] == false) {
return Contact(pubkey: pubKey); return Contact(pubKey: pubKey);
} }
final String? nick = await gvaNick(pubKey); final String? nick = await gvaNick(pubKey);
...@@ -68,7 +68,7 @@ Future<Contact> getProfile(String pubKey) async { ...@@ -68,7 +68,7 @@ Future<Contact> getProfile(String pubKey) async {
return c.copyWith(nick: nick); return c.copyWith(nick: nick);
} catch (e) { } catch (e) {
logger('Error in getProfile $e'); logger('Error in getProfile $e');
return Contact(pubkey: pubKey); return Contact(pubKey: pubKey);
} }
} }
...@@ -100,7 +100,7 @@ Future<List<Contact>> searchWot(String searchTerm) async { ...@@ -100,7 +100,7 @@ Future<List<Contact>> searchWot(String searchTerm) async {
final String pubKey = resultMap['pubkey'] as String; final String pubKey = resultMap['pubkey'] as String;
// ignore: avoid_dynamic_calls // ignore: avoid_dynamic_calls
final String nick = resultMap['uids'][0]['uid']! as String; final String nick = resultMap['uids'][0]['uid']! as String;
contacts.add(Contact(nick: nick, pubkey: pubKey)); contacts.add(Contact(nick: nick, pubKey: pubKey));
} }
} }
} }
...@@ -110,7 +110,7 @@ Future<List<Contact>> searchWot(String searchTerm) async { ...@@ -110,7 +110,7 @@ Future<List<Contact>> searchWot(String searchTerm) async {
Future<Contact> getWot(Contact contact) async { Future<Contact> getWot(Contact contact) async {
final Response response = await requestDuniterWithRetry( final Response response = await requestDuniterWithRetry(
'/wot/lookup/${contact.pubkey}', '/wot/lookup/${contact.pubKey}',
retryWith404: false); retryWith404: false);
// Will be better to analyze the 404 response (to detect faulty node) // Will be better to analyze the 404 response (to detect faulty node)
if (response.statusCode == HttpStatus.ok) { if (response.statusCode == HttpStatus.ok) {
......
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:html'; import 'dart:html';
...@@ -7,34 +8,6 @@ import '../data/models/contact.dart'; ...@@ -7,34 +8,6 @@ import '../data/models/contact.dart';
import '../g1/api.dart'; import '../g1/api.dart';
import 'logger.dart'; import 'logger.dart';
class ContactsCacheBasic {
factory ContactsCacheBasic() {
_instance ??= ContactsCacheBasic._internal();
return _instance!;
}
ContactsCacheBasic._internal();
static ContactsCacheBasic? _instance;
final Map<String, Contact> _cache = <String, Contact>{};
Future<Contact> getContact(String pubKey) async {
final String cacheKey = 'avatar-$pubKey';
final Contact? cachedContact = _cache[cacheKey];
if (cachedContact != null) {
return cachedContact;
}
final Contact contact = await getProfile(pubKey);
_cache[cacheKey] = contact;
return contact;
}
}
class ContactsCache { class ContactsCache {
factory ContactsCache() { factory ContactsCache() {
_instance ??= ContactsCache._internal(); _instance ??= ContactsCache._internal();
...@@ -44,6 +17,7 @@ class ContactsCache { ...@@ -44,6 +17,7 @@ class ContactsCache {
ContactsCache._internal(); ContactsCache._internal();
static ContactsCache? _instance; static ContactsCache? _instance;
final Map<String, List<Completer<Contact>>> _pendingRequests = {};
Future<Contact> getContact(String pubKey) async { Future<Contact> getContact(String pubKey) async {
final String cacheKey = 'avatar-$pubKey'; final String cacheKey = 'avatar-$pubKey';
...@@ -53,13 +27,13 @@ class ContactsCache { ...@@ -53,13 +27,13 @@ class ContactsCache {
final String? cachedValue = window.localStorage[cacheKey]; final String? cachedValue = window.localStorage[cacheKey];
if (cachedValue != null) { if (cachedValue != null) {
final Map<String, dynamic> decodedValue = final Map<String, dynamic> decodedValue =
json.decode(cachedValue) as Map<String, dynamic>; json.decode(cachedValue) as Map<String, dynamic>;
final DateTime timestamp = final DateTime timestamp =
DateTime.parse(decodedValue['timestamp'] as String); DateTime.parse(decodedValue['timestamp'] as String);
if (DateTime.now().isBefore(timestamp.add(duration))) { if (DateTime.now().isBefore(timestamp.add(duration))) {
final Contact contact = final Contact contact =
Contact.fromJson(decodedValue['data'] as Map<String, dynamic>); Contact.fromJson(decodedValue['data'] as Map<String, dynamic>);
if (!kReleaseMode) { if (!kReleaseMode) {
logger('Returning cached contact $contact'); logger('Returning cached contact $contact');
} }
...@@ -70,16 +44,40 @@ class ContactsCache { ...@@ -70,16 +44,40 @@ class ContactsCache {
logger('Error while retrieving contact from cache: $e, $pubKey'); logger('Error while retrieving contact from cache: $e, $pubKey');
} }
final Contact contact = await getProfile(pubKey); if (_pendingRequests.containsKey(pubKey)) {
final Completer<Contact> completer = Completer<Contact>();
_pendingRequests[pubKey]!.add(completer);
return completer.future;
}
final Completer<Contact> completer = Completer<Contact>();
_pendingRequests[pubKey] = <Completer<Contact>>[completer];
try {
final Contact contact = await getProfile(pubKey);
final String encodedValue = json.encode(<String, dynamic>{
'timestamp': DateTime.now().toIso8601String(),
'data': contact.toJson(),
});
window.localStorage[cacheKey] = encodedValue;
if (!kReleaseMode) {
logger('Returning non cached contact $contact');
}
// Send to listeners
for (final Completer<Contact> completer in _pendingRequests[pubKey]!) {
completer.complete(contact);
}
_pendingRequests.remove(pubKey);
return contact;
} catch (e) {
// Send error to listeners
for (final Completer<Contact> completer in _pendingRequests[pubKey]!) {
completer.completeError(e);
}
_pendingRequests.remove(pubKey);
final String encodedValue = json.encode(<String, dynamic>{ rethrow;
'timestamp': DateTime.now().toIso8601String(),
'data': contact.toJson(),
});
window.localStorage[cacheKey] = encodedValue;
if (!kReleaseMode) {
logger('Returning non cached contact $contact');
} }
return contact;
} }
} }
...@@ -124,7 +124,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) { ...@@ -124,7 +124,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) {
final Map<String, dynamic> source = record['_source'] as Map<String, dynamic>; final Map<String, dynamic> source = record['_source'] as Map<String, dynamic>;
final Uint8List? avatarBase64 = _getAvatarFromResults(source); final Uint8List? avatarBase64 = _getAvatarFromResults(source);
return Contact( return Contact(
pubkey: record['_id'] as String, pubKey: record['_id'] as String,
name: source['title'] as String, name: source['title'] as String,
avatar: avatarBase64); avatar: avatarBase64);
} }
...@@ -132,7 +132,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) { ...@@ -132,7 +132,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) {
Contact contactFromUserProfile(Map<String, dynamic> source) { Contact contactFromUserProfile(Map<String, dynamic> source) {
final Uint8List? avatarBase64 = _getAvatarFromResults(source); final Uint8List? avatarBase64 = _getAvatarFromResults(source);
return Contact( return Contact(
pubkey: source['issuer'] as String, pubKey: source['issuer'] as String,
name: source['title'] as String, name: source['title'] as String,
avatar: avatarBase64); avatar: avatarBase64);
} }
......
...@@ -66,7 +66,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> { ...@@ -66,7 +66,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
logger('$_searchTerm looks like a plain pub key'); logger('$_searchTerm looks like a plain pub key');
setState(() { setState(() {
_isLoading = true; _isLoading = true;
final Contact contact = Contact(pubkey: _searchTerm); final Contact contact = Contact(pubKey: _searchTerm);
_results.add(contact); _results.add(contact);
_isLoading = false; _isLoading = false;
}); });
...@@ -107,7 +107,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> { ...@@ -107,7 +107,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
if (_results.length == 1 && pay != null) { if (_results.length == 1 && pay != null) {
final Contact contact = _results[0]; final Contact contact = _results[0];
paymentCubit.selectUser( paymentCubit.selectUser(
contact.pubkey, contact.pubKey,
contact.nick ?? contact.name, contact.nick ?? contact.name,
contact.avatar, contact.avatar,
pay.amount); pay.amount);
...@@ -191,7 +191,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> { ...@@ -191,7 +191,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
Widget _buildItem(Contact contact, int index, BuildContext context) { Widget _buildItem(Contact contact, int index, BuildContext context) {
logger('Contact retrieved $contact'); logger('Contact retrieved $contact');
final String pubKey = contact.pubkey; final String pubKey = contact.pubKey;
final String title = contact.nick ?? contact.name ?? humanizePubKey(pubKey); final String title = contact.nick ?? contact.name ?? humanizePubKey(pubKey);
final Widget? subtitle = (contact.nick != null || contact.name != null) final Widget? subtitle = (contact.nick != null || contact.name != null)
? Text(humanizePubKey(pubKey)) ? Text(humanizePubKey(pubKey))
...@@ -226,7 +226,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> { ...@@ -226,7 +226,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
contactsCubit.addContact(contact); contactsCubit.addContact(contact);
} else { } else {
contactsCubit.removeContact(Contact( contactsCubit.removeContact(Contact(
pubkey: pubKey, pubKey: pubKey,
)); ));
} }
}); });
......
...@@ -194,7 +194,7 @@ class TransactionListItem extends StatelessWidget { ...@@ -194,7 +194,7 @@ class TransactionListItem extends StatelessWidget {
})); }));
Future<Contact> _fetchContact(String pubKey, Transaction transaction) async { Future<Contact> _fetchContact(String pubKey, Transaction transaction) async {
return Contact(pubkey: pubKey); return Contact(pubKey: pubKey);
if (pubKey == transaction.from) { if (pubKey == transaction.from) {
return ContactsCache().getContact(transaction.to); return ContactsCache().getContact(transaction.to);
} else { } else {
......
...@@ -104,7 +104,7 @@ class _ContactsPageState extends State<ContactsPage> { ...@@ -104,7 +104,7 @@ class _ContactsPageState extends State<ContactsPage> {
children: <SlidableAction>[ children: <SlidableAction>[
SlidableAction( SlidableAction(
onPressed: (BuildContext c) { onPressed: (BuildContext c) {
FlutterClipboard.copy(contact.pubkey).then( FlutterClipboard.copy(contact.pubKey).then(
(dynamic value) => ScaffoldMessenger.of( (dynamic value) => ScaffoldMessenger.of(
context) context)
.showSnackBar(SnackBar( .showSnackBar(SnackBar(
...@@ -132,9 +132,9 @@ class _ContactsPageState extends State<ContactsPage> { ...@@ -132,9 +132,9 @@ class _ContactsPageState extends State<ContactsPage> {
? Text(contact.nick!) ? Text(contact.nick!)
: contact.name != null : contact.name != null
? Text(contact.name!) ? Text(contact.name!)
: humanizePubKeyAsWidget(contact.pubkey), : humanizePubKeyAsWidget(contact.pubKey),
subtitle: contact.nick != null || contact.name != null subtitle: contact.nick != null || contact.name != null
? humanizePubKeyAsWidget(contact.pubkey) ? humanizePubKeyAsWidget(contact.pubKey)
: null, : null,
leading: avatar( leading: avatar(
contact.avatar, contact.avatar,
...@@ -155,7 +155,7 @@ class _ContactsPageState extends State<ContactsPage> { ...@@ -155,7 +155,7 @@ class _ContactsPageState extends State<ContactsPage> {
void onSent(BuildContext c, Contact contact) { void onSent(BuildContext c, Contact contact) {
c c
.read<PaymentCubit>() .read<PaymentCubit>()
.selectUser(contact.pubkey, contact.nick, contact.avatar); .selectUser(contact.pubKey, contact.nick, contact.avatar);
c.read<BottomNavCubit>().updateIndex(0); c.read<BottomNavCubit>().updateIndex(0);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment