Added MD3 playing theme
This commit is contained in:
parent
ae13590204
commit
7debeb13c0
13 changed files with 771 additions and 0 deletions
|
@ -49,6 +49,7 @@ import code.name.monkey.retromusic.fragments.player.flat.FlatPlayerFragment
|
|||
import code.name.monkey.retromusic.fragments.player.full.FullPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.gradient.GradientPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.material.MaterialFragment
|
||||
import code.name.monkey.retromusic.fragments.player.md3.MD3PlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.peek.PeekPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.plain.PlainPlayerFragment
|
||||
|
@ -457,6 +458,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
Peek -> PeekPlayerFragment()
|
||||
Circle -> CirclePlayerFragment()
|
||||
Classic -> ClassicPlayerFragment()
|
||||
MD3 -> MD3PlayerFragment()
|
||||
else -> PlayerFragment()
|
||||
} // must implement AbsPlayerFragment
|
||||
supportFragmentManager.commit {
|
||||
|
|
|
@ -292,6 +292,9 @@ fun Context.accentColorVariant(): Int {
|
|||
inline val @receiver:ColorInt Int.isColorLight
|
||||
get() = ColorUtil.isColorLight(this)
|
||||
|
||||
inline val @receiver:ColorInt Int.lightColor
|
||||
get() = ColorUtil.withAlpha(this, 0.5F)
|
||||
|
||||
inline val @receiver:ColorInt Int.lighterColor
|
||||
get() = ColorUtil.lightenColor(this)
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
|||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -163,6 +164,23 @@ fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int): Animator {
|
|||
}
|
||||
}
|
||||
|
||||
fun MaterialCardView.animateRadius(cornerRadius: Float, pause: Boolean = true) {
|
||||
ValueAnimator.ofFloat(radius, cornerRadius).apply {
|
||||
addUpdateListener { radius = animatedValue as Float }
|
||||
start()
|
||||
}
|
||||
ValueAnimator.ofInt(measuredWidth, if (pause) (height * 1.5).toInt() else height).apply {
|
||||
addUpdateListener {
|
||||
updateLayoutParams<ViewGroup.LayoutParams> { width = animatedValue as Int }
|
||||
}
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
fun MaterialCardView.animateToCircle() {
|
||||
animateRadius(measuredHeight / 2F, pause = false)
|
||||
}
|
||||
|
||||
fun View.focusAndShowKeyboard() {
|
||||
/**
|
||||
* This is to be called when the window already has focus.
|
||||
|
|
|
@ -39,6 +39,7 @@ enum class NowPlayingScreen constructor(
|
|||
Full(R.string.full, R.drawable.np_full, 2, AlbumCoverStyle.Full),
|
||||
Gradient(R.string.gradient, R.drawable.np_gradient, 17, AlbumCoverStyle.Full),
|
||||
Material(R.string.material, R.drawable.np_material, 11, AlbumCoverStyle.Normal),
|
||||
MD3(R.string.md3, R.drawable.np_normal, 18, AlbumCoverStyle.Normal),
|
||||
Normal(R.string.normal, R.drawable.np_normal, 0, AlbumCoverStyle.Normal),
|
||||
Peek(R.string.peek, R.drawable.np_peek, 14, AlbumCoverStyle.Normal),
|
||||
Plain(R.string.plain, R.drawable.np_plain, 3, AlbumCoverStyle.Normal),
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package code.name.monkey.retromusic.fragments.player.md3
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.ImageButton
|
||||
import android.widget.SeekBar
|
||||
import android.widget.TextView
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.FragmentMd3PlayerPlaybackControlsBinding
|
||||
import code.name.monkey.retromusic.extensions.*
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
||||
import code.name.monkey.retromusic.fragments.base.goToAlbum
|
||||
import code.name.monkey.retromusic.fragments.base.goToArtist
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
|
||||
class MD3PlaybackControlsFragment :
|
||||
AbsPlayerControlsFragment(R.layout.fragment_md3_player_playback_controls) {
|
||||
|
||||
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
||||
private var _binding: FragmentMd3PlayerPlaybackControlsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override val progressSlider: SeekBar
|
||||
get() = binding.progressSlider
|
||||
|
||||
override val shuffleButton: ImageButton
|
||||
get() = binding.shuffleButton
|
||||
|
||||
override val repeatButton: ImageButton
|
||||
get() = binding.repeatButton
|
||||
|
||||
override val nextButton: ImageButton
|
||||
get() = binding.nextButton
|
||||
|
||||
override val previousButton: ImageButton
|
||||
get() = binding.previousButton
|
||||
|
||||
override val songTotalTime: TextView
|
||||
get() = binding.songTotalTime
|
||||
|
||||
override val songCurrentProgress: TextView
|
||||
get() = binding.songCurrentProgress
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentMd3PlayerPlaybackControlsBinding.bind(view)
|
||||
setUpMusicControllers()
|
||||
binding.playPauseButton.setOnClickListener {
|
||||
if (MusicPlayerRemote.isPlaying) {
|
||||
MusicPlayerRemote.pauseSong()
|
||||
} else {
|
||||
MusicPlayerRemote.resumePlaying()
|
||||
}
|
||||
}
|
||||
binding.title.isSelected = true
|
||||
binding.text.isSelected = true
|
||||
binding.title.setOnClickListener {
|
||||
goToAlbum(requireActivity())
|
||||
}
|
||||
binding.text.setOnClickListener {
|
||||
goToArtist(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
override fun setColor(color: MediaNotificationProcessor) {
|
||||
val colorBg = ATHUtil.resolveColor(requireContext(), android.R.attr.colorBackground)
|
||||
if (ColorUtil.isColorLight(colorBg)) {
|
||||
lastPlaybackControlsColor =
|
||||
MaterialValueHelper.getSecondaryTextColor(requireContext(), true)
|
||||
lastDisabledPlaybackControlsColor =
|
||||
MaterialValueHelper.getSecondaryDisabledTextColor(requireContext(), true)
|
||||
} else {
|
||||
lastPlaybackControlsColor =
|
||||
MaterialValueHelper.getPrimaryTextColor(requireContext(), false)
|
||||
lastDisabledPlaybackControlsColor =
|
||||
MaterialValueHelper.getPrimaryDisabledTextColor(requireContext(), false)
|
||||
}
|
||||
|
||||
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
|
||||
color.primaryTextColor
|
||||
} else {
|
||||
ThemeStore.accentColor(requireContext())
|
||||
}.ripAlpha()
|
||||
|
||||
TintHelper.setTintAuto(
|
||||
binding.playPauseButton,
|
||||
MaterialValueHelper.getPrimaryTextColor(
|
||||
requireContext(),
|
||||
ColorUtil.isColorLight(colorFinal)
|
||||
),
|
||||
false
|
||||
)
|
||||
binding.playPauseCard.setCardBackgroundColor(colorFinal)
|
||||
|
||||
binding.progressSlider.applyColor(colorFinal)
|
||||
volumeFragment?.setTintable(colorFinal)
|
||||
updateRepeatState()
|
||||
updateShuffleState()
|
||||
updatePrevNextColor()
|
||||
updatePlayPauseDrawableState()
|
||||
}
|
||||
|
||||
private fun updateSong() {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
binding.title.text = song.title
|
||||
binding.text.text = song.artistName
|
||||
|
||||
if (PreferenceUtil.isSongInfo) {
|
||||
binding.songInfo.text = getSongInfo(song)
|
||||
binding.songInfo.show()
|
||||
} else {
|
||||
binding.songInfo.hide()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
progressViewUpdateHelper.start()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
progressViewUpdateHelper.stop()
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
updatePlayPauseDrawableState()
|
||||
updateRepeatState()
|
||||
updateShuffleState()
|
||||
updateSong()
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
super.onPlayingMetaChanged()
|
||||
updateSong()
|
||||
}
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState()
|
||||
}
|
||||
|
||||
override fun onRepeatModeChanged() {
|
||||
updateRepeatState()
|
||||
}
|
||||
|
||||
override fun onShuffleModeChanged() {
|
||||
updateShuffleState()
|
||||
}
|
||||
|
||||
private fun setUpPlayPauseFab() {
|
||||
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
|
||||
updatePlayPauseDrawableState()
|
||||
}
|
||||
|
||||
private fun updatePlayPauseDrawableState() {
|
||||
if (MusicPlayerRemote.isPlaying) {
|
||||
binding.playPauseButton.setImageResource(R.drawable.ic_pause_outline_small)
|
||||
binding.playPauseCard.animateRadius(40F)
|
||||
} else {
|
||||
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_outline_small)
|
||||
binding.playPauseCard.animateToCircle()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpMusicControllers() {
|
||||
setUpPlayPauseFab()
|
||||
}
|
||||
|
||||
public override fun show() {
|
||||
binding.playPauseButton.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.rotation(360f)
|
||||
.setInterpolator(DecelerateInterpolator())
|
||||
.start()
|
||||
}
|
||||
|
||||
public override fun hide() {
|
||||
binding.playPauseButton.apply {
|
||||
scaleX = 0f
|
||||
scaleY = 0f
|
||||
rotation = 0f
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
binding.progressSlider.max = total
|
||||
|
||||
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
|
||||
animator.duration = SLIDER_ANIMATION_TIME
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.start()
|
||||
|
||||
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
||||
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package code.name.monkey.retromusic.fragments.player.md3
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.FragmentMd3PlayerBinding
|
||||
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
|
||||
class MD3PlayerFragment : AbsPlayerFragment(R.layout.fragment_md3_player) {
|
||||
|
||||
private var lastColor: Int = 0
|
||||
override val paletteColor: Int
|
||||
get() = lastColor
|
||||
|
||||
private lateinit var controlsFragment: MD3PlaybackControlsFragment
|
||||
|
||||
private var _binding: FragmentMd3PlayerBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onShow() {
|
||||
controlsFragment.show()
|
||||
}
|
||||
|
||||
override fun onHide() {
|
||||
controlsFragment.hide()
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun toolbarIconColor(): Int {
|
||||
return ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal)
|
||||
}
|
||||
|
||||
override fun onColorChanged(color: MediaNotificationProcessor) {
|
||||
controlsFragment.setColor(color)
|
||||
lastColor = color.backgroundColor
|
||||
libraryViewModel.updateColor(color.backgroundColor)
|
||||
|
||||
ToolbarContentTintHelper.colorizeToolbar(
|
||||
binding.playerToolbar,
|
||||
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
|
||||
requireActivity()
|
||||
)
|
||||
}
|
||||
|
||||
override fun toggleFavorite(song: Song) {
|
||||
super.toggleFavorite(song)
|
||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||
updateIsFavorite()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFavoriteToggled() {
|
||||
toggleFavorite(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentMd3PlayerBinding.bind(view)
|
||||
setUpSubFragments()
|
||||
setUpPlayerToolbar()
|
||||
playerToolbar().drawAboveSystemBars()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun setUpSubFragments() {
|
||||
controlsFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as MD3PlaybackControlsFragment
|
||||
val playerAlbumCoverFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
||||
playerAlbumCoverFragment.setCallbacks(this)
|
||||
}
|
||||
|
||||
private fun setUpPlayerToolbar() {
|
||||
binding.playerToolbar.inflateMenu(R.menu.menu_player)
|
||||
//binding.playerToolbar.menu.setUpWithIcons()
|
||||
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
|
||||
binding.playerToolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
ToolbarContentTintHelper.colorizeToolbar(
|
||||
binding.playerToolbar,
|
||||
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
|
||||
requireActivity()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
updateIsFavorite()
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
updateIsFavorite()
|
||||
}
|
||||
|
||||
override fun playerToolbar(): Toolbar {
|
||||
return binding.playerToolbar
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): MD3PlayerFragment {
|
||||
return MD3PlayerFragment()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue