update
This commit is contained in:
parent
eb81f9bda7
commit
b49547cb9b
@ -13,6 +13,7 @@ import melody.offline.music.databinding.MusicResponsiveItemBinding
|
|||||||
import melody.offline.music.innertube.models.MusicCarouselShelfRenderer
|
import melody.offline.music.innertube.models.MusicCarouselShelfRenderer
|
||||||
import melody.offline.music.media.MediaControllerManager
|
import melody.offline.music.media.MediaControllerManager
|
||||||
import melody.offline.music.util.AnalysisUtil
|
import melody.offline.music.util.AnalysisUtil
|
||||||
|
import melody.offline.music.util.LogTag
|
||||||
|
|
||||||
class ResponsiveListAdapter(
|
class ResponsiveListAdapter(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@ -83,15 +84,20 @@ class ResponsiveListAdapter(
|
|||||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc)
|
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc)
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
|
|
||||||
if(itemClickListener!=null){
|
if (itemClickListener != null) {
|
||||||
itemClickListener?.onItemClick(position)
|
itemClickListener?.onItemClick(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
holder.binding.moreBtn.setOnClickListener {
|
||||||
|
if (itemMoreClickListener != null) {
|
||||||
|
itemMoreClickListener?.onItemMoreClick(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = list.size
|
override fun getItemCount(): Int = list.size
|
||||||
|
|
||||||
inner class ViewHolder(private val binding: MusicResponsiveItemBinding) :
|
inner class ViewHolder(val binding: MusicResponsiveItemBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(url: String?, name: String?, desc: String?, videoID: String?) {
|
fun bind(url: String?, name: String?, desc: String?, videoID: String?) {
|
||||||
@ -129,4 +135,14 @@ class ResponsiveListAdapter(
|
|||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onItemClick(position: Int)
|
fun onItemClick(position: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var itemMoreClickListener: OnItemMoreClickListener? = null
|
||||||
|
|
||||||
|
fun setOnItemMoreClickListener(listener: OnItemMoreClickListener) {
|
||||||
|
itemMoreClickListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnItemMoreClickListener {
|
||||||
|
fun onItemMoreClick(position: Int)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,9 +1,27 @@
|
|||||||
package melody.offline.music.fragment
|
package melody.offline.music.fragment
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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 com.gyf.immersionbar.ktx.immersionBar
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import melody.offline.music.databinding.FragmentMoHomeBinding
|
import melody.offline.music.databinding.FragmentMoHomeBinding
|
||||||
import melody.offline.music.innertube.Innertube
|
import melody.offline.music.innertube.Innertube
|
||||||
import melody.offline.music.innertube.models.MusicCarouselShelfRenderer
|
import melody.offline.music.innertube.models.MusicCarouselShelfRenderer
|
||||||
@ -14,12 +32,32 @@ import melody.offline.music.view.MusicResponsiveListView
|
|||||||
import melody.offline.music.view.MusicTowRowListView
|
import melody.offline.music.view.MusicTowRowListView
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.selects.select
|
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.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.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
|
import org.json.JSONObject
|
||||||
|
|
||||||
class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
@OptIn(UnstableApi::class)
|
||||||
|
class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>(),
|
||||||
|
MusicResponsiveListView.OnMoreClickListener, ListMoreBottomSheetDialog.ListMoreViewListener,
|
||||||
|
ListMoreBottomSheetDialog.UpdateAdapterListener {
|
||||||
|
|
||||||
|
|
||||||
interface MoHomeFragmentToSearchClickListener {
|
interface MoHomeFragmentToSearchClickListener {
|
||||||
@ -31,12 +69,18 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var toSearchClickListener: MoHomeFragmentToSearchClickListener? = null
|
private var toSearchClickListener: MoHomeFragmentToSearchClickListener? = null
|
||||||
|
private var moreDialog: ListMoreBottomSheetDialog? = null
|
||||||
|
|
||||||
private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
|
private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
|
||||||
|
|
||||||
enum class Request {
|
sealed class Request {
|
||||||
TryAgain,
|
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
|
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentMoHomeBinding
|
||||||
@ -63,6 +107,166 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
|||||||
Request.TryAgain -> {
|
Request.TryAgain -> {
|
||||||
initData()
|
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 {
|
events.onReceive {
|
||||||
@ -97,19 +301,16 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
|||||||
for (home: Innertube.HomePage in it.homePage) {
|
for (home: Innertube.HomePage in it.homePage) {
|
||||||
for (content: MusicCarouselShelfRenderer.Content in home.contents) {
|
for (content: MusicCarouselShelfRenderer.Content in home.contents) {
|
||||||
if (content.musicResponsiveListItemRenderer != null) {
|
if (content.musicResponsiveListItemRenderer != null) {
|
||||||
binding.contentLayout.addView(
|
val musicResponsiveListView =
|
||||||
MusicResponsiveListView(
|
MusicResponsiveListView(requireActivity(), home)
|
||||||
requireActivity(),
|
musicResponsiveListView.setOnItemMoreClickListener(this)
|
||||||
home
|
binding.contentLayout.addView(musicResponsiveListView)
|
||||||
)
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (content.musicTwoRowItemRenderer != null) {
|
if (content.musicTwoRowItemRenderer != null) {
|
||||||
binding.contentLayout.addView(
|
binding.contentLayout.addView(
|
||||||
MusicTowRowListView(
|
MusicTowRowListView(
|
||||||
requireActivity(),
|
requireActivity(), home
|
||||||
home
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
@ -135,14 +336,14 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
|||||||
if (content.musicResponsiveListItemRenderer != null) {
|
if (content.musicResponsiveListItemRenderer != null) {
|
||||||
val musicResponsiveListView =
|
val musicResponsiveListView =
|
||||||
MusicResponsiveListView(requireActivity(), home)
|
MusicResponsiveListView(requireActivity(), home)
|
||||||
|
musicResponsiveListView.setOnItemMoreClickListener(this)
|
||||||
binding.contentLayout.addView(musicResponsiveListView)
|
binding.contentLayout.addView(musicResponsiveListView)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (content.musicTwoRowItemRenderer != null) {
|
if (content.musicTwoRowItemRenderer != null) {
|
||||||
binding.contentLayout.addView(
|
binding.contentLayout.addView(
|
||||||
MusicTowRowListView(
|
MusicTowRowListView(
|
||||||
requireActivity(),
|
requireActivity(), home
|
||||||
home
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
@ -206,4 +407,233 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
|||||||
binding.noContentLayout.visibility = View.VISIBLE
|
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<TextView>(R.id.dialog_ok_btn)
|
||||||
|
val cancelBtn = dialogView.findViewById<TextView>(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<LinearLayout>(R.id.newPlayListBtn)
|
||||||
|
val rv = view.findViewById<RecyclerView>(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<EditText>(R.id.playlistEt)
|
||||||
|
val confirmBtn = view.findViewById<TextView>(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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +49,7 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
|
|||||||
|
|
||||||
sealed class Request {
|
sealed class Request {
|
||||||
data class AddPlaylist(val text: String) : Request()
|
data class AddPlaylist(val text: String) : Request()
|
||||||
|
data object UpdateUi : Request()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentMoMeBinding
|
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentMoMeBinding
|
||||||
@ -90,6 +91,10 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
|
|||||||
getPlaylistData()
|
getPlaylistData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Request.UpdateUi -> {
|
||||||
|
fragmentOnResume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +173,8 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
|
|||||||
super.onHiddenChanged(hidden)
|
super.onHiddenChanged(hidden)
|
||||||
if (!hidden) {
|
if (!hidden) {
|
||||||
initImmersionBar()
|
initImmersionBar()
|
||||||
|
|
||||||
|
requests.trySend(Request.UpdateUi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,4 +220,5 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
|
|||||||
bottomSheetDialog?.show()
|
bottomSheetDialog?.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -9,7 +9,9 @@ import org.json.JSONObject
|
|||||||
import melody.offline.music.R
|
import melody.offline.music.R
|
||||||
import melody.offline.music.adapter.ResponsiveListAdapter
|
import melody.offline.music.adapter.ResponsiveListAdapter
|
||||||
import melody.offline.music.innertube.Innertube
|
import melody.offline.music.innertube.Innertube
|
||||||
|
import melody.offline.music.innertube.models.MusicCarouselShelfRenderer
|
||||||
import melody.offline.music.util.AnalysisUtil
|
import melody.offline.music.util.AnalysisUtil
|
||||||
|
import melody.offline.music.util.LogTag
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) :
|
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)
|
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?.layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false)
|
||||||
rv?.adapter = adapter
|
rv?.adapter = adapter
|
||||||
}
|
}
|
||||||
@ -43,4 +53,14 @@ class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) :
|
|||||||
adapter?.notifyDataSetChanged()
|
adapter?.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var moreClickListener: OnMoreClickListener? = null
|
||||||
|
|
||||||
|
fun setOnItemMoreClickListener(listener: OnMoreClickListener) {
|
||||||
|
moreClickListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnMoreClickListener {
|
||||||
|
fun onMoreClick(bean: MusicCarouselShelfRenderer.Content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -50,8 +50,9 @@
|
|||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
@ -79,6 +80,19 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/moreBtn"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:visibility="visible"
|
||||||
|
android:layout_height="40dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:src="@drawable/three_dots_icon" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Loading…
Reference in New Issue
Block a user