From e9a3b041b0b5a7f87fbebe4cbcbd64de4873e25b Mon Sep 17 00:00:00 2001 From: CraZyLegenD Date: Mon, 21 Dec 2020 19:36:11 +0100 Subject: [PATCH] fix: better audio loading --- .../adapters/single/AudioSingleViewHolder.kt | 6 ++- .../audiopicker/audios/AudiosVM.kt | 10 +++-- .../java/com/crazylegend/core/Extensions.kt | 17 +++++++++ .../crazylegend/core/abstracts/AbstractAVM.kt | 17 ++++++++- .../core/adapters/BaseViewHolder.kt | 38 +++++++++++++++++++ .../imagepicker/images/ImagesVM.kt | 7 ++-- .../videopicker/videos/VideosVM.kt | 7 ++-- 7 files changed, 90 insertions(+), 12 deletions(-) diff --git a/audiopicker/src/main/java/com/crazylegend/audiopicker/adapters/single/AudioSingleViewHolder.kt b/audiopicker/src/main/java/com/crazylegend/audiopicker/adapters/single/AudioSingleViewHolder.kt index c93db13..137d3f3 100644 --- a/audiopicker/src/main/java/com/crazylegend/audiopicker/adapters/single/AudioSingleViewHolder.kt +++ b/audiopicker/src/main/java/com/crazylegend/audiopicker/adapters/single/AudioSingleViewHolder.kt @@ -1,5 +1,6 @@ package com.crazylegend.audiopicker.adapters.single +import com.bumptech.glide.Glide import com.crazylegend.audiopicker.audios.AudioModel import com.crazylegend.audiopicker.databinding.ItemviewAudioBinding import com.crazylegend.core.adapters.BaseViewHolder @@ -23,7 +24,10 @@ internal class AudioSingleViewHolder(private val binding: ItemviewAudioBinding, if (item.thumbnail == null) { loadPlaceHolders(viewHolderPlaceholderModifier, binding.image) } else { - binding.image.setImageBitmap(item.thumbnail) + Glide + .with(binding.image) + .load(item.thumbnail) + .into(binding.image) } viewHolderTitleTextModifier?.apply { applyTextParamsConstraint(binding.bottomText) diff --git a/audiopicker/src/main/java/com/crazylegend/audiopicker/audios/AudiosVM.kt b/audiopicker/src/main/java/com/crazylegend/audiopicker/audios/AudiosVM.kt index 7316306..c5bc1c6 100644 --- a/audiopicker/src/main/java/com/crazylegend/audiopicker/audios/AudiosVM.kt +++ b/audiopicker/src/main/java/com/crazylegend/audiopicker/audios/AudiosVM.kt @@ -8,6 +8,7 @@ import androidx.core.database.getLongOrNull import androidx.core.database.getStringOrNull import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.crazylegend.audiopicker.listeners.onShouldRecycleBitmaps import com.crazylegend.core.abstracts.AbstractAVM @@ -22,7 +23,8 @@ import kotlinx.coroutines.withContext /** * Created by crazy on 5/8/20 to long live and prosper ! */ -internal class AudiosVM(application: Application) : AbstractAVM(application) { +internal class AudiosVM(application: Application, + stateHandle: SavedStateHandle) : AbstractAVM(application, stateHandle) { private val audioData = MutableLiveData>() val audio: LiveData> = audioData @@ -46,7 +48,8 @@ internal class AudiosVM(application: Application) : AbstractAVM(application) { private fun initializeContentObserver(sortOrder: SortOrder) { if (contentObserver == null) { contentObserver = contentResolver.registerObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI) { - canLoad = true + setCanLoad() + loadAudios(sortOrder) } } @@ -132,7 +135,8 @@ internal class AudiosVM(application: Application) : AbstractAVM(application) { } } } - canLoad = false + + setCanNotLoad() loadingIndicatorData.value = false return audio } diff --git a/core/src/main/java/com/crazylegend/core/Extensions.kt b/core/src/main/java/com/crazylegend/core/Extensions.kt index ca04120..6d82fe8 100644 --- a/core/src/main/java/com/crazylegend/core/Extensions.kt +++ b/core/src/main/java/com/crazylegend/core/Extensions.kt @@ -43,6 +43,23 @@ internal inline fun AppCompatImageView.loadImage(uri: Uri, crossinline onLoadFai .into(this) } +internal inline fun AppCompatImageView.loadWholeImage(uri: Uri, crossinline onLoadFailed: () -> Unit = {}) { + Glide.with(this) + .load(uri) + .listener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { + onLoadFailed() + return true + } + + override fun onResourceReady(resource: Drawable?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { + return false + } + }) + .centerCrop() + .into(this) +} + inline fun setupModifier(modifier: BaseMultiPickerModifier.() -> Unit) = BaseMultiPickerModifier().also(modifier) diff --git a/core/src/main/java/com/crazylegend/core/abstracts/AbstractAVM.kt b/core/src/main/java/com/crazylegend/core/abstracts/AbstractAVM.kt index b8fea3e..505785f 100644 --- a/core/src/main/java/com/crazylegend/core/abstracts/AbstractAVM.kt +++ b/core/src/main/java/com/crazylegend/core/abstracts/AbstractAVM.kt @@ -12,13 +12,19 @@ import android.util.Size import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import com.crazylegend.core.context /** * Created by crazy on 5/14/20 to long live and prosper ! */ -abstract class AbstractAVM(application: Application) : AndroidViewModel(application) { +abstract class AbstractAVM(application: Application, + private val stateHandle: SavedStateHandle) : AndroidViewModel(application) { + + companion object { + private const val CAN_LOAD_KEY = "canLoad" + } protected val contentResolver get() = context.contentResolver protected var contentObserver: ContentObserver? = null @@ -29,8 +35,15 @@ abstract class AbstractAVM(application: Application) : AndroidViewModel(applicat /** * Using this instead of event since it serves the same purpose thus it's needed here */ - protected var canLoad = true + protected val canLoad get() = stateHandle[CAN_LOAD_KEY] ?: true + protected fun setCanLoad() { + stateHandle[CAN_LOAD_KEY] = true + } + + protected fun setCanNotLoad() { + stateHandle[CAN_LOAD_KEY] = false + } override fun onCleared() { super.onCleared() diff --git a/core/src/main/java/com/crazylegend/core/adapters/BaseViewHolder.kt b/core/src/main/java/com/crazylegend/core/adapters/BaseViewHolder.kt index 33009b1..5d5370d 100644 --- a/core/src/main/java/com/crazylegend/core/adapters/BaseViewHolder.kt +++ b/core/src/main/java/com/crazylegend/core/adapters/BaseViewHolder.kt @@ -1,6 +1,12 @@ package com.crazylegend.core.adapters +import android.content.ContentResolver +import android.graphics.Bitmap +import android.graphics.BitmapFactory import android.net.Uri +import android.os.Build +import android.provider.MediaStore +import android.util.Size import androidx.appcompat.widget.AppCompatImageView import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding @@ -23,6 +29,38 @@ open class BaseViewHolder(binding: ViewBinding) : RecyclerView.ViewHolder(bindin } } + /** + * Or just use Glide with the contentUri + * @param contentResolver ContentResolver + * @param customSize Size + * @param options Options? + * @return Bitmap? + */ + @Suppress("DEPRECATION") + fun loadThumbnail(contentResolver: ContentResolver, + contentUri: Uri, + id: Long, + customSize: Size = Size(350, 350), + legacyKind: Int = MediaStore.Video.Thumbnails.MICRO_KIND, + options: BitmapFactory.Options? = null): Bitmap? { + return tryOrNull { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + contentResolver.loadThumbnail(contentUri, customSize, null) + } else { + MediaStore.Video.Thumbnails.getThumbnail(contentResolver, id, legacyKind, + options ?: BitmapFactory.Options()) + } + } + } + + private fun tryOrNull(function: () -> Bitmap): Bitmap? { + return try { + function() + } catch (e: Exception) { + null + } + } + fun loadPlaceHolders(viewHolderPlaceholderModifier: ImageModifier?, image: AppCompatImageView) { if (viewHolderPlaceholderModifier != null) { viewHolderPlaceholderModifier.resID = viewHolderPlaceholderModifier.resID diff --git a/imagepicker/src/main/java/com/crazylegend/imagepicker/images/ImagesVM.kt b/imagepicker/src/main/java/com/crazylegend/imagepicker/images/ImagesVM.kt index 0fa21ca..423069a 100644 --- a/imagepicker/src/main/java/com/crazylegend/imagepicker/images/ImagesVM.kt +++ b/imagepicker/src/main/java/com/crazylegend/imagepicker/images/ImagesVM.kt @@ -8,6 +8,7 @@ import androidx.core.database.getLongOrNull import androidx.core.database.getStringOrNull import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.crazylegend.core.abstracts.AbstractAVM import com.crazylegend.core.sorting.SortOrder @@ -21,7 +22,7 @@ import kotlinx.coroutines.withContext /** * Created by crazy on 5/8/20 to long live and prosper ! */ -internal class ImagesVM(application: Application) : AbstractAVM(application) { +internal class ImagesVM(application: Application, stateHandle: SavedStateHandle) : AbstractAVM(application, stateHandle) { private val imagesData = MutableLiveData>() val images: LiveData> = imagesData @@ -39,7 +40,7 @@ internal class ImagesVM(application: Application) : AbstractAVM(application) { private fun initializeContentObserver(sortOrder: SortOrder) { if (contentObserver == null) { contentObserver = contentResolver.registerObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI) { - canLoad = true + setCanLoad() loadImages(sortOrder) } } @@ -108,7 +109,7 @@ internal class ImagesVM(application: Application) : AbstractAVM(application) { } } } - canLoad = false + setCanNotLoad() loadingIndicatorData.value = false return images } diff --git a/videopicker/src/main/java/com/crazylegend/videopicker/videos/VideosVM.kt b/videopicker/src/main/java/com/crazylegend/videopicker/videos/VideosVM.kt index 2100692..a8a3cf9 100644 --- a/videopicker/src/main/java/com/crazylegend/videopicker/videos/VideosVM.kt +++ b/videopicker/src/main/java/com/crazylegend/videopicker/videos/VideosVM.kt @@ -8,6 +8,7 @@ import androidx.core.database.getLongOrNull import androidx.core.database.getStringOrNull import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.crazylegend.core.abstracts.AbstractAVM import com.crazylegend.core.sorting.SortOrder @@ -21,7 +22,7 @@ import kotlinx.coroutines.withContext /** * Created by crazy on 5/8/20 to long live and prosper ! */ -internal class VideosVM(application: Application) : AbstractAVM(application) { +internal class VideosVM(application: Application, stateHandle: SavedStateHandle) : AbstractAVM(application, stateHandle) { private val videoData = MutableLiveData>() val videos: LiveData> = videoData @@ -39,7 +40,7 @@ internal class VideosVM(application: Application) : AbstractAVM(application) { private fun initializeContentObserver(sortOrder: SortOrder) { if (contentObserver == null) { contentObserver = contentResolver.registerObserver(MediaStore.Video.Media.EXTERNAL_CONTENT_URI) { - canLoad = true + setCanLoad() loadVideos(sortOrder) } } @@ -115,7 +116,7 @@ internal class VideosVM(application: Application) : AbstractAVM(application) { } } } - canLoad = false + setCanNotLoad() loadingIndicatorData.value = false return video }