From 573b01ff6509e7dc8724fc0ece1dc6ac6ec4923c Mon Sep 17 00:00:00 2001 From: Moez Bhatti Date: Sun, 24 Nov 2019 00:27:39 -0500 Subject: [PATCH] =?UTF-8?q?Store=20contact=E2=80=99s=20photoUri?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So much less complicated now! --- .../moez/QKSMS/mapper/CursorToContactImpl.kt | 7 +- .../moez/QKSMS/migration/QkRealmMigration.kt | 1 + .../com/moez/QKSMS/util/ContactImageLoader.kt | 103 ------------------ .../com/moez/QKSMS/util/GlideAppModule.kt | 9 +- .../main/java/com/moez/QKSMS/model/Contact.kt | 1 + .../common/util/NotificationManagerImpl.kt | 9 +- .../common/util/QkChooserTargetService.kt | 8 +- .../moez/QKSMS/common/widget/AvatarView.kt | 37 ++----- .../QKSMS/common/widget/GroupAvatarView.kt | 4 +- .../QKSMS/feature/compose/MessagesAdapter.kt | 2 +- .../feature/compose/editing/ChipsAdapter.kt | 2 +- .../compose/editing/DetailedChipView.kt | 2 +- .../ConversationRecipientAdapter.kt | 2 +- .../QKSMS/feature/widget/WidgetAdapter.kt | 17 +-- .../com/moez/QKSMS/injection/AppComponent.kt | 5 +- 15 files changed, 36 insertions(+), 173 deletions(-) delete mode 100644 data/src/main/java/com/moez/QKSMS/util/ContactImageLoader.kt diff --git a/data/src/main/java/com/moez/QKSMS/mapper/CursorToContactImpl.kt b/data/src/main/java/com/moez/QKSMS/mapper/CursorToContactImpl.kt index 23ba4e5f..5b618d03 100644 --- a/data/src/main/java/com/moez/QKSMS/mapper/CursorToContactImpl.kt +++ b/data/src/main/java/com/moez/QKSMS/mapper/CursorToContactImpl.kt @@ -41,6 +41,7 @@ class CursorToContactImpl @Inject constructor( Phone.TYPE, Phone.LABEL, Phone.DISPLAY_NAME, + Phone.PHOTO_URI, Phone.STARRED, Phone.CONTACT_LAST_UPDATED_TIMESTAMP ) @@ -52,13 +53,15 @@ class CursorToContactImpl @Inject constructor( const val COLUMN_TYPE = 4 const val COLUMN_LABEL = 5 const val COLUMN_DISPLAY_NAME = 6 - const val COLUMN_STARRED = 7 - const val CONTACT_LAST_UPDATED = 8 + const val COLUMN_PHOTO_URI = 7 + const val COLUMN_STARRED = 8 + const val CONTACT_LAST_UPDATED = 9 } override fun map(from: Cursor) = Contact().apply { lookupKey = from.getString(COLUMN_LOOKUP_KEY) name = from.getString(COLUMN_DISPLAY_NAME) ?: "" + photoUri = from.getString(COLUMN_PHOTO_URI) numbers.add(PhoneNumber( id = from.getLong(COLUMN_ID), accountType = from.getString(COLUMN_ACCOUNT_TYPE), diff --git a/data/src/main/java/com/moez/QKSMS/migration/QkRealmMigration.kt b/data/src/main/java/com/moez/QKSMS/migration/QkRealmMigration.kt index 06a10c53..9d0970c9 100644 --- a/data/src/main/java/com/moez/QKSMS/migration/QkRealmMigration.kt +++ b/data/src/main/java/com/moez/QKSMS/migration/QkRealmMigration.kt @@ -126,6 +126,7 @@ class QkRealmMigration : RealmMigration { realm.schema.get("Contact") ?.addField("starred", Boolean::class.java, FieldAttribute.REQUIRED) + ?.addField("photoUri", String::class.java) realm.schema.get("PhoneNumber") ?.addField("id", Long::class.java, FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED) diff --git a/data/src/main/java/com/moez/QKSMS/util/ContactImageLoader.kt b/data/src/main/java/com/moez/QKSMS/util/ContactImageLoader.kt deleted file mode 100644 index c50ef35a..00000000 --- a/data/src/main/java/com/moez/QKSMS/util/ContactImageLoader.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package com.moez.QKSMS.util - -import android.content.Context -import android.provider.ContactsContract -import com.bumptech.glide.Priority -import com.bumptech.glide.load.DataSource -import com.bumptech.glide.load.Key -import com.bumptech.glide.load.Options -import com.bumptech.glide.load.data.DataFetcher -import com.bumptech.glide.load.model.ModelLoader -import com.bumptech.glide.load.model.ModelLoaderFactory -import com.bumptech.glide.load.model.MultiModelLoaderFactory -import com.moez.QKSMS.repository.ContactRepository -import com.moez.QKSMS.repository.ContactRepositoryImpl -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import java.io.InputStream -import java.security.MessageDigest - -class ContactImageLoader( - private val context: Context, - private val contactRepo: ContactRepository, - private val phoneNumberUtils: PhoneNumberUtils -) : ModelLoader { - - override fun handles(model: String): Boolean { - return model.startsWith("tel:") - } - - override fun buildLoadData( - model: String, - width: Int, - height: Int, - options: Options - ): ModelLoader.LoadData? { - return ModelLoader.LoadData( - ContactImageKey(phoneNumberUtils.normalizeNumber(model)), - ContactImageFetcher(context, contactRepo, model)) - } - - class Factory( - private val context: Context, - private val prefs: Preferences - ) : ModelLoaderFactory { - - override fun build(multiFactory: MultiModelLoaderFactory): ContactImageLoader { - return ContactImageLoader(context, ContactRepositoryImpl(context, prefs), PhoneNumberUtils(context)) - } - - override fun teardown() {} // nothing to do here - } - - class ContactImageKey(private val address: String) : Key { - override fun updateDiskCacheKey(digest: MessageDigest) = digest.update(address.toByteArray()) - } - - class ContactImageFetcher( - private val context: Context, - private val contactRepo: ContactRepository, - private val address: String - ) : DataFetcher { - - private var loadPhotoDisposable: Disposable? = null - - override fun cleanup() {} - override fun getDataClass() = InputStream::class.java - override fun getDataSource() = DataSource.LOCAL - - override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { - loadPhotoDisposable = contactRepo.findContactUri(address) - .map { uri -> - ContactsContract.Contacts.openContactPhotoInputStream(context.contentResolver, uri, true) - } - .subscribeOn(Schedulers.io()) - .subscribe( - { inputStream -> callback.onDataReady(inputStream) }, - { error -> callback.onLoadFailed(Exception(error)) }) - } - - override fun cancel() { - loadPhotoDisposable?.dispose() - } - } - -} \ No newline at end of file diff --git a/data/src/main/java/com/moez/QKSMS/util/GlideAppModule.kt b/data/src/main/java/com/moez/QKSMS/util/GlideAppModule.kt index f3b43507..cddc39f2 100644 --- a/data/src/main/java/com/moez/QKSMS/util/GlideAppModule.kt +++ b/data/src/main/java/com/moez/QKSMS/util/GlideAppModule.kt @@ -19,15 +19,12 @@ package com.moez.QKSMS.util import android.content.Context -import android.preference.PreferenceManager import android.util.Log import com.bumptech.glide.Glide import com.bumptech.glide.GlideBuilder import com.bumptech.glide.Registry import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.module.AppGlideModule -import com.f2prateek.rx.preferences2.RxSharedPreferences -import java.io.InputStream @GlideModule class GlideAppModule : AppGlideModule() { @@ -37,10 +34,6 @@ class GlideAppModule : AppGlideModule() { } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { - // TODO use DI to create the ContactImageLoader.Factory - val rxPrefs = RxSharedPreferences.create(PreferenceManager.getDefaultSharedPreferences(context)) - val prefs = Preferences(context, rxPrefs) - registry.append(String::class.java, InputStream::class.java, ContactImageLoader.Factory(context, prefs)) } -} \ No newline at end of file +} diff --git a/domain/src/main/java/com/moez/QKSMS/model/Contact.kt b/domain/src/main/java/com/moez/QKSMS/model/Contact.kt index 7e8cd27c..8c08e42a 100644 --- a/domain/src/main/java/com/moez/QKSMS/model/Contact.kt +++ b/domain/src/main/java/com/moez/QKSMS/model/Contact.kt @@ -26,6 +26,7 @@ open class Contact( @PrimaryKey var lookupKey: String = "", var numbers: RealmList = RealmList(), var name: String = "", + var photoUri: String? = null, var starred: Boolean = false, var lastUpdate: Long = 0 ) : RealmObject() { diff --git a/presentation/src/main/java/com/moez/QKSMS/common/util/NotificationManagerImpl.kt b/presentation/src/main/java/com/moez/QKSMS/common/util/NotificationManagerImpl.kt index 487b358a..4fa3a392 100644 --- a/presentation/src/main/java/com/moez/QKSMS/common/util/NotificationManagerImpl.kt +++ b/presentation/src/main/java/com/moez/QKSMS/common/util/NotificationManagerImpl.kt @@ -154,11 +154,10 @@ class NotificationManagerImpl @Inject constructor( .firstOrNull { phoneNumberUtils.compare(it.address, message.address) } person.setName(recipient?.getDisplayName() ?: message.address) - person.setIcon(GlideApp.with(context) .asBitmap() .circleCrop() - .load("tel:${message.address}") + .load(recipient?.contact?.photoUri) .submit(64.dpToPx(context), 64.dpToPx(context)) .let { futureGet -> tryOrNull(false) { futureGet.get() } } ?.let(IconCompat::createWithBitmap)) @@ -178,12 +177,12 @@ class NotificationManagerImpl @Inject constructor( // Set the large icon val avatar = conversation.recipients.takeIf { it.size == 1 } - ?.first()?.address - ?.let { address -> + ?.first()?.contact?.photoUri + ?.let { photoUri -> GlideApp.with(context) .asBitmap() .circleCrop() - .load("tel:$address") + .load(photoUri) .submit(64.dpToPx(context), 64.dpToPx(context)) } ?.let { futureGet -> tryOrNull(false) { futureGet.get() } } diff --git a/presentation/src/main/java/com/moez/QKSMS/common/util/QkChooserTargetService.kt b/presentation/src/main/java/com/moez/QKSMS/common/util/QkChooserTargetService.kt index 0d97a675..13cd86b0 100644 --- a/presentation/src/main/java/com/moez/QKSMS/common/util/QkChooserTargetService.kt +++ b/presentation/src/main/java/com/moez/QKSMS/common/util/QkChooserTargetService.kt @@ -52,13 +52,13 @@ class QkChooserTargetService : ChooserTargetService() { } private fun createShortcutForConversation(conversation: Conversation): ChooserTarget { - val icon = when { - conversation.recipients.size == 1 -> { - val address = conversation.recipients.first()!!.address + val icon = when (conversation.recipients.size) { + 1 -> { + val photoUri = conversation.recipients.first()?.contact?.photoUri val request = GlideApp.with(this) .asBitmap() .circleCrop() - .load("tel:$address") + .load(photoUri) .submit() val bitmap = tryOrNull(false) { request.get() } diff --git a/presentation/src/main/java/com/moez/QKSMS/common/widget/AvatarView.kt b/presentation/src/main/java/com/moez/QKSMS/common/widget/AvatarView.kt index a5b2ca15..70fc0b39 100644 --- a/presentation/src/main/java/com/moez/QKSMS/common/widget/AvatarView.kt +++ b/presentation/src/main/java/com/moez/QKSMS/common/widget/AvatarView.kt @@ -22,7 +22,6 @@ import android.content.Context import android.util.AttributeSet import android.view.View import android.widget.FrameLayout -import com.bumptech.glide.signature.ObjectKey import com.moez.QKSMS.R import com.moez.QKSMS.common.Navigator import com.moez.QKSMS.common.util.Colors @@ -30,7 +29,6 @@ import com.moez.QKSMS.common.util.extensions.setBackgroundTint import com.moez.QKSMS.common.util.extensions.setTint import com.moez.QKSMS.injection.appComponent import com.moez.QKSMS.model.Contact -import com.moez.QKSMS.model.Recipient import com.moez.QKSMS.util.GlideApp import kotlinx.android.synthetic.main.avatar_view.view.* import javax.inject.Inject @@ -54,7 +52,7 @@ class AvatarView @JvmOverloads constructor( private var lookupKey: String? = null private var name: String? = null - private var address: String? = null + private var photoUri: String? = null private var lastUpdated: Long? = null init { @@ -68,33 +66,13 @@ class AvatarView @JvmOverloads constructor( clipToOutline = true } - /** - * If the [recipient] has a contact: use the contact's avatar, but keep the address. - * Use the recipient address otherwise. - */ - fun setContact(recipient: Recipient?) { - // If the recipient has a contact, just use that and return - recipient?.contact?.let { contact -> - setContact(contact, recipient.address) - return - } - - lookupKey = null - name = null - address = recipient?.address - lastUpdated = 0 - updateView() - } - /** * Use the [contact] information to display the avatar. - * A specific [contactAddress] can be specified (useful when the contact has several addresses). */ - fun setContact(contact: Contact?, contactAddress: String? = null) { + fun setContact(contact: Contact?) { lookupKey = contact?.lookupKey name = contact?.name - // If a contactAddress has been given, we use it. Use the contact address otherwise. - address = contactAddress?.takeIf { it.isNotEmpty() } ?: contact?.numbers?.firstOrNull()?.address + photoUri = contact?.photoUri lastUpdated = contact?.lastUpdate updateView() } @@ -108,7 +86,7 @@ class AvatarView @JvmOverloads constructor( } } - fun applyTheme(threadId: Long) { + private fun applyTheme(threadId: Long) { colors.theme(threadId).run { setBackgroundTint(theme) initial.setTextColor(textPrimary) @@ -130,11 +108,10 @@ class AvatarView @JvmOverloads constructor( } photo.setImageDrawable(null) - address?.let { address -> + photoUri?.let { photoUri -> GlideApp.with(photo) - .load("tel:$address") - .signature(ObjectKey(lastUpdated ?: 0L)) + .load(photoUri) .into(photo) } } -} \ No newline at end of file +} diff --git a/presentation/src/main/java/com/moez/QKSMS/common/widget/GroupAvatarView.kt b/presentation/src/main/java/com/moez/QKSMS/common/widget/GroupAvatarView.kt index 904ec460..706e5425 100644 --- a/presentation/src/main/java/com/moez/QKSMS/common/widget/GroupAvatarView.kt +++ b/presentation/src/main/java/com/moez/QKSMS/common/widget/GroupAvatarView.kt @@ -63,8 +63,8 @@ class GroupAvatarView @JvmOverloads constructor( } avatar2.isVisible = contacts.size > 1 - avatar1.setContact(contacts.getOrNull(0)) - avatar2.setContact(contacts.getOrNull(1)) + avatar1.setContact(contacts.getOrNull(0)?.contact) + avatar2.setContact(contacts.getOrNull(1)?.contact) } } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt index 9443fb34..de24eff1 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt @@ -234,7 +234,7 @@ class MessagesAdapter @Inject constructor( // Bind the avatar if (!message.isMe()) { view.avatar.threadId = conversation?.id ?: 0 - view.avatar.setContact(contactCache[message.address]) + view.avatar.setContact(contactCache[message.address]?.contact) view.avatar.setVisible(!canGroup(message, next), View.INVISIBLE) } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/ChipsAdapter.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/ChipsAdapter.kt index f0dc7935..9c23632a 100755 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/ChipsAdapter.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/ChipsAdapter.kt @@ -51,7 +51,7 @@ class ChipsAdapter @Inject constructor() : QkAdapter() { val chip = getItem(position) val view = holder.containerView - view.avatar.setContact(chip.contact, chip.address) + view.avatar.setContact(chip.contact) view.name.text = chip.contact?.name?.takeIf { it.isNotBlank() } ?: chip.address } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/DetailedChipView.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/DetailedChipView.kt index 262d0ab6..ce35202a 100755 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/DetailedChipView.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/editing/DetailedChipView.kt @@ -54,7 +54,7 @@ class DetailedChipView(context: Context) : RelativeLayout(context) { } fun setChip(chip: Chip) { - avatar.setContact(chip.contact, chip.address) + avatar.setContact(chip.contact) name.text = chip.contact?.name?.takeIf { it.isNotBlank() } ?: chip.address info.text = chip.address } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/conversationinfo/ConversationRecipientAdapter.kt b/presentation/src/main/java/com/moez/QKSMS/feature/conversationinfo/ConversationRecipientAdapter.kt index f98f51bd..92f0b2cf 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/conversationinfo/ConversationRecipientAdapter.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/conversationinfo/ConversationRecipientAdapter.kt @@ -55,7 +55,7 @@ class ConversationRecipientAdapter @Inject constructor() : QkRealmAdapter - val futureGet = GlideApp.with(context) - .asBitmap() - .load("tel:$address") - .submit(48.dpToPx(context), 48.dpToPx(context)) - - try { - remoteViews.setImageViewBitmap(R.id.photo, futureGet.get()) - } catch (e: Exception) { - } - } + val futureGet = GlideApp.with(context) + .asBitmap() + .load(contact?.photoUri) + .submit(48.dpToPx(context), 48.dpToPx(context)) + tryOrNull(false) { remoteViews.setImageViewBitmap(R.id.photo, futureGet.get()) } // Name remoteViews.setTextColor(R.id.name, textPrimary) diff --git a/presentation/src/main/java/com/moez/QKSMS/injection/AppComponent.kt b/presentation/src/main/java/com/moez/QKSMS/injection/AppComponent.kt index ae548127..a1208c9b 100644 --- a/presentation/src/main/java/com/moez/QKSMS/injection/AppComponent.kt +++ b/presentation/src/main/java/com/moez/QKSMS/injection/AppComponent.kt @@ -43,7 +43,6 @@ import com.moez.QKSMS.feature.widget.WidgetAdapter import com.moez.QKSMS.injection.android.ActivityBuilderModule import com.moez.QKSMS.injection.android.BroadcastReceiverBuilderModule import com.moez.QKSMS.injection.android.ServiceBuilderModule -import com.moez.QKSMS.util.ContactImageLoader import dagger.Component import dagger.android.support.AndroidSupportInjectionModule import javax.inject.Singleton @@ -73,8 +72,6 @@ interface AppComponent { fun inject(dialog: QkDialog) - fun inject(fetcher: ContactImageLoader.ContactImageFetcher) - fun inject(service: WidgetAdapter) /** @@ -91,4 +88,4 @@ interface AppComponent { fun inject(view: QkSwitch) fun inject(view: QkTextView) -} \ No newline at end of file +}