Here's a list of changes/features: https://github.com/RetroMusicPlayer/RetroMusicPlayer/releases/tag/v5.0

Internal Changes:
1) Migrated to ViewBinding
2) Migrated to Glide V4
3) Migrated to kotlin version of Material Dialogs
This commit is contained in:
Prathamesh More 2021-09-09 00:00:20 +05:30
parent fc42767031
commit bce6dbfa27
421 changed files with 13285 additions and 5757 deletions

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.fragments
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.doOnPreDraw
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
@ -28,26 +29,48 @@ import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding
import code.name.monkey.retromusic.db.toSong
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.util.RetroUtil
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import com.google.android.material.transition.MaterialSharedAxis
class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail),
IArtistClickListener, IAlbumClickListener {
private val args by navArgs<DetailListFragmentArgs>()
private var _binding: FragmentPlaylistDetailBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlaylistDetailBinding.bind(view)
when (args.type) {
TOP_ARTISTS,
RECENT_ARTISTS,
TOP_ALBUMS,
RECENT_ALBUMS,
FAVOURITES -> {
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
else -> {
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
}
}
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mainActivity.setBottomBarVisibility(false)
mainActivity.setSupportActionBar(toolbar)
progressIndicator.hide()
mainActivity.setSupportActionBar(binding.toolbar)
binding.progressIndicator.hide()
when (args.type) {
TOP_ARTISTS -> loadArtists(R.string.top_artists, TOP_ARTISTS)
RECENT_ARTISTS -> loadArtists(R.string.recent_artists, RECENT_ARTISTS)
@ -59,23 +82,23 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
TOP_PLAYED_PLAYLIST -> topPlayed()
}
recyclerView.adapter?.registerAdapterDataObserver(object : AdapterDataObserver() {
binding.recyclerView.adapter?.registerAdapterDataObserver(object : AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
val height = dipToPix(52f)
recyclerView.setPadding(0, 0, 0, height.toInt())
binding.recyclerView.setPadding(0, 0, 0, height.toInt())
}
})
}
private fun lastAddedSongs() {
toolbar.setTitle(R.string.last_added)
binding.toolbar.setTitle(R.string.last_added)
val songAdapter = ShuffleButtonSongAdapter(
requireActivity(),
mutableListOf(),
R.layout.item_list, null
)
recyclerView.apply {
binding.recyclerView.apply {
adapter = songAdapter
layoutManager = linearLayoutManager()
}
@ -85,13 +108,13 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
}
private fun topPlayed() {
toolbar.setTitle(R.string.my_top_tracks)
binding.toolbar.setTitle(R.string.my_top_tracks)
val songAdapter = ShuffleButtonSongAdapter(
requireActivity(),
mutableListOf(),
R.layout.item_list, null
)
recyclerView.apply {
binding.recyclerView.apply {
adapter = songAdapter
layoutManager = linearLayoutManager()
}
@ -101,14 +124,14 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
}
private fun loadHistory() {
toolbar.setTitle(R.string.history)
binding.toolbar.setTitle(R.string.history)
val songAdapter = ShuffleButtonSongAdapter(
requireActivity(),
mutableListOf(),
R.layout.item_list, null
)
recyclerView.apply {
binding.recyclerView.apply {
adapter = songAdapter
layoutManager = linearLayoutManager()
}
@ -118,13 +141,13 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
}
private fun loadFavorite() {
toolbar.setTitle(R.string.favorites)
binding.toolbar.setTitle(R.string.favorites)
val songAdapter = SongAdapter(
requireActivity(),
mutableListOf(),
R.layout.item_list, null
)
recyclerView.apply {
binding.recyclerView.apply {
adapter = songAdapter
layoutManager = linearLayoutManager()
}
@ -135,9 +158,9 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
}
private fun loadArtists(title: Int, type: Int) {
toolbar.setTitle(title)
binding.toolbar.setTitle(title)
libraryViewModel.artists(type).observe(viewLifecycleOwner, { artists ->
recyclerView.apply {
binding.recyclerView.apply {
adapter = artistAdapter(artists)
layoutManager = gridLayoutManager()
}
@ -145,9 +168,9 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
}
private fun loadAlbums(title: Int, type: Int) {
toolbar.setTitle(title)
binding.toolbar.setTitle(title)
libraryViewModel.albums(type).observe(viewLifecycleOwner, { albums ->
recyclerView.apply {
binding.recyclerView.apply {
adapter = albumAdapter(albums)
layoutManager = gridLayoutManager()
}
@ -186,7 +209,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId),
null,
FragmentNavigatorExtras(view to "artist")
FragmentNavigatorExtras(view to artistId.toString())
)
}
@ -196,8 +219,13 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to "album"
view to albumId.toString()
)
)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -25,9 +25,7 @@ import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LibraryViewModel(
private val repository: RealRepository
@ -129,16 +127,16 @@ class LibraryViewModel(
}
}
private fun fetchHomeSections() {
fun fetchHomeSections() {
viewModelScope.launch(IO) {
home.postValue(repository.homeSections())
}
}
fun search(query: String?) {
fun search(query: String?, filters: List<Boolean>) {
viewModelScope.launch(IO) {
val result = repository.search(query)
withContext(Main) { searchResults.postValue(result) }
val result = repository.search(query, filters)
searchResults.postValue(result)
}
}
@ -190,6 +188,10 @@ class LibraryViewModel(
println("onShuffleModeChanged")
}
override fun onFavoriteStateChanged() {
println("onFavoriteStateChanged")
}
fun shuffleSongs() = viewModelScope.launch(IO) {
val songs = repository.allSongs()
MusicPlayerRemote.openAndShuffleQueue(

View file

@ -26,23 +26,26 @@ import android.view.MotionEvent
import android.view.View
import android.view.animation.DecelerateInterpolator
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentMiniPlayerBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.textColorPrimary
import code.name.monkey.retromusic.extensions.textColorSecondary
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
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.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import kotlin.math.abs
import kotlinx.android.synthetic.main.fragment_mini_player.*
open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_player),
MusicProgressViewUpdateHelper.Callback, View.OnClickListener {
private var _binding: FragmentMiniPlayerBinding? = null
private val binding get() = _binding!!
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
override fun onCreate(savedInstanceState: Bundle?) {
@ -59,38 +62,38 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMiniPlayerBinding.bind(view)
view.setOnTouchListener(FlingPlayBackController(requireContext()))
setUpMiniPlayer()
if (RetroUtil.isTablet()) {
actionNext.show()
actionPrevious.show()
actionNext?.show()
actionPrevious?.show()
binding.actionNext.show()
binding.actionPrevious.show()
} else {
actionNext.visibility = if (PreferenceUtil.isExtraControls) View.VISIBLE else View.GONE
actionPrevious.visibility =
binding.actionNext.visibility =
if (PreferenceUtil.isExtraControls) View.VISIBLE else View.GONE
binding.actionPrevious.visibility =
if (PreferenceUtil.isExtraControls) View.VISIBLE else View.GONE
}
actionNext.setOnClickListener(this)
actionPrevious.setOnClickListener(this)
actionNext?.setOnClickListener(this)
actionPrevious?.setOnClickListener(this)
binding.actionNext.setOnClickListener(this)
binding.actionPrevious.setOnClickListener(this)
}
private fun setUpMiniPlayer() {
setUpPlayPauseButton()
progressBar.accentColor()
binding.progressBar.accentColor()
}
private fun setUpPlayPauseButton() {
miniPlayerPlayPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.miniPlayerPlayPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updateSongTitle() {
val builder = SpannableStringBuilder()
val song = MusicPlayerRemote.currentSong
val builder = SpannableStringBuilder()
val title = SpannableString(song.title)
title.setSpan(ForegroundColorSpan(textColorPrimary()), 0, title.length, 0)
@ -99,17 +102,34 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
builder.append(title).append("").append(text)
miniPlayerTitle.isSelected = true
miniPlayerTitle.text = builder
binding.miniPlayerTitle.isSelected = true
binding.miniPlayerTitle.text = builder
// binding.title.isSelected = true
// binding.title.text = song.title
// binding.text.isSelected = true
// binding.text.text = song.artistName
}
private fun updateSongCover() {
// val song = MusicPlayerRemote.currentSong
// GlideApp.with(requireContext())
// .asBitmap()
// .songCoverOptions(song)
// .transition(RetroGlideExtension.getDefaultTransition())
// .load(RetroGlideExtension.getSongModel(song))
// .into(binding.image)
}
override fun onServiceConnected() {
updateSongTitle()
updateSongCover()
updatePlayPauseDrawableState()
}
override fun onPlayingMetaChanged() {
updateSongTitle()
updateSongCover()
}
override fun onPlayStateChanged() {
@ -117,8 +137,8 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressBar.max = total
val animator = ObjectAnimator.ofInt(progressBar, "progress", progress)
binding.progressBar.max = total
val animator = ObjectAnimator.ofInt(binding.progressBar, "progress", progress)
animator.duration = 1000
animator.interpolator = DecelerateInterpolator()
animator.start()
@ -136,16 +156,12 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
protected fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
miniPlayerPlayPauseButton.setImageResource(R.drawable.ic_pause)
binding.miniPlayerPlayPauseButton.setImageResource(R.drawable.ic_pause)
} else {
miniPlayerPlayPauseButton.setImageResource(R.drawable.ic_play_arrow)
binding.miniPlayerPlayPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
fun updateProgressBar(paletteColor: Int) {
progressBar.applyColor(paletteColor)
}
class FlingPlayBackController(context: Context) : View.OnTouchListener {
private var flingPlayBackController: GestureDetector
@ -178,4 +194,9 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
return flingPlayBackController.onTouchEvent(event)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -26,34 +26,38 @@ import android.widget.SeekBar
import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentVolumeBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.volume.AudioVolumeObserver
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
import kotlinx.android.synthetic.main.fragment_volume.*
class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolumeChangedListener,
View.OnClickListener {
private var _binding: FragmentVolumeBinding? = null
private val binding get() = _binding!!
private var audioVolumeObserver: AudioVolumeObserver? = null
private val audioManager: AudioManager?
private val audioManager: AudioManager
get() = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_volume, container, false)
): View {
_binding = FragmentVolumeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setTintable(ThemeStore.accentColor(requireContext()))
volumeDown.setOnClickListener(this)
volumeUp.setOnClickListener(this)
binding.volumeDown.setOnClickListener(this)
binding.volumeUp.setOnClickListener(this)
}
override fun onResume() {
@ -64,33 +68,30 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this)
val audioManager = audioManager
if (audioManager != null) {
volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
}
volumeSeekBar.setOnSeekBarChangeListener(this)
binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.setOnSeekBarChangeListener(this)
}
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
if (volumeSeekBar == null) {
return
if (_binding != null) {
binding.volumeSeekBar.max = maxVolume
binding.volumeSeekBar.progress = currentVolume
binding.volumeDown.setImageResource(if (currentVolume == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
volumeSeekBar.max = maxVolume
volumeSeekBar.progress = currentVolume
volumeDown.setImageResource(if (currentVolume == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
override fun onDestroyView() {
super.onDestroyView()
audioVolumeObserver?.unregister()
_binding = null
}
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
val audioManager = audioManager
audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, i, 0)
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, i, 0)
setPauseWhenZeroVolume(i < 1)
volumeDown?.setImageResource(if (i == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
binding.volumeDown.setImageResource(if (i == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
@ -102,10 +103,10 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
override fun onClick(view: View) {
val audioManager = audioManager
when (view.id) {
R.id.volumeDown -> audioManager?.adjustStreamVolume(
R.id.volumeDown -> audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0
)
R.id.volumeUp -> audioManager?.adjustStreamVolume(
R.id.volumeUp -> audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0
)
}
@ -113,13 +114,13 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
fun tintWhiteColor() {
val color = Color.WHITE
volumeDown.setColorFilter(color, PorterDuff.Mode.SRC_IN)
volumeUp.setColorFilter(color, PorterDuff.Mode.SRC_IN)
volumeSeekBar.applyColor(color)
binding.volumeDown.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.volumeUp.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.volumeSeekBar.applyColor(color)
}
fun setTintable(color: Int) {
volumeSeekBar.applyColor(color)
binding.volumeSeekBar.applyColor(color)
}
private fun setPauseWhenZeroVolume(pauseWhenZeroVolume: Boolean) {
@ -129,10 +130,10 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
}
fun setTintableColor(color: Int) {
volumeDown.setColorFilter(color, PorterDuff.Mode.SRC_IN)
volumeUp.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.volumeDown.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.volumeUp.setColorFilter(color, PorterDuff.Mode.SRC_IN)
// TintHelper.setTint(volumeSeekBar, color, false)
volumeSeekBar.applyColor(color)
binding.volumeSeekBar.applyColor(color)
}
companion object {

View file

@ -27,20 +27,20 @@ import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.ContributorAdapter
import code.name.monkey.retromusic.databinding.FragmentAboutBinding
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.util.NavigationUtil
import kotlinx.android.synthetic.main.card_credit.*
import kotlinx.android.synthetic.main.card_other.*
import kotlinx.android.synthetic.main.card_retro_info.*
import kotlinx.android.synthetic.main.card_social.*
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
private var _binding: FragmentAboutBinding? = null
private val binding get() = _binding!!
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
version.setSummary(getAppVersion())
_binding = FragmentAboutBinding.bind(view)
binding.aboutContent.cardOther.version.setSummary(getAppVersion())
setUpView()
loadContributors()
}
@ -53,19 +53,20 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
}
private fun setUpView() {
appGithub.setOnClickListener(this)
faqLink.setOnClickListener(this)
telegramLink.setOnClickListener(this)
appRate.setOnClickListener(this)
appTranslation.setOnClickListener(this)
appShare.setOnClickListener(this)
donateLink.setOnClickListener(this)
instagramLink.setOnClickListener(this)
twitterLink.setOnClickListener(this)
changelog.setOnClickListener(this)
openSource.setOnClickListener(this)
pinterestLink.setOnClickListener(this)
bugReportLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appGithub.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.faqLink.setOnClickListener(this)
binding.aboutContent.cardSocial.telegramLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appRate.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appTranslation.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appShare.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.donateLink.setOnClickListener(this)
binding.aboutContent.cardSocial.instagramLink.setOnClickListener(this)
binding.aboutContent.cardSocial.twitterLink.setOnClickListener(this)
binding.aboutContent.cardOther.changelog.setOnClickListener(this)
binding.aboutContent.cardOther.openSource.setOnClickListener(this)
binding.aboutContent.cardSocial.pinterestLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.bugReportLink.setOnClickListener(this)
binding.aboutContent.cardSocial.websiteLink.setOnClickListener(this)
}
override fun onClick(view: View) {
@ -80,9 +81,10 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
R.id.donateLink -> NavigationUtil.goToSupportDevelopment(requireActivity())
R.id.instagramLink -> openUrl(Constants.APP_INSTAGRAM_LINK)
R.id.twitterLink -> openUrl(Constants.APP_TWITTER_LINK)
R.id.changelog -> openUrl(Constants.TELEGRAM_CHANGE_LOG)
R.id.changelog -> NavigationUtil.gotoWhatNews(requireActivity())
R.id.openSource -> NavigationUtil.goToOpenSource(requireActivity())
R.id.bugReportLink -> NavigationUtil.bugReport(requireActivity())
R.id.websiteLink -> openUrl(Constants.WEBSITE)
}
}
@ -99,7 +101,7 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
}
private fun shareApp() {
ShareCompat.IntentBuilder.from(requireActivity()).setType("text/plain")
ShareCompat.IntentBuilder(requireActivity()).setType("text/plain")
.setChooserTitle(R.string.share_app)
.setText(String.format(getString(R.string.app_share), requireActivity().packageName))
.startChooser()
@ -107,7 +109,7 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
private fun loadContributors() {
val contributorAdapter = ContributorAdapter(emptyList())
recyclerView.apply {
binding.aboutContent.cardCredit.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
itemAnimator = DefaultItemAnimator()
adapter = contributorAdapter
@ -116,4 +118,9 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
contributorAdapter.swapData(contributors)
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -19,11 +19,12 @@ import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.*
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.Observer
import androidx.core.view.doOnPreDraw
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
@ -35,17 +36,19 @@ import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackg
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.databinding.FragmentAlbumDetailsBinding
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -54,6 +57,7 @@ import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_TRACK_LIST
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_Z_A
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
@ -61,14 +65,12 @@ import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform
import com.google.android.material.transition.MaterialElevationScale
import kotlinx.android.synthetic.main.fragment_album_content.*
import kotlinx.android.synthetic.main.fragment_album_details.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -78,7 +80,10 @@ import org.koin.core.parameter.parametersOf
import java.util.*
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
IAlbumClickListener {
IAlbumClickListener, ICabHolder {
private var _binding: FragmentAlbumDetailsBinding? = null
private val binding get() = _binding!!
private val arguments by navArgs<AlbumDetailsFragmentArgs>()
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
@ -87,6 +92,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album
private var albumArtistExists = false
private val savedSortOrder: String
get() = PreferenceUtil.albumDetailSongSortOrder
@ -104,51 +110,70 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentAlbumDetailsBinding.bind(view)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(false)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(toolbar)
mainActivity.setSupportActionBar(binding.toolbar)
toolbar.title = " "
ViewCompat.setTransitionName(albumCoverContainer, "album")
binding.toolbar.title = " "
ViewCompat.setTransitionName(binding.albumCoverContainer, arguments.extraAlbumId.toString())
postponeEnterTransition()
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
startPostponedEnterTransition()
detailsViewModel.getAlbum().observe(viewLifecycleOwner, {
requireView().doOnPreDraw {
startPostponedEnterTransition()
}
albumArtistExists = !it.albumArtist.isNullOrEmpty()
showAlbum(it)
if (albumArtistExists) {
ViewCompat.setTransitionName(binding.artistImage, album.albumArtist)
} else {
ViewCompat.setTransitionName(binding.artistImage, album.artistId.toString())
}
})
setupRecyclerView()
artistImage.setOnClickListener { artistView ->
ViewCompat.setTransitionName(artistView, "artist")
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
binding.artistImage.setOnClickListener { artistView ->
if (albumArtistExists) {
findActivityNavController(R.id.fragment_container)
.navigate(
R.id.albumArtistDetailsFragment,
bundleOf(EXTRA_ARTIST_NAME to album.albumArtist),
null,
FragmentNavigatorExtras(artistView to album.albumArtist.toString())
)
} else {
findActivityNavController(R.id.fragment_container)
.navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to album.artistId),
null,
FragmentNavigatorExtras(artistView to album.artistId.toString())
)
}
reenterTransition = MaterialElevationScale(true).apply {
duration = 300L
}
findActivityNavController(R.id.fragment_container)
.navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to album.artistId),
null,
FragmentNavigatorExtras(artistView to "artist")
)
}
playAction.setOnClickListener {
binding.fragmentAlbumContent.playAction.setOnClickListener {
MusicPlayerRemote.openQueue(album.songs, 0, true)
}
shuffleAction.setOnClickListener {
binding.fragmentAlbumContent.shuffleAction.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(
album.songs,
true
)
}
aboutAlbumText.setOnClickListener {
if (aboutAlbumText.maxLines == 4) {
aboutAlbumText.maxLines = Integer.MAX_VALUE
binding.fragmentAlbumContent.aboutAlbumText.setOnClickListener {
if (binding.fragmentAlbumContent.aboutAlbumText.maxLines == 4) {
binding.fragmentAlbumContent.aboutAlbumText.maxLines = Integer.MAX_VALUE
} else {
aboutAlbumText.maxLines = 4
binding.fragmentAlbumContent.aboutAlbumText.maxLines = 4
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
@ -163,9 +188,9 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
requireActivity() as AppCompatActivity,
ArrayList(),
R.layout.item_song,
null
this
)
recyclerView.apply {
binding.fragmentAlbumContent.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
itemAnimator = DefaultItemAnimator()
isNestedScrollingEnabled = false
@ -179,21 +204,21 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
this.album = album
albumTitle.text = album.title
binding.albumTitle.text = album.title
val songText = resources.getQuantityString(
R.plurals.albumSongs,
album.songCount,
album.songCount
)
songTitle.text = songText
binding.fragmentAlbumContent.songTitle.text = songText
if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format(
binding.albumText.text = String.format(
"%s • %s",
album.artistName,
if (albumArtistExists) album.albumArtist else album.artistName,
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
} else {
albumText.text = String.format(
binding.albumText.text = String.format(
"%s • %s • %s",
album.artistName,
MusicUtil.getYearString(album.year),
@ -202,11 +227,18 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
loadAlbumCover(album)
simpleSongAdapter.swapDataSet(album.songs)
detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer {
loadArtistImage(it)
})
if (albumArtistExists) {
detailsViewModel.getAlbumArtist(album.albumArtist.toString()).observe(viewLifecycleOwner, {
loadArtistImage(it)
})
} else {
detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, {
loadArtistImage(it)
})
}
detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, Observer { result ->
detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, { result ->
when (result) {
is Result.Loading -> {
println("Loading")
@ -222,41 +254,44 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
private fun moreAlbums(albums: List<Album>) {
moreTitle.show()
moreRecyclerView.show()
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
binding.fragmentAlbumContent.moreTitle.show()
binding.fragmentAlbumContent.moreRecyclerView.show()
binding.fragmentAlbumContent.moreTitle.text =
String.format(getString(R.string.label_more_from), album.artistName)
val albumAdapter =
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, null, this)
moreRecyclerView.layoutManager = GridLayoutManager(
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, this, this)
binding.fragmentAlbumContent.moreRecyclerView.layoutManager = GridLayoutManager(
requireContext(),
1,
GridLayoutManager.HORIZONTAL,
false
)
moreRecyclerView.adapter = albumAdapter
binding.fragmentAlbumContent.moreRecyclerView.adapter = albumAdapter
}
private fun aboutAlbum(lastFmAlbum: LastFmAlbum) {
if (lastFmAlbum.album != null) {
if (lastFmAlbum.album.wiki != null) {
aboutAlbumText.show()
aboutAlbumTitle.show()
aboutAlbumTitle.text =
binding.fragmentAlbumContent.aboutAlbumText.show()
binding.fragmentAlbumContent.aboutAlbumTitle.show()
binding.fragmentAlbumContent.aboutAlbumTitle.text =
String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
aboutAlbumText.text = HtmlCompat.fromHtml(
binding.fragmentAlbumContent.aboutAlbumText.text = HtmlCompat.fromHtml(
lastFmAlbum.album.wiki.content,
HtmlCompat.FROM_HTML_MODE_LEGACY
)
}
if (lastFmAlbum.album.listeners.isNotEmpty()) {
listeners.show()
listenersLabel.show()
scrobbles.show()
scrobblesLabel.show()
binding.fragmentAlbumContent.listeners.show()
binding.fragmentAlbumContent.listenersLabel.show()
binding.fragmentAlbumContent.scrobbles.show()
binding.fragmentAlbumContent.scrobblesLabel.show()
listeners.text = RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat())
scrobbles.text = RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat())
binding.fragmentAlbumContent.listeners.text =
RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat())
binding.fragmentAlbumContent.scrobbles.text =
RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat())
}
}
}
@ -265,24 +300,22 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner, {
moreAlbums(it)
})
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
.generatePalette(requireContext())
.build()
GlideApp.with(requireContext()).asBitmapPalette().artistImageOptions(artist)
//.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
.load(RetroGlideExtension.getArtistModel(artist, PreferenceUtil.isAllowedToDownloadMetadata()))
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(artistImage) {
.into(object : RetroMusicColoredTarget(binding.artistImage) {
override fun onColorReady(colors: MediaNotificationProcessor) {
}
})
}
private fun loadAlbumCover(album: Album) {
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
.checkIgnoreMediaStore()
.generatePalette(requireContext())
.build()
.into(object : SingleColorTarget(image) {
GlideApp.with(requireContext()).asBitmapPalette().albumCoverOptions(album.safeGetFirstSong())
//.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
.into(object : SingleColorTarget(binding.image) {
override fun onColorReady(color: Int) {
setColors(color)
}
@ -290,23 +323,17 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
private fun setColors(color: Int) {
shuffleAction?.applyColor(color)
playAction?.applyOutlineColor(color)
binding.fragmentAlbumContent.shuffleAction.applyColor(color)
binding.fragmentAlbumContent.playAction.applyOutlineColor(color)
}
override fun onAlbumClick(albumId: Long, view: View) {
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(false).apply {
duration = 300L
}
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to "album"
view to albumId.toString()
)
)
}
@ -318,9 +345,9 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
setUpSortOrderMenu(sortOrder.subMenu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
toolbar,
binding.toolbar,
menu,
getToolbarBackgroundColor(toolbar)
getToolbarBackgroundColor(binding.toolbar)
)
}
@ -360,7 +387,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
val options = ActivityOptions.makeSceneTransitionAnimation(
requireActivity(),
albumCoverContainer,
binding.albumCoverContainer,
"${getString(R.string.transition_album_art)}_${album.id}"
)
startActivityForResult(
@ -421,6 +448,37 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
simpleSongAdapter.swapDataSet(album.songs)
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()
return true
}
}
return false
}
private var cab: MaterialCab? = null
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
cab?.let {
if (it.isActive) {
it.finish()
}
}
cab = MaterialCab(mainActivity, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(surfaceColor()))
.start(callback)
return cab as MaterialCab
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
const val TAG_EDITOR_REQUEST = 9002
}

View file

@ -14,11 +14,7 @@
*/
package code.name.monkey.retromusic.fragments.albums
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
@ -51,6 +47,11 @@ class AlbumDetailsViewModel(
emit(artist)
}
fun getAlbumArtist(artistName: String): LiveData<Artist> = liveData(IO) {
val artist = repository.albumArtistByName(artistName)
emit(artist)
}
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData {
emit(Result.Loading)
emit(repository.albumInfo(album.artistName ?: "-", album.title ?: "-"))
@ -73,4 +74,5 @@ class AlbumDetailsViewModel(
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
override fun onFavoriteStateChanged() {}
}

View file

@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.albums
import android.os.Bundle
import android.view.*
import androidx.activity.addCallback
import androidx.core.os.bundleOf
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
@ -33,7 +34,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.transition.MaterialElevationScale
import com.google.android.gms.cast.framework.CastButtonFactory
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
IAlbumClickListener, ICabHolder {
@ -46,8 +47,17 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
else
adapter?.swapDataSet(listOf())
})
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
override val titleRes: Int
get() = R.string.albums
override val emptyMessage: Int
get() = R.string.no_albums
@ -114,20 +124,15 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
}
override fun onAlbumClick(albumId: Long, view: View) {
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(true).apply {
duration = 300L
}
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to "album"
view to albumId.toString()
)
)
reenterTransition = null
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -140,6 +145,8 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
val layoutItem = menu.findItem(R.id.action_layout_type)
setupLayoutMenu(layoutItem.subMenu)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
private fun setUpSortOrderMenu(
@ -175,6 +182,13 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
R.string.sort_order_year
).isChecked =
currentSortOrder.equals(AlbumSortOrder.ALBUM_YEAR)
sortOrderMenu.add(
0,
R.id.action_album_sort_order_num_songs,
4,
R.string.sort_order_num_songs
).isChecked =
currentSortOrder.equals(AlbumSortOrder.ALBUM_NUMBER_OF_SONGS)
sortOrderMenu.setGroupCheckable(0, true, true)
}
@ -251,6 +265,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
R.id.action_album_sort_order_desc -> AlbumSortOrder.ALBUM_Z_A
R.id.action_album_sort_order_artist -> AlbumSortOrder.ALBUM_ARTIST
R.id.action_album_sort_order_year -> AlbumSortOrder.ALBUM_YEAR
R.id.action_album_sort_order_num_songs -> AlbumSortOrder.ALBUM_NUMBER_OF_SONGS
else -> PreferenceUtil.albumSortOrder
}
if (sortOrder != PreferenceUtil.albumSortOrder) {
@ -303,6 +318,21 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
return false
}
override fun onResume() {
super.onResume()
libraryViewModel.forceReload(ReloadType.Albums)
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()
return true
}
}
return false
}
private var cab: MaterialCab? = null
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {

View file

@ -0,0 +1,342 @@
package code.name.monkey.retromusic.fragments.artists
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.text.Spanned
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.core.view.ViewCompat
import androidx.core.view.doOnPreDraw
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.databinding.FragmentArtistDetailsBinding
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.CustomArtistImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import java.util.*
import kotlin.collections.ArrayList
abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details),
IAlbumClickListener, ICabHolder {
private var _binding: FragmentArtistDetailsBinding? = null
private val binding get() = _binding!!
abstract val detailsViewModel: ArtistDetailsViewModel
abstract val artistId: Long?
abstract val artistName: String?
private lateinit var artist: Artist
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: HorizontalAlbumAdapter
private var forceDownload: Boolean = false
private var lang: String? = null
private var biography: Spanned? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment_container
duration = 300L
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().resolveColor(R.attr.colorSurface))
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentArtistDetailsBinding.bind(view)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
binding.toolbar.title = null
ViewCompat.setTransitionName(
binding.artistCoverContainer,
(artistId ?: artistName).toString()
)
postponeEnterTransition()
detailsViewModel.getArtist().observe(viewLifecycleOwner, {
requireView().doOnPreDraw {
startPostponedEnterTransition()
}
showArtist(it)
})
setupRecyclerView()
binding.fragmentArtistContent.playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
binding.fragmentArtistContent.shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
binding.fragmentArtistContent.biographyText.setOnClickListener {
if (binding.fragmentArtistContent.biographyText.maxLines == 4) {
binding.fragmentArtistContent.biographyText.maxLines = Integer.MAX_VALUE
} else {
binding.fragmentArtistContent.biographyText.maxLines = 4
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), this, this)
binding.fragmentArtistContent.albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter
}
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, this)
binding.fragmentArtistContent.recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context)
adapter = songAdapter
}
}
private fun showArtist(artist: Artist) {
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
loadBiography(artist.name)
}
binding.artistTitle.text = artist.name
binding.text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(requireContext(), artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
)
val songText = resources.getQuantityString(
R.plurals.albumSongs,
artist.songCount,
artist.songCount
)
val albumText = resources.getQuantityString(
R.plurals.albums,
artist.songCount,
artist.songCount
)
binding.fragmentArtistContent.songTitle.text = songText
binding.fragmentArtistContent.albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
albumAdapter.swapDataSet(artist.albums)
}
private fun loadBiography(
name: String,
lang: String? = Locale.getDefault().language
) {
biography = null
this.lang = lang
detailsViewModel.getArtistInfo(name, lang, null)
.observe(viewLifecycleOwner, { result ->
when (result) {
is Result.Loading -> println("Loading")
is Result.Error -> println("Error")
is Result.Success -> artistInfo(result.data)
}
})
}
private fun artistInfo(lastFmArtist: LastFmArtist?) {
if (lastFmArtist != null && lastFmArtist.artist != null && lastFmArtist.artist.bio != null) {
val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
binding.fragmentArtistContent.biographyText.visibility = View.VISIBLE
binding.fragmentArtistContent.biographyTitle.visibility = View.VISIBLE
biography = HtmlCompat.fromHtml(bioContent, HtmlCompat.FROM_HTML_MODE_LEGACY)
binding.fragmentArtistContent.biographyText.text = biography
if (lastFmArtist.artist.stats.listeners.isNotEmpty()) {
binding.fragmentArtistContent.listeners.show()
binding.fragmentArtistContent.listenersLabel.show()
binding.fragmentArtistContent.scrobbles.show()
binding.fragmentArtistContent.scrobblesLabel.show()
binding.fragmentArtistContent.listeners.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat())
binding.fragmentArtistContent.scrobbles.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat())
}
}
}
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
private fun loadArtistImage(artist: Artist) {
GlideApp.with(requireContext()).asBitmapPalette().artistImageOptions(artist)
.load(RetroGlideExtension.getArtistModel(artist))
.dontAnimate()
.into(object : SingleColorTarget(binding.image) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
private fun setColors(color: Int) {
if (_binding != null) {
binding.fragmentArtistContent.shuffleAction.applyColor(color)
binding.fragmentArtistContent.playAction.applyOutlineColor(color)
}
}
override fun onAlbumClick(albumId: Long, view: View) {
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to albumId.toString()
)
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
when (item.itemId) {
android.R.id.home -> findNavController().navigateUp()
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
lifecycleScope.launch(Dispatchers.IO) {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, songs)
.show(childFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(intent, getString(R.string.pick_from_local_storage)),
REQUEST_CODE_SELECT_IMAGE
)
return true
}
R.id.action_reset_artist_image -> {
showToast(resources.getString(R.string.updating))
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
forceDownload = true
return true
}
}
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let {
CustomArtistImageUtil.getInstance(requireContext())
.setCustomArtistImage(artist, it)
}
}
else -> if (resultCode == Activity.RESULT_OK) {
println("OK")
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_artist_detail, menu)
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()
return true
}
}
return false
}
private var cab: MaterialCab? = null
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
cab?.let {
if (it.isActive) {
it.finish()
}
}
cab = MaterialCab(mainActivity, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(surfaceColor()))
.start(callback)
return cab as MaterialCab
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
const val REQUEST_CODE_SELECT_IMAGE = 9002
}
}

View file

@ -0,0 +1,32 @@
/*
* 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.artists
import androidx.navigation.fragment.navArgs
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
class AlbumArtistDetailsFragment : AbsArtistDetailsFragment() {
private val arguments by navArgs<AlbumArtistDetailsFragmentArgs>()
override val detailsViewModel: ArtistDetailsViewModel by viewModel {
parametersOf(null, arguments.extraArtistName)
}
override val artistId: Long?
get() = null
override val artistName: String
get() = arguments.extraArtistName
}

View file

@ -0,0 +1,66 @@
/*
* 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.artists
import androidx.lifecycle.*
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.repository.RealRepository
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
class AlbumArtistDetailsViewModel(
private val realRepository: RealRepository,
private val artistName: String
) : ViewModel(), IMusicServiceEventListener {
private val artistDetails = MutableLiveData<Artist>()
init {
fetchAlbumArtist()
}
private fun fetchAlbumArtist() {
viewModelScope.launch(IO) {
artistDetails.postValue(realRepository.albumArtistByName(artistName))
}
}
fun getArtist(): LiveData<Artist> = artistDetails
fun getArtistInfo(
name: String,
lang: String?,
cache: String?
): LiveData<Result<LastFmArtist>> = liveData(IO) {
emit(Result.Loading)
val info = realRepository.artistInfo(name, lang, cache)
emit(info)
}
override fun onMediaStoreChanged() {
fetchAlbumArtist()
}
override fun onServiceConnected() {}
override fun onServiceDisconnected() {}
override fun onQueueChanged() {}
override fun onFavoriteStateChanged() {}
override fun onPlayingMetaChanged() {}
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
}

View file

@ -14,298 +14,18 @@
*/
package code.name.monkey.retromusic.fragments.artists
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.text.Spanned
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.CustomArtistImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide
import com.google.android.material.transition.MaterialContainerTransform
import com.google.android.material.transition.MaterialElevationScale
import kotlinx.android.synthetic.main.fragment_artist_content.*
import kotlinx.android.synthetic.main.fragment_artist_details.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
import kotlin.collections.ArrayList
class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details),
IAlbumClickListener {
class ArtistDetailsFragment : AbsArtistDetailsFragment() {
private val arguments by navArgs<ArtistDetailsFragmentArgs>()
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
parametersOf(arguments.extraArtistId)
override val detailsViewModel: ArtistDetailsViewModel by viewModel {
parametersOf(arguments.extraArtistId, null)
}
private lateinit var artist: Artist
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: HorizontalAlbumAdapter
private var forceDownload: Boolean = false
private var lang: String? = null
private var biography: Spanned? = null
override val artistId: Long
get() = arguments.extraArtistId
override val artistName: String?
get() = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment_container
duration = 300L
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().resolveColor(R.attr.colorSurface))
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(false)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(toolbar)
toolbar.title = null
ViewCompat.setTransitionName(artistCoverContainer, "artist")
postponeEnterTransition()
detailsViewModel.getArtist().observe(viewLifecycleOwner, {
startPostponedEnterTransition()
showArtist(it)
})
setupRecyclerView()
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
biographyText.setOnClickListener {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE
} else {
biographyText.maxLines = 4
}
}
}
private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), null, this)
albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter
}
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, null)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context)
adapter = songAdapter
}
}
private fun showArtist(artist: Artist) {
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
loadBiography(artist.name)
}
artistTitle.text = artist.name
text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(requireContext(), artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
)
val songText = resources.getQuantityString(
R.plurals.albumSongs,
artist.songCount,
artist.songCount
)
val albumText = resources.getQuantityString(
R.plurals.albums,
artist.songCount,
artist.songCount
)
songTitle.text = songText
albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
albumAdapter.swapDataSet(artist.albums)
}
private fun loadBiography(
name: String,
lang: String? = Locale.getDefault().language
) {
biography = null
this.lang = lang
detailsViewModel.getArtistInfo(name, lang, null)
.observe(viewLifecycleOwner, { result ->
when (result) {
is Result.Loading -> println("Loading")
is Result.Error -> println("Error")
is Result.Success -> artistInfo(result.data)
}
})
}
private fun artistInfo(lastFmArtist: LastFmArtist?) {
if (lastFmArtist != null && lastFmArtist.artist != null) {
val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
biographyText.visibility = View.VISIBLE
biographyTitle.visibility = View.VISIBLE
biography = HtmlCompat.fromHtml(bioContent, HtmlCompat.FROM_HTML_MODE_LEGACY)
biographyText.text = biography
if (lastFmArtist.artist.stats.listeners.isNotEmpty()) {
listeners.show()
listenersLabel.show()
scrobbles.show()
scrobblesLabel.show()
listeners.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat())
scrobbles.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat())
}
}
}
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
private fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.generatePalette(requireContext()).build()
.dontAnimate()
.into(object : SingleColorTarget(image) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
private fun setColors(color: Int) {
shuffleAction?.applyColor(color)
playAction?.applyOutlineColor(color)
}
override fun onAlbumClick(albumId: Long, view: View) {
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(false).apply {
duration = 300L
}
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to "album"
)
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
when (item.itemId) {
android.R.id.home -> findNavController().navigateUp()
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
lifecycleScope.launch(Dispatchers.IO) {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, songs)
.show(childFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(intent, getString(R.string.pick_from_local_storage)),
REQUEST_CODE_SELECT_IMAGE
)
return true
}
R.id.action_reset_artist_image -> {
showToast(resources.getString(R.string.updating))
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
forceDownload = true
return true
}
}
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let {
CustomArtistImageUtil.getInstance(requireContext())
.setCustomArtistImage(artist, it)
}
}
else -> if (resultCode == Activity.RESULT_OK) {
println("OK")
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_artist_detail, menu)
}
companion object {
const val REQUEST_CODE_SELECT_IMAGE = 9002
}
}

View file

@ -14,11 +14,7 @@
*/
package code.name.monkey.retromusic.fragments.artists
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
@ -29,7 +25,8 @@ import kotlinx.coroutines.launch
class ArtistDetailsViewModel(
private val realRepository: RealRepository,
private val artistId: Long
private val artistId: Long?,
private val artistName: String?
) : ViewModel(), IMusicServiceEventListener {
private val artistDetails = MutableLiveData<Artist>()
@ -39,7 +36,9 @@ class ArtistDetailsViewModel(
private fun fetchArtist() {
viewModelScope.launch(IO) {
artistDetails.postValue(realRepository.artistById(artistId))
artistId?.let { artistDetails.postValue(realRepository.artistById(it)) }
artistName?.let { artistDetails.postValue(realRepository.albumArtistByName(it)) }
}
}
@ -56,7 +55,7 @@ class ArtistDetailsViewModel(
}
override fun onMediaStoreChanged() {
fetchArtist()
fetchArtist()
}
override fun onServiceConnected() {}
@ -66,4 +65,5 @@ class ArtistDetailsViewModel(
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
override fun onFavoriteStateChanged() {}
}

View file

@ -16,38 +16,48 @@ package code.name.monkey.retromusic.fragments.artists
import android.os.Bundle
import android.view.*
import androidx.activity.addCallback
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder
import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.transition.MaterialElevationScale
import com.google.android.gms.cast.framework.CastButtonFactory
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
IArtistClickListener, ICabHolder {
IArtistClickListener, IAlbumArtistClickListener, ICabHolder {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
libraryViewModel.getArtists().observe(viewLifecycleOwner, Observer {
libraryViewModel.getArtists().observe(viewLifecycleOwner, {
if (it.isNotEmpty())
adapter?.swapDataSet(it)
else
adapter?.swapDataSet(listOf())
})
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
override val titleRes: Int
get() = R.string.artists
override val emptyMessage: Int
get() = R.string.no_artists
@ -66,7 +76,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
dataSet,
itemLayoutRes(),
this,
this
this, this
)
}
@ -115,18 +125,23 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
}
override fun onArtist(artistId: Long, view: View) {
exitTransition = MaterialElevationScale(true).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(false).apply {
duration = 300L
}
findNavController().navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId),
null,
FragmentNavigatorExtras(view to "artist")
FragmentNavigatorExtras(view to artistId.toString())
)
reenterTransition = null
}
override fun onAlbumArtist(artistName: String, view: View) {
findNavController().navigate(
R.id.albumArtistDetailsFragment,
bundleOf(EXTRA_ARTIST_NAME to artistName),
null,
FragmentNavigatorExtras(view to artistName)
)
reenterTransition = null
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -139,6 +154,16 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
val layoutItem = menu.findItem(R.id.action_layout_type)
setupLayoutMenu(layoutItem.subMenu)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
setupAlbumArtistMenu(menu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
private fun setupAlbumArtistMenu(menu: Menu) {
menu.add(0, R.id.action_album_artist, 0, R.string.show_album_artists).apply {
isCheckable = true
isChecked = PreferenceUtil.albumArtistsOnly
}
}
private fun setUpSortOrderMenu(
@ -222,9 +247,23 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
if (handleSortOrderMenuItem(item)) {
return true
}
if (handleAlbumArtistMenu(item)) {
return true
}
return super.onOptionsItemSelected(item)
}
private fun handleAlbumArtistMenu(item: MenuItem): Boolean {
return if (item.itemId == R.id.action_album_artist) {
PreferenceUtil.albumArtistsOnly = !item.isChecked
item.isChecked = !item.isChecked
libraryViewModel.forceReload(ReloadType.Artists)
true
} else {
false
}
}
private fun handleSortOrderMenuItem(
item: MenuItem
): Boolean {
@ -283,6 +322,16 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
return false
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()
return true
}
}
return false
}
private var cab: MaterialCab? = null
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
@ -298,4 +347,9 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
.start(callback)
return cab as MaterialCab
}
override fun onResume() {
super.onResume()
libraryViewModel.forceReload(ReloadType.Artists)
}
}

View file

@ -27,10 +27,9 @@ import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.RetroUtil
import org.jaudiotagger.audio.AudioFileIO
import java.io.File
import java.net.URLEncoder
import java.util.*
import org.jaudiotagger.audio.AudioFileIO
/**
* Created by hemanths on 18/08/17.
@ -78,6 +77,9 @@ open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
serviceActivity?.removeMusicServiceEventListener(this)
}
override fun onFavoriteStateChanged() {
}
override fun onPlayingMetaChanged() {
}
@ -121,10 +123,10 @@ open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
return "-"
}
private fun getMimeType(url: String): String? {
private fun getMimeType(url: String): String {
var type: String? = MimeTypeMap.getFileExtensionFromUrl(
URLEncoder.encode(url, "utf-8")
).toUpperCase(Locale.getDefault())
).uppercase()
if (type == null) {
type = url.substring(url.lastIndexOf(".") + 1)
}

View file

@ -44,7 +44,7 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
abstract fun setColor(color: MediaNotificationProcessor)
fun showBonceAnimation(view: View) {
fun showBounceAnimation(view: View) {
view.apply {
clearAnimation()
scaleX = 0.9f

View file

@ -14,31 +14,41 @@
*/
package code.name.monkey.retromusic.fragments.base
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.media.MediaMetadataRetriever
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.text.TextUtils
import android.view.GestureDetector
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.annotation.LayoutRes
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.viewpager.widget.ViewPager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.dialogs.*
import code.name.monkey.retromusic.extensions.currentFragment
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.ReloadType
@ -50,13 +60,14 @@ import code.name.monkey.retromusic.model.lyrics.Lyrics
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.*
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import java.io.FileNotFoundException
import kotlin.math.abs
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
Toolbar.OnMenuItemClickListener, IPaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
@ -68,6 +79,11 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
): Boolean {
val song = MusicPlayerRemote.currentSong
when (item.itemId) {
R.id.action_toggle_lyrics -> {
PreferenceUtil.showLyrics = !PreferenceUtil.showLyrics
showLyricsIcon(item)
return true
}
R.id.action_toggle_favorite -> {
toggleFavorite(song)
return true
@ -114,6 +130,8 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
return true
}
R.id.action_go_to_album -> {
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
mainActivity.setBottomBarVisibility(false)
mainActivity.collapsePanel()
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
@ -122,11 +140,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
return true
}
R.id.action_go_to_artist -> {
mainActivity.collapsePanel()
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId)
)
goToArtist(requireActivity())
return true
}
R.id.now_playing -> {
@ -158,7 +172,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
val trackUri =
ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
song.id.toLong()
song.id
)
retriever.setDataSource(activity, trackUri)
var genre: String? =
@ -173,6 +187,18 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
return false
}
private fun showLyricsIcon(item: MenuItem) {
val icon =
if (PreferenceUtil.showLyrics) R.drawable.ic_lyrics else R.drawable.ic_lyrics_outline
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
requireContext(),
icon,
toolbarIconColor()
)
item.isChecked = PreferenceUtil.showLyrics
item.icon = drawable
}
abstract fun playerToolbar(): Toolbar?
abstract fun onShow()
@ -185,7 +211,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
override fun onServiceConnected() {
updateIsFavorite()
updateLyrics()
}
override fun onPlayingMetaChanged() {
@ -193,9 +218,13 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
updateLyrics()
}
override fun onFavoriteStateChanged() {
updateIsFavorite(animate = true)
}
protected open fun toggleFavorite(song: Song) {
lifecycleScope.launch(IO) {
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
@ -210,26 +239,36 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
}
}
fun updateIsFavorite() {
fun updateIsFavorite(animate: Boolean = false) {
lifecycleScope.launch(IO) {
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
if (playlist != null) {
val song: SongEntity =
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
withContext(Main) {
val icon =
val icon = if (animate) {
if (isFavorite) R.drawable.avd_favorite else R.drawable.avd_unfavorite
} else {
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
}
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
requireContext(),
icon,
toolbarIconColor()
)
if (playerToolbar() != null) {
playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite)
?.setIcon(drawable)?.title =
if (isFavorite) getString(R.string.action_remove_from_favorites)
else getString(R.string.action_add_to_favorites)
playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite)?.apply {
setIcon(drawable)
title =
if (isFavorite) getString(R.string.action_remove_from_favorites)
else getString(R.string.action_add_to_favorites)
getIcon().also {
if (it is AnimatedVectorDrawable) {
it.start()
}
}
}
}
}
}
@ -273,7 +312,50 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
playerAlbumCoverFragment?.setCallbacks(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
statusBarShadow?.hide()
view.findViewById<RelativeLayout>(R.id.statusBarShadow)?.hide()
}
@SuppressLint("ClickableViewAccessibility")
override fun onStart() {
super.onStart()
requireView().setOnTouchListener(
SwipeDetector(
requireContext(),
playerAlbumCoverFragment?.viewPager,
requireView()
)
)
}
class SwipeDetector(val context: Context, val viewPager: ViewPager?, val view: View) :
View.OnTouchListener {
private var flingPlayBackController: GestureDetector = GestureDetector(
context,
object : GestureDetector.SimpleOnGestureListener() {
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
): Boolean {
return when {
abs(distanceX) > abs(distanceY) -> {
// Disallow Intercept Touch Event so that parent(BottomSheet) doesn't consume the events
view.parent.requestDisallowInterceptTouchEvent(true)
true
}
else -> {
false
}
}
}
})
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent?): Boolean {
viewPager?.dispatchTouchEvent(event)
return flingPlayBackController.onTouchEvent(event)
}
}
companion object {
@ -290,3 +372,44 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
)
}
}
fun goToArtist(activity: Activity) {
if (activity !is MainActivity) return
val song = MusicPlayerRemote.currentSong
activity.apply {
// Remove exit transition of current fragment so
// it doesn't exit with a weird transition
currentFragment(R.id.fragment_container)?.exitTransition = null
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
setBottomBarVisibility(false)
if (getBottomSheetBehavior().state == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
}
findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId)
)
}
}
fun goToAlbum(activity: Activity) {
if (activity !is MainActivity) return
val song = MusicPlayerRemote.currentSong
activity.apply {
currentFragment(R.id.fragment_container)?.exitTransition = null
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
setBottomBarVisibility(false)
if (getBottomSheetBehavior().state == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
}
findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
}
}

View file

@ -14,12 +14,12 @@
*/
package code.name.monkey.retromusic.fragments.base
import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.material.transition.MaterialFade
abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
AbsRecyclerViewFragment<A, LM>() {
@ -86,6 +86,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
} else {
saveGridSize(gridSize)
}
recyclerView().isVisible = false
invalidateLayoutManager()
// only recreate the adapter and layout manager if the layout currentLayoutRes has changed
if (oldLayoutRes != itemLayoutRes()) {
@ -93,26 +94,11 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
} else {
setGridSize(gridSize)
}
}
protected fun notifyLayoutResChanged(@LayoutRes res: Int) {
this.currentLayoutRes = res
val recyclerView = recyclerView()
applyRecyclerViewPaddingForLayoutRes(recyclerView, currentLayoutRes)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
applyRecyclerViewPaddingForLayoutRes(recyclerView(), currentLayoutRes)
}
private fun applyRecyclerViewPaddingForLayoutRes(recyclerView: RecyclerView, res: Int) {
val padding: Int = if (res == R.layout.item_grid) {
(resources.displayMetrics.density * 2).toInt()
} else {
0
val transition = MaterialFade().apply {
addTarget(recyclerView())
}
//recyclerView.setPadding(padding, padding, padding, padding)
TransitionManager.beginDelayedTransition(getContainer(), transition)
recyclerView().isVisible = true
}
protected abstract fun setGridSize(gridSize: Int)

View file

@ -15,80 +15,73 @@
package code.name.monkey.retromusic.fragments.base
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.*
import androidx.annotation.NonNull
import androidx.annotation.StringRes
import androidx.core.text.HtmlCompat
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.doOnPreDraw
import androidx.core.view.updatePadding
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentMainRecyclerBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.ThemedFastScroller.create
import com.google.android.material.appbar.AppBarLayout
import kotlinx.android.synthetic.main.fragment_main_recycler.*
import com.google.android.material.transition.MaterialFadeThrough
import com.google.android.material.transition.MaterialSharedAxis
import me.zhanghai.android.fastscroll.FastScroller
import me.zhanghai.android.fastscroll.FastScrollerBuilder
abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
AbsMainActivityFragment(R.layout.fragment_main_recycler),
AppBarLayout.OnOffsetChangedListener {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
}
AbsMainActivityFragment(R.layout.fragment_main_recycler) {
private var _binding: FragmentMainRecyclerBinding? = null
private val binding get() = _binding!!
protected var adapter: A? = null
protected var layoutManager: LM? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMainRecyclerBinding.bind(view)
enterTransition = MaterialFadeThrough()
exitTransition = MaterialFadeThrough()
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
mainActivity.setBottomBarVisibility(true)
mainActivity.setSupportActionBar(toolbar)
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
initLayoutManager()
initAdapter()
setUpRecyclerView()
setupTitle()
setupToolbar()
}
private fun setupTitle() {
toolbar.setNavigationOnClickListener {
private fun setupToolbar() {
binding.toolbar.setNavigationOnClickListener {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(requireView())
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
findNavController().navigate(
R.id.searchFragment,
null,
navOptions
)
}
val color = ThemeStore.accentColor(requireContext())
val hexColor = String.format("#%06X", 0xFFFFFF and color)
val appName = HtmlCompat.fromHtml(
"Retro <span style='color:$hexColor';>Music</span>",
HtmlCompat.FROM_HTML_MODE_COMPACT
)
appNameText.text = appName
val appName = resources.getString(titleRes)
binding.appNameText.text = appName
}
abstract val titleRes: Int
private fun setUpRecyclerView() {
recyclerView.apply {
binding.recyclerView.apply {
layoutManager = this@AbsRecyclerViewFragment.layoutManager
adapter = this@AbsRecyclerViewFragment.adapter
val fastScroller = create(this)
create(this)
}
checkForPadding()
}
@ -116,8 +109,8 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
}
private fun checkIsEmpty() {
emptyText.setText(emptyMessage)
empty.visibility = if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE
binding.emptyText.setText(emptyMessage)
binding.empty.visibility = if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkForPadding() {
@ -125,10 +118,10 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
val height = DensityUtil.dip2px(requireContext(), 112f)
recyclerView.updatePadding(0, 0, 0, height)
binding.recyclerView.updatePadding(0, 0, 0, height)
} else {
val height = DensityUtil.dip2px(requireContext(), 56f)
recyclerView.updatePadding(0, 0, 0, height)
binding.recyclerView.updatePadding(0, 0, 0, height)
}
}
@ -141,15 +134,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
@NonNull
protected abstract fun createAdapter(): A
override fun onOffsetChanged(p0: AppBarLayout?, i: Int) {
/*recyclerView.setPadding(
recyclerView.paddingLeft,
recyclerView.paddingTop,
recyclerView.paddingRight,
i
)*/
}
override fun onQueueChanged() {
super.onQueueChanged()
checkForPadding()
@ -162,22 +146,31 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
protected fun invalidateLayoutManager() {
initLayoutManager()
recyclerView.layoutManager = layoutManager
binding.recyclerView.layoutManager = layoutManager
}
protected fun invalidateAdapter() {
initAdapter()
checkIsEmpty()
recyclerView.adapter = adapter
binding.recyclerView.adapter = adapter
}
fun recyclerView(): RecyclerView {
return recyclerView
return binding.recyclerView
}
fun getContainer(): CoordinatorLayout {
return binding.root
}
fun scrollToTop() {
recyclerView().scrollToPosition(0)
binding.appBarLayout.setExpanded(true, true)
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -185,9 +178,9 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
inflater.inflate(R.menu.menu_main, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
toolbar,
binding.toolbar,
menu,
ATHToolbarActivity.getToolbarBackgroundColor(toolbar)
ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar)
)
}
@ -209,4 +202,9 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
}
return super.onOptionsItemSelected(item)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -14,13 +14,14 @@
package code.name.monkey.retromusic.fragments.folder;
import static code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor;
import android.app.Dialog;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.Environment;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -30,13 +31,11 @@ import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.webkit.MimeTypeMap;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.text.HtmlCompat;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.navigation.Navigation;
@ -46,25 +45,36 @@ import androidx.recyclerview.widget.RecyclerView;
import com.afollestad.materialcab.MaterialCab;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.transition.MaterialFadeThrough;
import com.google.android.material.transition.MaterialSharedAxis;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import code.name.monkey.appthemehelper.ThemeStore;
import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
import code.name.monkey.retromusic.App;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.adapter.SongFileAdapter;
import code.name.monkey.retromusic.adapter.Storage;
import code.name.monkey.retromusic.adapter.StorageAdapter;
import code.name.monkey.retromusic.adapter.StorageClickListener;
import code.name.monkey.retromusic.databinding.FragmentFolderBinding;
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.helper.menu.SongMenuHelper;
@ -76,6 +86,7 @@ import code.name.monkey.retromusic.misc.DialogAsyncTask;
import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener;
import code.name.monkey.retromusic.misc.WrappedAsyncTaskLoader;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.providers.BlacklistStore;
import code.name.monkey.retromusic.util.DensityUtil;
import code.name.monkey.retromusic.util.FileUtil;
import code.name.monkey.retromusic.util.PreferenceUtil;
@ -85,15 +96,14 @@ import code.name.monkey.retromusic.views.BreadCrumbLayout;
import code.name.monkey.retromusic.views.ScrollingViewOnApplyWindowInsetsListener;
import me.zhanghai.android.fastscroll.FastScroller;
import static code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor;
public class FoldersFragment extends AbsMainActivityFragment
implements IMainActivityFragmentCallbacks,
ICabHolder,
BreadCrumbLayout.SelectionCallback,
ICallbacks,
LoaderManager.LoaderCallbacks<List<File>> {
LoaderManager.LoaderCallbacks<List<File>>, StorageClickListener {
private FragmentFolderBinding binding;
public static final String TAG = FoldersFragment.class.getSimpleName();
public static final FileFilter AUDIO_FILE_FILTER =
file ->
@ -106,14 +116,9 @@ public class FoldersFragment extends AbsMainActivityFragment
private static final String CRUMBS = "crumbs";
private static final int LOADER_ID = 5;
private SongFileAdapter adapter;
private Toolbar toolbar;
private TextView appNameText;
private BreadCrumbLayout breadCrumbs;
private StorageAdapter storageAdapter;
private MaterialCab cab;
private View coordinatorLayout;
private View empty;
private TextView emojiText;
private Comparator<File> fileComparator =
private final Comparator<File> fileComparator =
(lhs, rhs) -> {
if (lhs.isDirectory() && !rhs.isDirectory()) {
return -1;
@ -123,7 +128,7 @@ public class FoldersFragment extends AbsMainActivityFragment
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
};
private RecyclerView recyclerView;
private final ArrayList<Storage> storageItems = new ArrayList<>();
public FoldersFragment() {
super(R.layout.fragment_folder);
@ -158,35 +163,43 @@ public class FoldersFragment extends AbsMainActivityFragment
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_folder, container, false);
initViews(view);
return view;
binding = FragmentFolderBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
setEnterTransition(new MaterialFadeThrough());
setExitTransition(new MaterialFadeThrough());
getMainActivity().addMusicServiceEventListener(getLibraryViewModel());
getMainActivity().setBottomBarVisibility(true);
getMainActivity().setSupportActionBar(toolbar);
getMainActivity().setSupportActionBar(binding.toolbar);
getMainActivity().getSupportActionBar().setTitle(null);
setStatusBarColorAuto(view);
setUpAppbarColor();
setUpBreadCrumbs();
setUpRecyclerView();
listRoots();
setUpAdapter();
setUpTitle();
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (!handleBackPress()) {
remove();
requireActivity().onBackPressed();
}
}
});
}
private void setUpTitle() {
toolbar.setNavigationOnClickListener(
v -> Navigation.findNavController(v).navigate(R.id.searchFragment, null, getNavOptions()));
int color = ThemeStore.Companion.accentColor(requireContext());
String hexColor = String.format("#%06X", 0xFFFFFF & color);
Spanned appName =
HtmlCompat.fromHtml(
"Retro <span style='color:" + hexColor + ";'>Music</span>",
HtmlCompat.FROM_HTML_MODE_COMPACT);
appNameText.setText(appName);
binding.toolbar.setNavigationOnClickListener(
v -> {
setExitTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true).setDuration(300));
setReenterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false).setDuration(300));
Navigation.findNavController(v).navigate(R.id.searchFragment, null, getNavOptions());
});
binding.appNameText.setText(getResources().getString(R.string.folders));
}
@Override
@ -194,12 +207,14 @@ public class FoldersFragment extends AbsMainActivityFragment
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
if (savedInstanceState == null) {
switchToFileAdapter();
setCrumb(
new BreadCrumbLayout.Crumb(
FileUtil.safeGetCanonicalFile(PreferenceUtil.INSTANCE.getStartDirectory())),
true);
} else {
breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
binding.breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
LoaderManager.getInstance(this).initLoader(LOADER_ID, null, this);
}
}
@ -213,8 +228,8 @@ public class FoldersFragment extends AbsMainActivityFragment
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (breadCrumbs != null) {
outState.putParcelable(CRUMBS, breadCrumbs.getStateWrapper());
if (binding != null) {
outState.putParcelable(CRUMBS, binding.breadCrumbs.getStateWrapper());
}
}
@ -224,8 +239,8 @@ public class FoldersFragment extends AbsMainActivityFragment
cab.finish();
return true;
}
if (breadCrumbs != null && breadCrumbs.popHistory()) {
setCrumb(breadCrumbs.lastHistory(), false);
if (binding.breadCrumbs.popHistory()) {
setCrumb(binding.breadCrumbs.lastHistory(), false);
return true;
}
return false;
@ -268,6 +283,9 @@ public class FoldersFragment extends AbsMainActivityFragment
new ListSongsAsyncTask.LoadingInfo(
toList(file), AUDIO_FILE_FILTER, getFileComparator()));
return true;
case R.id.action_add_to_blacklist:
BlacklistStore.getInstance(App.Companion.getContext()).addPath(file);
return true;
case R.id.action_set_as_start_directory:
PreferenceUtil.INSTANCE.setStartDirectory(file);
Toast.makeText(
@ -347,7 +365,7 @@ public class FoldersFragment extends AbsMainActivityFragment
} else {
final File finalFile = file1;
Snackbar.make(
coordinatorLayout,
binding.coordinatorLayout,
Html.fromHtml(
String.format(
getString(R.string.not_listed_in_media_store), file1.getName())),
@ -376,7 +394,7 @@ public class FoldersFragment extends AbsMainActivityFragment
@Override
public void onLoaderReset(@NonNull Loader<List<File>> loader) {
updateAdapter(new LinkedList<File>());
updateAdapter(new LinkedList<>());
}
@Override
@ -393,7 +411,7 @@ public class FoldersFragment extends AbsMainActivityFragment
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu) {
super.onPrepareOptionsMenu(menu);
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar);
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar);
}
@Override
@ -407,7 +425,7 @@ public class FoldersFragment extends AbsMainActivityFragment
menu.removeItem(R.id.action_layout_type);
menu.removeItem(R.id.action_sort_order);
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(), toolbar, menu, getToolbarBackgroundColor(toolbar));
requireContext(), binding.toolbar, menu, getToolbarBackgroundColor(binding.toolbar));
}
@Override
@ -462,26 +480,32 @@ public class FoldersFragment extends AbsMainActivityFragment
private void checkForPadding() {
final int count = adapter.getItemCount();
final MarginLayoutParams params = (MarginLayoutParams) coordinatorLayout.getLayoutParams();
params.bottomMargin =
count > 0 && !MusicPlayerRemote.getPlayingQueue().isEmpty()
? DensityUtil.dip2px(requireContext(), 104f)
: DensityUtil.dip2px(requireContext(), 54f);
if (binding != null) {
final MarginLayoutParams params = (MarginLayoutParams) binding.coordinatorLayout.getLayoutParams();
params.bottomMargin =
count > 0 && !MusicPlayerRemote.getPlayingQueue().isEmpty()
? DensityUtil.dip2px(requireContext(), 104f)
: DensityUtil.dip2px(requireContext(), 54f);
binding.coordinatorLayout.setLayoutParams(params);
}
}
private void checkIsEmpty() {
emojiText.setText(getEmojiByUnicode(0x1F631));
if (empty != null) {
empty.setVisibility(
if (binding != null) {
binding.emptyEmoji.setText(getEmojiByUnicode(0x1F631));
binding.empty.setVisibility(
adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}
@Nullable
private BreadCrumbLayout.Crumb getActiveCrumb() {
return breadCrumbs != null && breadCrumbs.size() > 0
? breadCrumbs.getCrumb(breadCrumbs.getActiveIndex())
: null;
if (binding != null) {
return binding.breadCrumbs.size() > 0
? binding.breadCrumbs.getCrumb(binding.breadCrumbs.getActiveIndex())
: null;
}
return null;
}
private String getEmojiByUnicode(int unicode) {
@ -492,21 +516,11 @@ public class FoldersFragment extends AbsMainActivityFragment
return fileComparator;
}
private void initViews(View view) {
coordinatorLayout = view.findViewById(R.id.coordinatorLayout);
recyclerView = view.findViewById(R.id.recyclerView);
breadCrumbs = view.findViewById(R.id.breadCrumbs);
empty = view.findViewById(android.R.id.empty);
emojiText = view.findViewById(R.id.emptyEmoji);
toolbar = view.findViewById(R.id.toolbar);
appNameText = view.findViewById(R.id.appNameText);
}
private void saveScrollPosition() {
BreadCrumbLayout.Crumb crumb = getActiveCrumb();
if (crumb != null) {
crumb.setScrollPosition(
((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition());
((LinearLayoutManager) binding.recyclerView.getLayoutManager()).findFirstVisibleItemPosition());
}
}
@ -529,46 +543,39 @@ public class FoldersFragment extends AbsMainActivityFragment
if (crumb == null) {
return;
}
saveScrollPosition();
breadCrumbs.setActiveOrAdd(crumb, false);
if (addToHistory) {
breadCrumbs.addHistory(crumb);
String path = crumb.getFile().getPath();
if (path.equals("/") || path.equals("/storage") || path.equals("/storage/emulated")) {
switchToStorageAdapter();
} else {
saveScrollPosition();
binding.breadCrumbs.setActiveOrAdd(crumb, false);
if (addToHistory) {
binding.breadCrumbs.addHistory(crumb);
}
LoaderManager.getInstance(this).restartLoader(LOADER_ID, null, this);
}
LoaderManager.getInstance(this).restartLoader(LOADER_ID, null, this);
}
private void setUpAdapter() {
adapter =
new SongFileAdapter(getMainActivity(), new LinkedList<>(), R.layout.item_list, this, this);
adapter.registerAdapterDataObserver(
new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
checkIsEmpty();
checkForPadding();
}
});
recyclerView.setAdapter(adapter);
checkIsEmpty();
switchToFileAdapter();
}
private void setUpAppbarColor() {
breadCrumbs.setActivatedContentColor(
binding.breadCrumbs.setActivatedContentColor(
ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorPrimary));
breadCrumbs.setDeactivatedContentColor(
binding.breadCrumbs.setDeactivatedContentColor(
ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorSecondary));
}
private void setUpBreadCrumbs() {
breadCrumbs.setCallback(this);
binding.breadCrumbs.setCallback(this);
}
private void setUpRecyclerView() {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
FastScroller fastScroller = ThemedFastScroller.INSTANCE.create(recyclerView);
recyclerView.setOnApplyWindowInsetsListener(
new ScrollingViewOnApplyWindowInsetsListener(recyclerView, fastScroller));
binding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
FastScroller fastScroller = ThemedFastScroller.INSTANCE.create(binding.recyclerView);
binding.recyclerView.setOnApplyWindowInsetsListener(
new ScrollingViewOnApplyWindowInsetsListener(binding.recyclerView, fastScroller));
}
private ArrayList<File> toList(File file) {
@ -580,16 +587,22 @@ public class FoldersFragment extends AbsMainActivityFragment
private void updateAdapter(@NonNull List<File> files) {
adapter.swapDataSet(files);
BreadCrumbLayout.Crumb crumb = getActiveCrumb();
if (crumb != null && recyclerView != null) {
((LinearLayoutManager) recyclerView.getLayoutManager())
if (crumb != null) {
((LinearLayoutManager) binding.recyclerView.getLayoutManager())
.scrollToPositionWithOffset(crumb.getScrollPosition(), 0);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
public static class ListPathsAsyncTask
extends ListingFilesDialogAsyncTask<ListPathsAsyncTask.LoadingInfo, String, String[]> {
private WeakReference<OnPathsListedCallback> onPathsListedCallbackWeakReference;
private final WeakReference<OnPathsListedCallback> onPathsListedCallbackWeakReference;
public ListPathsAsyncTask(Context context, OnPathsListedCallback callback) {
super(context);
@ -679,7 +692,7 @@ public class FoldersFragment extends AbsMainActivityFragment
private static class AsyncFileLoader extends WrappedAsyncTaskLoader<List<File>> {
private WeakReference<FoldersFragment> fragmentWeakReference;
private final WeakReference<FoldersFragment> fragmentWeakReference;
AsyncFileLoader(FoldersFragment foldersFragment) {
super(foldersFragment.requireActivity());
@ -710,8 +723,8 @@ public class FoldersFragment extends AbsMainActivityFragment
extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, List<Song>> {
private final Object extra;
private WeakReference<OnSongsListedCallback> callbackWeakReference;
private WeakReference<Context> contextWeakReference;
private final WeakReference<OnSongsListedCallback> callbackWeakReference;
private final WeakReference<Context> contextWeakReference;
ListSongsAsyncTask(Context context, Object extra, OnSongsListedCallback callback) {
super(context);
@ -823,4 +836,107 @@ public class FoldersFragment extends AbsMainActivityFragment
.create();
}
}
// https://github.com/DrKLO/Telegram/blob/ab221dafadbc17459d78d9ea3e643ae18e934b16/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java#L939
private void listRoots() {
storageItems.clear();
HashSet<String> paths = new HashSet<>();
String defaultPath = Environment.getExternalStorageDirectory().getPath();
String defaultPathState = Environment.getExternalStorageState();
if (defaultPathState.equals(Environment.MEDIA_MOUNTED) || defaultPathState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
Storage ext = new Storage();
if (Environment.isExternalStorageRemovable()) {
ext.title = "SD Card";
} else {
ext.title = "Internal Storage";
}
ext.file = Environment.getExternalStorageDirectory();
storageItems.add(ext);
paths.add(defaultPath);
}
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.contains("vfat") || line.contains("/mnt")) {
StringTokenizer tokens = new StringTokenizer(line, " ");
tokens.nextToken();
String path = tokens.nextToken();
if (paths.contains(path)) {
continue;
}
if (line.contains("/dev/block/vold")) {
if (!line.contains("/mnt/secure") && !line.contains("/mnt/asec") && !line.contains("/mnt/obb") && !line.contains("/dev/mapper") && !line.contains("tmpfs")) {
if (!new File(path).isDirectory()) {
int index = path.lastIndexOf('/');
if (index != -1) {
String newPath = "/storage/" + path.substring(index + 1);
if (new File(newPath).isDirectory()) {
path = newPath;
}
}
}
paths.add(path);
try {
Storage item = new Storage();
if (path.toLowerCase().contains("sd")) {
item.title = "SD Card";
} else {
item.title = "External Storage";
}
item.file = new File(path);
storageItems.add(item);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public void onStorageClicked(@NonNull Storage storage) {
switchToFileAdapter();
setCrumb(
new BreadCrumbLayout.Crumb(
FileUtil.safeGetCanonicalFile(storage.file)),
true);
}
public void switchToFileAdapter() {
adapter =
new SongFileAdapter(getMainActivity(), new LinkedList<>(), R.layout.item_list, this, this);
adapter.registerAdapterDataObserver(
new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
checkIsEmpty();
checkForPadding();
}
});
binding.recyclerView.setAdapter(adapter);
checkIsEmpty();
}
public void switchToStorageAdapter() {
listRoots();
storageAdapter = new StorageAdapter(storageItems, this);
binding.recyclerView.setAdapter(storageAdapter);
binding.breadCrumbs.clearCrumbs();
}
}

View file

@ -14,28 +14,26 @@
*/
package code.name.monkey.retromusic.fragments.genres
import android.graphics.Color
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.view.ViewCompat
import androidx.core.view.doOnPreDraw
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.resolveColor
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.helper.menu.GenreMenuHelper
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import com.google.android.material.transition.MaterialSharedAxis
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
@ -47,37 +45,33 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
}
private lateinit var genre: Genre
private lateinit var songAdapter: SongAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment_container
duration = 300L
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().resolveColor(R.attr.colorSurface))
setPathMotion(MaterialArcMotion())
}
}
private var _binding: FragmentPlaylistDetailBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
_binding = FragmentPlaylistDetailBinding.bind(view)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(false)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(toolbar)
ViewCompat.setTransitionName(container, "genre")
mainActivity.setSupportActionBar(binding.toolbar)
ViewCompat.setTransitionName(binding.container, "genre")
genre = arguments.extraGenre
toolbar?.title = arguments.extraGenre.name
binding.toolbar.title = arguments.extraGenre.name
setupRecyclerView()
detailsViewModel.getSongs().observe(viewLifecycleOwner, {
songs(it)
})
postponeEnterTransition()
view.doOnPreDraw {
startPostponedEnterTransition()
}
}
private fun setupRecyclerView() {
songAdapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null)
recyclerView.apply {
binding.recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(requireContext())
adapter = songAdapter
@ -91,7 +85,7 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
}
fun songs(songs: List<Song>) {
progressIndicator.hide()
binding.progressIndicator.hide()
if (songs.isNotEmpty()) songAdapter.swapDataSet(songs)
else songAdapter.swapDataSet(emptyList())
}
@ -102,13 +96,13 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
private fun checkIsEmpty() {
checkForPadding()
emptyEmoji.text = getEmojiByUnicode(0x1F631)
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
binding.emptyEmoji.text = getEmojiByUnicode(0x1F631)
binding.empty.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkForPadding() {
val height = dipToPix(52f).toInt()
recyclerView.setPadding(0, 0, 0, height)
binding.recyclerView.setPadding(0, 0, 0, height)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -119,4 +113,9 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return GenreMenuHelper.handleMenuClick(requireActivity(), genre, item)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -60,4 +60,5 @@ class GenreDetailsViewModel(
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
override fun onFavoriteStateChanged() {}
}

View file

@ -15,25 +15,31 @@
package code.name.monkey.retromusic.fragments.genres
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.EXTRA_GENRE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.GenreAdapter
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
import code.name.monkey.retromusic.interfaces.IGenreClickListener
import code.name.monkey.retromusic.model.Genre
import com.google.android.material.transition.MaterialElevationScale
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.transition.MaterialSharedAxis
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
class
GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
IGenreClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
libraryViewModel.getGenre().observe(viewLifecycleOwner, Observer {
libraryViewModel.getGenre().observe(viewLifecycleOwner, {
if (it.isNotEmpty())
adapter?.swapDataSet(it)
else
@ -42,14 +48,37 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
}
override fun createLayoutManager(): LinearLayoutManager {
return LinearLayoutManager(activity)
return if (RetroUtil.isLandscape()) {
GridLayoutManager(activity, 4)
} else {
GridLayoutManager(activity, 2)
}
}
override fun createAdapter(): GenreAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return GenreAdapter(requireActivity(), dataSet, R.layout.item_list_no_image, this)
return GenreAdapter(requireActivity(), dataSet, R.layout.item_genre, this)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu.removeItem(R.id.action_grid_size)
menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_sort_order)
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
override fun onResume() {
super.onResume()
libraryViewModel.forceReload(ReloadType.Genres)
}
override val titleRes: Int
get() = R.string.genres
override val emptyMessage: Int
get() = R.string.no_genres
@ -64,19 +93,13 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
}
override fun onClickGenre(genre: Genre, view: View) {
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(true).apply {
duration = 300L
}
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(requireView())
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
findNavController().navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to genre),
null,
FragmentNavigatorExtras(
view to "genre"
)
null
)
}
}

View file

@ -0,0 +1,31 @@
package code.name.monkey.retromusic.fragments.home
import code.name.monkey.retromusic.databinding.FragmentBannerHomeBinding
import code.name.monkey.retromusic.databinding.FragmentHomeBinding
class HomeBindingAdapter(
homeBinding: FragmentHomeBinding?,
bannerHomeBinding: FragmentBannerHomeBinding?
) {
val root = homeBinding?.root ?: bannerHomeBinding?.root!!
val container = homeBinding?.container ?: bannerHomeBinding?.container!!
val contentContainer = homeBinding?.contentContainer ?: bannerHomeBinding?.contentContainer!!
val appBarLayout = homeBinding?.appBarLayout ?: bannerHomeBinding?.appBarLayout!!
val toolbar = homeBinding?.toolbar
?: bannerHomeBinding?.toolbar!!
val bannerImage = bannerHomeBinding?.bannerImage
val userImage = homeBinding?.userImage
?: bannerHomeBinding?.userImage!!
val lastAdded = homeBinding?.homeContent?.absPlaylists?.lastAdded
?: bannerHomeBinding?.homeContent?.absPlaylists?.lastAdded!!
val topPlayed = homeBinding?.homeContent?.absPlaylists?.topPlayed
?: bannerHomeBinding?.homeContent?.absPlaylists?.topPlayed!!
val actionShuffle = homeBinding?.homeContent?.absPlaylists?.actionShuffle
?: bannerHomeBinding?.homeContent?.absPlaylists?.actionShuffle!!
val history = homeBinding?.homeContent?.absPlaylists?.history
?: bannerHomeBinding?.homeContent?.absPlaylists?.history!!
val recyclerView = homeBinding?.homeContent?.recyclerView
?: bannerHomeBinding?.homeContent?.recyclerView!!
val titleWelcome = homeBinding?.titleWelcome ?: bannerHomeBinding?.titleWelcome!!
val appNameText = homeBinding?.appNameText ?: bannerHomeBinding?.appNameText!!
}

View file

@ -23,7 +23,7 @@ import android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.lifecycle.Observer
import androidx.core.view.doOnPreDraw
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
@ -31,105 +31,111 @@ import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.adapter.HomeAdapter
import code.name.monkey.retromusic.databinding.FragmentBannerHomeBinding
import code.name.monkey.retromusic.databinding.FragmentHomeBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
import code.name.monkey.retromusic.glide.UserProfileGlideRequest
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.abs_playlists.*
import kotlinx.android.synthetic.main.fragment_banner_home.*
import kotlinx.android.synthetic.main.home_content.*
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.transition.MaterialFadeThrough
import com.google.android.material.transition.MaterialSharedAxis
class HomeFragment :
AbsMainActivityFragment(if (PreferenceUtil.typeHomeBanner == 1) R.layout.fragment_banner_home else R.layout.fragment_home) {
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
private var _binding: HomeBindingAdapter? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setBottomBarVisibility(true)
mainActivity.setSupportActionBar(toolbar)
_binding = getBinding(PreferenceUtil.isHomeBanner, view)
enterTransition = MaterialFadeThrough()
exitTransition = MaterialFadeThrough()
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
setStatusBarColorAuto(view)
val needShowProfileOrBanner = (PreferenceUtil.typeHomeBanner != 2)
if (needShowProfileOrBanner) {
bannerImage?.setOnClickListener {
val options = ActivityOptions.makeSceneTransitionAnimation(
mainActivity,
userImage,
getString(R.string.transition_user_image)
)
NavigationUtil.goToUserInfo(requireActivity(), options)
}
} else {
userImage?.visibility = View.GONE
titleWelcome?.visibility = View.GONE
text?.visibility = View.GONE
binding.bannerImage?.setOnClickListener {
val options = ActivityOptions.makeSceneTransitionAnimation(
mainActivity,
binding.userImage,
getString(R.string.transition_user_image)
)
NavigationUtil.goToUserInfo(requireActivity(), options)
}
lastAdded.setOnClickListener {
binding.lastAdded.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf(EXTRA_PLAYLIST_TYPE to LAST_ADDED_PLAYLIST)
)
setSharedAxisYTransitions()
}
topPlayed.setOnClickListener {
binding.topPlayed.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf(EXTRA_PLAYLIST_TYPE to TOP_PLAYED_PLAYLIST)
)
setSharedAxisYTransitions()
}
actionShuffle.setOnClickListener {
binding.actionShuffle.setOnClickListener {
libraryViewModel.shuffleSongs()
}
history.setOnClickListener {
binding.history.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf(EXTRA_PLAYLIST_TYPE to HISTORY_PLAYLIST)
)
setSharedAxisYTransitions()
}
if (needShowProfileOrBanner) {
userImage.setOnClickListener {
val options = ActivityOptions.makeSceneTransitionAnimation(
mainActivity,
userImage,
getString(R.string.transition_user_image)
)
NavigationUtil.goToUserInfo(requireActivity(), options)
}
titleWelcome?.text = String.format("%s", PreferenceUtil.userName)
binding.userImage.setOnClickListener {
val options = ActivityOptions.makeSceneTransitionAnimation(
mainActivity,
binding.userImage,
getString(R.string.transition_user_image)
)
NavigationUtil.goToUserInfo(requireActivity(), options)
}
binding.titleWelcome.text = String.format("%s", PreferenceUtil.userName)
val homeAdapter = HomeAdapter(mainActivity)
recyclerView.apply {
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(mainActivity)
adapter = homeAdapter
}
libraryViewModel.getHome().observe(viewLifecycleOwner, Observer {
libraryViewModel.getHome().observe(viewLifecycleOwner, {
homeAdapter.swapData(it)
})
if (needShowProfileOrBanner) {
loadProfile()
}
loadProfile()
setupTitle()
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
}
private fun getBinding(homeBanner: Boolean, view: View): HomeBindingAdapter {
return if (homeBanner) {
val homeBannerBinding = FragmentBannerHomeBinding.bind(view)
HomeBindingAdapter(null, homeBannerBinding)
} else {
val homeBinding = FragmentHomeBinding.bind(view)
HomeBindingAdapter(homeBinding, null)
}
}
private fun setupTitle() {
toolbar.setNavigationOnClickListener {
findNavController().navigate(
R.id.searchFragment,
null,
navOptions
)
binding.toolbar.setNavigationOnClickListener {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(binding.root)
reenterTransition =
MaterialSharedAxis(MaterialSharedAxis.Z, false)
findNavController().navigate(R.id.searchFragment, null, navOptions)
}
val color = ThemeStore.accentColor(requireContext())
val hexColor = String.format("#%06X", 0xFFFFFF and color)
@ -137,20 +143,21 @@ class HomeFragment :
"Retro <span style='color:$hexColor';>Music</span>",
HtmlCompat.FROM_HTML_MODE_COMPACT
)
appNameText.text = appName
binding.appNameText.text = appName
}
private fun loadProfile() {
bannerImage?.let {
ProfileBannerGlideRequest.Builder.from(
Glide.with(requireContext()),
ProfileBannerGlideRequest.getBannerModel()
).build().into(it)
binding.bannerImage?.let {
GlideApp.with(requireContext())
.asBitmap()
.profileBannerOptions(RetroGlideExtension.getBannerModel())
.load(RetroGlideExtension.getBannerModel())
.into(it)
}
UserProfileGlideRequest.Builder.from(
Glide.with(requireActivity()),
UserProfileGlideRequest.getUserModel()
).build().into(userImage)
GlideApp.with(requireActivity()).asBitmap()
.userProfileOptions(RetroGlideExtension.getUserModel())
.load(RetroGlideExtension.getUserModel())
.into(binding.userImage)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -162,10 +169,31 @@ class HomeFragment :
menu.findItem(R.id.action_settings).setShowAsAction(SHOW_AS_ACTION_IF_ROOM)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
toolbar,
binding.toolbar,
menu,
ATHToolbarActivity.getToolbarBackgroundColor(toolbar)
ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar)
)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
fun scrollToTop() {
binding.container.scrollTo(0, 0)
binding.appBarLayout.setExpanded(true)
}
fun setSharedAxisXTransitions() {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply {
addTarget(binding.root)
}
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
private fun setSharedAxisYTransitions() {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true).apply {
addTarget(binding.root)
}
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
}
companion object {
@ -199,6 +227,16 @@ class HomeFragment :
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}
override fun onResume() {
super.onResume()
libraryViewModel.fetchHomeSections()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -27,24 +27,32 @@ import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentLibraryBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.state.NowPlayingPanelState
import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.android.synthetic.main.fragment_library.*
import com.google.android.gms.cast.framework.CastButtonFactory
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
private var _binding: FragmentLibraryBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentLibraryBinding.bind(view)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(true)
mainActivity.setSupportActionBar(toolbar)
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
toolbar.setNavigationOnClickListener {
binding.toolbar.setNavigationOnClickListener {
findNavController().navigate(
R.id.searchFragment,
null,
@ -62,7 +70,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
"Retro <span style='color:$hexColor';>Music</span>",
HtmlCompat.FROM_HTML_MODE_COMPACT
)
appNameText.text = appName
binding.appNameText.text = appName
}
private fun setupNavigationController() {
@ -73,18 +81,18 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
val categoryInfo: CategoryInfo = PreferenceUtil.libraryCategory.first { it.visible }
if (categoryInfo.visible) {
navGraph.startDestination = categoryInfo.category.id
navGraph.setStartDestination(categoryInfo.category.id)
}
navController.graph = navGraph
NavigationUI.setupWithNavController(mainActivity.getBottomNavigationView(), navController)
navController.addOnDestinationChangedListener { _, _, _ ->
appBarLayout.setExpanded(true, true)
binding.appBarLayout.setExpanded(true, true)
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -92,10 +100,12 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
inflater.inflate(R.menu.menu_main, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
toolbar,
binding.toolbar,
menu,
getToolbarBackgroundColor(toolbar)
getToolbarBackgroundColor(binding.toolbar)
)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -116,4 +126,9 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
}
return super.onOptionsItemSelected(item)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -14,26 +14,53 @@
*/
package code.name.monkey.retromusic.fragments.player
import android.content.SharedPreferences
import android.os.Bundle
import android.text.TextUtils
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
import androidx.viewpager.widget.ViewPager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.SHOW_LYRICS
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment
import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
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
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
import code.name.monkey.retromusic.util.LyricUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_player_album_cover.*
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
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
ViewPager.OnPageChangeListener {
ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback,
SharedPreferences.OnSharedPreferenceChangeListener {
private var _binding: FragmentPlayerAlbumCoverBinding? = null
private val binding get() = _binding!!
private var callbacks: Callbacks? = null
private var currentPosition: Int = 0
val viewPager get() = binding.viewPager
private val colorReceiver = object : AlbumCoverFragment.ColorReceiver {
override fun onColorReady(color: MediaNotificationProcessor, request: Int) {
if (currentPosition == request) {
@ -41,64 +68,221 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
}
}
}
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
fun removeSlideEffect() {
val transformer = ParallaxPagerTransformer(R.id.player_image)
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
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewPager.addOnPageChangeListener(this)
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
binding.viewPager.addOnPageChangeListener(this)
val nps = PreferenceUtil.nowPlayingScreen
val metrics = resources.displayMetrics
val ratio = metrics.heightPixels.toFloat() / metrics.widthPixels.toFloat()
if (nps == Full || nps == Classic || nps == Fit || nps == Gradient) {
viewPager.offscreenPageLimit = 2
binding.viewPager.offscreenPageLimit = 2
} else if (PreferenceUtil.isCarouselEffect) {
viewPager.clipToPadding = false
binding.viewPager.clipToPadding = false
val padding =
if (ratio >= 1.777f) {
40
} else {
100
}
viewPager.setPadding(padding, 0, padding, 0)
viewPager.pageMargin = 0
viewPager.setPageTransformer(false, CarousalPagerTransformer(requireContext()))
binding.viewPager.setPadding(padding, 0, padding, 0)
binding.viewPager.pageMargin = 0
binding.viewPager.setPageTransformer(false, CarousalPagerTransformer(requireContext()))
} else {
viewPager.offscreenPageLimit = 2
viewPager.setPageTransformer(
binding.viewPager.offscreenPageLimit = 2
binding.viewPager.setPageTransformer(
true,
PreferenceUtil.albumCoverTransform
)
}
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 {
NavigationUtil.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)
}
override fun onDestroyView() {
super.onDestroyView()
viewPager.removeOnPageChangeListener(this)
PreferenceManager.getDefaultSharedPreferences(requireContext())
.unregisterOnSharedPreferenceChangeListener(this)
binding.viewPager.removeOnPageChangeListener(this)
progressViewUpdateHelper?.stop()
_binding = null
}
override fun onServiceConnected() {
updatePlayingQueue()
updateLyrics()
}
override fun onPlayingMetaChanged() {
viewPager.currentItem = MusicPlayerRemote.position
binding.viewPager.currentItem = MusicPlayerRemote.position
updateLyrics()
}
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
}
}
}
}
}
private fun updatePlayingQueue() {
viewPager.apply {
binding.viewPager.apply {
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
viewPager.adapter!!.notifyDataSetChanged()
viewPager.currentItem = MusicPlayerRemote.position
adapter!!.notifyDataSetChanged()
currentItem = MusicPlayerRemote.position
onPageSelected(MusicPlayerRemote.position)
}
}
@ -108,8 +292,11 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
override fun onPageSelected(position: Int) {
currentPosition = position
if (viewPager.adapter != null) {
(viewPager.adapter as AlbumCoverPagerAdapter).receiveColor(colorReceiver, position)
if (binding.viewPager.adapter != null) {
(binding.viewPager.adapter as AlbumCoverPagerAdapter).receiveColor(
colorReceiver,
position
)
}
if (position != MusicPlayerRemote.position) {
MusicPlayerRemote.playSongAt(position)
@ -119,6 +306,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
override fun onPageScrollStateChanged(state: Int) {
}
private fun notifyColorChange(color: MediaNotificationProcessor) {
callbacks?.onColorChanged(color)
}

View file

@ -20,6 +20,7 @@ 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.FragmentAdaptivePlayerBinding
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.extensions.textColorPrimary
import code.name.monkey.retromusic.extensions.textColorSecondary
@ -28,12 +29,13 @@ 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
import kotlinx.android.synthetic.main.fragment_adaptive_player.*
class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
private var _binding: FragmentAdaptivePlayerBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -41,6 +43,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentAdaptivePlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -57,7 +60,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
ToolbarContentTintHelper.colorizeToolbar(this, surfaceColor(), requireActivity())
@ -80,7 +83,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
playerToolbar.apply {
binding.playerToolbar.apply {
title = song.title
subtitle = song.artistName
}
@ -102,7 +105,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
lastColor = color.primaryTextColor
libraryViewModel.updateColor(color.primaryTextColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -119,6 +122,11 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
return false
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun toolbarIconColor(): Int {
return ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal)
}

View file

@ -28,6 +28,7 @@ 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.FragmentAdaptivePlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
@ -41,7 +42,6 @@ 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 kotlinx.android.synthetic.main.fragment_adaptive_player_playback_controls.*
class AdaptivePlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_adaptive_player_playback_controls) {
@ -49,6 +49,8 @@ class AdaptivePlaybackControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
private var _binding: FragmentAdaptivePlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -59,34 +61,31 @@ class AdaptivePlaybackControlsFragment :
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(
R.layout.fragment_adaptive_player_playback_controls,
container,
false
)
): View {
_binding = FragmentAdaptivePlayerPlaybackControlsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpMusicControllers()
playPauseButton.setOnClickListener {
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation(playPauseButton)
showBounceAnimation(binding.playPauseButton)
}
}
private fun updateSong() {
if (PreferenceUtil.isSongInfo) {
songInfo?.text = getSongInfo(MusicPlayerRemote.currentSong)
songInfo.show()
binding.songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
binding.songInfo.show()
} else {
songInfo?.hide()
binding.songInfo.hide()
}
}
@ -153,12 +152,12 @@ class AdaptivePlaybackControlsFragment :
}.ripAlpha()
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(colorFinal)),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
progressSlider.applyColor(colorFinal)
TintHelper.setTintAuto(binding.playPauseButton, colorFinal, true)
binding.progressSlider.applyColor(colorFinal)
volumeFragment?.setTintable(colorFinal)
}
@ -167,14 +166,14 @@ class AdaptivePlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -188,17 +187,17 @@ class AdaptivePlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun show() {
@ -209,11 +208,11 @@ class AdaptivePlaybackControlsFragment :
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -221,31 +220,37 @@ class AdaptivePlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -259,14 +264,19 @@ class AdaptivePlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -28,9 +28,12 @@ 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.FragmentBlurPlayerPlaybackControlsBinding
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
@ -39,11 +42,11 @@ 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 kotlinx.android.synthetic.main.fragment_blur_player_playback_controls.*
class BlurPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_blur_player_playback_controls) {
private var _binding: FragmentBlurPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
@ -55,30 +58,37 @@ class BlurPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentBlurPlayerPlaybackControlsBinding.bind(view)
setUpMusicControllers()
playPauseButton.setOnClickListener {
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation()
showBounceAnimation()
}
binding.title.isSelected = true
binding.text.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
title.isSelected = true
text.isSelected = true
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = String.format("%s • %s", song.artistName, song.albumName)
binding.title.text = song.title
binding.text.text = String.format("%s • %s", song.artistName, song.albumName)
if (PreferenceUtil.isSongInfo) {
songInfo.show()
songInfo?.text = getSongInfo(song)
binding.songInfo.show()
binding.songInfo.text = getSongInfo(song)
} else {
songInfo?.hide()
binding.songInfo.hide()
}
}
@ -121,41 +131,41 @@ class BlurPlaybackControlsFragment :
lastDisabledPlaybackControlsColor =
ContextCompat.getColor(requireContext(), R.color.md_grey_500)
title.setTextColor(lastPlaybackControlsColor)
binding.title.setTextColor(lastPlaybackControlsColor)
songCurrentProgress.setTextColor(lastPlaybackControlsColor)
songTotalTime.setTextColor(lastPlaybackControlsColor)
binding.songCurrentProgress.setTextColor(lastPlaybackControlsColor)
binding.songTotalTime.setTextColor(lastPlaybackControlsColor)
updateRepeatState()
updateShuffleState()
updatePrevNextColor()
text.setTextColor(lastDisabledPlaybackControlsColor)
songInfo.setTextColor(lastDisabledPlaybackControlsColor)
binding.text.setTextColor(lastPlaybackControlsColor)
binding.songInfo.setTextColor(lastDisabledPlaybackControlsColor)
TintHelper.setTintAuto(progressSlider, lastPlaybackControlsColor, false)
TintHelper.setTintAuto(binding.progressSlider, lastPlaybackControlsColor, false)
volumeFragment?.setTintableColor(lastPlaybackControlsColor)
setFabColor(lastPlaybackControlsColor)
}
private fun setFabColor(i: Int) {
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(i)),
false
)
TintHelper.setTintAuto(playPauseButton, i, true)
TintHelper.setTintAuto(binding.playPauseButton, i, true)
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -169,26 +179,26 @@ class BlurPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -196,31 +206,37 @@ class BlurPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -229,17 +245,15 @@ class BlurPlaybackControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
private fun showBonceAnimation() {
playPauseButton.apply {
private fun showBounceAnimation() {
binding.playPauseButton.apply {
clearAnimation()
scaleX = 0.9f
scaleY = 0.9f
@ -262,7 +276,7 @@ class BlurPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -276,14 +290,19 @@ class BlurPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -23,30 +23,35 @@ import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.NEW_BLUR_AMOUNT
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentBlurBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_blur.*
class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
SharedPreferences.OnSharedPreferenceChangeListener {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private lateinit var playbackControlsFragment: BlurPlaybackControlsFragment
private var lastColor: Int = 0
private var _binding: FragmentBlurBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentBlurBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -60,7 +65,7 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
ToolbarContentTintHelper.colorizeToolbar(this, Color.WHITE, activity)
@ -75,7 +80,7 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
playbackControlsFragment.setColor(color)
lastColor = color.backgroundColor
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
}
override fun toggleFavorite(song: Song) {
@ -105,20 +110,20 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
private fun updateBlur() {
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(NEW_BLUR_AMOUNT, 25)
colorBackground.clearColorFilter()
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext())
.generatePalette(requireContext()).build()
binding.colorBackground.clearColorFilter()
GlideApp.with(requireActivity()).asBitmapPalette()
.songCoverOptions(MusicPlayerRemote.currentSong)
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
.dontAnimate()
.transform(
BlurTransformation.Builder(requireContext())
.blurRadius(blurAmount.toFloat())
.build()
)
.into(object : RetroMusicColoredTarget(colorBackground) {
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
override fun onColorReady(colors: MediaNotificationProcessor) {
if (colors.backgroundColor == defaultFooterColor) {
colorBackground.setColorFilter(colors.backgroundColor)
binding.colorBackground.setColorFilter(colors.backgroundColor)
}
}
})
@ -144,6 +149,7 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
super.onDestroyView()
PreferenceManager.getDefaultSharedPreferences(requireContext())
.unregisterOnSharedPreferenceChangeListener(this)
_binding = null
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {

View file

@ -20,17 +20,17 @@ import android.view.View
import androidx.appcompat.widget.Toolbar
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardPlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_card_player.*
class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -38,6 +38,9 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
get() = lastColor
private lateinit var playbackControlsFragment: CardPlaybackControlsFragment
private var _binding: FragmentCardPlayerBinding? = null
private val binding get() = _binding!!
override fun onShow() {
playbackControlsFragment.show()
@ -60,7 +63,7 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
playbackControlsFragment.setColor(color)
lastColor = color.primaryTextColor
libraryViewModel.updateColor(color.primaryTextColor)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
}
override fun toggleFavorite(song: Song) {
@ -76,6 +79,7 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardPlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -90,11 +94,11 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
}
override fun onServiceConnected() {
@ -105,6 +109,11 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
updateIsFavorite()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
fun newInstance(): PlayerFragment {

View file

@ -26,10 +26,13 @@ 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.FragmentCardPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
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
@ -38,8 +41,6 @@ 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 kotlinx.android.synthetic.main.fragment_card_player_playback_controls.*
import kotlinx.android.synthetic.main.media_button.*
class CardPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_card_player_playback_controls) {
@ -47,6 +48,9 @@ class CardPlaybackControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
private var _binding: FragmentCardPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -55,30 +59,37 @@ class CardPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardPlayerPlaybackControlsBinding.bind(view)
setUpMusicControllers()
playPauseButton.setOnClickListener {
binding.mediaButton.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation(playPauseButton)
showBounceAnimation(binding.mediaButton.playPauseButton)
}
binding.title.isSelected = true
binding.text.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
title.isSelected = true
text.isSelected = true
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
songInfo.show()
binding.songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -139,13 +150,13 @@ class CardPlaybackControlsFragment :
} else {
ThemeStore.accentColor(requireContext()).ripAlpha()
}
image.setColorFilter(colorFinal, PorterDuff.Mode.SRC_IN)
binding.image.setColorFilter(colorFinal, PorterDuff.Mode.SRC_IN)
TintHelper.setTintAuto(
playPauseButton,
binding.mediaButton.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(colorFinal)),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
TintHelper.setTintAuto(binding.mediaButton.playPauseButton, colorFinal, true)
volumeFragment?.setTintable(colorFinal)
}
@ -155,14 +166,14 @@ class CardPlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.mediaButton.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.mediaButton.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.mediaButton.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -176,26 +187,32 @@ class CardPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.mediaButton.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.mediaButton.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.nextButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.mediaButton.previousButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.mediaButton.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.mediaButton.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.mediaButton.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -203,45 +220,51 @@ class CardPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.mediaButton.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.mediaButton.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.mediaButton.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.mediaButton.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
private fun updateProgressTextColor() {
val color = MaterialValueHelper.getPrimaryTextColor(context, false)
songTotalTime!!.setTextColor(color)
songCurrentProgress!!.setTextColor(color)
binding.songTotalTime.setTextColor(color)
binding.songCurrentProgress.setTextColor(color)
}
public override fun show() {
@ -253,7 +276,7 @@ class CardPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -265,4 +288,10 @@ class CardPlaybackControlsFragment :
}
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -23,22 +23,22 @@ import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.NEW_BLUR_AMOUNT
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardBlurPlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_card_blur_player.*
class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
SharedPreferences.OnSharedPreferenceChangeListener {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -46,6 +46,9 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
get() = lastColor
private lateinit var playbackControlsFragment: CardBlurPlaybackControlsFragment
private var _binding: FragmentCardBlurPlayerBinding? = null
private val binding get() = _binding!!
override fun onShow() {
playbackControlsFragment.show()
}
@ -67,10 +70,10 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
playbackControlsFragment.setColor(color)
lastColor = color.backgroundColor
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
playerToolbar.setTitleTextColor(Color.WHITE)
playerToolbar.setSubtitleTextColor(Color.WHITE)
binding.playerToolbar.setTitleTextColor(Color.WHITE)
binding.playerToolbar.setSubtitleTextColor(Color.WHITE)
}
override fun toggleFavorite(song: Song) {
@ -86,6 +89,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardBlurPlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -99,12 +103,12 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setTitleTextColor(Color.WHITE)
setSubtitleTextColor(Color.WHITE)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
}.setOnMenuItemClickListener(this)
}
@ -122,7 +126,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
playerToolbar.apply {
binding.playerToolbar.apply {
title = song.title
subtitle = song.artistName
}
@ -131,19 +135,19 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
private fun updateBlur() {
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(NEW_BLUR_AMOUNT, 25)
colorBackground!!.clearColorFilter()
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext())
.generatePalette(requireContext()).build()
binding.colorBackground.clearColorFilter()
GlideApp.with(requireActivity()).asBitmapPalette()
.songCoverOptions(MusicPlayerRemote.currentSong)
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
.dontAnimate()
.transform(
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
.build()
)
.into(object : RetroMusicColoredTarget(colorBackground) {
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
override fun onColorReady(colors: MediaNotificationProcessor) {
if (colors.backgroundColor == defaultFooterColor) {
colorBackground.setColorFilter(colors.backgroundColor)
binding.colorBackground.setColorFilter(colors.backgroundColor)
}
}
})
@ -159,6 +163,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
super.onDestroyView()
PreferenceManager.getDefaultSharedPreferences(requireContext())
.unregisterOnSharedPreferenceChangeListener(this)
_binding = null
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {

View file

@ -25,6 +25,7 @@ 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.FragmentCardBlurPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
@ -37,8 +38,6 @@ 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 kotlinx.android.synthetic.main.fragment_card_blur_player_playback_controls.*
import kotlinx.android.synthetic.main.media_button.*
class CardBlurPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_card_blur_player_playback_controls) {
@ -47,6 +46,10 @@ class CardBlurPlaybackControlsFragment :
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentCardBlurPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
@ -54,6 +57,7 @@ class CardBlurPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardBlurPlayerPlaybackControlsBinding.bind(view)
setUpMusicControllers()
}
@ -70,7 +74,7 @@ class CardBlurPlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.apply {
binding.mediaButton.playPauseButton.apply {
TintHelper.setTintAuto(this, Color.WHITE, true)
TintHelper.setTintAuto(this, Color.BLACK, false)
setOnClickListener(PlayPauseButtonOnClickHandler())
@ -79,16 +83,16 @@ class CardBlurPlaybackControlsFragment :
private fun updatePlayPauseDrawableState() {
when {
MusicPlayerRemote.isPlaying -> playPauseButton.setImageResource(R.drawable.ic_pause)
else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
MusicPlayerRemote.isPlaying -> binding.mediaButton.playPauseButton.setImageResource(R.drawable.ic_pause)
else -> binding.mediaButton.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
private fun updateProgressTextColor() {
val color = Color.WHITE
songTotalTime.setTextColor(color)
songCurrentProgress.setTextColor(color)
songInfo.setTextColor(color)
binding.songTotalTime.setTextColor(color)
binding.songCurrentProgress.setTextColor(color)
binding.songInfo.setTextColor(color)
}
override fun onResume() {
@ -115,10 +119,10 @@ class CardBlurPlaybackControlsFragment :
private fun updateSong() {
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
songInfo.show()
binding.songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -144,26 +148,32 @@ class CardBlurPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.mediaButton.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.mediaButton.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.nextButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.mediaButton.previousButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.mediaButton.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.mediaButton.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.mediaButton.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -171,31 +181,37 @@ class CardBlurPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.mediaButton.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.mediaButton.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.mediaButton.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.mediaButton.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.mediaButton.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.mediaButton.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -204,18 +220,16 @@ class CardBlurPlaybackControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.mediaButton.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
override fun setUpProgressSlider() {
progressSlider.applyColor(Color.WHITE)
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.applyColor(Color.WHITE)
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -229,14 +243,19 @@ class CardBlurPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -32,12 +32,15 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCirclePlayerBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.applyColor
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.AbsPlayerFragment
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.MusicProgressViewUpdateHelper.Callback
@ -51,7 +54,6 @@ import code.name.monkey.retromusic.views.SeekArc
import code.name.monkey.retromusic.views.SeekArc.OnSeekArcChangeListener
import code.name.monkey.retromusic.volume.AudioVolumeObserver
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
import kotlinx.android.synthetic.main.fragment_circle_player.*
/**
* Created by hemanths on 2020-01-06.
@ -67,6 +69,9 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private val audioManager: AudioManager?
get() = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
private var _binding: FragmentCirclePlayerBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
@ -76,18 +81,25 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_circle_player, container, false)
): View {
_binding = FragmentCirclePlayerBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupViews()
title.isSelected = true
binding.title.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@CirclePlayerFragment)
@ -102,12 +114,12 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun setupViews() {
setUpProgressSlider()
ViewUtil.setProgressDrawable(
progressSlider,
binding.progressSlider,
ThemeStore.accentColor(requireContext()),
false
)
volumeSeekBar.progressColor = accentColor()
volumeSeekBar.arcColor = ColorUtil.withAlpha(accentColor(), 0.25f)
binding.volumeSeekBar.progressColor = accentColor()
binding.volumeSeekBar.arcColor = ColorUtil.withAlpha(accentColor(), 0.25f)
setUpPlayPauseFab()
setUpPrevNext()
setUpPlayerToolbar()
@ -115,19 +127,23 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
val accentColor = ThemeStore.accentColor(requireContext())
nextButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpPlayPauseFab() {
TintHelper.setTintAuto(playPauseButton, ThemeStore.accentColor(requireContext()), false)
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
TintHelper.setTintAuto(
binding.playPauseButton,
ThemeStore.accentColor(requireContext()),
false
)
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
override fun onResume() {
@ -140,10 +156,10 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
val audioManager = audioManager
if (audioManager != null) {
volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
}
volumeSeekBar.setOnSeekArcChangeListener(this)
binding.volumeSeekBar.setOnSeekArcChangeListener(this)
}
override fun onPause() {
@ -151,8 +167,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
progressViewUpdateHelper.stop()
}
override fun playerToolbar(): Toolbar? {
return playerToolbar
override fun playerToolbar(): Toolbar {
return binding.playerToolbar
}
override fun onShow() {
@ -192,30 +208,27 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
private fun updatePlayPauseDrawableState() {
when {
MusicPlayerRemote.isPlaying -> playPauseButton.setImageResource(R.drawable.ic_pause)
else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow)
MusicPlayerRemote.isPlaying -> binding.playPauseButton.setImageResource(R.drawable.ic_pause)
else -> binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
if (volumeSeekBar == null) {
return
}
volumeSeekBar.max = maxVolume
volumeSeekBar.progress = currentVolume
_binding?.volumeSeekBar?.max = maxVolume
_binding?.volumeSeekBar?.progress = currentVolume
}
override fun onDestroyView() {
@ -223,6 +236,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
if (audioVolumeObserver != null) {
audioVolumeObserver!!.unregister()
}
_binding = null
}
override fun onProgressChanged(seekArc: SeekArc?, progress: Int, fromUser: Boolean) {
@ -237,8 +251,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
}
fun setUpProgressSlider() {
progressSlider.applyColor(accentColor())
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.applyColor(accentColor())
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -252,14 +266,14 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
}

View file

@ -35,11 +35,14 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
import code.name.monkey.retromusic.databinding.FragmentClassicPlayerBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.VolumeFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
@ -60,13 +63,14 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropM
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.fragment_classic_controls.*
import kotlinx.android.synthetic.main.fragment_classic_player.*
class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player),
View.OnLayoutChangeListener,
MusicProgressViewUpdateHelper.Callback {
private var _binding: FragmentClassicPlayerBinding? = null
private val binding get() = _binding!!
private var lastColor: Int = 0
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
@ -83,11 +87,11 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
playerQueueSheet.setContentPadding(
playerQueueSheet.contentPaddingLeft,
(slideOffset * status_bar.height).toInt(),
playerQueueSheet.contentPaddingRight,
playerQueueSheet.contentPaddingBottom
binding.playerQueueSheet.setContentPadding(
binding.playerQueueSheet.contentPaddingLeft,
(slideOffset * binding.statusBar.height).toInt(),
binding.playerQueueSheet.contentPaddingRight,
binding.playerQueueSheet.contentPaddingBottom
)
shapeDrawable.interpolation = 1 - slideOffset
@ -118,6 +122,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentClassicPlayerBinding.bind(view)
setupPanel()
setUpMusicControllers()
setUpPlayerToolbar()
@ -139,19 +144,25 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
)
shapeDrawable.fillColor =
ColorStateList.valueOf(ATHUtil.resolveColor(requireContext(), R.attr.colorSurface))
playerQueueSheet.background = shapeDrawable
binding.playerQueueSheet.background = shapeDrawable
playerQueueSheet.setOnTouchListener { _, _ ->
binding.playerQueueSheet.setOnTouchListener { _, _ ->
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
getQueuePanel().setAllowDragging(true)
return@setOnTouchListener false
}
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
Color.WHITE,
requireActivity()
)
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
private fun hideVolumeIfAvailable() {
@ -179,18 +190,19 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
WrapperAdapterUtils.releaseAll(wrappedAdapter)
_binding = null
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.playerControlsContainer.songInfo.text = getSongInfo(song)
binding.playerControlsContainer.songInfo.show()
} else {
songInfo.hide()
binding.playerControlsContainer.songInfo.hide()
}
}
@ -236,7 +248,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
override fun playerToolbar(): Toolbar? {
return playerToolbar
return binding.playerToolbar
}
override fun onShow() {
@ -269,25 +281,37 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
lastPlaybackControlsColor = color.primaryTextColor
lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(color.primaryTextColor, 0.3f)
playerContainer.setBackgroundColor(color.backgroundColor)
songInfo.setTextColor(color.primaryTextColor)
player_queue_sub_header.setTextColor(color.primaryTextColor)
binding.playerContainer.setBackgroundColor(color.backgroundColor)
binding.playerControlsContainer.songInfo.setTextColor(color.primaryTextColor)
binding.playerQueueSubHeader.setTextColor(color.primaryTextColor)
songCurrentProgress.setTextColor(lastPlaybackControlsColor)
songTotalTime.setTextColor(lastPlaybackControlsColor)
binding.playerControlsContainer.songCurrentProgress.setTextColor(lastPlaybackControlsColor)
binding.playerControlsContainer.songTotalTime.setTextColor(lastPlaybackControlsColor)
ViewUtil.setProgressDrawable(progressSlider, color.primaryTextColor, true)
ViewUtil.setProgressDrawable(
binding.playerControlsContainer.progressSlider,
color.primaryTextColor,
true
)
volumeFragment?.setTintableColor(color.primaryTextColor)
TintHelper.setTintAuto(playPauseButton, color.primaryTextColor, true)
TintHelper.setTintAuto(playPauseButton, color.backgroundColor, false)
TintHelper.setTintAuto(
binding.playerControlsContainer.playPauseButton,
color.primaryTextColor,
true
)
TintHelper.setTintAuto(
binding.playerControlsContainer.playPauseButton,
color.backgroundColor,
false
)
updateRepeatState()
updateShuffleState()
updatePrevNextColor()
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
Color.WHITE,
requireActivity()
)
@ -305,15 +329,21 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.playerControlsContainer.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(
binding.playerControlsContainer.progressSlider,
"progress",
progress
)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.playerControlsContainer.songTotalTime.text =
MusicUtil.getReadableDurationString(total.toLong())
binding.playerControlsContainer.songCurrentProgress.text =
MusicUtil.getReadableDurationString(progress.toLong())
}
private fun updateQueuePosition() {
@ -327,33 +357,33 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
binding.recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
private fun getQueuePanel(): RetroBottomSheetBehavior<MaterialCardView> {
return RetroBottomSheetBehavior.from(playerQueueSheet) as RetroBottomSheetBehavior<MaterialCardView>
return RetroBottomSheetBehavior.from(binding.playerQueueSheet) as RetroBottomSheetBehavior<MaterialCardView>
}
private fun setupPanel() {
if (!ViewCompat.isLaidOut(playerContainer) || playerContainer.isLayoutRequested) {
playerContainer.addOnLayoutChangeListener(this)
if (!ViewCompat.isLaidOut(binding.playerContainer) || binding.playerContainer.isLayoutRequested) {
binding.playerContainer.addOnLayoutChangeListener(this)
return
}
val height = playerContainer.height
val width = playerContainer.width
val height = binding.playerContainer.height
val width = binding.playerContainer.width
val finalHeight = height - width
val panel = getQueuePanel()
panel.peekHeight = finalHeight
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
Color.WHITE,
requireActivity()
)
@ -377,18 +407,19 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!) as RecyclerView.Adapter<*>
wrappedAdapter =
recyclerViewSwipeManager?.createWrappedAdapter(wrappedAdapter) as RecyclerView.Adapter<*>
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = wrappedAdapter
recyclerView.itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(recyclerView)
binding.recyclerView.layoutManager = linearLayoutManager
binding.recyclerView.adapter = wrappedAdapter
binding.recyclerView.itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(binding.recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(binding.recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(binding.recyclerView)
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.playerControlsContainer.progressSlider.setOnSeekBarChangeListener(object :
SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -402,14 +433,16 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playerControlsContainer.playPauseButton.setOnClickListener(
PlayPauseButtonOnClickHandler()
)
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playerControlsContainer.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow)
binding.playerControlsContainer.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
@ -423,27 +456,33 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.playerControlsContainer.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.playerControlsContainer.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playerControlsContainer.nextButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playerControlsContainer.previousButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.playerControlsContainer.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE ->
shuffleButton.setColorFilter(
binding.playerControlsContainer.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.playerControlsContainer.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -451,25 +490,31 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.playerControlsContainer.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.playerControlsContainer.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.playerControlsContainer.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playerControlsContainer.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.playerControlsContainer.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playerControlsContainer.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.playerControlsContainer.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -485,9 +530,9 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
oldRight: Int,
oldBottom: Int
) {
val height = playerContainer.height
val width = playerContainer.width
val finalHeight = height - (playerControlsContainer.height + width)
val height = binding.playerContainer.height
val width = binding.playerContainer.width
val finalHeight = height - (binding.playerControlsContainer.root.height + width)
val panel = getQueuePanel()
panel.peekHeight = finalHeight
}

View file

@ -19,16 +19,17 @@ import android.os.Bundle
import android.os.Handler
import android.view.View
import androidx.appcompat.widget.Toolbar
import androidx.core.animation.doOnEnd
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentColorPlayerBinding
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
import kotlinx.android.synthetic.main.fragment_color_player.*
class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
@ -36,9 +37,12 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
private var navigationColor: Int = 0
private lateinit var playbackControlsFragment: ColorPlaybackControlsFragment
private var valueAnimator: ValueAnimator? = null
private var _binding: FragmentColorPlayerBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
override val paletteColor: Int
@ -50,11 +54,17 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
playbackControlsFragment.setColor(color)
navigationColor = color.backgroundColor
colorGradientBackground?.setBackgroundColor(color.backgroundColor)
binding.colorGradientBackground.setBackgroundColor(color.backgroundColor)
val animator =
playbackControlsFragment.createRevealAnimator(binding.colorGradientBackground)
animator.doOnEnd {
_binding?.root?.setBackgroundColor(color.backgroundColor)
}
animator.start()
serviceActivity?.setLightNavigationBar(ColorUtil.isColorLight(color.backgroundColor))
Handler().post {
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
color.secondaryTextColor,
requireActivity()
)
@ -95,10 +105,12 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
valueAnimator!!.cancel()
valueAnimator = null
}
_binding = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentColorPlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
val playerAlbumCoverFragment =
@ -112,7 +124,7 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@ColorFragment)

View file

@ -14,23 +14,29 @@
*/
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.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
@ -39,7 +45,7 @@ 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 kotlinx.android.synthetic.main.fragment_color_player_playback_controls.*
import kotlin.math.sqrt
class ColorPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_adaptive_player_playback_controls) {
@ -47,6 +53,9 @@ class ColorPlaybackControlsFragment :
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)
@ -57,8 +66,9 @@ class ColorPlaybackControlsFragment :
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_color_player_playback_controls, container, false)
): View {
_binding = FragmentColorPlayerPlaybackControlsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
@ -74,20 +84,26 @@ class ColorPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpMusicControllers()
title.isSelected = true
text.isSelected = true
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
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -116,15 +132,15 @@ class ColorPlaybackControlsFragment :
}
override fun setColor(color: MediaNotificationProcessor) {
TintHelper.setTintAuto(playPauseButton, color.primaryTextColor, true)
TintHelper.setTintAuto(playPauseButton, color.backgroundColor, false)
progressSlider.applyColor(color.primaryTextColor)
TintHelper.setTintAuto(binding.playPauseButton, color.primaryTextColor, true)
TintHelper.setTintAuto(binding.playPauseButton, color.backgroundColor, false)
binding.progressSlider.applyColor(color.primaryTextColor)
title.setTextColor(color.primaryTextColor)
text.setTextColor(color.secondaryTextColor)
songInfo.setTextColor(color.secondaryTextColor)
songCurrentProgress.setTextColor(color.secondaryTextColor)
songTotalTime.setTextColor(color.secondaryTextColor)
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
@ -136,15 +152,15 @@ class ColorPlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
TintHelper.setTintAuto(playPauseButton, Color.WHITE, true)
TintHelper.setTintAuto(playPauseButton, Color.BLACK, false)
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
TintHelper.setTintAuto(binding.playPauseButton, Color.WHITE, true)
TintHelper.setTintAuto(binding.playPauseButton, Color.BLACK, false)
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
when {
MusicPlayerRemote.isPlaying -> playPauseButton.setImageResource(R.drawable.ic_pause)
else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow)
MusicPlayerRemote.isPlaying -> binding.playPauseButton.setImageResource(R.drawable.ic_pause)
else -> binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
@ -158,26 +174,26 @@ class ColorPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -185,31 +201,37 @@ class ColorPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -218,7 +240,7 @@ class ColorPlaybackControlsFragment :
}
public override fun hide() {
playPauseButton.apply {
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
@ -226,7 +248,7 @@ class ColorPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -240,14 +262,37 @@ class ColorPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
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
}
}

View file

@ -20,16 +20,19 @@ 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.FragmentFitBinding
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
import kotlinx.android.synthetic.main.fragment_fit.*
class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) {
private var _binding: FragmentFitBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -60,7 +63,7 @@ class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) {
lastColor = color.primaryTextColor
libraryViewModel.updateColor(color.primaryTextColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -79,6 +82,7 @@ class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentFitBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -92,7 +96,7 @@ class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@FitFragment)
@ -112,6 +116,11 @@ class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) {
updateIsFavorite()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
fun newInstance(): FitFragment {
return FitFragment()

View file

@ -28,10 +28,13 @@ 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.FragmentFitPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
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
@ -40,10 +43,12 @@ 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 kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
class FitPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_fit_playback_controls) {
private var _binding: FragmentFitPlaybackControlsBinding? = null
private val binding get() = _binding!!
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
@ -56,30 +61,38 @@ class FitPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentFitPlaybackControlsBinding.bind(view)
setUpMusicControllers()
title.isSelected = true
text.isSelected = true
binding.title.isSelected = true
binding.text.isSelected = true
playPauseButton.setOnClickListener {
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation()
showBounceAnimation()
}
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -146,22 +159,22 @@ class FitPlaybackControlsFragment :
private fun setFabColor(i: Int) {
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(i)),
false
)
TintHelper.setTintAuto(playPauseButton, i, true)
TintHelper.setTintAuto(binding.playPauseButton, i, true)
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -175,26 +188,26 @@ class FitPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -202,31 +215,37 @@ class FitPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -235,17 +254,15 @@ class FitPlaybackControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
private fun showBonceAnimation() {
playPauseButton.apply {
private fun showBounceAnimation() {
binding.playPauseButton.apply {
clearAnimation()
scaleX = 0.9f
scaleY = 0.9f
@ -268,7 +285,7 @@ class FitPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -282,14 +299,19 @@ class FitPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -27,11 +27,14 @@ 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.FragmentFlatPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
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.MusicProgressViewUpdateHelper.Callback
@ -41,7 +44,6 @@ 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 kotlinx.android.synthetic.main.fragment_flat_player_playback_controls.*
class FlatPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_flat_player_playback_controls), Callback {
@ -49,6 +51,9 @@ class FlatPlaybackControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentFlatPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -57,9 +62,16 @@ class FlatPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentFlatPlayerPlaybackControlsBinding.bind(view)
setUpMusicControllers()
title.isSelected = true
text.isSelected = true
binding.title.isSelected = true
binding.text.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
override fun onResume() {
@ -73,7 +85,7 @@ class FlatPlaybackControlsFragment :
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.setInterpolator(DecelerateInterpolator())
@ -81,7 +93,7 @@ class FlatPlaybackControlsFragment :
}
public override fun hide() {
playPauseButton!!.apply {
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
@ -109,7 +121,7 @@ class FlatPlaybackControlsFragment :
updateTextColors(colorFinal)
volumeFragment?.setTintable(colorFinal)
progressSlider.applyColor(colorFinal)
binding.progressSlider.applyColor(colorFinal)
updateRepeatState()
updateShuffleState()
}
@ -121,15 +133,15 @@ class FlatPlaybackControlsFragment :
val colorSecondary =
MaterialValueHelper.getSecondaryTextColor(context, ColorUtil.isColorLight(darkColor))
TintHelper.setTintAuto(playPauseButton, colorPrimary, false)
TintHelper.setTintAuto(playPauseButton, color, true)
TintHelper.setTintAuto(binding.playPauseButton, colorPrimary, false)
TintHelper.setTintAuto(binding.playPauseButton, color, true)
title.setBackgroundColor(color)
title.setTextColor(colorPrimary)
text.setBackgroundColor(darkColor)
text.setTextColor(colorSecondary)
songInfo.setBackgroundColor(darkColor)
songInfo.setTextColor(colorSecondary)
binding.title.setBackgroundColor(color)
binding.title.setTextColor(colorPrimary)
binding.text.setBackgroundColor(darkColor)
binding.text.setTextColor(colorSecondary)
binding.songInfo.setBackgroundColor(darkColor)
binding.songInfo.setTextColor(colorSecondary)
}
override fun onServiceConnected() {
@ -149,14 +161,14 @@ class FlatPlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -169,13 +181,13 @@ class FlatPlaybackControlsFragment :
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -188,40 +200,46 @@ class FlatPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -229,7 +247,7 @@ class FlatPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -243,14 +261,19 @@ class FlatPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -25,6 +25,7 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentFlatPlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -33,11 +34,10 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import code.name.monkey.retromusic.views.DrawableGradient
import kotlinx.android.synthetic.main.fragment_flat_player.*
class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var valueAnimator: ValueAnimator? = null
@ -46,6 +46,10 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
override val paletteColor: Int
get() = lastColor
private var _binding: FragmentFlatPlayerBinding? = null
private val binding get() = _binding!!
private fun setUpSubFragments() {
controlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FlatPlaybackControlsFragment
@ -55,11 +59,11 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { _ -> requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -76,13 +80,14 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(animation.animatedValue as Int, android.R.color.transparent), 0
)
colorGradientBackground?.background = drawable
binding.colorGradientBackground.background = drawable
}
valueAnimator?.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong())?.start()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentFlatPlayerBinding.bind(view)
setUpPlayerToolbar()
setUpSubFragments()
}
@ -117,7 +122,11 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
MaterialValueHelper.getPrimaryTextColor(requireContext(), isLight)
else
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, iconColor, requireActivity())
ToolbarContentTintHelper.colorizeToolbar(
binding.playerToolbar,
iconColor,
requireActivity()
)
if (PreferenceUtil.isAdaptiveColor) {
colorize(color.backgroundColor)
}
@ -133,4 +142,9 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) {
updateIsFavorite()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -15,13 +15,12 @@
package code.name.monkey.retromusic.fragments.player.full
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.os.Bundle
import android.view.MenuItem
import android.view.View
@ -31,8 +30,8 @@ import android.widget.PopupMenu
import android.widget.SeekBar
import androidx.lifecycle.lifecycleScope
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.FragmentFullPlayerControlsBinding
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.db.toSongEntity
@ -42,6 +41,8 @@ import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType
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
@ -52,7 +53,6 @@ import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_full_player_controls.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -70,6 +70,8 @@ class FullPlaybackControlsFragment :
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private val libraryViewModel: LibraryViewModel by sharedViewModel()
private var _binding: FragmentFullPlayerControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -78,11 +80,18 @@ class FullPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpMusicControllers()
_binding = FragmentFullPlayerControlsBinding.bind(view)
songTotalTime.setTextColor(Color.WHITE)
songCurrentProgress.setTextColor(Color.WHITE)
title.isSelected = true
setUpMusicControllers()
binding.songTotalTime.setTextColor(Color.WHITE)
binding.songCurrentProgress.setTextColor(Color.WHITE)
binding.title.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
override fun onResume() {
@ -96,7 +105,7 @@ class FullPlaybackControlsFragment :
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.setInterpolator(DecelerateInterpolator())
@ -104,7 +113,7 @@ class FullPlaybackControlsFragment :
}
public override fun hide() {
playPauseButton.apply {
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
@ -116,18 +125,18 @@ class FullPlaybackControlsFragment :
lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(color.primaryTextColor, 0.3f)
val tintList = ColorStateList.valueOf(color.primaryTextColor)
playerMenu.imageTintList = tintList
songFavourite.imageTintList = tintList
binding.playerMenu.imageTintList = tintList
binding.songFavourite.imageTintList = tintList
volumeFragment?.setTintableColor(color.primaryTextColor)
progressSlider.applyColor(color.primaryTextColor)
title.setTextColor(color.primaryTextColor)
text.setTextColor(color.secondaryTextColor)
songInfo.setTextColor(color.secondaryTextColor)
songCurrentProgress.setTextColor(color.secondaryTextColor)
songTotalTime.setTextColor(color.secondaryTextColor)
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)
playPauseButton.backgroundTintList = tintList
playPauseButton.imageTintList = ColorStateList.valueOf(color.backgroundColor)
binding.playPauseButton.backgroundTintList = tintList
binding.playPauseButton.imageTintList = ColorStateList.valueOf(color.backgroundColor)
updateRepeatState()
updateShuffleState()
@ -143,14 +152,14 @@ class FullPlaybackControlsFragment :
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
updateIsFavorite()
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -165,19 +174,17 @@ class FullPlaybackControlsFragment :
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
playPauseButton.post {
if (playPauseButton != null) {
playPauseButton.pivotX = (playPauseButton.width / 2).toFloat()
playPauseButton.pivotY = (playPauseButton.height / 2).toFloat()
}
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.post {
binding.playPauseButton.pivotX = (binding.playPauseButton.width / 2).toFloat()
binding.playPauseButton.pivotY = (binding.playPauseButton.height / 2).toFloat()
}
}
@ -192,10 +199,11 @@ class FullPlaybackControlsFragment :
}
private fun setupMenu() {
playerMenu.setOnClickListener {
binding.playerMenu.setOnClickListener {
val popupMenu = PopupMenu(requireContext(), it)
popupMenu.setOnMenuItemClickListener(this)
popupMenu.inflate(R.menu.menu_player)
popupMenu.menu.findItem(R.id.action_toggle_favorite).isVisible = false
popupMenu.show()
}
}
@ -206,17 +214,17 @@ class FullPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -230,15 +238,15 @@ class FullPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onRepeatModeChanged() {
@ -250,16 +258,16 @@ class FullPlaybackControlsFragment :
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -267,36 +275,46 @@ class FullPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
private fun setupFavourite() {
songFavourite?.setOnClickListener {
binding.songFavourite.setOnClickListener {
toggleFavorite(MusicPlayerRemote.currentSong)
}
}
fun updateIsFavorite() {
override fun onFavoriteStateChanged() {
updateIsFavorite(animate = true)
}
fun updateIsFavorite(animate: Boolean = false) {
lifecycleScope.launch(Dispatchers.IO) {
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
if (playlist != null) {
@ -304,19 +322,30 @@ class FullPlaybackControlsFragment :
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
withContext(Dispatchers.Main) {
val icon =
val icon = if (animate) {
if (isFavorite) R.drawable.avd_favorite else R.drawable.avd_unfavorite
} else {
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
val drawable = TintHelper.createTintedDrawable(activity, icon, Color.WHITE)
songFavourite?.setImageDrawable(drawable)
}
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
requireContext(),
icon,
Color.WHITE
)
binding.songFavourite.apply {
setImageDrawable(drawable)
getDrawable().also {
if (it is AnimatedVectorDrawable) {
it.start()
}
}
}
}
}
}
}
private fun toggleFavorite(song: Song) {
if (song.id == MusicPlayerRemote.currentSong.id) {
updateIsFavorite()
}
lifecycleScope.launch(Dispatchers.IO) {
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
if (playlist != null) {
@ -336,4 +365,9 @@ class FullPlaybackControlsFragment :
fun onFavoriteToggled() {
toggleFavorite(MusicPlayerRemote.currentSong)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -18,119 +18,29 @@ import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
import androidx.navigation.fragment.findNavController
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentFullBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
import code.name.monkey.retromusic.model.lyrics.Lyrics
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_full.*
class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
MusicProgressViewUpdateHelper.Callback {
private lateinit var lyricsLayout: FrameLayout
private lateinit var lyricsLine1: TextView
private lateinit var lyricsLine2: TextView
private var lyrics: Lyrics? = null
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
override fun onUpdateProgressViews(progress: Int, total: Int) {
if (!isLyricsLayoutBound()) 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 = VISIBILITY_ANIM_DURATION
lyricsLine2.alpha = 0f
lyricsLine2.translationY = h
lyricsLine2.animate().alpha(1f).translationY(0f).duration = VISIBILITY_ANIM_DURATION
}
}
private fun isLyricsLayoutVisible(): Boolean {
return lyrics != null && lyrics!!.isSynchronized && lyrics!!.isValid
}
private fun isLyricsLayoutBound(): Boolean {
return lyricsLayout != null && lyricsLine1 != null && lyricsLine2 != null
}
private fun hideLyricsLayout() {
lyricsLayout.animate().alpha(0f).setDuration(VISIBILITY_ANIM_DURATION)
.withEndAction(Runnable {
if (!isLyricsLayoutBound()) return@Runnable
lyricsLayout.visibility = View.GONE
lyricsLine1.text = null
lyricsLine2.text = null
})
}
override fun setLyrics(l: Lyrics?) {
lyrics = l
if (!isLyricsLayoutBound()) return
if (!isLyricsLayoutVisible()) {
hideLyricsLayout()
return
}
lyricsLine1.text = null
lyricsLine2.text = null
lyricsLayout.visibility = View.VISIBLE
lyricsLayout.animate().alpha(1f).duration = VISIBILITY_ANIM_DURATION
}
class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full) {
private var _binding: FragmentFullBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -139,33 +49,24 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
private lateinit var controlsFragment: FullPlaybackControlsFragment
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
setNavigationOnClickListener { requireActivity().onBackPressed() }
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lyricsLayout = view.findViewById(R.id.playerLyrics)
lyricsLine1 = view.findViewById(R.id.player_lyrics_line1)
lyricsLine2 = view.findViewById(R.id.player_lyrics_line2)
_binding = FragmentFullBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
setupArtist()
nextSong.isSelected = true
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
progressViewUpdateHelper.start()
binding.nextSong.isSelected = true
}
private fun setupArtist() {
artistImage.setOnClickListener {
mainActivity.collapsePanel()
findNavController().navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to MusicPlayerRemote.currentSong.artistId),
)
binding.artistImage.setOnClickListener {
goToArtist(mainActivity)
}
}
@ -192,10 +93,10 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
override fun onColorChanged(color: MediaNotificationProcessor) {
lastColor = color.backgroundColor
mask.backgroundTintList = ColorStateList.valueOf(color.backgroundColor)
binding.mask.backgroundTintList = ColorStateList.valueOf(color.backgroundColor)
controlsFragment.setColor(color)
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity)
}
override fun onFavoriteToggled() {
@ -224,16 +125,15 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
override fun onDestroyView() {
super.onDestroyView()
progressViewUpdateHelper.stop()
_binding = null
}
private fun updateArtistImage() {
libraryViewModel.artist(MusicPlayerRemote.currentSong.artistId)
.observe(viewLifecycleOwner, { artist ->
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.generatePalette(requireContext())
.build()
.into(object : RetroMusicColoredTarget(artistImage) {
GlideApp.with(requireActivity()).asBitmapPalette().artistImageOptions(artist)
.load(RetroGlideExtension.getArtistModel(artist))
.into(object : RetroMusicColoredTarget(binding.artistImage) {
override fun onColorReady(colors: MediaNotificationProcessor) {
}
})
@ -248,12 +148,12 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
private fun updateLabel() {
(MusicPlayerRemote.playingQueue.size - 1).apply {
if (this == (MusicPlayerRemote.position)) {
nextSongLabel.setText(R.string.last_song)
nextSong.hide()
binding.nextSongLabel.setText(R.string.last_song)
binding.nextSong.hide()
} else {
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
nextSongLabel.setText(R.string.next_song)
nextSong.apply {
binding.nextSongLabel.setText(R.string.next_song)
binding.nextSong.apply {
text = title
show()
}

View file

@ -19,6 +19,7 @@ import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.AnimatedVectorDrawable
import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
@ -35,6 +36,7 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
import code.name.monkey.retromusic.databinding.FragmentGradientPlayerBinding
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.db.toSongEntity
@ -44,11 +46,12 @@ import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.VolumeFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
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.model.Song
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
@ -60,9 +63,6 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropM
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.fragment_gradient_controls.*
import kotlinx.android.synthetic.main.fragment_gradient_player.*
import kotlinx.android.synthetic.main.status_bar.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -82,14 +82,17 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager
private var _binding: FragmentGradientPlayerBinding? = null
private val binding get() = _binding!!
private val bottomSheetCallbackList = object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
playerQueueSheet.setPadding(
playerQueueSheet.paddingLeft,
(slideOffset * status_bar.height).toInt(),
playerQueueSheet.paddingRight,
playerQueueSheet.paddingBottom
binding.playerQueueSheet.setPadding(
binding.playerQueueSheet.paddingLeft,
(slideOffset * binding.statusBarLayout.statusBar.height).toInt(),
binding.playerQueueSheet.paddingRight,
binding.playerQueueSheet.paddingBottom
)
}
@ -111,23 +114,24 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
private fun setupFavourite() {
songFavourite.setOnClickListener {
binding.playbackControlsFragment.songFavourite.setOnClickListener {
toggleFavorite(MusicPlayerRemote.currentSong)
}
}
private fun setupMenu() {
playerMenu.setOnClickListener {
binding.playbackControlsFragment.playerMenu.setOnClickListener {
val popupMenu = PopupMenu(requireContext(), it)
popupMenu.setOnMenuItemClickListener(this)
popupMenu.inflate(R.menu.menu_player)
popupMenu.menu.findItem(R.id.action_toggle_favorite).isVisible = false
popupMenu.show()
}
}
private fun setupPanel() {
if (!ViewCompat.isLaidOut(colorBackground) || colorBackground.isLayoutRequested) {
colorBackground.addOnLayoutChangeListener(this)
if (!ViewCompat.isLaidOut(binding.colorBackground) || binding.colorBackground.isLayoutRequested) {
binding.colorBackground.addOnLayoutChangeListener(this)
return
}
}
@ -139,6 +143,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentGradientPlayerBinding.bind(view)
hideVolumeIfAvailable()
setUpMusicControllers()
setupPanel()
@ -146,12 +151,18 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
setupSheet()
setupMenu()
setupFavourite()
binding.playbackControlsFragment.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.playbackControlsFragment.text.setOnClickListener {
goToArtist(requireActivity())
}
}
@SuppressLint("ClickableViewAccessibility")
private fun setupSheet() {
getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList)
playerQueueSheet.setOnTouchListener { _, _ ->
binding.playerQueueSheet.setOnTouchListener { _, _ ->
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
getQueuePanel().setAllowDragging(true)
return@setOnTouchListener false
@ -159,7 +170,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
private fun getQueuePanel(): RetroBottomSheetBehavior<ConstraintLayout> {
return RetroBottomSheetBehavior.from(playerQueueSheet) as RetroBottomSheetBehavior<ConstraintLayout>
return RetroBottomSheetBehavior.from(binding.playerQueueSheet) as RetroBottomSheetBehavior<ConstraintLayout>
}
override fun onResume() {
@ -184,6 +195,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
override fun onBackPressed(): Boolean {
println("OK")
var wasExpanded = false
if (getQueuePanel().state == STATE_EXPANDED) {
wasExpanded = getQueuePanel().state == STATE_EXPANDED
@ -203,46 +215,62 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
override fun onColorChanged(color: MediaNotificationProcessor) {
lastColor = color.backgroundColor
libraryViewModel.updateColor(color.backgroundColor)
mask.backgroundTintList = ColorStateList.valueOf(color.backgroundColor)
colorBackground.setBackgroundColor(color.backgroundColor)
playerQueueSheet.setBackgroundColor(ColorUtil.darkenColor(color.backgroundColor))
binding.mask.backgroundTintList = ColorStateList.valueOf(color.backgroundColor)
binding.colorBackground.setBackgroundColor(color.backgroundColor)
binding.playerQueueSheet.setBackgroundColor(ColorUtil.darkenColor(color.backgroundColor))
lastPlaybackControlsColor = color.primaryTextColor
lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(color.primaryTextColor, 0.3f)
title.setTextColor(lastPlaybackControlsColor)
text.setTextColor(lastDisabledPlaybackControlsColor)
playPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
songFavourite.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
queueIcon.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
playerMenu.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
songCurrentProgress.setTextColor(lastDisabledPlaybackControlsColor)
songTotalTime.setTextColor(lastDisabledPlaybackControlsColor)
nextSong.setTextColor(lastPlaybackControlsColor)
songInfo.setTextColor(lastDisabledPlaybackControlsColor)
binding.playbackControlsFragment.title.setTextColor(lastPlaybackControlsColor)
binding.playbackControlsFragment.text.setTextColor(lastDisabledPlaybackControlsColor)
binding.playbackControlsFragment.playPauseButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playbackControlsFragment.nextButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playbackControlsFragment.previousButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playbackControlsFragment.songFavourite.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.queueIcon.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playbackControlsFragment.playerMenu.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playbackControlsFragment.songCurrentProgress.setTextColor(
lastDisabledPlaybackControlsColor
)
binding.playbackControlsFragment.songTotalTime.setTextColor(
lastDisabledPlaybackControlsColor
)
binding.nextSong.setTextColor(lastPlaybackControlsColor)
binding.playbackControlsFragment.songInfo.setTextColor(lastDisabledPlaybackControlsColor)
volumeFragment?.setTintableColor(lastPlaybackControlsColor.ripAlpha())
ViewUtil.setProgressDrawable(progressSlider, lastPlaybackControlsColor.ripAlpha(), true)
ViewUtil.setProgressDrawable(
binding.playbackControlsFragment.progressSlider,
lastPlaybackControlsColor.ripAlpha(),
true
)
updateRepeatState()
updateShuffleState()
updatePrevNextColor()
}
override fun toggleFavorite(song: Song) {
super.toggleFavorite(song)
if (song.id == MusicPlayerRemote.currentSong.id) {
updateIsFavoriteIcon()
}
}
override fun onFavoriteToggled() {
toggleFavorite(MusicPlayerRemote.currentSong)
}
private fun updateIsFavoriteIcon() {
private fun updateIsFavoriteIcon(animate: Boolean = false) {
lifecycleScope.launch(Dispatchers.IO) {
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
if (playlist != null) {
@ -250,10 +278,19 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
withContext(Dispatchers.Main) {
val icon =
if (isFavorite) R.drawable.ic_favorite
else R.drawable.ic_favorite_border
songFavourite.setImageResource(icon)
val icon = if (animate) {
if (isFavorite) R.drawable.avd_favorite else R.drawable.avd_unfavorite
} else {
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
}
binding.playbackControlsFragment.songFavourite.apply {
setImageResource(icon)
drawable.also {
if (it is AnimatedVectorDrawable) {
it.start()
}
}
}
}
}
}
@ -298,6 +335,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
updateIsFavoriteIcon()
}
override fun onFavoriteStateChanged() {
updateIsFavoriteIcon(animate = true)
}
override fun onQueueChanged() {
super.onQueueChanged()
updateLabel()
@ -306,14 +347,14 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.playbackControlsFragment.title.text = song.title
binding.playbackControlsFragment.text.text = song.artistName
updateLabel()
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.playbackControlsFragment.songInfo.text = getSongInfo(song)
binding.playbackControlsFragment.songInfo.show()
} else {
songInfo.hide()
binding.playbackControlsFragment.songInfo.hide()
}
}
@ -323,45 +364,53 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
setUpRepeatButton()
setUpShuffleButton()
setUpProgressSlider()
title.isSelected = true
text.isSelected = true
binding.playbackControlsFragment.title.isSelected = true
binding.playbackControlsFragment.text.isSelected = true
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause_white_64dp)
binding.playbackControlsFragment.playPauseButton.setImageResource(R.drawable.ic_pause_white_64dp)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_64dp)
binding.playbackControlsFragment.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_64dp)
}
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playbackControlsFragment.playPauseButton.setOnClickListener(
PlayPauseButtonOnClickHandler()
)
}
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.playbackControlsFragment.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.playbackControlsFragment.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playbackControlsFragment.nextButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
binding.playbackControlsFragment.previousButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE ->
shuffleButton.setColorFilter(
binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -369,25 +418,31 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -395,10 +450,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
private fun updateLabel() {
(MusicPlayerRemote.playingQueue.size - 1).apply {
if (this == (MusicPlayerRemote.position)) {
nextSong.text = "Last song"
binding.nextSong.text = "Last song"
} else {
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
nextSong.text = title
binding.nextSong.text = title
}
}
}
@ -415,7 +470,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
oldBottom: Int
) {
val panel = getQueuePanel()
panel.peekHeight = container.height
panel.peekHeight = binding.container.height
}
private fun setupRecyclerView() {
@ -436,12 +491,14 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!) as RecyclerView.Adapter<*>
wrappedAdapter =
recyclerViewSwipeManager?.createWrappedAdapter(wrappedAdapter) as RecyclerView.Adapter<*>
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = wrappedAdapter
recyclerView.itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(recyclerView)
binding.recyclerView.apply {
layoutManager = linearLayoutManager
adapter = wrappedAdapter
itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(this)
recyclerViewDragDropManager?.attachRecyclerView(this)
recyclerViewSwipeManager?.attachRecyclerView(this)
}
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
@ -460,6 +517,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
WrapperAdapterUtils.releaseAll(wrappedAdapter)
_binding = null
}
private fun updateQueuePosition() {
@ -473,12 +531,13 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
binding.recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.playbackControlsFragment.progressSlider.setOnSeekBarChangeListener(object :
SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -492,12 +551,18 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
binding.playbackControlsFragment.progressSlider.max = total
val animator = ObjectAnimator.ofInt(
binding.playbackControlsFragment.progressSlider,
"progress",
progress
)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.playbackControlsFragment.songTotalTime.text =
MusicUtil.getReadableDurationString(total.toLong())
binding.playbackControlsFragment.songCurrentProgress.text =
MusicUtil.getReadableDurationString(progress.toLong())
}
}

View file

@ -21,19 +21,23 @@ 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.FragmentHomePlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_home_player.*
class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
MusicProgressViewUpdateHelper.Callback {
private var lastColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentHomePlayerBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
@ -41,6 +45,7 @@ class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentHomePlayerBinding.bind(view)
setUpPlayerToolbar()
}
@ -54,8 +59,8 @@ class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
progressViewUpdateHelper.stop()
}
override fun playerToolbar(): Toolbar? {
return playerToolbar
override fun playerToolbar(): Toolbar {
return binding.playerToolbar
}
override fun onShow() {
@ -76,8 +81,8 @@ class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
}
override fun onBackPressed(): Boolean {
@ -95,7 +100,7 @@ class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
lastColor = color.backgroundColor
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
Color.WHITE,
requireActivity()
)
@ -113,18 +118,23 @@ class HomePlayerFragment : AbsPlayerFragment(R.layout.fragment_home_player),
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
songTotalTime.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(progress.toLong())
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -26,6 +26,7 @@ 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.FragmentLockScreenPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.textColorSecondary
@ -38,7 +39,6 @@ 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 kotlinx.android.synthetic.main.fragment_lock_screen_playback_controls.*
/**
* @author Hemanth S (h4h13).
@ -50,6 +50,10 @@ class LockScreenControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private var _binding: FragmentLockScreenPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
@ -57,14 +61,15 @@ class LockScreenControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentLockScreenPlaybackControlsBinding.bind(view)
setUpMusicControllers()
title.isSelected = true
binding.title.isSelected = true
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = String.format("%s - %s", song.artistName, song.albumName)
binding.title.text = song.title
binding.text.text = String.format("%s - %s", song.artistName, song.albumName)
}
override fun onResume() {
@ -123,32 +128,32 @@ class LockScreenControlsFragment :
}.ripAlpha()
volumeFragment?.setTintable(colorFinal)
progressSlider.applyColor(colorFinal)
binding.progressSlider.applyColor(colorFinal)
updateRepeatState()
updateShuffleState()
updatePrevNextColor()
val isDark = ColorUtil.isColorLight(colorFinal)
text.setTextColor(colorFinal)
binding.text.setTextColor(colorFinal)
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(requireContext(), isDark),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
TintHelper.setTintAuto(binding.playPauseButton, colorFinal, true)
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -162,26 +167,26 @@ class LockScreenControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -189,31 +194,37 @@ class LockScreenControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -222,17 +233,15 @@ class LockScreenControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -246,14 +255,19 @@ class LockScreenControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -20,11 +20,15 @@ import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentMaterialPlaybackControlsBinding
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
@ -33,7 +37,6 @@ 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 kotlinx.android.synthetic.main.fragment_material_playback_controls.*
/**
* @author Hemanth S (h4h13).
@ -44,6 +47,9 @@ class MaterialControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentMaterialPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -52,21 +58,28 @@ class MaterialControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMaterialPlaybackControlsBinding.bind(view)
setUpMusicControllers()
title.isSelected = true
text.isSelected = true
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
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -125,8 +138,8 @@ class MaterialControlsFragment :
textColorSecondary()
}.ripAlpha()
text.setTextColor(colorFinal)
progressSlider.applyColor(colorFinal)
binding.text.setTextColor(colorFinal)
binding.progressSlider.applyColor(colorFinal)
volumeFragment?.setTintable(colorFinal)
@ -137,18 +150,28 @@ class MaterialControlsFragment :
}
private fun updatePlayPauseColor() {
playPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause_sharp_white_64dp)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_sharp_white_64dp)
binding.playPauseButton.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.ic_pause_outline
)
)
} else if (!MusicPlayerRemote.isPlaying) {
binding.playPauseButton.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.ic_play_arrow_outline
)
)
}
}
@ -162,26 +185,26 @@ class MaterialControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -189,25 +212,31 @@ class MaterialControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat_sharp)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat_sharp)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat_sharp)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_sharp)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one_sharp)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one_sharp)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -219,7 +248,7 @@ class MaterialControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -233,14 +262,19 @@ class MaterialControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -20,13 +20,13 @@ 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.FragmentMaterialBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_material.*
/**
* @author Hemanth S (h4h13).
@ -34,7 +34,7 @@ import kotlinx.android.synthetic.main.fragment_material.*
class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -44,6 +44,10 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
private lateinit var playbackControlsFragment: MaterialControlsFragment
private var _binding: FragmentMaterialBinding? = null
private val binding get() = _binding!!
override fun onShow() {
playbackControlsFragment.show()
}
@ -67,7 +71,7 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -86,6 +90,7 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMaterialBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -99,7 +104,7 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@MaterialFragment)
@ -125,4 +130,9 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
return PlayerFragment()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -23,6 +23,7 @@ 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.FragmentPlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -31,7 +32,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import code.name.monkey.retromusic.views.DrawableGradient
import kotlinx.android.synthetic.main.fragment_player.*
class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
@ -42,6 +42,10 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
private lateinit var controlsFragment: PlayerPlaybackControlsFragment
private var valueAnimator: ValueAnimator? = null
private var _binding: FragmentPlayerBinding? = null
private val binding get() = _binding!!
private fun colorize(i: Int) {
if (valueAnimator != null) {
valueAnimator?.cancel()
@ -61,7 +65,7 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)
), 0
)
colorGradientBackground?.background = drawable
binding.colorGradientBackground.background = drawable
}
}
valueAnimator?.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong())?.start()
@ -90,7 +94,7 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
libraryViewModel.updateColor(color.backgroundColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -113,10 +117,16 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun setUpSubFragments() {
controlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
@ -126,12 +136,13 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
//binding.playerToolbar.menu.setUpWithIcons()
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -146,7 +157,7 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player) {
}
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
companion object {

View file

@ -27,11 +27,14 @@ 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.FragmentPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
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
@ -40,7 +43,6 @@ 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 kotlinx.android.synthetic.main.fragment_player_playback_controls.*
class PlayerPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_player_playback_controls) {
@ -48,6 +50,8 @@ class PlayerPlaybackControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -56,17 +60,24 @@ class PlayerPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlayerPlaybackControlsBinding.bind(view)
setUpMusicControllers()
playPauseButton.setOnClickListener {
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation(playPauseButton)
showBounceAnimation(binding.playPauseButton)
}
binding.title.isSelected = true
binding.text.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
title.isSelected = true
text.isSelected = true
}
override fun setColor(color: MediaNotificationProcessor) {
@ -90,15 +101,15 @@ class PlayerPlaybackControlsFragment :
}.ripAlpha()
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(
requireContext(),
ColorUtil.isColorLight(colorFinal)
),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
progressSlider.applyColor(colorFinal)
TintHelper.setTintAuto(binding.playPauseButton, colorFinal, true)
binding.progressSlider.applyColor(colorFinal)
volumeFragment?.setTintable(colorFinal)
updateRepeatState()
updateShuffleState()
@ -107,14 +118,14 @@ class PlayerPlaybackControlsFragment :
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -153,14 +164,14 @@ class PlayerPlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
@ -174,26 +185,26 @@ class PlayerPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -201,31 +212,37 @@ class PlayerPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -234,7 +251,7 @@ class PlayerPlaybackControlsFragment :
}
public override fun hide() {
playPauseButton.apply {
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
@ -242,7 +259,7 @@ class PlayerPlaybackControlsFragment :
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -256,14 +273,19 @@ class PlayerPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -26,6 +26,7 @@ import code.name.monkey.appthemehelper.util.ATHUtil
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.FragmentPeakControlPlayerBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -36,7 +37,6 @@ 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 kotlinx.android.synthetic.main.fragment_peak_control_player.*
/**
* Created by hemanths on 2019-10-04.
@ -47,6 +47,8 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private var _binding: FragmentPeakControlPlayerBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -68,6 +70,7 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
savedInstanceState: Bundle?
) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPeakControlPlayerBinding.bind(view)
setUpMusicControllers()
}
@ -84,11 +87,11 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
} else {
ThemeStore.accentColor(requireContext())
}
progressSlider.applyColor(controlsColor)
binding.progressSlider.applyColor(controlsColor)
volumeFragment?.setTintableColor(controlsColor)
playPauseButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
nextButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
binding.playPauseButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(controlsColor, PorterDuff.Mode.SRC_IN)
if (!ATHUtil.isWindowBackgroundDark(requireContext())) {
lastPlaybackControlsColor =
@ -107,9 +110,9 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
@ -122,19 +125,19 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener {
binding.shuffleButton.setOnClickListener {
MusicPlayerRemote.toggleShuffleMode()
}
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener {
binding.repeatButton.setOnClickListener {
MusicPlayerRemote.cycleRepeatMode()
}
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -148,41 +151,41 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
private fun setUpPlayPauseFab() {
TintHelper.setTintAuto(playPauseButton, Color.WHITE, true)
TintHelper.setTintAuto(playPauseButton, Color.BLACK, false)
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
TintHelper.setTintAuto(binding.playPauseButton, Color.WHITE, true)
TintHelper.setTintAuto(binding.playPauseButton, Color.BLACK, false)
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -192,19 +195,25 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -226,4 +235,9 @@ class PeakPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
override fun onShuffleModeChanged() {
updateShuffleState()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -20,14 +20,16 @@ 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.FragmentPeakPlayerBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_peak_player.*
/**
* Created by hemanths on 2019-10-03.
@ -37,12 +39,22 @@ class PeakPlayerFragment : AbsPlayerFragment(R.layout.fragment_peak_player) {
private lateinit var controlsFragment: PeakPlayerControlFragment
private var lastColor: Int = 0
private var _binding: FragmentPeakPlayerBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPeakPlayerBinding.bind(view)
setUpPlayerToolbar()
setUpSubFragments()
title.isSelected = true
binding.title.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
private fun setUpSubFragments() {
@ -55,7 +67,7 @@ class PeakPlayerFragment : AbsPlayerFragment(R.layout.fragment_peak_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@PeakPlayerFragment)
@ -68,7 +80,7 @@ class PeakPlayerFragment : AbsPlayerFragment(R.layout.fragment_peak_player) {
}
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
override fun onShow() {
@ -99,14 +111,14 @@ class PeakPlayerFragment : AbsPlayerFragment(R.layout.fragment_peak_player) {
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -119,4 +131,9 @@ class PeakPlayerFragment : AbsPlayerFragment(R.layout.fragment_peak_player) {
super.onPlayingMetaChanged()
updateSong()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -28,6 +28,7 @@ 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.FragmentPlainControlsFragmentBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
@ -40,15 +41,6 @@ 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 kotlinx.android.synthetic.main.fragment_adaptive_player_playback_controls.*
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.nextButton
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.playPauseButton
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.previousButton
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.progressSlider
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.repeatButton
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.shuffleButton
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.songCurrentProgress
import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.songTotalTime
/**
* @author Hemanth S (h4h13).
@ -60,6 +52,8 @@ class PlainPlaybackControlsFragment :
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentPlainControlsFragmentBinding? = null
private val binding get() = _binding!!
override fun onPlayStateChanged() {
updatePlayPauseDrawableState()
@ -87,10 +81,10 @@ class PlainPlaybackControlsFragment :
private fun updateSong() {
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
songInfo.show()
binding.songInfo.text = getSongInfo(MusicPlayerRemote.currentSong)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -111,20 +105,21 @@ class PlainPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlainControlsFragmentBinding.bind(view)
setUpMusicControllers()
playPauseButton.setOnClickListener {
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation()
showBounceAnimation()
}
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun setUpMusicControllers() {
@ -137,13 +132,13 @@ class PlainPlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
override fun setColor(color: MediaNotificationProcessor) {
@ -166,17 +161,17 @@ class PlainPlaybackControlsFragment :
ThemeStore.accentColor(requireContext())
}
volumeFragment?.setTintable(colorFinal)
progressSlider.applyColor(colorFinal)
binding.progressSlider.applyColor(colorFinal)
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(
requireContext(),
ColorUtil.isColorLight(colorFinal)
),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
TintHelper.setTintAuto(binding.playPauseButton, colorFinal, true)
updateRepeatState()
updateShuffleState()
@ -184,16 +179,16 @@ class PlainPlaybackControlsFragment :
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -201,31 +196,37 @@ class PlainPlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -234,17 +235,15 @@ class PlainPlaybackControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
private fun showBonceAnimation() {
playPauseButton.apply {
private fun showBounceAnimation() {
binding.playPauseButton.apply {
clearAnimation()
scaleX = 0.9f
scaleY = 0.9f
@ -268,14 +267,14 @@ class PlainPlaybackControlsFragment :
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
override fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -289,14 +288,19 @@ class PlainPlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -20,22 +20,27 @@ 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.FragmentPlainPlayerBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
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
import kotlinx.android.synthetic.main.fragment_plain_player.*
class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private lateinit var plainPlaybackControlsFragment: PlainPlaybackControlsFragment
private var lastColor: Int = 0
override val paletteColor: Int
get() = lastColor
private var _binding: FragmentPlainPlayerBinding? = null
private val binding get() = _binding!!
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
@ -44,8 +49,8 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
}
override fun onServiceConnected() {
@ -54,7 +59,7 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@PlainPlayerFragment)
@ -68,10 +73,17 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlainPlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
title.isSelected = true
text.isSelected = true
binding.title.isSelected = true
binding.text.isSelected = true
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
private fun setUpSubFragments() {
@ -104,7 +116,7 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
lastColor = color.primaryTextColor
libraryViewModel.updateColor(color.primaryTextColor)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -120,4 +132,9 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) {
updateIsFavorite()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -24,9 +24,12 @@ 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.FragmentSimpleControlsFragmentBinding
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
@ -34,7 +37,6 @@ 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 kotlinx.android.synthetic.main.fragment_simple_controls_fragment.*
/**
* @author Hemanth S (h4h13).
@ -43,6 +45,10 @@ import kotlinx.android.synthetic.main.fragment_simple_controls_fragment.*
class SimplePlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_simple_controls_fragment) {
private var _binding: FragmentSimpleControlsFragmentBinding? = null
private val binding get() = _binding!!
private var lastPlaybackControlsColor: Int = 0
private var lastDisabledPlaybackControlsColor: Int = 0
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
@ -83,15 +89,25 @@ class SimplePlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentSimpleControlsFragmentBinding.bind(view)
setUpMusicControllers()
title.isSelected = true
playPauseButton.setOnClickListener {
binding.title.isSelected = true
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
binding.playPauseButton.setOnClickListener {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
showBonceAnimation(playPauseButton)
showBounceAnimation(binding.playPauseButton)
}
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
@ -105,26 +121,26 @@ class SimplePlaybackControlsFragment :
private fun setUpPrevNext() {
updatePrevNextColor()
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun updatePrevNextColor() {
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -132,39 +148,45 @@ class SimplePlaybackControlsFragment :
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = song.artistName
binding.title.text = song.title
binding.text.text = song.artistName
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@ -174,7 +196,7 @@ class SimplePlaybackControlsFragment :
}
public override fun show() {
playPauseButton!!.animate()
binding.playPauseButton.animate()
.scaleX(1f)
.scaleY(1f)
.rotation(360f)
@ -183,12 +205,10 @@ class SimplePlaybackControlsFragment :
}
public override fun hide() {
if (playPauseButton != null) {
playPauseButton!!.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
binding.playPauseButton.apply {
scaleX = 0f
scaleY = 0f
rotation = 0f
}
}
@ -196,7 +216,7 @@ class SimplePlaybackControlsFragment :
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
songCurrentProgress!!.text = String.format(
binding.songCurrentProgress.text = String.format(
"%s / %s",
MusicUtil.getReadableDurationString(progress.toLong()),
MusicUtil.getReadableDurationString(total.toLong())
@ -226,15 +246,15 @@ class SimplePlaybackControlsFragment :
volumeFragment?.setTintable(colorFinal)
TintHelper.setTintAuto(
playPauseButton,
binding.playPauseButton,
MaterialValueHelper.getPrimaryTextColor(
requireContext(),
ColorUtil.isColorLight(colorFinal)
),
false
)
TintHelper.setTintAuto(playPauseButton, colorFinal, true)
text.setTextColor(colorFinal)
TintHelper.setTintAuto(binding.playPauseButton, colorFinal, true)
binding.text.setTextColor(colorFinal)
updateRepeatState()
updateShuffleState()
@ -242,14 +262,19 @@ class SimplePlaybackControlsFragment :
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -20,12 +20,12 @@ 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.FragmentSimplePlayerBinding
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
import kotlinx.android.synthetic.main.fragment_simple_player.*
/**
* @author Hemanth S (h4h13).
@ -33,8 +33,11 @@ import kotlinx.android.synthetic.main.fragment_simple_player.*
class SimplePlayerFragment : AbsPlayerFragment(R.layout.fragment_simple_player) {
private var _binding: FragmentSimplePlayerBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
private var lastColor: Int = 0
@ -45,6 +48,7 @@ class SimplePlayerFragment : AbsPlayerFragment(R.layout.fragment_simple_player)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentSimplePlayerBinding.bind(view)
setUpSubFragments()
setUpPlayerToolbar()
}
@ -78,7 +82,7 @@ class SimplePlayerFragment : AbsPlayerFragment(R.layout.fragment_simple_player)
libraryViewModel.updateColor(color.backgroundColor)
controlsFragment.setColor(color)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
@ -96,13 +100,18 @@ class SimplePlayerFragment : AbsPlayerFragment(R.layout.fragment_simple_player)
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this)
binding.playerToolbar.inflateMenu(R.menu.menu_player)
binding.playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
requireActivity()
)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -19,14 +19,16 @@ import android.os.Bundle
import android.view.View
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentTinyControlsFragmentBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_tiny_controls_fragment.*
class TinyPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_tiny_controls_fragment) {
private var _binding: FragmentTinyControlsFragmentBinding? = null
private val binding get() = _binding!!
override fun show() {
}
@ -53,6 +55,7 @@ class TinyPlaybackControlsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentTinyControlsFragmentBinding.bind(view)
setUpMusicControllers()
}
@ -63,20 +66,20 @@ class TinyPlaybackControlsFragment :
}
private fun setUpShuffleButton() {
playerShuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.playerShuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
private fun setUpRepeatButton() {
playerRepeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.playerRepeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
override fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> playerShuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.playerShuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> playerShuffleButton.setColorFilter(
else -> binding.playerShuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -86,19 +89,25 @@ class TinyPlaybackControlsFragment :
override fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
playerRepeatButton.setImageResource(R.drawable.ic_repeat)
playerRepeatButton.setColorFilter(
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat)
binding.playerRepeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
playerRepeatButton.setImageResource(R.drawable.ic_repeat)
playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat)
binding.playerRepeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
playerRepeatButton.setImageResource(R.drawable.ic_repeat_one)
playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.playerRepeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -115,4 +124,9 @@ class TinyPlaybackControlsFragment :
override fun onShuffleModeChanged() {
updateShuffleState()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -16,17 +16,22 @@ package code.name.monkey.retromusic.fragments.player.tiny
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.os.Bundle
import android.os.Handler
import android.annotation.SuppressLint
import android.content.Context
import android.os.*
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.appcompat.widget.Toolbar
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
@ -36,15 +41,20 @@ import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_tiny_player.*
import kotlin.math.abs
class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
MusicProgressViewUpdateHelper.Callback {
private var _binding: FragmentTinyPlayerBinding? = null
private val binding get() = _binding!!
private var lastColor: Int = 0
private var toolbarColor: Int = 0
private var isDragEnabled = false
lateinit var animator: ObjectAnimator
override fun playerToolbar(): Toolbar {
return playerToolbar
return binding.playerToolbar
}
override fun onShow() {
@ -70,21 +80,22 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
toolbarColor = color.secondaryTextColor
controlsFragment.setColor(color)
title.setTextColor(color.primaryTextColor)
playerSongTotalTime.setTextColor(color.primaryTextColor)
text.setTextColor(color.secondaryTextColor)
songInfo.setTextColor(color.secondaryTextColor)
ViewUtil.setProgressDrawable(progressBar, color.backgroundColor)
binding.title.setTextColor(color.primaryTextColor)
binding.playerSongTotalTime.setTextColor(color.primaryTextColor)
binding.text.setTextColor(color.secondaryTextColor)
binding.songInfo.setTextColor(color.secondaryTextColor)
ViewUtil.setProgressDrawable(binding.progressBar, color.backgroundColor)
Handler().post {
Handler(Looper.myLooper()!!).post {
ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
binding.playerToolbar,
color.secondaryTextColor,
requireActivity()
)
}
}
override fun onFavoriteToggled() {
toggleFavorite(MusicPlayerRemote.currentSong)
}
@ -109,25 +120,33 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
title.text = song.title
text.text = String.format("%s \nby - %s", song.albumName, song.artistName)
binding.title.text = song.title
binding.text.text = String.format("%s \nby - %s", song.albumName, song.artistName)
if (PreferenceUtil.isSongInfo) {
songInfo.text = getSongInfo(song)
songInfo.show()
binding.songInfo.text = getSongInfo(song)
binding.songInfo.show()
} else {
songInfo.hide()
binding.songInfo.hide()
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
title.isSelected = true
progressBar.setOnClickListener(PlayPauseButtonOnClickHandler())
progressBar.setOnTouchListener(MiniPlayerFragment.FlingPlayBackController(requireContext()))
_binding = FragmentTinyPlayerBinding.bind(view)
binding.title.isSelected = true
binding.progressBar.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.progressBar.setOnTouchListener(ProgressHelper(requireContext()))
setUpPlayerToolbar()
setUpSubFragments()
binding.title.setOnClickListener {
goToAlbum(requireActivity())
}
binding.text.setOnClickListener {
goToArtist(requireActivity())
}
}
private fun setUpSubFragments() {
@ -139,7 +158,7 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
}
private fun setUpPlayerToolbar() {
playerToolbar.apply {
binding.playerToolbar.apply {
inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@TinyPlayerFragment)
@ -164,20 +183,113 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressBar.max = total
binding.progressBar.max = total
val animator = ObjectAnimator.ofInt(progressBar, "progress", progress)
if (isDragEnabled) {
binding.progressBar.progress = progress
} else {
animator = ObjectAnimator.ofInt(binding.progressBar, "progress", progress)
val animatorSet = AnimatorSet()
animatorSet.playSequentially(animator)
val animatorSet = AnimatorSet()
animatorSet.playSequentially(animator)
animatorSet.duration = 1500
animatorSet.interpolator = LinearInterpolator()
animatorSet.start()
playerSongTotalTime.text = String.format(
animatorSet.duration = 1500
animatorSet.interpolator = LinearInterpolator()
animatorSet.start()
}
binding.playerSongTotalTime.text = String.format(
"%s/%s", MusicUtil.getReadableDurationString(total.toLong()),
MusicUtil.getReadableDurationString(progress.toLong())
)
}
inner class ProgressHelper(context: Context) : View.OnTouchListener {
private var initialY: Int = 0
private var initialProgress = 0
private var progress: Int = 0
private val displayHeight = resources.displayMetrics.heightPixels
private var gestureDetector: GestureDetector
init {
gestureDetector = GestureDetector(context, object :
GestureDetector.SimpleOnGestureListener() {
override fun onLongPress(e: MotionEvent?) {
if (abs(e!!.y - initialY) <= 2) {
vibrate()
isDragEnabled = true
binding.progressBar.parent.requestDisallowInterceptTouchEvent(true)
animator.pause()
}
super.onLongPress(e)
}
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
if (abs(velocityX) > abs(velocityY)) {
if (velocityX < 0) {
MusicPlayerRemote.playNextSong()
return true
} else if (velocityX > 0) {
MusicPlayerRemote.playPreviousSong()
return true
}
}
return false
}
})
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
initialProgress = MusicPlayerRemote.songProgressMillis
initialY = event.y.toInt()
progressViewUpdateHelper.stop()
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
progressViewUpdateHelper.start()
if (isDragEnabled) {
MusicPlayerRemote.seekTo(progress)
isDragEnabled = false
return true
}
}
MotionEvent.ACTION_MOVE -> {
if (isDragEnabled) {
val diffY = (initialY - event.y).toInt()
progress =
initialProgress + diffY * (binding.progressBar.max / displayHeight) // Multiplier
if (progress > 0 && progress < binding.progressBar.max) {
onUpdateProgressViews(
progress,
MusicPlayerRemote.songDurationMillis
)
}
}
}
}
return gestureDetector.onTouchEvent(event)
}
private fun vibrate() {
val v = requireContext().getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v!!.vibrate(VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE))
} else {
v!!.vibrate(10)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -1,77 +1,101 @@
package code.name.monkey.retromusic.fragments.playlists
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
import androidx.core.view.ViewCompat
import androidx.core.view.doOnPreDraw
import androidx.core.view.isVisible
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.resolveColor
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song
import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import code.name.monkey.retromusic.util.RetroColorUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.transition.MaterialSharedAxis
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail) {
class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail),
ICabHolder {
private val arguments by navArgs<PlaylistDetailsFragmentArgs>()
private val viewModel by viewModel<PlaylistDetailsViewModel> {
parametersOf(arguments.extraPlaylist)
}
private lateinit var playlist: PlaylistWithSongs
private lateinit var playlistSongAdapter: ShuffleButtonSongAdapter
private var _binding: FragmentPlaylistDetailBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment_container
duration = 300L
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().resolveColor(R.attr.colorSurface))
setPathMotion(MaterialArcMotion())
}
}
private lateinit var playlist: PlaylistWithSongs
private lateinit var playlistSongAdapter: OrderablePlaylistSongAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlaylistDetailBinding.bind(view)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(false)
mainActivity.addMusicServiceEventListener(viewModel)
mainActivity.setSupportActionBar(toolbar)
ViewCompat.setTransitionName(container, "playlist")
mainActivity.setSupportActionBar(binding.toolbar)
ViewCompat.setTransitionName(binding.container, "playlist")
playlist = arguments.extraPlaylist
toolbar.title = playlist.playlistEntity.playlistName
binding.toolbar.title = playlist.playlistEntity.playlistName
setUpRecyclerView()
viewModel.getSongs().observe(viewLifecycleOwner, {
songs(it.toSongs())
})
postponeEnterTransition()
requireView().doOnPreDraw { startPostponedEnterTransition() }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
private fun setUpRecyclerView() {
playlistSongAdapter = ShuffleButtonSongAdapter(
playlistSongAdapter = OrderablePlaylistSongAdapter(
playlist.playlistEntity,
requireActivity(),
ArrayList(),
R.layout.item_list,
null,
this
)
recyclerView.apply {
val dragDropManager = RecyclerViewDragDropManager()
val wrappedAdapter: RecyclerView.Adapter<*> =
dragDropManager.createWrappedAdapter(playlistSongAdapter)
val animator: GeneralItemAnimator = DraggableItemAnimator()
binding.recyclerView.itemAnimator = animator
dragDropManager.attachRecyclerView(binding.recyclerView)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = playlistSongAdapter
binding.recyclerView.adapter = wrappedAdapter
}
playlistSongAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
@ -93,32 +117,70 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
private fun checkForPadding() {
val height = dipToPix(52f)
recyclerView.setPadding(0, 0, 0, height.toInt())
binding.recyclerView.setPadding(0, 0, 0, height.toInt())
}
private fun checkIsEmpty() {
checkForPadding()
empty.isVisible = playlistSongAdapter.itemCount == 0
emptyText.isVisible = playlistSongAdapter.itemCount == 0
binding.empty.isVisible = playlistSongAdapter.itemCount == 0
binding.emptyText.isVisible = playlistSongAdapter.itemCount == 0
}
override fun onDestroy() {
recyclerView?.itemAnimator = null
recyclerView?.adapter = null
super.onDestroy()
_binding = null
}
override fun onPause() {
playlistSongAdapter.saveSongs(playlist.playlistEntity)
super.onPause()
}
private fun showEmptyView() {
empty.visibility = View.VISIBLE
emptyText.visibility = View.VISIBLE
binding.empty.visibility = View.VISIBLE
binding.emptyText.visibility = View.VISIBLE
}
fun songs(songs: List<Song>) {
progressIndicator.hide()
binding.progressIndicator.hide()
if (songs.isNotEmpty()) {
Log.i("Updated", songs[0].title)
playlistSongAdapter.swapDataSet(songs)
} else {
showEmptyView()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()
return true
}
}
return false
}
private var cab: MaterialCab? = null
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
cab?.let {
println("Cab")
if (it.isActive) {
it.finish()
}
}
cab = MaterialCab(mainActivity, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(surfaceColor()))
.start(callback)
return cab as MaterialCab
}
}

View file

@ -41,4 +41,5 @@ class PlaylistDetailsViewModel(
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
override fun onFavoriteStateChanged() {}
}

View file

@ -15,17 +15,11 @@
package code.name.monkey.retromusic.fragments.playlists
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import android.view.*
import androidx.core.os.bundleOf
import androidx.core.view.MenuCompat
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
@ -35,12 +29,13 @@ import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeF
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.transition.MaterialElevationScale
import kotlinx.android.synthetic.main.fragment_library.*
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.transition.MaterialSharedAxis
class PlaylistsFragment :
AbsRecyclerViewCustomGridSizeFragment<PlaylistAdapter, GridLayoutManager>(),
IPlaylistClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, {
@ -51,6 +46,8 @@ class PlaylistsFragment :
})
}
override val titleRes: Int
get() = R.string.playlists
override val emptyMessage: Int
get() = R.string.no_playlists
@ -68,11 +65,6 @@ class PlaylistsFragment :
)
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu.removeItem(R.id.action_grid_size)
@ -81,7 +73,9 @@ class PlaylistsFragment :
menu.add(0, R.id.action_import_playlist, 0, R.string.import_playlist)
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
MenuCompat.setGroupDividerEnabled(menu, true);
MenuCompat.setGroupDividerEnabled(menu, true)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -160,7 +154,7 @@ class PlaylistsFragment :
}
override fun loadGridSize(): Int {
return 1
return 2
}
override fun saveGridSize(gridColumns: Int) {
@ -168,7 +162,7 @@ class PlaylistsFragment :
}
override fun loadGridSizeLand(): Int {
return 2
return 4
}
override fun saveGridSizeLand(gridColumns: Int) {
@ -176,7 +170,7 @@ class PlaylistsFragment :
}
override fun loadLayoutRes(): Int {
return R.layout.item_list
return R.layout.item_card
}
override fun saveLayoutRes(layoutRes: Int) {
@ -184,17 +178,13 @@ class PlaylistsFragment :
}
override fun onPlaylistClick(playlistWithSongs: PlaylistWithSongs, view: View) {
exitTransition = MaterialElevationScale(false).apply {
duration = 300L
}
reenterTransition = MaterialElevationScale(true).apply {
duration = 300L
}
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(requireView())
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
findNavController().navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to playlistWithSongs),
null,
FragmentNavigatorExtras(view to "playlist")
null
)
}
}

View file

@ -28,7 +28,6 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropM
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.activity_playing_queue.*
/**
* Created by hemanths on 2019-12-08.
@ -39,6 +38,8 @@ class PlayingQueueFragment : AbsRecyclerViewFragment<PlayingQueueAdapter, Linear
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
override val titleRes: Int
get() = R.string.now_playing_queue
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -59,9 +60,9 @@ class PlayingQueueFragment : AbsRecyclerViewFragment<PlayingQueueAdapter, Linear
recyclerView().layoutManager = layoutManager
recyclerView().adapter = wrappedAdapter
recyclerView().itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(recyclerView)
recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView())
recyclerViewDragDropManager?.attachRecyclerView(recyclerView())
recyclerViewSwipeManager?.attachRecyclerView(recyclerView())
layoutManager?.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
@ -104,7 +105,7 @@ class PlayingQueueFragment : AbsRecyclerViewFragment<PlayingQueueAdapter, Linear
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
recyclerView().stopScroll()
layoutManager?.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}

View file

@ -17,66 +17,65 @@ package code.name.monkey.retromusic.fragments.search
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.content.res.ColorStateList
import android.os.Bundle
import android.speech.RecognizerIntent
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.CompoundButton
import androidx.core.view.children
import androidx.core.view.doOnPreDraw
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.SearchAdapter
import code.name.monkey.retromusic.databinding.FragmentSearchBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.android.synthetic.main.fragment_search.*
import com.google.android.material.transition.MaterialSharedAxis
import java.util.*
import kotlin.collections.ArrayList
class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWatcher {
class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWatcher,
CompoundButton.OnCheckedChangeListener {
companion object {
const val QUERY = "query"
const val REQ_CODE_SPEECH_INPUT = 9001
}
private var _binding: FragmentSearchBinding? = null
private val binding get() = _binding!!
private lateinit var searchAdapter: SearchAdapter
private var query: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment_container
duration = 300L
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().resolveColor(R.attr.colorSurface))
setPathMotion(MaterialArcMotion())
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setBottomBarVisibility(false)
mainActivity.setSupportActionBar(toolbar)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
_binding = FragmentSearchBinding.bind(view)
mainActivity.setSupportActionBar(binding.toolbar)
libraryViewModel.clearSearchResult()
setupRecyclerView()
voiceSearch.setOnClickListener { startMicSearch() }
clearText.setOnClickListener { searchView.clearText() }
searchView.apply {
binding.voiceSearch.setOnClickListener { startMicSearch() }
binding.clearText.setOnClickListener { binding.searchView.clearText() }
binding.searchView.apply {
addTextChangedListener(this@SearchFragment)
focusAndShowKeyboard()
}
keyboardPopup.apply {
binding.keyboardPopup.apply {
accentColor()
setOnClickListener {
searchView.focusAndShowKeyboard()
binding.searchView.focusAndShowKeyboard()
}
}
if (savedInstanceState != null) {
@ -85,6 +84,36 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
libraryViewModel.getSearchResult().observe(viewLifecycleOwner, {
showData(it)
})
setupChips()
postponeEnterTransition()
view.doOnPreDraw {
startPostponedEnterTransition()
}
}
private fun setupChips() {
val chips = binding.searchFilterGroup.children.map { it as Chip }
val states = arrayOf(
intArrayOf(-android.R.attr.state_checked),
intArrayOf(android.R.attr.state_checked)
)
val colors = intArrayOf(
android.R.color.transparent,
ThemeStore.accentColor(requireContext())
)
chips.forEach {
it.chipBackgroundColor = ColorStateList(states, colors)
it.chipIconTint = ColorStateList.valueOf(ThemeStore.textColorPrimary(requireContext()))
it.chipStrokeColor =
ColorStateList.valueOf(ThemeStore.textColorSecondary(requireContext()))
.withAlpha(30)
it.closeIconTint =
ColorStateList.valueOf(ThemeStore.textColorPrimaryInverse(requireContext()))
it.chipStrokeWidth = 2F
it.setOnCheckedChangeListener(this)
}
}
private fun showData(data: List<Any>) {
@ -100,21 +129,21 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
searchAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
empty.isVisible = searchAdapter.itemCount < 1
binding.empty.isVisible = searchAdapter.itemCount < 1
val height = dipToPix(52f)
recyclerView.setPadding(0, 0, 0, height.toInt())
binding.recyclerView.setPadding(0, 0, 0, height.toInt())
}
})
recyclerView.apply {
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = searchAdapter
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
keyboardPopup.shrink()
binding.keyboardPopup.shrink()
} else if (dy < 0) {
keyboardPopup.extend()
binding.keyboardPopup.extend()
}
}
})
@ -122,7 +151,7 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
}
override fun afterTextChanged(newText: Editable?) {
search(newText.toString())
if (!newText.isNullOrEmpty()) search(newText.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
@ -133,10 +162,17 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
private fun search(query: String) {
this.query = query
TransitionManager.beginDelayedTransition(appBarLayout)
voiceSearch.isGone = query.isNotEmpty()
clearText.isVisible = query.isNotEmpty()
libraryViewModel.search(query)
TransitionManager.beginDelayedTransition(binding.appBarLayout)
binding.voiceSearch.isGone = query.isNotEmpty()
binding.clearText.isVisible = query.isNotEmpty()
val filters = getFilters()
libraryViewModel.search(query, filters)
}
private fun getFilters(): List<Boolean> {
return binding.searchFilterGroup.children.toList().map {
(it as Chip).isChecked
}
}
private fun startMicSearch() {
@ -161,6 +197,17 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
override fun onDestroyView() {
hideKeyboard(view)
super.onDestroyView()
_binding = null
}
override fun onPause() {
super.onPause()
hideKeyboard(view)
}
override fun onResume() {
super.onResume()
mainActivity.setBottomBarVisibility(false)
}
private fun hideKeyboard(view: View?) {
@ -170,6 +217,27 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
}
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
val checkedChip = (buttonView as Chip)
checkedChip.isCloseIconVisible = isChecked
if (isChecked) {
val color = ThemeStore.textColorPrimaryInverse(requireContext())
checkedChip.apply {
setTextColor(color)
chipIconTint = ColorStateList.valueOf(color)
chipStrokeWidth = 0F
}
} else {
val color = ThemeStore.textColorPrimary(requireContext())
checkedChip.apply {
setTextColor(color)
chipIconTint = ColorStateList.valueOf(color)
chipStrokeWidth = 2F
}
}
search(binding.searchView.text.toString())
}
}
fun TextInputEditText.clearText() {

View file

@ -87,6 +87,10 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() {
val fragment = BlacklistPreferenceDialog.newInstance()
fragment.show(childFragmentManager, preference.key)
}
is DurationPreference -> {
val fragment = DurationPreferenceDialog.newInstance()
fragment.show(childFragmentManager, preference.key)
}
else -> super.onDisplayPreferenceDialog(preference)
}
}

View file

@ -24,12 +24,17 @@ import androidx.navigation.fragment.findNavController
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.util.NavigationUtil
import kotlinx.android.synthetic.main.fragment_main_settings.*
class MainSettingsFragment : Fragment(), View.OnClickListener {
private var _binding: FragmentMainSettingsBinding? = null
private val binding get() = _binding!!
override fun onClick(view: View) {
when (view.id) {
R.id.generalSettings -> findNavController().navigate(R.id.action_mainSettingsFragment_to_themeSettingsFragment)
@ -47,34 +52,40 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_main_settings, container, false)
): View {
_binding = FragmentMainSettingsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
generalSettings.setOnClickListener(this)
audioSettings.setOnClickListener(this)
nowPlayingSettings.setOnClickListener(this)
personalizeSettings.setOnClickListener(this)
imageSettings.setOnClickListener(this)
notificationSettings.setOnClickListener(this)
otherSettings.setOnClickListener(this)
aboutSettings.setOnClickListener(this)
binding.generalSettings.setOnClickListener(this)
binding.audioSettings.setOnClickListener(this)
binding.nowPlayingSettings.setOnClickListener(this)
binding.personalizeSettings.setOnClickListener(this)
binding.imageSettings.setOnClickListener(this)
binding.notificationSettings.setOnClickListener(this)
binding.otherSettings.setOnClickListener(this)
binding.aboutSettings.setOnClickListener(this)
buyProContainer.apply {
binding.buyProContainer.apply {
if (App.isProVersion()) hide() else show()
setOnClickListener {
NavigationUtil.goToProVersion(requireContext())
}
}
buyPremium.setOnClickListener {
binding.buyPremium.setOnClickListener {
NavigationUtil.goToProVersion(requireContext())
}
ThemeStore.accentColor(requireContext()).let {
buyPremium.setTextColor(it)
diamondIcon.imageTintList = ColorStateList.valueOf(it)
binding.buyPremium.setTextColor(it)
binding.diamondIcon.imageTintList = ColorStateList.valueOf(it)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -23,7 +23,10 @@ import code.name.monkey.retromusic.LAST_ADDED_CUTOFF
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType.HomeSections
import com.google.android.play.core.splitinstall.SplitInstallManagerFactory
import com.google.android.play.core.splitinstall.SplitInstallRequest
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import java.util.*
/**
* @author Hemanth S (h4h13).
@ -35,6 +38,7 @@ class OtherSettingsFragment : AbsSettingsFragment() {
override fun invalidateSettings() {
val languagePreference: ATEListPreference? = findPreference(LANGUAGE_NAME)
languagePreference?.setOnPreferenceChangeListener { _, _ ->
println("Invalidated")
requireActivity().recreate()
return@setOnPreferenceChangeListener true
}
@ -55,6 +59,21 @@ class OtherSettingsFragment : AbsSettingsFragment() {
val languagePreference: Preference? = findPreference(LANGUAGE_NAME)
languagePreference?.setOnPreferenceChangeListener { prefs, newValue ->
setSummary(prefs, newValue)
val code = newValue.toString()
val manager = SplitInstallManagerFactory.create(requireContext())
if (code != "auto") {
// Try to download language resources
val request =
SplitInstallRequest.newBuilder().addLanguage(Locale.forLanguageTag(code))
.build()
manager.startInstall(request)
// Recreate the activity on download complete
.addOnCompleteListener {
activity?.recreate()
}
} else {
requireActivity().recreate()
}
true
}
}

View file

@ -18,6 +18,8 @@ import android.os.Build
import android.os.Bundle
import androidx.preference.Preference
import androidx.preference.TwoStatePreference
import code.name.monkey.appthemehelper.ACCENT_COLORS
import code.name.monkey.appthemehelper.ACCENT_COLORS_SUB
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
@ -26,7 +28,8 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.color.ColorChooserDialog
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.colorChooser
/**
* @author Hemanth S (h4h13).
@ -55,12 +58,19 @@ class ThemeSettingsFragment : AbsSettingsFragment() {
val accentColor = ThemeStore.accentColor(requireContext())
accentColorPref?.setColor(accentColor, ColorUtil.darkenColor(accentColor))
accentColorPref?.setOnPreferenceClickListener {
ColorChooserDialog.Builder(requireContext(), R.string.accent_color)
.accentMode(true)
.allowUserColorInput(true)
.allowUserColorInputAlpha(false)
.preselect(accentColor)
.show(requireActivity())
MaterialDialog(requireContext()).show {
colorChooser(
initialSelection = accentColor,
showAlphaSelector = false,
colors = ACCENT_COLORS,
subColors = ACCENT_COLORS_SUB, allowCustomArgb = true
) { _, color ->
ThemeStore.editTheme(requireContext()).accentColor(color).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
requireActivity().recreate()
}
}
return@setOnPreferenceClickListener true
}
val blackTheme: ATESwitchPreference? = findPreference(BLACK_THEME)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
* Cop()yright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
@ -16,8 +16,8 @@ package code.name.monkey.retromusic.fragments.songs
import android.os.Bundle
import android.view.*
import androidx.activity.addCallback
import androidx.annotation.LayoutRes
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
@ -31,6 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.gms.cast.framework.CastButtonFactory
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>(),
ICabHolder {
@ -42,13 +43,29 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
else
adapter?.swapDataSet(listOf())
})
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
}
override val titleRes: Int
get() = R.string.songs
override val emptyMessage: Int
get() = R.string.no_songs
override fun createLayoutManager(): GridLayoutManager {
return GridLayoutManager(requireActivity(), getGridSize())
return GridLayoutManager(requireActivity(), getGridSize()).apply {
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (position == 0) getGridSize() else 1
}
}
}
}
override fun createAdapter(): SongAdapter {
@ -112,6 +129,8 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
val layoutItem = menu.findItem(R.id.action_layout_type)
setupLayoutMenu(layoutItem.subMenu)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
private fun setUpSortOrderMenu(
@ -175,6 +194,13 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
R.string.sort_order_composer
).isChecked =
currentSortOrder == SongSortOrder.COMPOSER
sortOrderMenu.add(
0,
R.id.action_song_sort_order_album_artist,
8,
R.string.album_artist
).isChecked =
currentSortOrder == SongSortOrder.SONG_ALBUM_ARTIST
sortOrderMenu.setGroupCheckable(0, true, true)
}
@ -249,6 +275,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
R.id.action_song_sort_order_asc -> SongSortOrder.SONG_A_Z
R.id.action_song_sort_order_desc -> SongSortOrder.SONG_Z_A
R.id.action_song_sort_order_artist -> SongSortOrder.SONG_ARTIST
R.id.action_song_sort_order_album_artist -> SongSortOrder.SONG_ALBUM_ARTIST
R.id.action_song_sort_order_album -> SongSortOrder.SONG_ALBUM
R.id.action_song_sort_order_year -> SongSortOrder.SONG_YEAR
R.id.action_song_sort_order_date -> SongSortOrder.SONG_DATE
@ -306,6 +333,11 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
return false
}
override fun onResume() {
super.onResume()
libraryViewModel.forceReload(ReloadType.Songs)
}
companion object {
@JvmField
var TAG: String = SongsFragment::class.java.simpleName
@ -318,7 +350,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
private var cab: MaterialCab? = null
fun handleBackPress(): Boolean {
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive) {
it.finish()