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(
|
||||
name: String,
|
||||
lang: String? = Locale.getDefault().language
|
||||
lang: String? = Locale.getDefault().language,
|
||||
) {
|
||||
biography = null
|
||||
this.lang = lang
|
||||
|
@ -274,12 +274,16 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
|||
R.id.action_set_artist_image -> {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
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
|
||||
}
|
||||
R.id.action_reset_artist_image -> {
|
||||
showToast(resources.getString(R.string.updating))
|
||||
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
|
||||
lifecycleScope.launch {
|
||||
CustomArtistImageUtil.getInstance(requireContext())
|
||||
.resetCustomArtistImage(artist)
|
||||
}
|
||||
forceDownload = true
|
||||
return true
|
||||
}
|
||||
|
@ -335,14 +339,18 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
|||
}
|
||||
}
|
||||
|
||||
private val selectImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {result->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
CustomArtistImageUtil.getInstance(requireContext())
|
||||
.setCustomArtistImage(artist, it)
|
||||
private val selectImageLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
lifecycleScope.launch {
|
||||
CustomArtistImageUtil.getInstance(requireContext())
|
||||
.setCustomArtistImage(artist, it)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_artist_detail, menu)
|
||||
|
|
|
@ -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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.provider.MediaStore
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.extensions.showToast
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
@ -43,77 +40,71 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
|||
Context.MODE_PRIVATE
|
||||
)
|
||||
|
||||
fun setCustomArtistImage(artist: Artist, uri: Uri) {
|
||||
Glide.with(App.getContext())
|
||||
.asBitmap()
|
||||
.load(uri)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.skipMemoryCache(true)
|
||||
.into(object : SimpleTarget<Bitmap>() {
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(errorDrawable)
|
||||
App.getContext().showToast("Load Failed")
|
||||
suspend fun setCustomArtistImage(artist: Artist, uri: Uri) {
|
||||
val context = App.getContext()
|
||||
withContext(IO) {
|
||||
runCatching {
|
||||
GlideApp.with(context)
|
||||
.asBitmap()
|
||||
.load(uri)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.skipMemoryCache(true)
|
||||
.submit()
|
||||
.get()
|
||||
}
|
||||
.onSuccess {
|
||||
saveImage(context, artist, it)
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
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()
|
||||
.onFailure {
|
||||
context.showToast("Load Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
fun resetCustomArtistImage(artist: Artist) {
|
||||
object : AsyncTask<Void, Void, Void>() {
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun doInBackground(vararg params: Void): Void? {
|
||||
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
|
||||
private fun saveImage(context: Context, artist: Artist, bitmap: Bitmap) {
|
||||
val dir = File(context.filesDir, FOLDER_NAME)
|
||||
if (!dir.exists()) {
|
||||
if (!dir.mkdirs()) { // create the folder
|
||||
return
|
||||
}
|
||||
}.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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue