Migrate to coroutines from AsyncTask for saving of custom artist images
This commit is contained in:
parent
612b492aee
commit
ee300722af
4 changed files with 80 additions and 186 deletions
|
@ -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,12 +339,16 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val selectImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {result->
|
private val selectImageLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
result.data?.data?.let {
|
result.data?.data?.let {
|
||||||
|
lifecycleScope.launch {
|
||||||
CustomArtistImageUtil.getInstance(requireContext())
|
CustomArtistImageUtil.getInstance(requireContext())
|
||||||
.setCustomArtistImage(artist, it)
|
.setCustomArtistImage(artist, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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()
}
|
|
|
@ -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,62 +40,60 @@ 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()
|
||||||
|
withContext(IO) {
|
||||||
|
runCatching {
|
||||||
|
GlideApp.with(context)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(uri)
|
.load(uri)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.skipMemoryCache(true)
|
.skipMemoryCache(true)
|
||||||
.into(object : SimpleTarget<Bitmap>() {
|
.submit()
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
.get()
|
||||||
super.onLoadFailed(errorDrawable)
|
}
|
||||||
App.getContext().showToast("Load Failed")
|
.onSuccess {
|
||||||
|
saveImage(context, artist, it)
|
||||||
|
}
|
||||||
|
.onFailure {
|
||||||
|
context.showToast("Load Failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
private fun saveImage(context: Context, artist: Artist, bitmap: Bitmap) {
|
||||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
val dir = File(context.filesDir, FOLDER_NAME)
|
||||||
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.exists()) {
|
||||||
if (!dir.mkdirs()) { // create the folder
|
if (!dir.mkdirs()) { // create the folder
|
||||||
return null
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val file = File(dir, getFileName(artist))
|
val file = File(dir, getFileName(artist))
|
||||||
|
|
||||||
var succesful = false
|
var successful = false
|
||||||
try {
|
try {
|
||||||
file.outputStream().buffered().use { bos ->
|
file.outputStream().buffered().use { bos ->
|
||||||
succesful = ImageUtil.resizeBitmap(resource, 2048)
|
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
||||||
.compress(Bitmap.CompressFormat.JPEG, 100, bos)
|
.compress(Bitmap.CompressFormat.JPEG, 100, bos)
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.getContext().showToast(e.toString(), Toast.LENGTH_LONG)
|
context.showToast(e.toString(), Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (succesful) {
|
if (successful) {
|
||||||
mPreferences.edit { putBoolean(getFileName(artist), true) }
|
mPreferences.edit { putBoolean(getFileName(artist), true) }
|
||||||
ArtistSignatureUtil.getInstance(App.getContext())
|
ArtistSignatureUtil.getInstance(context)
|
||||||
.updateArtistSignature(artist.name)
|
.updateArtistSignature(artist.name)
|
||||||
App.getContext().contentResolver.notifyChange(
|
context.contentResolver.notifyChange(
|
||||||
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
|
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
|
||||||
null
|
null
|
||||||
) // trigger media store changed to force artist image reload
|
) // trigger media store changed to force artist image reload
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
suspend fun resetCustomArtistImage(artist: Artist) {
|
||||||
fun resetCustomArtistImage(artist: Artist) {
|
withContext(IO) {
|
||||||
object : AsyncTask<Void, Void, Void>() {
|
mPreferences.edit { putBoolean(getFileName(artist), false) }
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
override fun doInBackground(vararg params: Void): Void? {
|
|
||||||
mPreferences.edit(commit = true) { putBoolean(getFileName(artist), false) }
|
|
||||||
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
||||||
App.getContext().contentResolver.notifyChange(
|
App.getContext().contentResolver.notifyChange(
|
||||||
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
|
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
|
||||||
|
@ -106,14 +101,10 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
||||||
) // trigger media store changed to force artist image reload
|
) // trigger media store changed to force artist image reload
|
||||||
|
|
||||||
val file = getFile(artist)
|
val file = getFile(artist)
|
||||||
if (!file.exists()) {
|
if (file.exists()) {
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
file.delete()
|
file.delete()
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// shared prefs saves us many IO operations
|
// shared prefs saves us many IO operations
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue