PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt

329 lines
12 KiB
Kotlin
Raw Normal View History

2020-10-06 08:46:04 +00:00
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* 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.
*
*/
2019-04-20 05:29:45 +00:00
package code.name.monkey.retromusic.fragments.player
2018-11-30 01:06:16 +00:00
import android.content.SharedPreferences
2018-11-30 01:06:16 +00:00
import android.os.Bundle
import android.text.TextUtils
2018-11-30 01:06:16 +00:00
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
2018-11-30 01:06:16 +00:00
import androidx.viewpager.widget.ViewPager
2019-07-30 18:30:19 +00:00
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.SHOW_LYRICS
2019-04-20 05:29:45 +00:00
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter
2019-07-30 18:30:19 +00:00
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment
import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
2019-04-20 05:29:45 +00:00
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
2021-11-27 08:36:49 +00:00
import code.name.monkey.retromusic.fragments.base.goToLyrics
2019-07-30 18:30:19 +00:00
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
import code.name.monkey.retromusic.model.lyrics.Lyrics
2019-07-30 18:30:19 +00:00
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
import code.name.monkey.retromusic.util.LyricUtil
2020-06-06 18:57:28 +00:00
import code.name.monkey.retromusic.util.PreferenceUtil
2020-05-05 19:55:15 +00:00
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.exceptions.CannotReadException
import org.jaudiotagger.tag.FieldKey
import java.io.File
import java.io.FileNotFoundException
2018-11-30 01:06:16 +00:00
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback,
SharedPreferences.OnSharedPreferenceChangeListener {
2020-08-11 21:31:09 +00:00
private var _binding: FragmentPlayerAlbumCoverBinding? = null
private val binding get() = _binding!!
2018-11-30 01:06:16 +00:00
private var callbacks: Callbacks? = null
private var currentPosition: Int = 0
val viewPager get() = binding.viewPager
2019-07-30 18:30:19 +00:00
private val colorReceiver = object : AlbumCoverFragment.ColorReceiver {
2020-05-05 19:55:15 +00:00
override fun onColorReady(color: MediaNotificationProcessor, request: Int) {
2018-11-30 01:06:16 +00:00
if (currentPosition == request) {
notifyColorChange(color)
}
}
}
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
private val lyricsLayout: FrameLayout get() = binding.playerLyrics
private val lyricsLine1: TextView get() = binding.playerLyricsLine1
private val lyricsLine2: TextView get() = binding.playerLyricsLine2
var lyrics: Lyrics? = null
2018-11-30 01:06:16 +00:00
fun removeSlideEffect() {
2019-07-30 18:30:19 +00:00
val transformer = ParallaxPagerTransformer(R.id.player_image)
2018-11-30 01:06:16 +00:00
transformer.setSpeed(0.3f)
}
private fun updateLyrics() {
lyrics = null
lifecycleScope.launch(Dispatchers.IO) {
val song = MusicPlayerRemote.currentSong
val lyrics = try {
var lrcFile: File? = null
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
lrcFile = LyricUtil.getLocalLyricOriginalFile(song.data)
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
lrcFile = LyricUtil.getLocalLyricFile(song.title, song.artistName)
}
val data: String = LyricUtil.getStringFromLrc(lrcFile)
if (!TextUtils.isEmpty(data)) {
Lyrics.parse(song, data)
} else {
// Get Embedded Lyrics and check if they are Synchronized
val embeddedLyrics = try{
AudioFileIO.read(File(song.data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
} catch(e: Exception){
null
}
if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) {
Lyrics.parse(song, embeddedLyrics)
} else {
null
}
}
} catch (err: FileNotFoundException) {
null
} catch (e: CannotReadException){
null
}
withContext(Dispatchers.Main) {
this@PlayerAlbumCoverFragment.lyrics = lyrics
}
}
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
if (_binding == null) return
if (!isLyricsLayoutVisible()) {
hideLyricsLayout()
return
}
if (lyrics !is AbsSynchronizedLyrics) return
val synchronizedLyrics = lyrics as AbsSynchronizedLyrics
lyricsLayout.visibility = View.VISIBLE
lyricsLayout.alpha = 1f
val oldLine = lyricsLine2.text.toString()
val line = synchronizedLyrics.getLine(progress)
if (oldLine != line || oldLine.isEmpty()) {
lyricsLine1.text = oldLine
lyricsLine2.text = line
lyricsLine1.visibility = View.VISIBLE
lyricsLine2.visibility = View.VISIBLE
lyricsLine2.measure(
View.MeasureSpec.makeMeasureSpec(
lyricsLine2.measuredWidth,
View.MeasureSpec.EXACTLY
),
View.MeasureSpec.UNSPECIFIED
)
val h: Float = lyricsLine2.measuredHeight.toFloat()
lyricsLine1.alpha = 1f
lyricsLine1.translationY = 0f
lyricsLine1.animate().alpha(0f).translationY(-h).duration =
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
lyricsLine2.alpha = 0f
lyricsLine2.translationY = h
lyricsLine2.animate().alpha(1f).translationY(0f).duration =
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
}
}
private fun isLyricsLayoutVisible(): Boolean {
return lyrics != null && lyrics!!.isSynchronized && lyrics!!.isValid
}
private fun hideLyricsLayout() {
lyricsLayout.animate().alpha(0f).setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION)
.withEndAction {
if (_binding == null) return@withEndAction
lyricsLayout.visibility = View.GONE
lyricsLine1.text = null
lyricsLine2.text = null
}
}
2018-11-30 01:06:16 +00:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
binding.viewPager.addOnPageChangeListener(this)
2020-06-06 18:57:28 +00:00
val nps = PreferenceUtil.nowPlayingScreen
2020-01-24 16:54:08 +00:00
2020-05-11 23:00:22 +00:00
val metrics = resources.displayMetrics
val ratio = metrics.heightPixels.toFloat() / metrics.widthPixels.toFloat()
if (nps == Full || nps == Classic || nps == Fit || nps == Gradient) {
binding.viewPager.offscreenPageLimit = 2
2020-06-06 18:57:28 +00:00
} else if (PreferenceUtil.isCarouselEffect) {
binding.viewPager.clipToPadding = false
2020-05-11 23:00:22 +00:00
val padding =
if (ratio >= 1.777f) {
40
} else {
100
}
binding.viewPager.setPadding(padding, 0, padding, 0)
binding.viewPager.pageMargin = 0
binding.viewPager.setPageTransformer(false, CarousalPagerTransformer(requireContext()))
2020-05-07 06:57:24 +00:00
} else {
binding.viewPager.offscreenPageLimit = 2
binding.viewPager.setPageTransformer(
true,
2020-06-06 18:57:28 +00:00
PreferenceUtil.albumCoverTransform
)
2018-12-08 03:33:02 +00:00
}
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
// Don't show lyrics container for below conditions
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
progressViewUpdateHelper?.start()
}
// Go to lyrics activity when clicked lyrics
binding.playerLyricsLine2.setOnClickListener {
2021-11-27 08:36:49 +00:00
goToLyrics(requireActivity())
}
}
override fun onResume() {
super.onResume()
val nps = PreferenceUtil.nowPlayingScreen
// Don't show lyrics container for below conditions
if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) {
lyricsLayout.isVisible = false
progressViewUpdateHelper?.stop()
} else {
lyricsLayout.isVisible = true
progressViewUpdateHelper?.start()
}
PreferenceManager.getDefaultSharedPreferences(requireContext())
.registerOnSharedPreferenceChangeListener(this)
2018-11-30 01:06:16 +00:00
}
override fun onDestroyView() {
super.onDestroyView()
PreferenceManager.getDefaultSharedPreferences(requireContext())
.unregisterOnSharedPreferenceChangeListener(this)
binding.viewPager.removeOnPageChangeListener(this)
progressViewUpdateHelper?.stop()
_binding = null
2018-11-30 01:06:16 +00:00
}
override fun onServiceConnected() {
updatePlayingQueue()
updateLyrics()
2018-11-30 01:06:16 +00:00
}
override fun onPlayingMetaChanged() {
binding.viewPager.currentItem = MusicPlayerRemote.position
updateLyrics()
2018-11-30 01:06:16 +00:00
}
override fun onQueueChanged() {
updatePlayingQueue()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
if (key == SHOW_LYRICS) {
if (sharedPreferences.getBoolean(key, false)) {
progressViewUpdateHelper?.start()
lyricsLayout.animate().alpha(1f).duration =
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
binding.playerLyrics.isVisible = true
} else {
progressViewUpdateHelper?.stop()
lyricsLayout.animate().alpha(0f)
.setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION)
.withEndAction {
if (_binding != null) {
binding.playerLyrics.isVisible = false
lyricsLine1.text = null
lyricsLine2.text = null
}
}
}
}
}
2018-11-30 01:06:16 +00:00
private fun updatePlayingQueue() {
binding.viewPager.apply {
2020-01-24 16:54:08 +00:00
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
adapter?.notifyDataSetChanged()
currentItem = MusicPlayerRemote.position
2018-11-30 01:06:16 +00:00
onPageSelected(MusicPlayerRemote.position)
}
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
currentPosition = position
if (binding.viewPager.adapter != null) {
(binding.viewPager.adapter as AlbumCoverPagerAdapter).receiveColor(
colorReceiver,
position
)
2018-11-30 01:06:16 +00:00
}
if (position != MusicPlayerRemote.position) {
MusicPlayerRemote.playSongAt(position)
}
}
override fun onPageScrollStateChanged(state: Int) {
}
2020-05-05 19:55:15 +00:00
private fun notifyColorChange(color: MediaNotificationProcessor) {
2020-01-24 16:54:08 +00:00
callbacks?.onColorChanged(color)
2018-11-30 01:06:16 +00:00
}
fun setCallbacks(listener: Callbacks) {
callbacks = listener
}
interface Callbacks {
2020-05-05 19:55:15 +00:00
fun onColorChanged(color: MediaNotificationProcessor)
2018-11-30 01:06:16 +00:00
fun onFavoriteToggled()
}
companion object {
val TAG: String = PlayerAlbumCoverFragment::class.java.simpleName
}
}