Added MD3 playing theme

This commit is contained in:
Prathamesh More 2022-05-07 11:47:36 +05:30
parent ae13590204
commit 7debeb13c0
13 changed files with 771 additions and 0 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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.

View file

@ -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),

View file

@ -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
}
}

View file

@ -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()
}
}
}