diff --git a/app/src/main/java/melody/offline/music/adapter/ResponsiveListAdapter.kt b/app/src/main/java/melody/offline/music/adapter/ResponsiveListAdapter.kt index 1d5af07..3d3748d 100644 --- a/app/src/main/java/melody/offline/music/adapter/ResponsiveListAdapter.kt +++ b/app/src/main/java/melody/offline/music/adapter/ResponsiveListAdapter.kt @@ -13,6 +13,7 @@ import melody.offline.music.databinding.MusicResponsiveItemBinding import melody.offline.music.innertube.models.MusicCarouselShelfRenderer import melody.offline.music.media.MediaControllerManager import melody.offline.music.util.AnalysisUtil +import melody.offline.music.util.LogTag class ResponsiveListAdapter( private val context: Context, @@ -83,15 +84,20 @@ class ResponsiveListAdapter( intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc) context.startActivity(intent) - if(itemClickListener!=null){ + if (itemClickListener != null) { itemClickListener?.onItemClick(position) } } + holder.binding.moreBtn.setOnClickListener { + if (itemMoreClickListener != null) { + itemMoreClickListener?.onItemMoreClick(position) + } + } } override fun getItemCount(): Int = list.size - inner class ViewHolder(private val binding: MusicResponsiveItemBinding) : + inner class ViewHolder(val binding: MusicResponsiveItemBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(url: String?, name: String?, desc: String?, videoID: String?) { @@ -129,4 +135,14 @@ class ResponsiveListAdapter( interface OnItemClickListener { fun onItemClick(position: Int) } + + private var itemMoreClickListener: OnItemMoreClickListener? = null + + fun setOnItemMoreClickListener(listener: OnItemMoreClickListener) { + itemMoreClickListener = listener + } + + interface OnItemMoreClickListener { + fun onItemMoreClick(position: Int) + } } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/fragment/MoHomeFragment.kt b/app/src/main/java/melody/offline/music/fragment/MoHomeFragment.kt index f82e69d..657a40c 100644 --- a/app/src/main/java/melody/offline/music/fragment/MoHomeFragment.kt +++ b/app/src/main/java/melody/offline/music/fragment/MoHomeFragment.kt @@ -1,9 +1,27 @@ package melody.offline.music.fragment +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.OptIn +import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat +import androidx.core.net.toUri +import androidx.media3.common.util.UnstableApi +import androidx.media3.exoplayer.offline.Download +import androidx.media3.exoplayer.offline.DownloadRequest +import androidx.media3.exoplayer.offline.DownloadService +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.bottomsheet.BottomSheetDialog import com.gyf.immersionbar.ktx.immersionBar +import kotlinx.coroutines.Dispatchers import melody.offline.music.databinding.FragmentMoHomeBinding import melody.offline.music.innertube.Innertube import melody.offline.music.innertube.models.MusicCarouselShelfRenderer @@ -14,12 +32,32 @@ import melody.offline.music.view.MusicResponsiveListView import melody.offline.music.view.MusicTowRowListView import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import kotlinx.coroutines.selects.select +import kotlinx.coroutines.withContext +import melody.offline.music.App +import melody.offline.music.R +import melody.offline.music.activity.MoListDetailsActivity +import melody.offline.music.adapter.NewPlayListAdapter +import melody.offline.music.ads.AdPlacement import melody.offline.music.ads.AnalysisAdState +import melody.offline.music.ads.LolAdWrapper +import melody.offline.music.bean.FavoriteBean +import melody.offline.music.bean.OfflineBean +import melody.offline.music.bean.Playlist +import melody.offline.music.bean.PlaylistItem +import melody.offline.music.service.MyDownloadService import melody.offline.music.util.AnalysisUtil +import melody.offline.music.util.DownloadUtil +import melody.offline.music.util.FileSizeConverter +import melody.offline.music.util.asPlaylistItem +import melody.offline.music.view.ListMoreBottomSheetDialog import org.json.JSONObject -class MoHomeFragment : MoBaseFragment() { +@OptIn(UnstableApi::class) +class MoHomeFragment : MoBaseFragment(), + MusicResponsiveListView.OnMoreClickListener, ListMoreBottomSheetDialog.ListMoreViewListener, + ListMoreBottomSheetDialog.UpdateAdapterListener { interface MoHomeFragmentToSearchClickListener { @@ -31,12 +69,18 @@ class MoHomeFragment : MoBaseFragment() { } private var toSearchClickListener: MoHomeFragmentToSearchClickListener? = null - - + private var moreDialog: ListMoreBottomSheetDialog? = null private val requests: Channel = Channel(Channel.UNLIMITED) - enum class Request { - TryAgain, + sealed class Request { + data object TryAgain : Request() + data class ShowDialog(val bean: MusicCarouselShelfRenderer.Content) : Request() + data class UpdateFavorite(val bean: PlaylistItem) : Request() + data class OnFavorites(val bean: PlaylistItem) : Request() + data class OnDownload(val bean: PlaylistItem) : Request() + data class OnDownloadRemove(val bean: PlaylistItem) : Request() + data class OnUpdateDownloadUi(val bean: PlaylistItem) : Request() + data class OnAddPlaylist(val bean: PlaylistItem) : Request() } override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentMoHomeBinding @@ -63,6 +107,166 @@ class MoHomeFragment : MoBaseFragment() { Request.TryAgain -> { initData() } + + is Request.ShowDialog -> { + moreDialog = ListMoreBottomSheetDialog( + requireActivity(), + initMoreDialogData(it.bean), + requireActivity(), + this@MoHomeFragment + ) + moreDialog?.setListMoreViewListener(this@MoHomeFragment) + moreDialog?.show() + } + + is Request.UpdateFavorite -> { + val currentFavoriteBean = + App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) + if (currentFavoriteBean != null) { + updateFavoriteUi(currentFavoriteBean.isFavorite) + } else { + updateFavoriteUi(false) + } + } + + is Request.OnFavorites -> { + val jsonObject = JSONObject() + jsonObject.put( + "song_title", it.bean.title + ) + val songMap = mutableMapOf( + Pair( + AnalysisUtil.PARAM_VALUE, jsonObject.toString() + ) + ) + val currentFavoriteBean = + App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) + if (currentFavoriteBean != null) { + currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite + App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean) + if (currentFavoriteBean.isFavorite) { + AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap) + } else { + AnalysisUtil.logEvent( + AnalysisUtil.PLAYER_B_UN_LOVE_CLICK, songMap + ) + } + } else { + val b = FavoriteBean( + videoId = it.bean.videoId, + title = it.bean.title, + name = it.bean.name, + thumbnail = it.bean.thumbnail, + isFavorite = true + ) + App.appFavoriteDBManager.insertFavoriteBean(b) + AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap) + } + requests.trySend(Request.UpdateFavorite(it.bean)) + } + + is Request.OnDownload -> { + val id = it.bean.videoId + val offBean = + App.appOfflineDBManager.getOfflineBeanByID(id)//得到当前ID的本地数据 + if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {//判断当前数据库是否有这条数据。 + showRemoveDownloadDialogHint(it.bean) + } else { + val isFavorite = + App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) + //判断是否已经下载了这条数据,已经下载,就直接进行数据库数据存储,反之走下载流程。 + if (DownloadUtil.downloadResourceExist(id)) { + val favoriteBean = FavoriteBean( + id, + it.bean.title, + it.bean.name, + it.bean.thumbnail, + isFavorite?.isFavorite ?: false + ) + insertOfflineData(favoriteBean) + it.bean.isOffline = true//更改状态 + requests.trySend(Request.OnUpdateDownloadUi(it.bean)) + } else { + val downloadRequest = DownloadRequest.Builder(id, id.toUri()) + .setCustomCacheKey(id).build() + + val downloadCount = DownloadUtil.getCurrentDownloads() + if (downloadCount >= 3) { + Toast.makeText( + requireActivity(), + getString(R.string.download_tips), + Toast.LENGTH_LONG + ).show() + } else { + DownloadService.sendAddDownload( + requireActivity(), + MyDownloadService::class.java, + downloadRequest, + false + ) + + LolAdWrapper.shared.showAdTiming( + requireActivity(), AdPlacement.INST_DOWNLOAD + ) + val favoriteBean = FavoriteBean( + id, + it.bean.title, + it.bean.name, + it.bean.thumbnail, + isFavorite?.isFavorite ?: false + ) + insertOfflineData(favoriteBean) + val jsonObject = JSONObject() + jsonObject.put( + "download_id", favoriteBean.videoId + ) + val songMap = mutableMapOf( + Pair( + AnalysisUtil.PARAM_VALUE, jsonObject.toString() + ) + ) + AnalysisUtil.logEvent( + AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap + ) + + LolAdWrapper.shared.loadAdIfNotCached( + requireActivity(), AdPlacement.INST_DOWNLOAD + ) + } + } + } + } + + is Request.OnDownloadRemove -> { + val currentOfflineBean = + App.appOfflineDBManager.getOfflineBeanByID(it.bean.videoId) + if (currentOfflineBean != null) { + App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean) + + it.bean.isOffline = false + } + requests.trySend(Request.OnUpdateDownloadUi(it.bean)) + } + + is Request.OnUpdateDownloadUi -> { + moreDialog?.updateDownloadBtnUi(it.bean.isOffline)//更新对话框的ui + } + + is Request.OnAddPlaylist -> { + val isFavorite = + App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) != null + + showAddPlaylistBottomDialog( + FavoriteBean( + videoId = it.bean.videoId, + title = it.bean.title, + name = it.bean.name, + thumbnail = it.bean.thumbnail, + isFavorite + ) + ) + } + } } events.onReceive { @@ -97,19 +301,16 @@ class MoHomeFragment : MoBaseFragment() { for (home: Innertube.HomePage in it.homePage) { for (content: MusicCarouselShelfRenderer.Content in home.contents) { if (content.musicResponsiveListItemRenderer != null) { - binding.contentLayout.addView( - MusicResponsiveListView( - requireActivity(), - home - ) - ) + val musicResponsiveListView = + MusicResponsiveListView(requireActivity(), home) + musicResponsiveListView.setOnItemMoreClickListener(this) + binding.contentLayout.addView(musicResponsiveListView) break } if (content.musicTwoRowItemRenderer != null) { binding.contentLayout.addView( MusicTowRowListView( - requireActivity(), - home + requireActivity(), home ) ) break @@ -135,14 +336,14 @@ class MoHomeFragment : MoBaseFragment() { if (content.musicResponsiveListItemRenderer != null) { val musicResponsiveListView = MusicResponsiveListView(requireActivity(), home) + musicResponsiveListView.setOnItemMoreClickListener(this) binding.contentLayout.addView(musicResponsiveListView) break } if (content.musicTwoRowItemRenderer != null) { binding.contentLayout.addView( MusicTowRowListView( - requireActivity(), - home + requireActivity(), home ) ) break @@ -206,4 +407,233 @@ class MoHomeFragment : MoBaseFragment() { binding.noContentLayout.visibility = View.VISIBLE } + override fun onMoreClick(bean: MusicCarouselShelfRenderer.Content) { + requests.trySend(Request.ShowDialog(bean)) + } + + private suspend fun initMoreDialogData(bean: MusicCarouselShelfRenderer.Content): PlaylistItem { + val watchEndpoint = + bean.musicResponsiveListItemRenderer?.flexColumns?.firstOrNull()?.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.firstOrNull()?.navigationEndpoint?.watchEndpoint + val thumbnailUrl = + bean.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.let { + it.getOrNull(1) ?: it.getOrNull(0) + }?.url + val title = + bean.musicResponsiveListItemRenderer?.flexColumns?.get(0)?.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.firstOrNull()?.text + val name = + bean.musicResponsiveListItemRenderer?.flexColumns?.get(1)?.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.firstOrNull()?.text + + val videoId = watchEndpoint?.videoId + + LogD(TAG, "title->$title videoId->$videoId") + + val offlineBean = App.appOfflineDBManager.getOfflineBeanByID(videoId ?: "") + val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(videoId ?: "") + + return PlaylistItem( + videoId = videoId ?: "", + title = title ?: "", + name = name ?: "", + thumbnail = thumbnailUrl, + bytesDownloaded = offlineBean?.bytesDownloaded ?: 0L, + size = offlineBean?.size, + isOffline = offlineBean?.isOffline ?: false, + isFavorite = favoriteBean?.isFavorite ?: false + ) + } + + override fun onUpdateAdapterListener(download: Download, playlistItem: PlaylistItem) { + + } + + override fun onFavoritesClicked(playlistItem: PlaylistItem) { + requests.trySend(Request.OnFavorites(playlistItem)) + } + + override fun onDownloadClicked(playlistItem: PlaylistItem) { + requests.trySend(Request.OnDownload(playlistItem)) + } + + override fun onAddToPlaylistClicked(playlistItem: PlaylistItem) { + requests.trySend(Request.OnAddPlaylist(playlistItem)) + } + + private fun updateFavoriteUi(b: Boolean) { + if (moreDialog != null) { + moreDialog?.updateFavoriteUi(b) + } + } + + private fun showRemoveDownloadDialogHint(playlistItem: PlaylistItem) { + val inflater = LayoutInflater.from(requireActivity()) + val dialogView = inflater.inflate(R.layout.dialog_hint, null) + val okBtn = dialogView.findViewById(R.id.dialog_ok_btn) + val cancelBtn = dialogView.findViewById(R.id.dialog_cancel_btn) + val dialogBuilder = AlertDialog.Builder(requireActivity()).setView(dialogView) + val dialog = dialogBuilder.create() + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + dialog.show() + okBtn.setOnClickListener { + dialog.dismiss() + requests.trySend(Request.OnDownloadRemove(playlistItem)) + } + cancelBtn.setOnClickListener { + dialog.dismiss() + } + } + + private suspend fun insertOfflineData(favoriteBean: FavoriteBean) { + val currentDownload = DownloadUtil.getCurrentIdDownload(favoriteBean.videoId) + if (currentDownload != null) { + val bytesDownloaded = currentDownload.bytesDownloaded + val size = FileSizeConverter(currentDownload.bytesDownloaded).formattedSize() + val bean = OfflineBean( + videoId = favoriteBean.videoId, + title = favoriteBean.title, + name = favoriteBean.name, + thumbnail = favoriteBean.thumbnail, + isOffline = true, + isFavorite = favoriteBean.isFavorite, + bytesDownloaded = bytesDownloaded, + size = size + ) + App.appOfflineDBManager.insertOfflineBean(bean) + } else { + val bean = OfflineBean( + videoId = favoriteBean.videoId, + title = favoriteBean.title, + name = favoriteBean.name, + thumbnail = favoriteBean.thumbnail, + isOffline = true, + isFavorite = favoriteBean.isFavorite, + ) + App.appOfflineDBManager.insertOfflineBean(bean) + } + } + + suspend fun showAddPlaylistBottomDialog(favoriteBean: FavoriteBean) { + val bottomAddPlaylistSheetDialog = BottomSheetDialog(requireActivity()) + val view = layoutInflater.inflate(R.layout.add_playlist_layout, null) + bottomAddPlaylistSheetDialog.setContentView(view) + val newPlayListBtn = view.findViewById(R.id.newPlayListBtn) + val rv = view.findViewById(R.id.newPlayListRv) + newPlayListBtn.setOnClickListener { + bottomAddPlaylistSheetDialog.dismiss() + showNewPlaylistBottomDialog(favoriteBean) + } + // 设置对话框背景为透明以显示圆角 + bottomAddPlaylistSheetDialog.window?.setBackgroundDrawableResource(android.R.color.transparent) + bottomAddPlaylistSheetDialog.window?.navigationBarColor = + ContextCompat.getColor(requireActivity(), R.color.main_bg_color) + bottomAddPlaylistSheetDialog.show() + + val playlist = (App.appPlaylistDBManager.getAllPlaylists()) + val adapter = NewPlayListAdapter(requireActivity(), playlist) + adapter.setOnItemClickListener(object : NewPlayListAdapter.OnItemClickListener { + override fun onItemClick(position: Int) { + launch { + val playlistItem = + App.appPlaylistDBManager.getPlaylistItems(playlist[position].id) + val isAny = playlistItem.any { it.title == favoriteBean.title } + if (isAny) {//如何这首歌曲已经存在歌单则不添加 + withContext(Dispatchers.Main) { + Toast.makeText( + requireActivity(), + getString(R.string.song_exists_playlist_hint), + Toast.LENGTH_LONG + ).show() + } + } else { + val isOffline = + App.appOfflineDBManager.getOfflineBeanByID(favoriteBean.videoId) != null + val isFavorite = + App.appFavoriteDBManager.getFavoriteBeanByID(favoriteBean.videoId) != null + App.appPlaylistDBManager.insertOrUpdatePlaylistItem( + PlaylistItem( + playlistId = playlist[position].id, + videoId = favoriteBean.videoId, + title = favoriteBean.title, + name = favoriteBean.name, + thumbnail = favoriteBean.thumbnail, + isOffline = isOffline, + isFavorite = isFavorite + ) + ) + withContext(Dispatchers.Main) { + bottomAddPlaylistSheetDialog.dismiss() + Toast.makeText( + requireActivity(), + getString(R.string.added_playlist_success_Hint), + Toast.LENGTH_LONG + ).show() + } + } + } + } + }) + rv.layoutManager = + LinearLayoutManager(requireActivity(), LinearLayoutManager.VERTICAL, false) + rv.adapter = adapter + } + + private var bottomSheetDialog: BottomSheetDialog? = null + private fun showNewPlaylistBottomDialog(favoriteBean: FavoriteBean) { + bottomSheetDialog = BottomSheetDialog(requireActivity()) + val view = layoutInflater.inflate(R.layout.new_playlist_layout, null) + bottomSheetDialog?.setContentView(view) + val edit = view.findViewById(R.id.playlistEt) + val confirmBtn = view.findViewById(R.id.confirmBtn) + confirmBtn.setOnClickListener { + val text = edit.text.toString().trim() + if (text.isNotEmpty()) { + launch { + val playlist = App.appPlaylistDBManager.getPlaylistByTitle(text) + if (playlist != null) { + withContext(Dispatchers.Main) { + Toast.makeText( + requireActivity(), + getString(R.string.new_playlist_duplicate_name_hint), + Toast.LENGTH_LONG + ).show() + } + } else { + val newPlaylist = Playlist(title = text) + App.appPlaylistDBManager.insertOrUpdatePlaylist(newPlaylist) + withContext(Dispatchers.Main) { + if (bottomSheetDialog != null) { + bottomSheetDialog?.dismiss() + } + Toast.makeText( + requireActivity(), + getString(R.string.created_successfully), + Toast.LENGTH_LONG + ).show() + } + val currentPlaylist = App.appPlaylistDBManager.getPlaylistByTitle(text) + if (currentPlaylist != null) { + val isOffline = + App.appOfflineDBManager.getOfflineBeanByID(favoriteBean.videoId) != null//返回非null则为true + val isFavorite = + App.appFavoriteDBManager.getFavoriteBeanByID(favoriteBean.videoId) != null + val playlistItem = PlaylistItem( + playlistId = currentPlaylist.id, + videoId = favoriteBean.videoId, + title = favoriteBean.title, + name = favoriteBean.name, + thumbnail = favoriteBean.thumbnail, + isOffline = isOffline, + isFavorite = isFavorite + ) + App.appPlaylistDBManager.insertOrUpdatePlaylistItem(playlistItem) + } + } + } + } + } + // 设置对话框背景为透明以显示圆角 + bottomSheetDialog?.window?.setBackgroundDrawableResource(android.R.color.transparent) + bottomSheetDialog?.window?.navigationBarColor = + ContextCompat.getColor(requireActivity(), R.color.main_bg_color) + bottomSheetDialog?.show() + } } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt b/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt index 4205395..fc9025b 100644 --- a/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt +++ b/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt @@ -49,6 +49,7 @@ class MoMeFragment : MoBaseFragment(), NewPlayListAdapter.O sealed class Request { data class AddPlaylist(val text: String) : Request() + data object UpdateUi : Request() } override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentMoMeBinding @@ -90,6 +91,10 @@ class MoMeFragment : MoBaseFragment(), NewPlayListAdapter.O getPlaylistData() } } + + Request.UpdateUi -> { + fragmentOnResume() + } } } @@ -168,6 +173,8 @@ class MoMeFragment : MoBaseFragment(), NewPlayListAdapter.O super.onHiddenChanged(hidden) if (!hidden) { initImmersionBar() + + requests.trySend(Request.UpdateUi) } } @@ -213,4 +220,5 @@ class MoMeFragment : MoBaseFragment(), NewPlayListAdapter.O bottomSheetDialog?.show() } + } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/view/MusicResponsiveListView.kt b/app/src/main/java/melody/offline/music/view/MusicResponsiveListView.kt index 3bb31ca..af6ce5c 100644 --- a/app/src/main/java/melody/offline/music/view/MusicResponsiveListView.kt +++ b/app/src/main/java/melody/offline/music/view/MusicResponsiveListView.kt @@ -9,7 +9,9 @@ import org.json.JSONObject import melody.offline.music.R import melody.offline.music.adapter.ResponsiveListAdapter import melody.offline.music.innertube.Innertube +import melody.offline.music.innertube.models.MusicCarouselShelfRenderer import melody.offline.music.util.AnalysisUtil +import melody.offline.music.util.LogTag @SuppressLint("ViewConstructor") class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) : @@ -33,6 +35,14 @@ class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) : AnalysisUtil.logEvent(AnalysisUtil.HOME_B_MODULE_CLICK, map) } }) + adapter?.setOnItemMoreClickListener(object : ResponsiveListAdapter.OnItemMoreClickListener { + override fun onItemMoreClick(position: Int) { + val bean = homePage.contents[position] + if (moreClickListener != null) { + moreClickListener?.onMoreClick(bean) + } + } + }) rv?.layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false) rv?.adapter = adapter } @@ -43,4 +53,14 @@ class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) : adapter?.notifyDataSetChanged() } } + + private var moreClickListener: OnMoreClickListener? = null + + fun setOnItemMoreClickListener(listener: OnMoreClickListener) { + moreClickListener = listener + } + + interface OnMoreClickListener { + fun onMoreClick(bean: MusicCarouselShelfRenderer.Content) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/music_responsive_item.xml b/app/src/main/res/layout/music_responsive_item.xml index 761b185..61faba3 100644 --- a/app/src/main/res/layout/music_responsive_item.xml +++ b/app/src/main/res/layout/music_responsive_item.xml @@ -50,8 +50,9 @@ @@ -79,6 +80,19 @@ + + + + \ No newline at end of file