[Tag Editor] Added artwork chooser for Song tag editor

This commit is contained in:
Prathamesh More 2021-12-13 16:06:48 +05:30
parent 305b075365
commit 4211ed1a9b
6 changed files with 452 additions and 71 deletions

View file

@ -34,7 +34,6 @@ 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
@ -60,14 +59,13 @@ import java.io.File
import java.util.*
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
abstract val editorImage: ImageView?
abstract val editorImage: ImageView
val repository by inject<Repository>()
lateinit var saveFab: MaterialButton
protected var id: Long = 0
private set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
private var songPaths: List<String>? = null
private var savedSongPaths: List<String>? = null
private val currentSongPath: String? = null
@ -239,7 +237,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
getString(R.string.web_search),
getString(R.string.remove_cover)
)
editorImage?.setOnClickListener { show }
editorImage.setOnClickListener { show }
}
private fun startImagePicker() {
@ -306,17 +304,6 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
return super.onOptionsItemSelected(item)
}
protected fun setNoImageMode() {
isInNoImageMode = true
setColors(
intent.getIntExtra(
EXTRA_PALETTE,
ATHUtil.resolveColor(this, R.attr.colorPrimary)
)
)
}
protected fun dataChanged() {
showFab()
}
@ -335,9 +322,9 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
if (bitmap == null) {
editorImage?.setImageResource(drawable.default_audio_art)
editorImage.setImageResource(drawable.default_audio_art)
} else {
editorImage?.setImageBitmap(bitmap)
editorImage.setImageBitmap(bitmap)
}
setColors(bgColor)
}

View file

@ -63,41 +63,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
window.enterTransition = slide
}
override fun loadImageFromFile(selectedFile: Uri?) {
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
getColor(resource.palette, Color.TRANSPARENT)
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(
albumArtBitmap,
getColor(
resource.palette,
ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
}
override fun setResource(resource: BitmapPaletteWrapper?) {}
})
}
private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false
@ -171,6 +136,41 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
dataChanged()
}
override fun loadImageFromFile(selectedFile: Uri?) {
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
getColor(resource.palette, Color.TRANSPARENT)
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(
albumArtBitmap,
getColor(
resource.palette,
ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
}
override fun setResource(resource: BitmapPaletteWrapper?) {}
})
}
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()

View file

@ -15,17 +15,33 @@
package code.name.monkey.retromusic.activities.tageditor
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
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.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.repository.SongRepository
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.shape.MaterialShapeDrawable
import org.jaudiotagger.tag.FieldKey
import org.koin.android.ext.android.inject
@ -39,12 +55,14 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
private val songRepository by inject<SongRepository>()
private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setUpViews()
setNoImageMode()
setSupportActionBar(binding.toolbar)
binding.appBarLayout.statusBarForeground =
binding.appBarLayout?.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(this)
}
@ -90,11 +108,30 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
println(songTitle + songYear)
}
override fun loadCurrentImage() {}
override fun loadCurrentImage() {
val bitmap = albumArt
setImageBitmap(
bitmap,
RetroColorUtil.getColor(
RetroColorUtil.generatePalette(bitmap),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
)
deleteAlbumArt = false
}
override fun searchImageOnWeb() {}
override fun searchImageOnWeb() {
searchWebFor(binding.songText.text.toString(), binding.artistText.text.toString())
}
override fun deleteImage() {}
override fun deleteImage() {
setImageBitmap(
BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
deleteAlbumArt = true
dataChanged()
}
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
@ -107,7 +144,12 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
writeValuesToFiles(fieldKeyValueMap, null)
writeValuesToFiles(fieldKeyValueMap, when {
deleteAlbumArt -> ArtworkInfo(id, null)
albumArtBitmap == null -> null
else -> ArtworkInfo(id, albumArtBitmap!!)
}
)
}
override fun getSongPaths(): List<String> = listOf(songRepository.song(id).data)
@ -115,6 +157,38 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id))
override fun loadImageFromFile(selectedFile: Uri?) {
GlideApp.with(this@SongTagEditorActivity).asBitmapPalette().load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(
albumArtBitmap,
RetroColorUtil.getColor(
resource.palette,
ATHUtil.resolveColor(
this@SongTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@SongTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
}
override fun setResource(resource: BitmapPaletteWrapper?) {}
})
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
@ -131,6 +205,6 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
override val editorImage: ImageView?
get() = null
override val editorImage: ImageView
get() = binding.editorImage
}

View file

@ -3,7 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
android:background="?attr/colorSurface"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
@ -16,20 +17,22 @@
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
app:title="@string/action_tag_editor" />
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="@+id/imageContainer"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:layout_weight="1"
android:transitionName="@string/transition_album_art"
app:cardCornerRadius="24dp"
app:cardElevation="8dp">
app:cardElevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/editorImage"
@ -50,11 +53,14 @@
<androidx.core.widget.NestedScrollView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:overScrollMode="@integer/overScrollMode"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageContainer"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
@ -138,7 +144,7 @@
android:layout_height="52dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton

View file

@ -0,0 +1,291 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:focusable="true"
android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
app:title="@string/action_tag_editor" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="@+id/imageContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="40dp"
android:transitionName="@string/transition_album_art"
app:cardCornerRadius="@dimen/m3_card_large_radius"
app:cardElevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/editorImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
</com.google.android.material.card.MaterialCardView>
<androidx.core.widget.NestedScrollView
android:id="@+id/content"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="@integer/overScrollMode"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageContainer"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/songTextContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/songText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/song"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/albumTextContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/albumText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/album"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/artistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/artistText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/artist"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/albumArtistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/albumArtistText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/album_artist"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/composerContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/songComposerText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/composer"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/genreContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_weight="1"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/genreText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/genre"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/yearContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_weight="1"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/yearText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/year"
android:inputType="text|number"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/trackNumberContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/trackNumberText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/track_hint"
android:inputType="text|number"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/lyricsContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/lyricsText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:hint="@string/lyrics"
android:inputType="textMultiLine"
android:maxLines="15" />
</com.google.android.material.textfield.TextInputLayout>
<Space
android:layout_width="match_parent"
android:layout_height="52dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/saveTags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:gravity="center"
android:paddingStart="32dp"
android:paddingTop="12dp"
android:paddingEnd="32dp"
android:paddingBottom="12dp"
android:text="@string/save"
app:cornerRadius="25dp"
app:icon="@drawable/ic_save"
app:iconGravity="textStart"
tools:backgroundTint="@color/md_red_400" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -2,6 +2,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:focusable="true"
android:focusableInTouchMode="true">
@ -33,6 +34,28 @@
android:orientation="vertical"
android:padding="16dp">
<code.name.monkey.retromusic.views.WidthFitSquareCardView
android:id="@+id/imageContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:transitionName="@string/transition_album_art"
app:cardCornerRadius="@dimen/m3_card_large_radius"
app:cardElevation="8dp"
app:cardUseCompatPadding="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/editorImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
</code.name.monkey.retromusic.views.WidthFitSquareCardView>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/songTextContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"