diff --git a/lib/contact.dart b/lib/contact.dart index 03ad4c8b..651c9d6b 100644 --- a/lib/contact.dart +++ b/lib/contact.dart @@ -78,9 +78,15 @@ class Contact { /// The full-resolution contact picture. Uint8List? photo; + /// The Logo element + Uint8List? logo; + /// Returns the full-resolution photo if available, the thumbnail otherwise. Uint8List? get photoOrThumbnail => photo ?? thumbnail; + /// The GEO element + List? geo; + /// Whether the contact is starred (Android only). bool isStarred; @@ -134,6 +140,7 @@ class Contact { this.displayName = '', this.thumbnail, this.photo, + this.logo, this.isStarred = false, Name? name, List? phones, @@ -163,6 +170,7 @@ class Contact { displayName: (json['displayName'] as String?) ?? '', thumbnail: json['thumbnail'] as Uint8List?, photo: json['photo'] as Uint8List?, + logo: json['logo'] as Uint8List?, isStarred: (json['isStarred'] as bool?) ?? false, name: Name.fromJson(Map.from(json['name'] ?? {})), phones: ((json['phones'] as List?) ?? []) @@ -200,12 +208,14 @@ class Contact { Map toJson({ bool withThumbnail = true, bool withPhoto = true, + bool withLogo = true, }) => Map.from({ 'id': id, 'displayName': displayName, 'thumbnail': withThumbnail ? thumbnail : null, 'photo': withPhoto ? photo : null, + 'logo': withLogo ? logo : null, 'isStarred': isStarred, 'name': name.toJson(), 'phones': phones.map((x) => x.toJson()).toList(), @@ -226,6 +236,7 @@ class Contact { displayName.hashCode ^ thumbnail.hashCode ^ photo.hashCode ^ + logo.hashCode ^ isStarred.hashCode ^ name.hashCode ^ _listHashCode(phones) ^ @@ -244,6 +255,7 @@ class Contact { o.displayName == displayName && o.thumbnail == thumbnail && o.photo == photo && + o.logo == logo && o.isStarred == isStarred && o.name == name && _listEqual(o.phones, phones) && @@ -258,7 +270,7 @@ class Contact { @override String toString() => 'Contact(id=$id, displayName=$displayName, thumbnail=$thumbnail, ' - 'photo=$photo, isStarred=$isStarred, name=$name, phones=$phones, ' + 'photo=$photo, logo=$logo, isStarred=$isStarred, name=$name, phones=$phones, ' 'emails=$emails, addresses=$addresses, organizations=$organizations, ' 'websites=$websites, socialMedias=$socialMedias, events=$events, ' 'notes=$notes, accounts=$accounts, groups=$groups)'; @@ -286,6 +298,7 @@ class Contact { /// "-//Apple Inc.//Mac OS X 10.15.7//EN" String toVCard({ bool withPhoto = true, + bool withLogo = true, String? productId, bool includeDate = false, }) { @@ -323,6 +336,17 @@ class Contact { v4 ? 'PHOTO:data:image/jpeg;base64,' : 'PHOTO;ENCODING=b;TYPE=JPEG:'; lines.add(prefix + encoding); } + if (withLogo && logo != null) { + final encoding = vCardEncode(base64.encode(logo!)); + final prefix = + v4 ? 'LOGO:data:image/jpeg;base64,' : 'LOGO;ENCODING=b;TYPE=JPEG:'; + lines.add(prefix + encoding); + } + if (geo != null && geo!.length == 2) { + final encoding = vCardEncode( + '${geo![0].toStringAsFixed(5)};${geo![1].toStringAsFixed(5)}'); + lines.add('GEO:$encoding'); + } lines.addAll([ name.toVCard(), phones.map((x) => x.toVCard()).expand((x) => x), diff --git a/lib/vcard.dart b/lib/vcard.dart index 67e127e4..668bb5cf 100644 --- a/lib/vcard.dart +++ b/lib/vcard.dart @@ -116,6 +116,28 @@ class VCardParser { // Pass. } break; + case 'LOGO': + // The content can be base64-encoded or a URL. Try to decode it, and + // ignore the line if it fails. + try { + contact.logo = base64.decode(decode(content)); + } on FormatException { + // Pass. + } + break; + case 'GEO': + if (content.isNotEmpty && content.contains(';')) { + final split = content.split(';'); + try { + contact.geo = [ + double.parse(split[0]), + double.parse(split[1]) + ]; + } on FormatException { + //pass + } + } + break; case 'N': // Format is N:;;;; final parts = content.split(';');