package code.name.monkey.retromusic.fragments.albums import android.app.ActivityOptions import android.content.Intent import android.os.Bundle import android.view.* import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController 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.ThemeStore import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor 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.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.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.applyOutlineColor import code.name.monkey.retromusic.extensions.show 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.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.SingleColorTarget import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.network.Result 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.RetroUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.Glide 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 import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import java.util.* class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details), AlbumClickListener { private val arguments by navArgs() private val detailsViewModel by viewModel { parametersOf(arguments.extraAlbumId) } private lateinit var simpleSongAdapter: SimpleSongAdapter private lateinit var album: Album private val savedSortOrder: String get() = PreferenceUtil.albumDetailSongSortOrder override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) setHasOptionsMenu(true) mainActivity.hideBottomBarVisibility(false) mainActivity.addMusicServiceEventListener(detailsViewModel) mainActivity.setSupportActionBar(toolbar) toolbar.title = null postponeEnterTransition() detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { startPostponedEnterTransition() showAlbum(it) }) setupRecyclerView() artistImage.setOnClickListener { requireActivity().findNavController(R.id.fragment_container) .navigate( R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to album.artistId) ) } playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) } shuffleAction.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue( album.songs!!, true ) } aboutAlbumText.setOnClickListener { if (aboutAlbumText.maxLines == 4) { aboutAlbumText.maxLines = Integer.MAX_VALUE } else { aboutAlbumText.maxLines = 4 } } image.apply { transitionName = getString(R.string.transition_album_art) } } override fun onDestroy() { super.onDestroy() playerActivity?.removeMusicServiceEventListener(detailsViewModel) } private fun setupRecyclerView() { simpleSongAdapter = SimpleSongAdapter( requireActivity() as AppCompatActivity, ArrayList(), R.layout.item_song, null ) recyclerView.apply { layoutManager = LinearLayoutManager(requireContext()) itemAnimator = DefaultItemAnimator() isNestedScrollingEnabled = false adapter = simpleSongAdapter } } private fun showAlbum(album: Album) { if (album.songs!!.isEmpty()) { return } this.album = album albumTitle.text = album.title val songText = resources.getQuantityString( R.plurals.albumSongs, album.songCount, album.songCount ) songTitle.text = songText if (MusicUtil.getYearString(album.year) == "-") { albumText.text = String.format( "%s • %s", album.artistName, MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) ) } else { albumText.text = String.format( "%s • %s • %s", album.artistName, MusicUtil.getYearString(album.year), MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) ) } loadAlbumCover(album) simpleSongAdapter.swapDataSet(album.songs) detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer { loadArtistImage(it) }) detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, Observer { result -> when (result) { is Result.Loading -> { println("Loading") } is Result.Error -> { println("Error") } is Result.Success -> { aboutAlbum(result.data) } } }) } private fun moreAlbums(albums: List) { moreTitle.show() moreRecyclerView.show() moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName) val albumAdapter = HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, null, this) moreRecyclerView.layoutManager = GridLayoutManager( requireContext(), 1, GridLayoutManager.HORIZONTAL, false ) moreRecyclerView.adapter = albumAdapter } private fun aboutAlbum(lastFmAlbum: LastFmAlbum) { if (lastFmAlbum.album != null) { if (lastFmAlbum.album.wiki != null) { aboutAlbumText.show() aboutAlbumTitle.show() aboutAlbumTitle.text = String.format(getString(R.string.about_album_label), lastFmAlbum.album.name) aboutAlbumText.text = lastFmAlbum.album.wiki.content } if (lastFmAlbum.album.listeners.isNotEmpty()) { listeners.show() listenersLabel.show() scrobbles.show() scrobblesLabel.show() listeners.text = RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat()) scrobbles.text = RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat()) } } } private fun loadArtistImage(artist: Artist) { detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner, Observer { moreAlbums(it) }) ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist) .forceDownload(PreferenceUtil.isAllowedToDownloadMetadata()) .generatePalette(requireContext()) .build() .dontAnimate() .dontTransform() .into(object : RetroMusicColoredTarget(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) { override fun onColorReady(color: Int) { setColors(color) } }) } private fun setColors(color: Int) { val finalColor = if (PreferenceUtil.isAdaptiveColor) color else ThemeStore.accentColor(requireContext()) shuffleAction.applyColor(finalColor) playAction.applyOutlineColor(finalColor) } override fun onAlbumClick(albumId: Int, view: View) { findNavController().navigate( R.id.albumDetailsFragment, bundleOf(EXTRA_ALBUM_ID to albumId) ) } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.menu_album_detail, menu) val sortOrder = menu.findItem(R.id.action_sort_order) setUpSortOrderMenu(sortOrder.subMenu) ToolbarContentTintHelper.handleOnCreateOptionsMenu( requireContext(), toolbar, menu, getToolbarBackgroundColor(toolbar) ) } override fun onOptionsItemSelected(item: MenuItem): Boolean { return handleSortOrderMenuItem(item) } private fun handleSortOrderMenuItem(item: MenuItem): Boolean { var sortOrder: String? = null val songs = simpleSongAdapter.dataSet 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().fetchPlaylists() withContext(Dispatchers.Main) { AddToPlaylistDialog.create(playlists, songs) .show(childFragmentManager, "ADD_PLAYLIST") } } return true } R.id.action_delete_from_device -> { DeleteSongsDialog.create(songs).show(childFragmentManager, "DELETE_SONGS") return true } R.id.action_tag_editor -> { val intent = Intent(requireContext(), AlbumTagEditorActivity::class.java) intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id) val options = ActivityOptions.makeSceneTransitionAnimation( requireActivity(), albumCoverContainer, "${getString(R.string.transition_album_art)}_${album.id}" ) startActivityForResult( intent, TAG_EDITOR_REQUEST, options.toBundle() ) return true } /*Sort*/ R.id.action_sort_order_title -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_A_Z R.id.action_sort_order_title_desc -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_Z_A R.id.action_sort_order_track_list -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST R.id.action_sort_order_artist_song_duration -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_DURATION } if (sortOrder != null) { item.isChecked = true setSaveSortOrder(sortOrder) } return true } private fun setUpSortOrderMenu(sortOrder: SubMenu) { when (savedSortOrder) { SortOrder.AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title) .isChecked = true SortOrder.AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc) .isChecked = true SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list) .isChecked = true SortOrder.AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration) .isChecked = true } } private fun setSaveSortOrder(sortOrder: String) { PreferenceUtil.albumDetailSongSortOrder = sortOrder when (sortOrder) { SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 -> o1.trackNumber.compareTo( o2.trackNumber ) }) SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 -> o1.title.compareTo( o2.title ) }) SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 -> o2.title.compareTo( o1.title ) }) SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 -> o1.duration.compareTo( o2.duration ) }) } album.songs?.let { simpleSongAdapter.swapDataSet(it) } } companion object { const val TAG_EDITOR_REQUEST = 9002 } }