From 0e9035eccbc280fad8c885711b0fa015a5714d8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Tue, 13 Dec 2022 19:09:52 -0500
Subject: [PATCH] vcard: cleanup, always use Bitmap for avatar

Change-Id: Ie4fca73ef691083dedd181d3a7fad53bb825eeeb
---
 .../cx/ring/services/ContactServiceImpl.kt    |  9 ++--
 .../java/cx/ring/services/VCardServiceImpl.kt |  8 +--
 .../main/java/cx/ring/views/AvatarDrawable.kt | 16 ++----
 .../kotlin/net/jami/model/Conversation.kt     | 15 +-----
 .../src/main/kotlin/net/jami/model/Profile.kt |  6 +--
 .../kotlin/net/jami/model/TrustRequest.kt     | 26 ++-------
 .../net/jami/services/AccountService.kt       | 53 +++++++++++++------
 7 files changed, 56 insertions(+), 77 deletions(-)

diff --git a/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.kt b/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.kt
index 74a47dfa1..dbaaaab88 100644
--- a/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.kt
+++ b/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.kt
@@ -356,24 +356,23 @@ class ContactServiceImpl(val mContext: Context, preferenceService: PreferencesSe
         val profile: Single<Profile> =
             if (contact.isFromSystem) loadSystemContactData(contact)
             else loadVCardContactData(contact, accountId)
-        return profile.onErrorReturn { Profile(null, null) }
+        return profile.onErrorReturn { Profile.EMPTY_PROFILE }
     }
 
     override fun saveVCardContactData(contact: Contact, accountId: String, vcard: VCard) {
-        contact.setProfile(VCardServiceImpl.readData(vcard))
+        contact.setProfile(VCardServiceImpl.loadVCardProfile(vcard))
         val filename = contact.primaryNumber + ".vcf"
         VCardUtils.savePeerProfileToDisk(vcard, accountId, filename, mContext.filesDir)
         AvatarFactory.clearCache()
     }
 
-    override fun saveVCardContact(accountId: String, uri: String?, displayName: String?, picture: String?): Single<VCard> {
-        return Single.fromCallable {
+    override fun saveVCardContact(accountId: String, uri: String?, displayName: String?, picture: String?): Single<VCard> =
+        Single.fromCallable {
             val vcard = VCardUtils.writeData(uri, displayName, Base64.decode(picture, Base64.DEFAULT))
             val filename = "$uri.vcf"
             VCardUtils.savePeerProfileToDisk(vcard, accountId, filename, mContext.filesDir)
             vcard
         }
-    }
 
     private fun loadVCardContactData(contact: Contact, accountId: String): Single<Profile> {
         val id = contact.primaryNumber
diff --git a/ring-android/app/src/main/java/cx/ring/services/VCardServiceImpl.kt b/ring-android/app/src/main/java/cx/ring/services/VCardServiceImpl.kt
index 0d4f59adf..ef21af214 100644
--- a/ring-android/app/src/main/java/cx/ring/services/VCardServiceImpl.kt
+++ b/ring-android/app/src/main/java/cx/ring/services/VCardServiceImpl.kt
@@ -62,9 +62,7 @@ class VCardServiceImpl(private val mContext: Context) : VCardService() {
         Single.fromCallable { VCardUtils.writeData(uri, displayName, Base64.decode(picture, Base64.DEFAULT)) }
             .flatMap { vcard: VCard -> VCardUtils.saveLocalProfileToDisk(vcard, accountId, mContext.filesDir) }
 
-    override fun loadVCardProfile(vcard: VCard): Single<Profile> = Single.fromCallable {
-        readData(vcard)
-    }
+    override fun loadVCardProfile(vcard: VCard): Single<Profile> = Companion.loadVCardProfile(vcard)
 
     override fun peerProfileReceived(accountId: String, peerId: String, vcard: File): Single<Profile> =
         VCardUtils.peerProfileReceived(mContext.filesDir, accountId, peerId, vcard)
@@ -96,6 +94,10 @@ class VCardServiceImpl(private val mContext: Context) : VCardService() {
             }
         }
 
+        fun loadVCardProfile(vcard: VCard): Single<Profile> = Single.fromCallable {
+            readData(vcard)
+        }
+
         fun readData(vcard: VCard?): Profile = readData(VCardUtils.readData(vcard))
 
         private fun readData(profile: Pair<String?, ByteArray?>): Profile =
diff --git a/ring-android/app/src/main/java/cx/ring/views/AvatarDrawable.kt b/ring-android/app/src/main/java/cx/ring/views/AvatarDrawable.kt
index 7fc63a084..4bf8a5cf5 100644
--- a/ring-android/app/src/main/java/cx/ring/views/AvatarDrawable.kt
+++ b/ring-android/app/src/main/java/cx/ring/views/AvatarDrawable.kt
@@ -222,11 +222,7 @@ class AvatarDrawable : Drawable {
             withName(if (profileName.isNullOrEmpty()) username else profileName)
 
         fun withContact(contact: ContactViewModel?) = if (contact == null) this else
-            withPhoto(if (contact.profile.avatar is Bitmap)
-                contact.profile.avatar as Bitmap
-            else
-                BitmapUtils.base64ToBitmap(contact.profile.avatar as String?)
-            )
+            withPhoto(contact.profile.avatar as? Bitmap?)
                 .withId(contact.contact.primaryNumber)
                 .withPresence(contact.presence)
                 .withOnlineState(contact.contact.isOnline)
@@ -237,10 +233,7 @@ class AvatarDrawable : Drawable {
                 if (!profile.displayName.isNullOrBlank())
                     withName(profile.displayName)
                 if (profile.avatar != null) {
-                    return withPhoto(if (profile.avatar is Bitmap)
-                        profile.avatar as Bitmap
-                    else
-                        BitmapUtils.base64ToBitmap(profile.avatar as String?))
+                    return withPhoto(profile.avatar as? Bitmap?)
                 }
             }
             val bitmaps: MutableList<Bitmap> = ArrayList(contacts.size)
@@ -248,10 +241,7 @@ class AvatarDrawable : Drawable {
             for (contact in contacts) {
                 if (contact.contact.isUser) continue
                 notTheUser++
-                val bitmap = if (profile.avatar is Bitmap)
-                    profile.avatar as Bitmap
-                else
-                    BitmapUtils.base64ToBitmap(profile.avatar as String?)
+                val bitmap = profile.avatar as? Bitmap?
                 if (bitmap != null) {
                     bitmaps.add(bitmap)
                 }
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
index fc42c19e9..8f1ea595a 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
@@ -62,13 +62,7 @@ class Conversation : ConversationHistory {
     private val mMode: Subject<Mode>
 
     private val profileSubject: Subject<Single<Profile>> = BehaviorSubject.createDefault(Profile.EMPTY_PROFILE_SINGLE)
-    val profile: Observable<Profile> = profileSubject.switchMapSingle { single -> single }
-    var loadedProfile: Single<Profile>? = null
-        set(profile) {
-            field = profile
-            if  (profile != null)
-                profileSubject.onNext(profile)
-        }
+    val profile: Observable<Profile> = profileSubject.switchMapSingle { it }
 
     // runtime flag set to true if the user is currently viewing this conversation
     private var mVisible = false
@@ -221,12 +215,7 @@ class Conversation : ConversationHistory {
     }
 
     fun setProfile(profile: Single<Profile>) {
-        loadedProfile = profile
-    }
-
-    fun setProfile(profile: Profile?) {
-        if (profile != null)
-            loadedProfile = Single.just(profile)
+        profileSubject.onNext(profile)
     }
 
     fun setMode(mode: Mode) {
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Profile.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Profile.kt
index d53ae0c05..d897ffbdd 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Profile.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Profile.kt
@@ -33,13 +33,11 @@ class ContactViewModel(val contact: Contact, val profile: Profile, val registere
         get() = registeredName ?: contact.uri.toString()
     val displayName: String
         get() = profile.displayName ?: displayUri
-    //val fullProfile: Profile
-    //    get() = Profile(displayName, profile.avatar)
 
     fun matches(query: String): Boolean =
-        (profile.displayName != null && profile.displayName.lowercase().contains(query)
+        profile.displayName != null && profile.displayName.lowercase().contains(query)
                 || registeredName != null && registeredName.contains(query)
-                || contact.uri.toString().contains(query))
+                || contact.uri.toString().contains(query)
 
     companion object {
         val EMPTY_VM: Observable<ContactViewModel> =
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/TrustRequest.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/TrustRequest.kt
index f1aad43b8..6f333881a 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/TrustRequest.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/TrustRequest.kt
@@ -26,26 +26,6 @@ class TrustRequest(
     val from: Uri,
     val timestamp: Long,
     val conversationUri: Uri?,
-    var profile: Single<Profile>? = null
-)
-{
-    var message: String? = null
-    var mode: Conversation.Mode = Conversation.Mode.OneToOne
-
-    constructor(accountId: String, conversationUri: Uri?, info: Map<String, String>) : this(
-        accountId,
-        Uri.fromId(info["from"]!!),
-        info["received"]!!.toLong() * 1000L,
-        conversationUri
-    ) {
-        val title = info["title"]
-        val descr = info["descr"]
-        val avatar = info["avatar"]
-        info["mode"]?.let { m -> mode = Conversation.Mode.values()[m.toInt()] }
-
-        if (!title.isNullOrBlank()) {
-            profile = Single.just(Profile(title, avatar))
-        }
-        message = descr
-    }
-}
+    val profile: Single<Profile>? = null,
+    val mode: Conversation.Mode
+)
\ No newline at end of file
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
index 7e5c20fd4..3a0448224 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
@@ -302,16 +302,26 @@ class AccountService(
                 }
                 Log.w(TAG, "$accountId loading conversation requests")
                 for (requestData in JamiService.getConversationRequests(account.accountId)) {
-                    /* for ((key, value) in requestData.entries)
+                    try {
+                        /* for ((key, value) in requestData.entries)
                         Log.e(TAG, "Request: $key $value") */
-                    val from = Uri.fromString(requestData["from"]!!)
-                    val conversationId = requestData["id"]
-                    val conversationUri =
-                        if (conversationId.isNullOrEmpty()) null
-                        else Uri(Uri.SWARM_SCHEME, conversationId)
-                    val request = account.getRequest(conversationUri ?: from)
-                    if (request == null || conversationUri != request.from) {
-                        account.addRequest(TrustRequest(account.accountId, conversationUri, requestData))
+                        val from = Uri.fromString(requestData["from"]!!)
+                        val conversationId = requestData["id"]
+                        val conversationUri =
+                            if (conversationId.isNullOrEmpty()) null
+                            else Uri(Uri.SWARM_SCHEME, conversationId)
+                        val request = account.getRequest(conversationUri ?: from)
+                        if (request == null || conversationUri != request.from) {
+                            account.addRequest(TrustRequest(
+                                account.accountId,
+                                from,
+                                requestData["received"]!!.toLong() * 1000L,
+                                conversationUri,
+                                mVCardService.loadConversationProfile(requestData),
+                                requestData["mode"]?.let { m -> Conversation.Mode.values()[m.toInt()] } ?: Conversation.Mode.OneToOne))
+                        }
+                    } catch (e: Exception) {
+                        Log.w(TAG, "Error loading request", e)
                     }
                 }
             }
@@ -1016,6 +1026,7 @@ class AccountService(
             mVCardService.peerProfileReceived(accountId, peerId, File(vcardPath))
                 .subscribe({ profile -> contact.setProfile(profile) })
                     { e -> Log.e(TAG, "Error saving contact profile", e) }
+            //contact.setProfile(mVCardService.peerProfileReceived(accountId, peerId, File(vcardPath)))
         }
     }
 
@@ -1154,15 +1165,18 @@ class AccountService(
         val r = UserSearchResult(accountId, query, state)
         r.results = results.map { m ->
             val uri = m["id"]!!
-            val firstName = m["firstName"]
-            val lastName = m["lastName"]
             account.getContactFromCache(uri).apply {
                 synchronized(this) {
                     m["username"]?.let { name ->
                         if (this.username == null)
                             this.username = Single.just(name)
                     }
-                    setProfile(Profile("$firstName $lastName", mVCardService.base64ToBitmap(m["profilePicture"])))
+                    setProfile(Single.fromCallable {
+                        val firstName = m["firstName"]
+                        val lastName = m["lastName"]
+                        val profilePicture = m["profilePicture"]
+                        Profile("$firstName $lastName", mVCardService.base64ToBitmap(profilePicture))
+                    }.cache())
                 }
             }
         }
@@ -1170,9 +1184,9 @@ class AccountService(
     }
 
     private fun getInteraction(account: Account, conversation: Conversation, message: Map<String, String>): Interaction {
-        for ((key, value) in message) {
+        /* for ((key, value) in message) {
             Log.w(TAG, "$key -> $value")
-        }
+        } */
         val id = message["id"]!!
         val type = message["type"]!!
         val author = message["author"]!!
@@ -1376,9 +1390,16 @@ class AccountService(
             return
         }
         val conversationUri = if (conversationId.isEmpty()) null else Uri(Uri.SWARM_SCHEME, conversationId)
-        val request = account.getRequest(Uri.fromId(metadata["from"]!!))
+        val from = Uri.fromId(metadata["from"]!!)
+        val request = account.getRequest(from)
         if (request == null || conversationUri != request.conversationUri) {
-            account.addRequest(TrustRequest(account.accountId, conversationUri, metadata))
+            account.addRequest(TrustRequest(
+                account.accountId,
+                from,
+                metadata["received"]!!.toLong() * 1000L,
+                conversationUri,
+                mVCardService.loadConversationProfile(metadata),
+                metadata["mode"]?.let { m -> Conversation.Mode.values()[m.toInt()] } ?: Conversation.Mode.OneToOne))
         }
     }
 
-- 
GitLab