package melody.offline.music.activity import android.annotation.SuppressLint import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.view.LayoutInflater import android.view.View import android.widget.TextView import androidx.annotation.OptIn import androidx.appcompat.app.AlertDialog import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.offline.Download import androidx.recyclerview.widget.LinearLayoutManager import com.gyf.immersionbar.ktx.immersionBar import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select import melody.offline.music.App import melody.offline.music.R import melody.offline.music.adapter.OfflineSongsAdapter import melody.offline.music.ads.AdPlacement import melody.offline.music.ads.LolAdWrapper import melody.offline.music.bean.FavoriteBean import melody.offline.music.bean.OfflineBean import melody.offline.music.bean.PlaylistItem import melody.offline.music.databinding.ActivityOfflineSongsBinding import melody.offline.music.util.AnalysisUtil import melody.offline.music.util.LogTag import melody.offline.music.view.ListMoreBottomSheetDialog import org.json.JSONObject @OptIn(UnstableApi::class) class MoOfflineSongsActivity : MoBaseActivity(), ListMoreBottomSheetDialog.ListMoreViewListener, ListMoreBottomSheetDialog.UpdateAdapterListener { private val requests: Channel = Channel(Channel.UNLIMITED) sealed class Request { data object TryAgain : Request() data class OnFavorites(val bean: PlaylistItem) : Request() data class OnDownloadRemove(val bean: PlaylistItem) : Request() data class UpdateFavorite(val bean: PlaylistItem) : Request() data class OnAddPlaylist(val bean: PlaylistItem) : Request() data class OnUpdateCurrentListItem(val bean: PlaylistItem) : Request() } private lateinit var binding: ActivityOfflineSongsBinding private var adapter: OfflineSongsAdapter? = null private var myList: MutableList = mutableListOf() private var moreDialog: ListMoreBottomSheetDialog? = null private var currentPosition = -1 override suspend fun main() { binding = ActivityOfflineSongsBinding.inflate(layoutInflater) setContentView(binding.root) LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_ME_PAGE_LIST) initImmersionBar() initView() initAdapter() LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST) initData() onReceive() } private fun initImmersionBar() { immersionBar { statusBarDarkFont(false) statusBarView(binding.view) } } @SuppressLint("NotifyDataSetChanged") private suspend fun onReceive() { while (isActive) { select { requests.onReceive { when (it) { Request.TryAgain -> { initData() } 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 { insertFavoriteData(OfflineBean( videoId = it.bean.videoId, title = it.bean.title, name = it.bean.name, thumbnail = it.bean.thumbnail, bytesDownloaded = it.bean.bytesDownloaded, size = it.bean.size, isOffline = it.bean.isOffline, isFavorite = it.bean.isFavorite )) AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap) } requests.trySend(Request.UpdateFavorite(it.bean)) } is Request.UpdateFavorite -> { val currentFavoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) if (currentFavoriteBean != null) { updateFavoriteUi(currentFavoriteBean.isFavorite) } else { updateFavoriteUi(false) } requests.trySend(Request.OnUpdateCurrentListItem(it.bean)) } is Request.OnDownloadRemove -> { val currentOfflineBean = App.appOfflineDBManager.getOfflineBeanByID(it.bean.videoId) if (currentOfflineBean != null) { App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean) } if (currentPosition >= 0) { myList.remove(myList[currentPosition]) } adapter?.notifyDataSetChanged() moreDialog?.dismiss() requests.trySend(Request.OnUpdateCurrentListItem(it.bean)) } is Request.OnAddPlaylist -> { showAddPlaylistBottomDialog( FavoriteBean( videoId = it.bean.videoId, title = it.bean.title, name = it.bean.name, thumbnail = it.bean.thumbnail, isFavorite = it.bean.isFavorite ) ) } is Request.OnUpdateCurrentListItem -> { updateCurrentItem(it.bean.videoId) } } } events.onReceive { when (it) { Event.ActivityOnResume -> { activityOnResume() } Event.AutomaticallySwitchSongs -> { if (adapter != null) { adapter?.notifyDataSetChanged() } } else -> {} } } } } } @SuppressLint("NotifyDataSetChanged") private fun activityOnResume() { addMusicPlayerViewToLayout(binding.playMusicLayout) if (adapter != null) { adapter?.notifyDataSetChanged() } LolAdWrapper.shared.loadAdShowNativeAd( this, AdPlacement.NATIVE_ME_PAGE_LIST, binding.frameAd, R.layout.ad_layout_admob_banner, R.layout.ad_layout_max_banner ) } private fun initView() { binding.backBtn.setOnClickListener { finish() } binding.tryAgainBtn.setOnClickListener { requests.trySend(Request.TryAgain) } } private fun initAdapter() { adapter = OfflineSongsAdapter(this, myList) adapter?.setOnMoreClickListener(object : OfflineSongsAdapter.OnMoreClickListener { override fun onMoreClick(position: Int) { currentPosition = position moreDialog = ListMoreBottomSheetDialog( this@MoOfflineSongsActivity, myList[position], this@MoOfflineSongsActivity, this@MoOfflineSongsActivity ) moreDialog?.setListMoreViewListener(this@MoOfflineSongsActivity) moreDialog?.show() } }) binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) binding.rv.adapter = adapter } @SuppressLint("NotifyDataSetChanged") private suspend fun initData() { showLoadingUi() val offlineBeans = App.appOfflineDBManager.getAllOfflineBeans() if (offlineBeans.isNotEmpty()) { myList.clear() offlineBeans.forEach { offlineBean -> val favoriteItem = App.appFavoriteDBManager.getFavoriteBeanByID(offlineBean.videoId) if (offlineBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) { myList.add( PlaylistItem( videoId = offlineBean.videoId, title = offlineBean.title, name = offlineBean.name, thumbnail = offlineBean.thumbnail, isOffline = offlineBean.isOffline, isFavorite = favoriteItem?.isFavorite ?: false, bytesDownloaded = offlineBean.bytesDownloaded, size = offlineBean.size ) ) } } if (myList.size > 0) { showDataUi() } else { showNoContentUi() } } else { showNoContentUi() } if (adapter != null) { adapter?.notifyDataSetChanged() } } private fun updateFavoriteUi(b: Boolean) { if (moreDialog != null) { moreDialog?.updateFavoriteUi(b) } } private suspend fun updateCurrentItem(id: String) { //更新当前界面的数据集合 myList.forEach { item -> if (item.videoId == id) { val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(item.videoId) val offlineBean = App.appOfflineDBManager.getOfflineBeanByID(item.videoId) item.isFavorite = favoriteBean?.isFavorite ?: false item.isOffline = offlineBean?.isOffline ?: false item.bytesDownloaded = offlineBean?.bytesDownloaded item.size = offlineBean?.size } } myList.forEach { item -> if (item.videoId == id) { LogTag.LogD(TAG, "updateCurrentItem -> $item") } } } override fun onFavoritesClicked(playlistItem: PlaylistItem) { requests.trySend(Request.OnFavorites(playlistItem)) } override fun onDownloadClicked(playlistItem: PlaylistItem) { //下载列表只有删除,删除后更新adapter showRemoveDownloadDialogHint(playlistItem) } override fun onAddToPlaylistClicked(playlistItem: PlaylistItem) { requests.trySend(Request.OnAddPlaylist(playlistItem)) } override fun onUpdateAdapterListener(download: Download, playlistItem: PlaylistItem) { } private fun showRemoveDownloadDialogHint(bean: PlaylistItem) { val inflater = LayoutInflater.from(this) 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(this).setView(dialogView) val dialog = dialogBuilder.create() dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) dialog.show() okBtn.setOnClickListener { dialog.dismiss() requests.trySend(Request.OnDownloadRemove(bean)) } cancelBtn.setOnClickListener { dialog.dismiss() } } private fun showDataUi() { binding.loadingLayout.visibility = View.GONE binding.noContentLayout.visibility = View.GONE } private fun showLoadingUi() { binding.loadingLayout.visibility = View.VISIBLE binding.noContentLayout.visibility = View.GONE } private fun showNoContentUi() { binding.loadingLayout.visibility = View.GONE binding.noContentLayout.visibility = View.VISIBLE } }