From 8e64f117f9fee0257fb1626bae69243f3c4b0451 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 22 Nov 2021 15:31:33 +0530 Subject: [PATCH] Fixed tag editing for Android 11+ devices --- .../tageditor/AbsTagEditorActivity.kt | 102 +++++++-- .../tageditor/AlbumTagEditorActivity.kt | 6 + .../tageditor/SongTagEditorActivity.kt | 3 + .../activities/tageditor/TagWriter.kt | 203 ++++++++++++++++++ .../tageditor/WriteTagsAsyncTask.java | 152 ------------- .../fragments/other/LyricsFragment.kt | 22 +- .../model/{LoadingInfo.kt => AudioTagInfo.kt} | 2 +- .../name/monkey/retromusic/util/MusicUtil.kt | 14 +- 8 files changed, 323 insertions(+), 181 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java rename app/src/main/java/code/name/monkey/retromusic/model/{LoadingInfo.kt => AudioTagInfo.kt} (90%) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt index 361555bb..3c6d0c7e 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt @@ -21,28 +21,36 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle +import android.provider.MediaStore import android.util.Log import android.view.LayoutInflater import android.view.MenuItem import android.view.animation.OvershootInterpolator import android.widget.ImageView +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.TintHelper +import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R.drawable import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.saf.SAFGuideActivity import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.model.ArtworkInfo -import code.name.monkey.retromusic.model.LoadingInfo +import code.name.monkey.retromusic.model.AudioTagInfo import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.SAFUtil import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.jaudiotagger.audio.AudioFile import org.jaudiotagger.audio.AudioFileIO import org.jaudiotagger.tag.FieldKey @@ -66,9 +74,12 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { private var savedArtworkInfo: ArtworkInfo? = null private var _binding: VB? = null protected val binding: VB get() = _binding!! + private var cacheFiles = listOf() abstract val bindingInflater: (LayoutInflater) -> VB + private lateinit var launcher: ActivityResultLauncher + protected abstract fun loadImageFromFile(selectedFile: Uri?) protected val show: AlertDialog @@ -195,7 +206,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { super.onCreate(savedInstanceState) _binding = bindingInflater.invoke(layoutInflater) setContentView(binding.root) - setStatusbarColorAuto() setTaskDescriptionColorAuto() saveFab = findViewById(R.id.saveTags) @@ -207,6 +217,11 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { finish() } setUpViews() + launcher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + writeToFiles(getSongUris(), cacheFiles) + } + } } private fun setUpViews() { @@ -265,6 +280,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { protected abstract fun getSongPaths(): List + protected abstract fun getSongUris(): List + protected fun searchWebFor(vararg keys: String) { val stringBuilder = StringBuilder() for (key in keys) { @@ -336,23 +353,53 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { hideFab() println(fieldKeyValueMap) - WriteTagsAsyncTask(this).execute( - LoadingInfo( - songPaths, - fieldKeyValueMap, - artworkInfo - ) - ) + GlobalScope.launch { + if (VersionUtils.hasR()) { + cacheFiles = TagWriter.writeTagsToFilesR( + this@AbsTagEditorActivity, AudioTagInfo( + songPaths, + fieldKeyValueMap, + artworkInfo + ) + ) + val pendingIntent = MediaStore.createWriteRequest(contentResolver, getSongUris()) + + launcher.launch(IntentSenderRequest.Builder(pendingIntent).build()) + } else { + TagWriter.writeTagsToFiles( + this@AbsTagEditorActivity, AudioTagInfo( + songPaths, + fieldKeyValueMap, + artworkInfo + ) + ) + } + } } private fun writeTags(paths: List?) { - WriteTagsAsyncTask(this).execute( - LoadingInfo( - paths, - savedTags, - savedArtworkInfo - ) - ) + GlobalScope.launch { + if (VersionUtils.hasR()) { + cacheFiles = TagWriter.writeTagsToFilesR( + this@AbsTagEditorActivity, AudioTagInfo( + paths, + savedTags, + savedArtworkInfo + ) + ) + val pendingIntent = MediaStore.createWriteRequest(contentResolver, getSongUris()) + + launcher.launch(IntentSenderRequest.Builder(pendingIntent).build()) + } else { + TagWriter.writeTagsToFiles( + this@AbsTagEditorActivity, AudioTagInfo( + paths, + savedTags, + savedArtworkInfo + ) + ) + } + } } @@ -391,9 +438,30 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { } } + private fun writeToFiles(songUris: List, cacheFiles: List) { + if (cacheFiles.size == songUris.size) { + for (i in cacheFiles.indices) { + contentResolver.openOutputStream(songUris[i])?.use { output -> + cacheFiles[i].inputStream().use { input -> + input.copyTo(output) + } + } + } + } + lifecycleScope.launch { + TagWriter.scan(this@AbsTagEditorActivity, getSongPaths()) + } + } + + override fun onDestroy() { + super.onDestroy() + // Delete Cache Files + cacheFiles.forEach { file -> + file.delete() + } + } companion object { - const val EXTRA_ID = "extra_id" const val EXTRA_PALETTE = "extra_palette" private val TAG = AbsTagEditorActivity::class.java.simpleName diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 6bbae4d9..53acf609 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -38,6 +38,7 @@ import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.model.ArtworkInfo import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.ImageUtil +import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette import code.name.monkey.retromusic.util.RetroColorUtil.getColor import com.bumptech.glide.load.engine.DiskCacheStrategy @@ -193,6 +194,11 @@ class AlbumTagEditorActivity : AbsTagEditorActivity = repository.albumById(id).songs.map { + MusicUtil.getSongFileUri(it.id) + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt index 34e3d3f8..8472f766 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt @@ -27,6 +27,7 @@ import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.setTint import code.name.monkey.retromusic.repository.SongRepository +import code.name.monkey.retromusic.util.MusicUtil import org.jaudiotagger.tag.FieldKey import org.koin.android.ext.android.inject import java.util.* @@ -111,6 +112,8 @@ class SongTagEditorActivity : AbsTagEditorActivity override fun getSongPaths(): List = listOf(songRepository.song(id).data) + override fun getSongUris(): List = listOf(MusicUtil.getSongFileUri(id)) + override fun loadImageFromFile(selectedFile: Uri?) { } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt new file mode 100644 index 00000000..39f24b44 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt @@ -0,0 +1,203 @@ +package code.name.monkey.retromusic.activities.tageditor + +import android.app.Activity +import android.content.Context +import android.graphics.Bitmap +import android.media.MediaScannerConnection +import android.os.Build +import android.util.Log +import android.widget.Toast +import androidx.annotation.RequiresApi +import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener +import code.name.monkey.retromusic.model.AudioTagInfo +import code.name.monkey.retromusic.util.MusicUtil.createAlbumArtFile +import code.name.monkey.retromusic.util.MusicUtil.deleteAlbumArt +import code.name.monkey.retromusic.util.MusicUtil.insertAlbumArt +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.jaudiotagger.audio.AudioFileIO +import org.jaudiotagger.audio.exceptions.CannotReadException +import org.jaudiotagger.audio.exceptions.CannotWriteException +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException +import org.jaudiotagger.tag.TagException +import org.jaudiotagger.tag.images.Artwork +import org.jaudiotagger.tag.images.ArtworkFactory +import java.io.File +import java.io.FileOutputStream +import java.io.IOException + +class TagWriter { + + companion object { + + suspend fun scan(context: Context, toBeScanned: List?) { + if (toBeScanned == null || toBeScanned.isEmpty()) { + Log.i("scan", "scan: Empty") + Toast.makeText(context, "Scan file from folder", Toast.LENGTH_SHORT).show() + return + } + MediaScannerConnection.scanFile( + context, + toBeScanned.toTypedArray(), + null, + withContext(Dispatchers.Main) { + if (context is Activity) UpdateToastMediaScannerCompletionListener( + context, toBeScanned + ) else null + } + ) + } + + suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) = + withContext(Dispatchers.IO) { + try { + var artwork: Artwork? = null + var albumArtFile: File? = null + if (info.artworkInfo?.artwork != null) { + try { + albumArtFile = createAlbumArtFile(context).canonicalFile + info.artworkInfo.artwork.compress( + Bitmap.CompressFormat.PNG, + 0, + FileOutputStream(albumArtFile) + ) + artwork = ArtworkFactory.createArtworkFromFile(albumArtFile) + } catch (e: IOException) { + e.printStackTrace() + } + } + var wroteArtwork = false + var deletedArtwork = false + for (filePath in info.filePaths!!) { + try { + val audioFile = AudioFileIO.read(File(filePath)) + val tag = audioFile.tagOrCreateAndSetDefault + if (info.fieldKeyValueMap != null) { + for ((key, value) in info.fieldKeyValueMap) { + try { + tag.setField(key, value) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + if (info.artworkInfo != null) { + if (info.artworkInfo.artwork == null) { + tag.deleteArtworkField() + deletedArtwork = true + } else if (artwork != null) { + tag.deleteArtworkField() + tag.setField(artwork) + wroteArtwork = true + } + } + audioFile.commit() + } catch (e: CannotReadException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } catch (e: CannotWriteException) { + e.printStackTrace() + } catch (e: TagException) { + e.printStackTrace() + } catch (e: ReadOnlyFileException) { + e.printStackTrace() + } catch (e: InvalidAudioFrameException) { + e.printStackTrace() + } + } + if (wroteArtwork) { + insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path) + } else if (deletedArtwork) { + deleteAlbumArt(context, info.artworkInfo!!.albumId) + } + scan(context, info.filePaths) + } catch (e: Exception) { + e.printStackTrace() + scan(context, null) + } + } + + + @RequiresApi(Build.VERSION_CODES.R) + suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo) = + withContext(Dispatchers.IO) { + val cacheFiles = mutableListOf() + try { + var artwork: Artwork? = null + var albumArtFile: File? = null + if (info.artworkInfo?.artwork != null) { + try { + albumArtFile = createAlbumArtFile(context).canonicalFile + info.artworkInfo.artwork.compress( + Bitmap.CompressFormat.PNG, + 0, + FileOutputStream(albumArtFile) + ) + artwork = ArtworkFactory.createArtworkFromFile(albumArtFile) + } catch (e: IOException) { + e.printStackTrace() + } + } + var wroteArtwork = false + var deletedArtwork = false + for (filePath in info.filePaths!!) { + try { + val originFile = File(filePath) + val cacheFile = File(context.cacheDir, originFile.name) + cacheFiles.add(cacheFile) + originFile.inputStream().use { input -> + cacheFile.outputStream().use { output -> + input.copyTo(output) + } + } + val audioFile = AudioFileIO.read(cacheFile) + val tag = audioFile.tagOrCreateAndSetDefault + if (info.fieldKeyValueMap != null) { + for ((key, value) in info.fieldKeyValueMap) { + try { + tag.setField(key, value) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + if (info.artworkInfo != null) { + if (info.artworkInfo.artwork == null) { + tag.deleteArtworkField() + deletedArtwork = true + } else if (artwork != null) { + tag.deleteArtworkField() + tag.setField(artwork) + wroteArtwork = true + } + } + audioFile.commit() + } catch (e: CannotReadException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } catch (e: CannotWriteException) { + e.printStackTrace() + } catch (e: TagException) { + e.printStackTrace() + } catch (e: ReadOnlyFileException) { + e.printStackTrace() + } catch (e: InvalidAudioFrameException) { + e.printStackTrace() + } + } + if (wroteArtwork) { + insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path) + } else if (deletedArtwork) { + deleteAlbumArt(context, info.artworkInfo!!.albumId) + } + cacheFiles + } catch (e: Exception) { + e.printStackTrace() + listOf() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java deleted file mode 100644 index 0ae1dc8d..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java +++ /dev/null @@ -1,152 +0,0 @@ -package code.name.monkey.retromusic.activities.tageditor; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.graphics.Bitmap; -import android.media.MediaScannerConnection; -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.jaudiotagger.audio.AudioFile; -import org.jaudiotagger.audio.AudioFileIO; -import org.jaudiotagger.audio.exceptions.CannotReadException; -import org.jaudiotagger.audio.exceptions.CannotWriteException; -import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; -import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; -import org.jaudiotagger.tag.FieldKey; -import org.jaudiotagger.tag.Tag; -import org.jaudiotagger.tag.TagException; -import org.jaudiotagger.tag.images.Artwork; -import org.jaudiotagger.tag.images.ArtworkFactory; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.misc.DialogAsyncTask; -import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener; -import code.name.monkey.retromusic.model.LoadingInfo; -import code.name.monkey.retromusic.util.MusicUtil; - -public class WriteTagsAsyncTask extends DialogAsyncTask> { - - public WriteTagsAsyncTask(Context context) { - super(context); - } - - @Override - protected List doInBackground(LoadingInfo... params) { - try { - LoadingInfo info = params[0]; - - Artwork artwork = null; - File albumArtFile = null; - if (info.getArtworkInfo() != null && info.getArtworkInfo().getArtwork() != null) { - try { - albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile(); - info.getArtworkInfo().getArtwork().compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile)); - artwork = ArtworkFactory.createArtworkFromFile(albumArtFile); - } catch (IOException e) { - e.printStackTrace(); - } - } - - int counter = 0; - boolean wroteArtwork = false; - boolean deletedArtwork = false; - for (String filePath : info.getFilePaths()) { - publishProgress(++counter, info.getFilePaths().size()); - try { - AudioFile audioFile = AudioFileIO.read(new File(filePath)); - Tag tag = audioFile.getTagOrCreateAndSetDefault(); - - if (info.getFieldKeyValueMap() != null) { - for (Map.Entry entry : info.getFieldKeyValueMap().entrySet()) { - try { - tag.setField(entry.getKey(), entry.getValue()); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - if (info.getArtworkInfo() != null) { - if (info.getArtworkInfo().getArtwork() == null) { - tag.deleteArtworkField(); - deletedArtwork = true; - } else if (artwork != null) { - tag.deleteArtworkField(); - tag.setField(artwork); - wroteArtwork = true; - } - } - - audioFile.commit(); - } catch (@NonNull CannotReadException | IOException | CannotWriteException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { - e.printStackTrace(); - } - } - - Context context = getContext(); - if (context != null) { - if (wroteArtwork) { - MusicUtil.INSTANCE. - insertAlbumArt(context, info.getArtworkInfo().getAlbumId(), albumArtFile.getPath()); - } else if (deletedArtwork) { - MusicUtil.INSTANCE.deleteAlbumArt(context, info.getArtworkInfo().getAlbumId()); - } - } - - return info.getFilePaths(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - protected void onPostExecute(List toBeScanned) { - super.onPostExecute(toBeScanned); - scan(toBeScanned); - } - - @Override - protected void onCancelled(List toBeScanned) { - super.onCancelled(toBeScanned); - scan(toBeScanned); - } - - private void scan(List toBeScanned) { - Context context = getContext(); - if (toBeScanned == null || toBeScanned.isEmpty()) { - Log.i("scan", "scan: Empty"); - Toast.makeText(context, "Scan file from folder", Toast.LENGTH_SHORT).show(); - return; - } - MediaScannerConnection.scanFile(context, toBeScanned.toArray(new String[0]), null, context instanceof Activity ? new UpdateToastMediaScannerCompletionListener((Activity) context, toBeScanned) : null); - } - - @Override - protected Dialog createDialog(@NonNull Context context) { - return new MaterialAlertDialogBuilder(context) - .setTitle(R.string.saving_changes) - .setCancelable(false) - .setView(R.layout.loading) - .create(); - } - - @Override - protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) { - super.onProgressUpdate(dialog, values); -// ((MaterialDialog) dialog).setMaxProgress(values[1]); -// ((MaterialDialog) dialog).setProgress(values[0]); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt index a197ddb6..4b43f4ea 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt @@ -14,19 +14,22 @@ */ package code.name.monkey.retromusic.fragments.other +import android.annotation.SuppressLint import android.os.Bundle import android.text.InputType import android.view.* import androidx.core.view.ViewCompat +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.navigation.fragment.findNavController import androidx.transition.Fade import androidx.viewpager2.adapter.FragmentStateAdapter import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper +import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.MainActivity -import code.name.monkey.retromusic.activities.tageditor.WriteTagsAsyncTask +import code.name.monkey.retromusic.activities.tageditor.TagWriter import code.name.monkey.retromusic.databinding.FragmentLyricsBinding import code.name.monkey.retromusic.databinding.FragmentNormalLyricsBinding import code.name.monkey.retromusic.databinding.FragmentSyncedLyricsBinding @@ -37,7 +40,7 @@ import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.lyrics.LrcView -import code.name.monkey.retromusic.model.LoadingInfo +import code.name.monkey.retromusic.model.AudioTagInfo import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.LyricUtil import code.name.monkey.retromusic.util.RetroUtil @@ -107,6 +110,9 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) { setupViews() setupToolbar() updateTitleSong() + if (VersionUtils.hasR()) { + binding.editButton.isVisible = false + } } private fun setupViews() { @@ -187,6 +193,7 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) { } + @SuppressLint("CheckResult") private fun editNormalLyrics() { var content = "" val file = File(MusicPlayerRemote.currentSong.data) @@ -205,11 +212,13 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) { ) { _, input -> val fieldKeyValueMap = EnumMap(FieldKey::class.java) fieldKeyValueMap[FieldKey.LYRICS] = input.toString() - WriteTagsAsyncTask(requireActivity()).execute( - LoadingInfo( - listOf(song.data), fieldKeyValueMap, null + GlobalScope.launch { + TagWriter.writeTagsToFiles( + requireContext(), AudioTagInfo( + listOf(song.data), fieldKeyValueMap, null + ) ) - ) + } } positiveButton(res = R.string.save) { (lyricsSectionsAdapter.fragments[1].first as NormalLyrics).loadNormalLyrics() @@ -219,6 +228,7 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) { } + @SuppressLint("CheckResult") private fun editSyncedLyrics() { var lrcFile: File? = null if (LyricUtil.isLrcOriginalFileExist(song.data)) { diff --git a/app/src/main/java/code/name/monkey/retromusic/model/LoadingInfo.kt b/app/src/main/java/code/name/monkey/retromusic/model/AudioTagInfo.kt similarity index 90% rename from app/src/main/java/code/name/monkey/retromusic/model/LoadingInfo.kt rename to app/src/main/java/code/name/monkey/retromusic/model/AudioTagInfo.kt index bfb9751f..3ac895df 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/LoadingInfo.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/AudioTagInfo.kt @@ -2,7 +2,7 @@ package code.name.monkey.retromusic.model import org.jaudiotagger.tag.FieldKey -class LoadingInfo( +class AudioTagInfo( val filePaths: List?, val fieldKeyValueMap: Map?, val artworkInfo: ArtworkInfo? diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index ff21dbb3..d9a66e21 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -17,6 +17,7 @@ import android.widget.Toast import androidx.annotation.RequiresApi import androidx.core.content.FileProvider import androidx.fragment.app.FragmentActivity +import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.SongEntity @@ -75,15 +76,18 @@ object MusicUtil : KoinComponent { return if (string2.isNullOrEmpty()) if (string1.isNullOrEmpty()) "" else string1 else "$string1 • $string2" } - fun createAlbumArtFile(): File { + fun createAlbumArtFile(context: Context): File { return File( - createAlbumArtDir(), + createAlbumArtDir(context), System.currentTimeMillis().toString() ) } - private fun createAlbumArtDir(): File { - val albumArtDir = File(Environment.getExternalStorageDirectory(), "/albumthumbs/") + private fun createAlbumArtDir(context: Context): File { + val albumArtDir = File( + if (VersionUtils.hasR()) context.cacheDir else Environment.getExternalStorageDirectory(), + "/albumthumbs/" + ) if (!albumArtDir.exists()) { albumArtDir.mkdirs() try { @@ -520,7 +524,7 @@ object MusicUtil : KoinComponent { } } - @RequiresApi(Build.VERSION_CODES.Q) + @RequiresApi(Build.VERSION_CODES.R) fun deleteTracksQ(activity: Activity, songs: List) { val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map { getSongFileUri(it.id)