PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt

403 lines
12 KiB
Kotlin
Raw Normal View History

2019-04-20 05:29:45 +00:00
package code.name.monkey.retromusic.activities.tageditor
2018-12-06 08:52:57 +00:00
import android.app.Activity
import android.app.SearchManager
import android.content.Intent
2019-03-25 12:43:43 +00:00
import android.content.res.ColorStateList
2018-12-06 08:52:57 +00:00
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
2019-07-31 16:42:19 +00:00
import android.os.Build
2018-12-06 08:52:57 +00:00
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.view.animation.OvershootInterpolator
import code.name.monkey.appthemehelper.ThemeStore
2019-03-25 12:43:43 +00:00
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
2018-12-06 08:52:57 +00:00
import code.name.monkey.appthemehelper.util.TintHelper
2019-04-20 05:29:45 +00:00
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
2019-07-31 16:42:19 +00:00
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
2018-12-06 08:52:57 +00:00
import code.name.monkey.retromusic.util.RetroUtil
2019-07-31 16:42:19 +00:00
import code.name.monkey.retromusic.util.SAFUtil
2018-12-06 08:52:57 +00:00
import com.afollestad.materialdialogs.MaterialDialog
2019-02-19 10:38:51 +00:00
import com.afollestad.materialdialogs.list.listItems
2019-03-25 12:43:43 +00:00
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
2018-12-06 08:52:57 +00:00
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.audio.AudioFile
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey
import java.io.File
2019-07-31 16:42:19 +00:00
import java.util.*
2018-12-06 08:52:57 +00:00
abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected var id: Int = 0
private set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
private var songPaths: List<String>? = null
2019-03-25 12:43:43 +00:00
lateinit var saveFab: ExtendedFloatingActionButton
2018-12-06 08:52:57 +00:00
2019-07-31 16:42:19 +00:00
private var savedSongPaths: List<String>? = null
private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null
2018-12-06 08:52:57 +00:00
protected val show: MaterialDialog
2019-02-19 10:38:51 +00:00
get() = MaterialDialog(this@AbsTagEditorActivity).show {
2019-07-31 16:42:19 +00:00
title(code.name.monkey.retromusic.R.string.update_image)
2019-02-23 17:39:02 +00:00
listItems(items = items) { _, position, _ ->
2019-02-19 10:38:51 +00:00
when (position) {
0 -> getImageFromLastFM()
1 -> startImagePicker()
2 -> searchImageOnWeb()
3 -> deleteImage()
}
}
}
2018-12-06 08:52:57 +00:00
protected abstract val contentViewLayout: Int
internal val albumArtist: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.getFirst(FieldKey.ALBUM_ARTIST)
} catch (ignored: Exception) {
null
}
}
protected val songTitle: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
} catch (ignored: Exception) {
null
}
}
protected val composer: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
} catch (ignored: Exception) {
null
}
}
2018-12-06 08:52:57 +00:00
protected val albumTitle: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
} catch (ignored: Exception) {
null
}
}
protected val artistName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
} catch (ignored: Exception) {
null
}
}
protected val albumArtistName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.getFirst(FieldKey.ALBUM_ARTIST)
} catch (ignored: Exception) {
null
}
}
protected val genreName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
} catch (ignored: Exception) {
null
}
}
protected val songYear: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
} catch (ignored: Exception) {
null
}
}
protected val trackNumber: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
} catch (ignored: Exception) {
null
}
}
protected val lyrics: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
} catch (ignored: Exception) {
null
}
}
protected val albumArt: Bitmap?
get() {
try {
val artworkTag = getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.firstArtwork
if (artworkTag != null) {
val artworkBinaryData = artworkTag.binaryData
return BitmapFactory.decodeByteArray(artworkBinaryData, 0, artworkBinaryData.size)
}
return null
} catch (ignored: Exception) {
return null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(contentViewLayout)
2019-07-31 16:42:19 +00:00
saveFab = findViewById(code.name.monkey.retromusic.R.id.saveTags)
2018-12-06 08:52:57 +00:00
getIntentExtras()
songPaths = getSongPaths()
if (songPaths!!.isEmpty()) {
finish()
return
}
setUpViews()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
}
private fun setUpViews() {
setUpScrollView()
setUpFab()
setUpImageView()
}
private fun setUpScrollView() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
}
2019-02-23 17:39:02 +00:00
private lateinit var items: List<String>
2018-12-06 08:52:57 +00:00
private fun setUpImageView() {
loadCurrentImage()
2019-07-31 16:42:19 +00:00
items = listOf(getString(code.name.monkey.retromusic.R.string.download_from_last_fm), getString(code.name.monkey.retromusic.R.string.pick_from_local_storage), getString(code.name.monkey.retromusic.R.string.web_search), getString(code.name.monkey.retromusic.R.string.remove_cover))
2018-12-06 08:52:57 +00:00
editorImage.setOnClickListener { show }
}
private fun startImagePicker() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
2019-07-31 16:42:19 +00:00
startActivityForResult(Intent.createChooser(intent, getString(code.name.monkey.retromusic.R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE)
2018-12-06 08:52:57 +00:00
}
protected abstract fun loadCurrentImage()
protected abstract fun getImageFromLastFM()
protected abstract fun searchImageOnWeb()
protected abstract fun deleteImage()
private fun setUpFab() {
2019-03-25 12:43:43 +00:00
saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply {
saveFab.setTextColor(this)
saveFab.iconTint = this
}
2018-12-06 08:52:57 +00:00
saveFab.apply {
scaleX = 0f
scaleY = 0f
isEnabled = false
setOnClickListener { save() }
TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
}
}
protected abstract fun save()
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID)
}
}
protected abstract fun getSongPaths(): List<String>
protected fun searchWebFor(vararg keys: String) {
val stringBuilder = StringBuilder()
for (key in keys) {
stringBuilder.append(key)
stringBuilder.append(" ")
}
val intent = Intent(Intent.ACTION_WEB_SEARCH)
intent.putExtra(SearchManager.QUERY, stringBuilder.toString())
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
android.R.id.home -> {
super.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
protected fun setNoImageMode() {
isInNoImageMode = true
imageContainer!!.visibility = View.GONE
editorImage.visibility = View.GONE
editorImage.isEnabled = false
setColors(intent.getIntExtra(EXTRA_PALETTE, ThemeStore.primaryColor(this)))
}
protected fun dataChanged() {
showFab()
}
private fun showFab() {
saveFab.animate()
.setDuration(500)
.setInterpolator(OvershootInterpolator())
.scaleX(1f)
.scaleY(1f)
.start()
saveFab.isEnabled = true
}
2019-07-31 16:42:19 +00:00
private fun hideFab() {
saveFab.animate()
.setDuration(500)
.setInterpolator(OvershootInterpolator())
.scaleX(0.0f)
.scaleY(0.0f)
.start()
saveFab.isEnabled = false
}
2018-12-06 08:52:57 +00:00
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
if (bitmap == null) {
2019-07-31 16:42:19 +00:00
editorImage.setImageResource(code.name.monkey.retromusic.R.drawable.default_album_art)
2018-12-06 08:52:57 +00:00
} else {
editorImage.setImageBitmap(bitmap)
}
setColors(bgColor)
}
protected open fun setColors(color: Int) {
paletteColorPrimary = color
}
protected fun writeValuesToFiles(fieldKeyValueMap: Map<FieldKey, String>,
artworkInfo: ArtworkInfo?) {
RetroUtil.hideSoftKeyboard(this)
2019-07-31 16:42:19 +00:00
hideFab()
savedSongPaths = getSongPaths()
savedTags = fieldKeyValueMap
savedArtworkInfo = artworkInfo
if (!SAFUtil.isSAFRequired(savedSongPaths)) {
writeTags(savedSongPaths)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (SAFUtil.isSDCardAccessGranted(this)) {
writeTags(savedSongPaths)
} else {
startActivityForResult(Intent(this, SAFGuideActivity::class.java), SAFGuideActivity.REQUEST_CODE_SAF_GUIDE)
}
}
}
}
private fun writeTags(paths: List<String>?) {
WriteTagsAsyncTask(this).execute(WriteTagsAsyncTask.LoadingInfo(paths, savedTags, savedArtworkInfo))
2018-12-06 08:52:57 +00:00
}
2019-07-31 16:42:19 +00:00
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
2018-12-06 08:52:57 +00:00
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
2019-07-31 16:42:19 +00:00
intent?.data?.let {
loadImageFromFile(it)
}
}
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(this, intent)
writeTags(savedSongPaths)
}
}
SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) {
writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))
}
2018-12-06 08:52:57 +00:00
}
}
}
protected abstract fun loadImageFromFile(selectedFile: Uri?)
private fun getAudioFile(path: String): AudioFile {
2019-02-23 17:39:02 +00:00
return try {
AudioFileIO.read(File(path))
2018-12-06 08:52:57 +00:00
} catch (e: Exception) {
Log.e(TAG, "Could not read audio file $path", e)
2019-02-23 17:39:02 +00:00
AudioFile()
2018-12-06 08:52:57 +00:00
}
}
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
companion object {
const val EXTRA_ID = "extra_id"
const val EXTRA_PALETTE = "extra_palette"
private val TAG = AbsTagEditorActivity::class.java.simpleName
private const val REQUEST_CODE_SELECT_IMAGE = 1000
}
}