Migrate to coroutines from AsyncTask for saving of custom artist images

This commit is contained in:
Prathamesh More 2022-05-05 10:48:21 +05:30
parent 612b492aee
commit ee300722af
4 changed files with 80 additions and 186 deletions

View file

@ -173,7 +173,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
private fun loadBiography( private fun loadBiography(
name: String, name: String,
lang: String? = Locale.getDefault().language lang: String? = Locale.getDefault().language,
) { ) {
biography = null biography = null
this.lang = lang this.lang = lang
@ -274,12 +274,16 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
R.id.action_set_artist_image -> { R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*" intent.type = "image/*"
selectImageLauncher.launch(Intent.createChooser(intent, getString(R.string.pick_from_local_storage))) selectImageLauncher.launch(Intent.createChooser(intent,
getString(R.string.pick_from_local_storage)))
return true return true
} }
R.id.action_reset_artist_image -> { R.id.action_reset_artist_image -> {
showToast(resources.getString(R.string.updating)) showToast(resources.getString(R.string.updating))
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist) lifecycleScope.launch {
CustomArtistImageUtil.getInstance(requireContext())
.resetCustomArtistImage(artist)
}
forceDownload = true forceDownload = true
return true return true
} }
@ -335,14 +339,18 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
} }
} }
private val selectImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {result-> private val selectImageLauncher =
if (result.resultCode == Activity.RESULT_OK) { registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
result.data?.data?.let { if (result.resultCode == Activity.RESULT_OK) {
CustomArtistImageUtil.getInstance(requireContext()) result.data?.data?.let {
.setCustomArtistImage(artist, it) lifecycleScope.launch {
CustomArtistImageUtil.getInstance(requireContext())
.setCustomArtistImage(artist, it)
}
}
} }
} }
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_artist_detail, menu) inflater.inflate(R.menu.menu_artist_detail, menu)

View file

@ -1,104 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This 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.
*
* This software 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.
*/
package code.name.monkey.retromusic.misc;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
public abstract class DialogAsyncTask<Params, Progress, Result>
extends WeakContextAsyncTask<Params, Progress, Result> {
private final int delay;
private WeakReference<Dialog> dialogWeakReference;
private boolean supposedToBeDismissed;
public DialogAsyncTask(Context context) {
this(context, 0);
}
public DialogAsyncTask(Context context, int showDelay) {
super(context);
this.delay = showDelay;
dialogWeakReference = new WeakReference<>(null);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (delay > 0) {
new Handler().postDelayed(this::initAndShowDialog, delay);
} else {
initAndShowDialog();
}
}
private void initAndShowDialog() {
Context context = getContext();
if (!supposedToBeDismissed && context != null) {
Dialog dialog = createDialog(context);
dialogWeakReference = new WeakReference<>(dialog);
dialog.show();
}
}
@SuppressWarnings("unchecked")
@Override
protected void onProgressUpdate(Progress... values) {
super.onProgressUpdate(values);
Dialog dialog = getDialog();
if (dialog != null) {
onProgressUpdate(dialog, values);
}
}
@SuppressWarnings("unchecked")
protected void onProgressUpdate(@NonNull Dialog dialog, Progress... values) {}
@Nullable
protected Dialog getDialog() {
return dialogWeakReference.get();
}
@Override
protected void onCancelled(Result result) {
super.onCancelled(result);
tryToDismiss();
}
@Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
tryToDismiss();
}
private void tryToDismiss() {
supposedToBeDismissed = true;
try {
Dialog dialog = getDialog();
if (dialog != null) dialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract Dialog createDialog(@NonNull Context context);
}

View file

@ -1 +0,0 @@
/* * Copyright (c) 2019 Hemanth Savarala. * * Licensed under the GNU General Public License v3 * * This 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. * * This software 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. */ package code.name.monkey.retromusic.misc import android.content.Context import android.os.AsyncTask import java.lang.ref.WeakReference abstract class WeakContextAsyncTask<Params, Progress, Result>(context: Context) : AsyncTask<Params, Progress, Result>() { private val contextWeakReference: WeakReference<Context> = WeakReference(context) protected val context: Context? get() = contextWeakReference.get() }

View file

@ -14,23 +14,20 @@
package code.name.monkey.retromusic.util package code.name.monkey.retromusic.util
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.AsyncTask
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast import android.widget.Toast
import androidx.core.content.edit import androidx.core.content.edit
import code.name.monkey.retromusic.App import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.SimpleTarget import kotlinx.coroutines.Dispatchers.IO
import com.bumptech.glide.request.transition.Transition import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.util.* import java.util.*
@ -43,77 +40,71 @@ class CustomArtistImageUtil private constructor(context: Context) {
Context.MODE_PRIVATE Context.MODE_PRIVATE
) )
fun setCustomArtistImage(artist: Artist, uri: Uri) { suspend fun setCustomArtistImage(artist: Artist, uri: Uri) {
Glide.with(App.getContext()) val context = App.getContext()
.asBitmap() withContext(IO) {
.load(uri) runCatching {
.diskCacheStrategy(DiskCacheStrategy.NONE) GlideApp.with(context)
.skipMemoryCache(true) .asBitmap()
.into(object : SimpleTarget<Bitmap>() { .load(uri)
override fun onLoadFailed(errorDrawable: Drawable?) { .diskCacheStrategy(DiskCacheStrategy.NONE)
super.onLoadFailed(errorDrawable) .skipMemoryCache(true)
App.getContext().showToast("Load Failed") .submit()
.get()
}
.onSuccess {
saveImage(context, artist, it)
} }
.onFailure {
@SuppressLint("StaticFieldLeak") context.showToast("Load Failed")
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void): Void? {
val dir = File(App.getContext().filesDir, FOLDER_NAME)
if (!dir.exists()) {
if (!dir.mkdirs()) { // create the folder
return null
}
}
val file = File(dir, getFileName(artist))
var succesful = false
try {
file.outputStream().buffered().use { bos ->
succesful = ImageUtil.resizeBitmap(resource, 2048)
.compress(Bitmap.CompressFormat.JPEG, 100, bos)
}
} catch (e: IOException) {
App.getContext().showToast(e.toString(), Toast.LENGTH_LONG)
}
if (succesful) {
mPreferences.edit { putBoolean(getFileName(artist), true) }
ArtistSignatureUtil.getInstance(App.getContext())
.updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
}
return null
}
}.execute()
} }
}) }
} }
@SuppressLint("StaticFieldLeak") private fun saveImage(context: Context, artist: Artist, bitmap: Bitmap) {
fun resetCustomArtistImage(artist: Artist) { val dir = File(context.filesDir, FOLDER_NAME)
object : AsyncTask<Void, Void, Void>() { if (!dir.exists()) {
@SuppressLint("ApplySharedPref") if (!dir.mkdirs()) { // create the folder
override fun doInBackground(vararg params: Void): Void? { return
mPreferences.edit(commit = true) { putBoolean(getFileName(artist), false) }
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
val file = getFile(artist)
if (!file.exists()) {
return null
} else {
file.delete()
}
return null
} }
}.execute() }
val file = File(dir, getFileName(artist))
var successful = false
try {
file.outputStream().buffered().use { bos ->
successful = ImageUtil.resizeBitmap(bitmap, 2048)
.compress(Bitmap.CompressFormat.JPEG, 100, bos)
}
} catch (e: IOException) {
context.showToast(e.toString(), Toast.LENGTH_LONG)
}
if (successful) {
mPreferences.edit { putBoolean(getFileName(artist), true) }
ArtistSignatureUtil.getInstance(context)
.updateArtistSignature(artist.name)
context.contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
}
}
suspend fun resetCustomArtistImage(artist: Artist) {
withContext(IO) {
mPreferences.edit { putBoolean(getFileName(artist), false) }
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
val file = getFile(artist)
if (file.exists()) {
file.delete()
}
}
} }
// shared prefs saves us many IO operations // shared prefs saves us many IO operations