/* * 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.color import android.animation.Animator import android.animation.ObjectAnimator import android.graphics.Color import android.graphics.PorterDuff import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewAnimationUtils import android.view.ViewGroup import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator import android.view.animation.LinearInterpolator import android.widget.SeekBar import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentColorPlayerPlaybackControlsBinding import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.getSongInfo import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show 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.misc.SimpleOnSeekbarChangeListener import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import kotlin.math.sqrt class ColorPlaybackControlsFragment : AbsPlayerControlsFragment(R.layout.fragment_adaptive_player_playback_controls) { private var lastPlaybackControlsColor: Int = 0 private var lastDisabledPlaybackControlsColor: Int = 0 private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper private var _binding: FragmentColorPlayerPlaybackControlsBinding? = null private val binding get() = _binding!! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentColorPlayerPlaybackControlsBinding.inflate(inflater, container, false) return binding.root } override fun onResume() { super.onResume() progressViewUpdateHelper.start() } override fun onPause() { super.onPause() progressViewUpdateHelper.stop() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setUpMusicControllers() binding.title.isSelected = true binding.text.isSelected = true binding.title.setOnClickListener { goToAlbum(requireActivity()) } binding.text.setOnClickListener { goToArtist(requireActivity()) } } 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 onServiceConnected() { updatePlayPauseDrawableState() updateRepeatState() updateShuffleState() updateSong() } override fun onPlayingMetaChanged() { super.onPlayingMetaChanged() updateSong() } override fun onPlayStateChanged() { updatePlayPauseDrawableState() } override fun onRepeatModeChanged() { updateRepeatState() } override fun onShuffleModeChanged() { updateShuffleState() } override fun setColor(color: MediaNotificationProcessor) { TintHelper.setTintAuto(binding.playPauseButton, color.primaryTextColor, true) TintHelper.setTintAuto(binding.playPauseButton, color.backgroundColor, false) binding.progressSlider.applyColor(color.primaryTextColor) binding.title.setTextColor(color.primaryTextColor) binding.text.setTextColor(color.secondaryTextColor) binding.songInfo.setTextColor(color.secondaryTextColor) binding.songCurrentProgress.setTextColor(color.secondaryTextColor) binding.songTotalTime.setTextColor(color.secondaryTextColor) volumeFragment?.setTintableColor(color.primaryTextColor) lastPlaybackControlsColor = color.secondaryTextColor lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(color.secondaryTextColor, 0.25f) updateRepeatState() updateShuffleState() updatePrevNextColor() } private fun setUpPlayPauseFab() { TintHelper.setTintAuto(binding.playPauseButton, Color.WHITE, true) TintHelper.setTintAuto(binding.playPauseButton, Color.BLACK, false) binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } private fun updatePlayPauseDrawableState() { when { MusicPlayerRemote.isPlaying -> binding.playPauseButton.setImageResource(R.drawable.ic_pause) else -> binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow) } } private fun setUpMusicControllers() { setUpPlayPauseFab() setUpPrevNext() setUpRepeatButton() setUpShuffleButton() setUpProgressSlider() } private fun setUpPrevNext() { updatePrevNextColor() binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } binding.previousButton.setOnClickListener { MusicPlayerRemote.back() } } private fun updatePrevNextColor() { binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } private fun setUpShuffleButton() { binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } } override fun updateShuffleState() { when (MusicPlayerRemote.shuffleMode) { MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter( lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) else -> binding.shuffleButton.setColorFilter( lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) } } private fun setUpRepeatButton() { binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() } } override fun updateRepeatState() { when (MusicPlayerRemote.repeatMode) { MusicService.REPEAT_MODE_NONE -> { binding.repeatButton.setImageResource(R.drawable.ic_repeat) binding.repeatButton.setColorFilter( lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) } MusicService.REPEAT_MODE_ALL -> { binding.repeatButton.setImageResource(R.drawable.ic_repeat) binding.repeatButton.setColorFilter( lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) } MusicService.REPEAT_MODE_THIS -> { binding.repeatButton.setImageResource(R.drawable.ic_repeat_one) binding.repeatButton.setColorFilter( lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) } } } 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 setUpProgressSlider() { binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) { MusicPlayerRemote.seekTo(progress) onUpdateProgressViews( MusicPlayerRemote.songProgressMillis, MusicPlayerRemote.songDurationMillis ) } } }) } 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()) } fun createRevealAnimator(view: View): Animator { val location = IntArray(2) binding.playPauseButton.getLocationOnScreen(location) val x = (location[0] + binding.playPauseButton.measuredWidth / 2) val y = (location[1] + binding.playPauseButton.measuredHeight / 2) val endRadius = sqrt((x * x + y * y).toFloat()) val startRadius = binding.playPauseButton.measuredWidth.coerceAtMost(binding.playPauseButton.measuredHeight) return ViewAnimationUtils.createCircularReveal( view, x, y, startRadius.toFloat(), endRadius ).apply { duration = 300 interpolator = AccelerateInterpolator() } } override fun onDestroyView() { super.onDestroyView() _binding = null } }