update
This commit is contained in:
parent
195ec0f242
commit
c90b8a6930
@ -1,5 +1,6 @@
|
||||
package com.player.musicoo.activity
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
@ -45,8 +46,10 @@ class MoListDetailsActivity : MoBaseActivity() {
|
||||
}
|
||||
|
||||
private suspend fun initData(browseId: String) {
|
||||
showLoadingUi()
|
||||
Innertube.moPlaylistPage(browseId)
|
||||
?.onSuccess {
|
||||
showDataUi()
|
||||
Glide.with(this)
|
||||
.load(it.thumbnail)
|
||||
.into(binding.imageView)
|
||||
@ -61,7 +64,23 @@ class MoListDetailsActivity : MoBaseActivity() {
|
||||
binding.rv.adapter = adapter
|
||||
|
||||
}?.onFailure {
|
||||
showNoContentUi()
|
||||
LogD(TAG, "moPlaylistPage onFailure->${it}")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1,28 +1,36 @@
|
||||
package com.player.musicoo.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import android.view.animation.AnimationUtils
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
import com.player.musicoo.R
|
||||
import com.player.musicoo.adapter.PlayListAdapter
|
||||
import com.player.musicoo.databinding.ActivityMoPlayDetailsBinding
|
||||
import com.player.musicoo.innertube.Innertube
|
||||
import com.player.musicoo.media.MediaControllerManager
|
||||
import com.player.musicoo.media.SongRadio
|
||||
import com.player.musicoo.util.LogTag.LogD
|
||||
import com.player.musicoo.util.asMediaItem
|
||||
import com.player.musicoo.util.convertMillisToMinutesAndSecondsString
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.selects.select
|
||||
import com.player.musicoo.util.LogTag.LogD
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
@ -42,6 +50,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
private var currentVideoID = ""
|
||||
|
||||
private var comeFrom: Class<*>? = null
|
||||
private var playListAdapter: PlayListAdapter? = null
|
||||
|
||||
private fun initImmersionBar() {
|
||||
immersionBar {
|
||||
@ -120,9 +129,8 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
if (meController != null && meController.currentMediaItem != null) {
|
||||
binding.playbackErrorLayout.visibility = View.GONE
|
||||
binding.loadingView.visibility = View.GONE
|
||||
|
||||
|
||||
val currentString = convertMillisToMinutesAndSecondsString(meController.currentPosition)
|
||||
binding.disableClicksLayout.visibility = View.GONE
|
||||
val currentString = convertMillisToMinutesAndSecondsString(MediaControllerManager.getCurrentPosition())
|
||||
binding.progressDurationTv.text = currentString
|
||||
if (MediaControllerManager.getDuration() > 0) {
|
||||
binding.totalDurationTv.visibility = View.VISIBLE
|
||||
@ -133,13 +141,31 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
binding.totalDurationTv.text =
|
||||
convertMillisToMinutesAndSecondsString(MediaControllerManager.getDuration())
|
||||
|
||||
binding.sbProgress.value = meController.currentPosition.toFloat()
|
||||
binding.sbProgress.value = MediaControllerManager.getCurrentPosition().toFloat()
|
||||
binding.sbProgress.valueTo = MediaControllerManager.getDuration().toFloat()
|
||||
updateProgressState()
|
||||
|
||||
binding.progressBar.progress = meController.bufferedPosition.toInt()
|
||||
binding.progressBar.progress = MediaControllerManager.getBufferedPosition().toInt()
|
||||
binding.progressBar.max = MediaControllerManager.getDuration().toInt()
|
||||
updateProgressBufferingState()
|
||||
|
||||
val mediaItemCount = meController.mediaItemCount
|
||||
val allMediaItems: MutableList<MediaItem> = mutableListOf()
|
||||
for (index in 0 until mediaItemCount) {
|
||||
val mediaItemAt = meController.getMediaItemAt(index)
|
||||
allMediaItems.add(mediaItemAt)
|
||||
}
|
||||
playListAdapter = PlayListAdapter(
|
||||
this@MoPlayDetailsActivity,
|
||||
allMediaItems
|
||||
)
|
||||
binding.playListRv.layoutManager =
|
||||
LinearLayoutManager(
|
||||
this@MoPlayDetailsActivity,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
binding.playListRv.adapter = playListAdapter
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +173,16 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
binding.backBtn.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
binding.tryAgainBtn.setOnClickListener {
|
||||
if (meController != null) {
|
||||
updateInfoUi(meController.currentMediaItem)
|
||||
updateProgressState()
|
||||
if (!meController.isPlaying) {
|
||||
meController.prepare()
|
||||
meController.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.playLayoutBtn.setOnClickListener {
|
||||
if (meController != null) {
|
||||
if (meController.isPlaying) {
|
||||
@ -184,7 +220,13 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
}
|
||||
}
|
||||
binding.listLayoutBtn.setOnClickListener {
|
||||
LogD(TAG, "meController?.mediaItemCount->${meController?.mediaItemCount}")
|
||||
toggleBottomLayout()
|
||||
}
|
||||
binding.bottomCloseBtn.setOnClickListener {
|
||||
toggleBottomLayout()
|
||||
}
|
||||
binding.bottomBlankLayout.setOnClickListener {
|
||||
toggleBottomLayout()
|
||||
}
|
||||
binding.progressBar.progress = 0
|
||||
binding.sbProgress.value = 0f
|
||||
@ -218,7 +260,20 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
|
||||
if (songRadioList.isEmpty()) {//集合为空则展示错误提示
|
||||
binding.loadingView.visibility = View.GONE
|
||||
binding.disableClicksLayout.visibility = View.GONE
|
||||
binding.playbackErrorLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
playListAdapter = PlayListAdapter(
|
||||
this@MoPlayDetailsActivity,
|
||||
songRadioList.map(Innertube.SongItem::asMediaItem)
|
||||
)
|
||||
binding.playListRv.layoutManager =
|
||||
LinearLayoutManager(
|
||||
this@MoPlayDetailsActivity,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
binding.playListRv.adapter = playListAdapter
|
||||
}
|
||||
|
||||
if (isFinishing) {
|
||||
@ -269,6 +324,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
private val playerListener = object : Player.Listener {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onPositionDiscontinuity(
|
||||
oldPosition: Player.PositionInfo,
|
||||
newPosition: Player.PositionInfo,
|
||||
@ -278,7 +334,11 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||
|| reason == Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT
|
||||
) {
|
||||
updateProgressUi()
|
||||
updateInfoUi(meController?.currentMediaItem)
|
||||
if (playListAdapter != null) {
|
||||
playListAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,11 +361,14 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
when (playbackState) {
|
||||
Player.STATE_BUFFERING -> {
|
||||
binding.loadingView.visibility = View.VISIBLE
|
||||
binding.disableClicksLayout.visibility = View.VISIBLE
|
||||
binding.playbackErrorLayout.visibility = View.GONE
|
||||
}
|
||||
|
||||
Player.STATE_READY -> {
|
||||
binding.playbackErrorLayout.visibility = View.GONE
|
||||
binding.loadingView.visibility = View.GONE
|
||||
binding.disableClicksLayout.visibility = View.GONE
|
||||
binding.totalDurationTv.visibility = View.VISIBLE
|
||||
binding.totalDurationTv.text =
|
||||
convertMillisToMinutesAndSecondsString(
|
||||
@ -320,6 +383,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
|
||||
else -> {
|
||||
binding.loadingView.visibility = View.GONE
|
||||
binding.disableClicksLayout.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
updateProgressState()
|
||||
@ -343,9 +407,24 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
binding.playbackErrorLayout.visibility = View.VISIBLE
|
||||
return
|
||||
}
|
||||
Glide.with(this@MoPlayDetailsActivity)
|
||||
|
||||
Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(mediaItem.mediaMetadata.artworkUri)
|
||||
.into(binding.thumbnail)
|
||||
.placeholder(R.mipmap.musicoo_logo_img)
|
||||
.into(object : CustomTarget<Bitmap>() {
|
||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||
binding.thumbnail.setImageBitmap(resource)
|
||||
val blurredBitmap = applyGaussianBlur(resource, 25f, this@MoPlayDetailsActivity)
|
||||
binding.imageView.setImageBitmap(blurredBitmap)
|
||||
}
|
||||
|
||||
override fun onLoadCleared(placeholder: Drawable?) {
|
||||
if (placeholder != null) {
|
||||
binding.thumbnail.setImageDrawable(placeholder)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
binding.nameTv.text = mediaItem.mediaMetadata.title
|
||||
binding.descTv.text = mediaItem.mediaMetadata.artist
|
||||
@ -372,11 +451,11 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
override fun handleMessage(msg: Message) {
|
||||
//判断是否ready与播放中,否则停止更新进度
|
||||
if (meController != null && meController.playbackState == Player.STATE_READY && meController.isPlaying) {
|
||||
val currentPosition = meController.currentPosition
|
||||
val currentPosition = MediaControllerManager.getCurrentPosition()
|
||||
val currentString = convertMillisToMinutesAndSecondsString(currentPosition)
|
||||
binding.progressDurationTv.text = currentString
|
||||
|
||||
val currentBufferedPosition = meController.bufferedPosition
|
||||
val currentBufferedPosition = MediaControllerManager.getBufferedPosition()
|
||||
binding.progressBar.progress = currentBufferedPosition.toInt()
|
||||
|
||||
// 更新 SeekBar 的进度
|
||||
@ -405,7 +484,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
private val progressBufferingHandler = object : Handler(Looper.myLooper()!!) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
if (meController != null && meController.isLoading) {
|
||||
val currentBufferedPosition = meController.bufferedPosition
|
||||
val currentBufferedPosition = MediaControllerManager.getBufferedPosition()
|
||||
binding.progressBar.progress = currentBufferedPosition.toInt()
|
||||
sendEmptyMessageDelayed(1, 50)
|
||||
}
|
||||
@ -419,4 +498,25 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
|
||||
binding.playImg.setImageResource(R.drawable.play_green_icon)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun toggleBottomLayout() {
|
||||
if (binding.bottomLayout.visibility == View.VISIBLE) {
|
||||
hideBottomLayout()
|
||||
} else {
|
||||
showBottomLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBottomLayout() {
|
||||
val slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_up)
|
||||
binding.bottomLayout.startAnimation(slideUpAnimation)
|
||||
binding.bottomLayout.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun hideBottomLayout() {
|
||||
val slideDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_down)
|
||||
binding.bottomLayout.startAnimation(slideDownAnimation)
|
||||
binding.bottomLayout.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.player.musicoo.App
|
||||
import com.player.musicoo.R
|
||||
import com.player.musicoo.activity.MoPlayDetailsActivity
|
||||
import com.player.musicoo.activity.PlayDetailsActivity
|
||||
import com.player.musicoo.bean.Audio
|
||||
import com.player.musicoo.databinding.DetailsListItemBinding
|
||||
@ -27,6 +28,10 @@ class DetailsListAdapter(
|
||||
) :
|
||||
RecyclerView.Adapter<DetailsListAdapter.ViewHolder>() {
|
||||
|
||||
companion object {
|
||||
const val FROM_TAG = "list_details_activity_to_adapter"
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val binding = DetailsListItemBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
return ViewHolder(binding)
|
||||
@ -35,6 +40,23 @@ class DetailsListAdapter(
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val bean = list[position]
|
||||
holder.bind(bean)
|
||||
|
||||
val videoId = bean.videoId
|
||||
|
||||
holder.itemView.setOnClickListener {
|
||||
val intent = Intent(context, MoPlayDetailsActivity::class.java)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_ID, bean.playlistId)
|
||||
intent.putExtra(
|
||||
MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_SET_VIDEO_ID,
|
||||
bean.playlistSetVideoId
|
||||
)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_PARAMS, bean.params)
|
||||
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.name)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.title)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = list.size
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
package com.player.musicoo.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.Player
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.player.musicoo.R
|
||||
import com.player.musicoo.databinding.PlayListItemBinding
|
||||
import com.player.musicoo.media.MediaControllerManager
|
||||
|
||||
class PlayListAdapter(
|
||||
private val context: Context,
|
||||
private val list: List<MediaItem>,
|
||||
) :
|
||||
RecyclerView.Adapter<PlayListAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val binding = PlayListItemBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
return ViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val bean = list[position]
|
||||
holder.bind(bean)
|
||||
|
||||
holder.itemView.setOnClickListener {
|
||||
val meController = MediaControllerManager.getController()
|
||||
if (meController != null && meController.currentMediaItem != null) {
|
||||
var index = holder.bindingAdapterPosition
|
||||
if (index > meController.mediaItemCount) {
|
||||
index = 1
|
||||
}
|
||||
meController.seekTo(index, C.TIME_UNSET)
|
||||
if (!meController.isPlaying) {
|
||||
meController.prepare()
|
||||
meController.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = list.size
|
||||
|
||||
inner class ViewHolder(private val binding: PlayListItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(bean: MediaItem) {
|
||||
|
||||
binding.apply {
|
||||
val meController = MediaControllerManager.getController()
|
||||
if (meController != null && meController.currentMediaItem != null) {
|
||||
if (meController.currentMediaItem?.mediaId == bean.mediaId) {
|
||||
binding.currentPlayingLayout.visibility = View.VISIBLE
|
||||
binding.title.setTextColor(context.getColor(R.color.green))
|
||||
binding.name.setTextColor(context.getColor(R.color.green_60))
|
||||
} else {
|
||||
binding.currentPlayingLayout.visibility = View.GONE
|
||||
binding.title.setTextColor(context.getColor(R.color.white))
|
||||
binding.name.setTextColor(context.getColor(R.color.white_60))
|
||||
}
|
||||
}
|
||||
|
||||
Glide.with(context)
|
||||
.load(bean.mediaMetadata.artworkUri)
|
||||
.into(image)
|
||||
title.text = bean.mediaMetadata.title
|
||||
if (bean.mediaMetadata.artist.isNullOrEmpty()) {
|
||||
name.visibility = View.GONE
|
||||
} else {
|
||||
name.visibility = View.VISIBLE
|
||||
name.text = bean.mediaMetadata.artist
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var itemClickListener: OnItemClickListener? = null
|
||||
|
||||
fun setOnItemClickListener(listener: OnItemClickListener) {
|
||||
itemClickListener = listener
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onItemClick(position: Int)
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.player.musicoo.activity.MoListDetailsActivity
|
||||
import com.player.musicoo.activity.MoPlayDetailsActivity
|
||||
import com.player.musicoo.databinding.MusicTowRowItemBinding
|
||||
import com.player.musicoo.innertube.models.MusicCarouselShelfRenderer
|
||||
|
||||
@ -34,38 +35,66 @@ class TowRowListAdapter(
|
||||
|
||||
val browseId = browseEndpoint?.browseId
|
||||
|
||||
holder.bind(bean)
|
||||
val watchEndpoint = bean.musicTwoRowItemRenderer
|
||||
?.navigationEndpoint
|
||||
?.watchEndpoint
|
||||
|
||||
val videoId = watchEndpoint?.videoId
|
||||
val playlistId = watchEndpoint?.playlistId
|
||||
val playlistSetVideoId = watchEndpoint?.playlistSetVideoId
|
||||
val params = watchEndpoint?.params
|
||||
|
||||
|
||||
val url = bean.musicTwoRowItemRenderer
|
||||
?.thumbnailRenderer
|
||||
?.musicThumbnailRenderer
|
||||
?.thumbnail
|
||||
?.thumbnails
|
||||
?.let { it.getOrNull(1) ?: it.getOrNull(0) }
|
||||
?.url ?: ""
|
||||
val name = bean.musicTwoRowItemRenderer
|
||||
?.title
|
||||
?.runs
|
||||
?.firstOrNull()
|
||||
?.text ?: ""
|
||||
val desc = bean.musicTwoRowItemRenderer
|
||||
?.subtitle
|
||||
?.runs
|
||||
?.map { it.text }
|
||||
?.joinToString("") ?: ""
|
||||
|
||||
holder.bind(url = url, name = name, desc = desc)
|
||||
|
||||
holder.itemView.setOnClickListener {
|
||||
if (browseId.isNullOrEmpty()) {
|
||||
val intent = Intent(context, MoPlayDetailsActivity::class.java)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_ID, playlistId)
|
||||
if (playlistSetVideoId != null) {
|
||||
intent.putExtra(
|
||||
MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_SET_VIDEO_ID,
|
||||
playlistSetVideoId
|
||||
)
|
||||
}
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_PARAMS, params)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, name)
|
||||
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
val intent = Intent(context, MoListDetailsActivity::class.java)
|
||||
intent.putExtra(MoListDetailsActivity.PLAY_LIST_PAGE_BROWSE_ID, browseId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = list.size
|
||||
|
||||
inner class ViewHolder(private val binding: MusicTowRowItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(content: MusicCarouselShelfRenderer.Content) {
|
||||
val url = content.musicTwoRowItemRenderer
|
||||
?.thumbnailRenderer
|
||||
?.musicThumbnailRenderer
|
||||
?.thumbnail
|
||||
?.thumbnails
|
||||
?.let { it.getOrNull(1) ?: it.getOrNull(0) }
|
||||
?.url
|
||||
val name = content.musicTwoRowItemRenderer
|
||||
?.title
|
||||
?.runs
|
||||
?.firstOrNull()
|
||||
?.text
|
||||
val desc = content.musicTwoRowItemRenderer
|
||||
?.subtitle
|
||||
?.runs
|
||||
?.map { it.text }
|
||||
?.joinToString("")
|
||||
fun bind(url: String, name: String, desc: String) {
|
||||
|
||||
binding.apply {
|
||||
Glide.with(context)
|
||||
.load(url)
|
||||
|
||||
@ -90,6 +90,7 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
||||
initHomeDataMore(it)
|
||||
} else {
|
||||
LogD(TAG, "homePage size 0")
|
||||
showNoContentUi()
|
||||
}
|
||||
}?.onFailure {
|
||||
showNoContentUi()
|
||||
@ -145,6 +146,7 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
|
||||
binding.loadingLayout.visibility = View.GONE
|
||||
binding.noContentLayout.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun showLoadingUi() {
|
||||
binding.loadingLayout.visibility = View.VISIBLE
|
||||
binding.noContentLayout.visibility = View.GONE
|
||||
|
||||
@ -193,7 +193,9 @@ object Innertube {
|
||||
val timeText: String?,
|
||||
val browseId: String,
|
||||
val videoId: String?,
|
||||
val playlistId: String?,
|
||||
val playlistId: String? = null,
|
||||
val playlistSetVideoId: String? = null,
|
||||
val params: String? = null,
|
||||
val musicVideoType: String?,
|
||||
val pageType: String?,
|
||||
val thumbnailUrl: String?
|
||||
|
||||
@ -80,7 +80,11 @@ suspend fun Innertube.moPlaylistPage(browseId: String): Result<Innertube.MoPlayl
|
||||
|
||||
val bean = Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean(
|
||||
title = runs0?.text,
|
||||
name = runs1?.text,
|
||||
name = runs1?.text ?: musicDetailHeaderRenderer
|
||||
?.subtitle
|
||||
?.runs
|
||||
?.map { it.text }
|
||||
?.joinToString(""),
|
||||
desc = runs2?.text,
|
||||
timeText = content.musicResponsiveListItemRenderer
|
||||
?.fixedColumns?.firstOrNull()
|
||||
@ -92,6 +96,8 @@ suspend fun Innertube.moPlaylistPage(browseId: String): Result<Innertube.MoPlayl
|
||||
browseId = browseEndpoint?.browseId.toString(),
|
||||
videoId = watchEndpoint?.videoId,
|
||||
playlistId = watchEndpoint?.playlistId,
|
||||
playlistSetVideoId = watchEndpoint?.playlistSetVideoId,
|
||||
params = watchEndpoint?.params,
|
||||
musicVideoType = watchEndpoint?.type,
|
||||
pageType = browseEndpoint?.type,
|
||||
thumbnailUrl = thumbnailUrl
|
||||
|
||||
@ -177,4 +177,26 @@ object MediaControllerManager {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun getCurrentPosition(): Long {
|
||||
mediaController?.let {
|
||||
if (it.currentPosition > 0 && it.currentPosition < it.duration) {
|
||||
return it.currentPosition
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun getBufferedPosition(): Long {
|
||||
mediaController?.let {
|
||||
if (it.bufferedPosition > 0) {
|
||||
return it.bufferedPosition
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,8 +61,6 @@ class PlaybackService : MediaSessionService(), Player.Listener {
|
||||
ExoPlayerDiskCacheMaxSize.Unlimited -> NoOpCacheEvictor()
|
||||
else -> LeastRecentlyUsedCacheEvictor(size.bytes)
|
||||
}
|
||||
|
||||
// TODO: Remove in a future release
|
||||
val directory = cacheDir.resolve("exoplayer").also { directory ->
|
||||
if (directory.exists()) return@also
|
||||
|
||||
@ -80,7 +78,6 @@ class PlaybackService : MediaSessionService(), Player.Listener {
|
||||
}
|
||||
cache = SimpleCache(directory, cacheEvictor, StandaloneDatabaseProvider(this))
|
||||
|
||||
|
||||
player = ExoPlayer.Builder(this, createRendersFactory(), createMediaSourceFactory())
|
||||
.setHandleAudioBecomingNoisy(true)
|
||||
.setWakeMode(C.WAKE_MODE_LOCAL)
|
||||
|
||||
8
app/src/main/res/drawable/drw_bottom_close_btn_bg.xml
Normal file
8
app/src/main/res/drawable/drw_bottom_close_btn_bg.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="#FF555555" />
|
||||
<corners android:radius="20dp" />
|
||||
|
||||
</shape>
|
||||
10
app/src/main/res/drawable/drw_bottom_layout_bg.xml
Normal file
10
app/src/main/res/drawable/drw_bottom_layout_bg.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="@color/bottom_layout_bg_color" />
|
||||
<corners
|
||||
android:topLeftRadius="18dp"
|
||||
android:topRightRadius="18dp" />
|
||||
|
||||
</shape>
|
||||
9
app/src/main/res/drawable/playing_small_green_icon.xml
Normal file
9
app/src/main/res/drawable/playing_small_green_icon.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="17dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="17">
|
||||
<path
|
||||
android:pathData="M7,16.8C6.629,16.8 6.273,16.653 6.01,16.39C5.747,16.127 5.6,15.771 5.6,15.4V1.4C5.6,1.029 5.747,0.673 6.01,0.41C6.273,0.147 6.629,0 7,0C7.371,0 7.727,0.147 7.99,0.41C8.252,0.673 8.4,1.029 8.4,1.4V15.4C8.4,15.771 8.252,16.127 7.99,16.39C7.727,16.653 7.371,16.8 7,16.8ZM1.4,14C1.029,14 0.673,13.852 0.41,13.59C0.147,13.327 0,12.971 0,12.6V5.6C0,5.229 0.148,4.873 0.41,4.61C0.673,4.348 1.029,4.2 1.4,4.2C1.771,4.2 2.127,4.348 2.39,4.61C2.652,4.873 2.8,5.229 2.8,5.6V12.6C2.8,12.784 2.764,12.966 2.693,13.136C2.623,13.306 2.52,13.46 2.39,13.59C2.26,13.72 2.106,13.823 1.936,13.893C1.766,13.964 1.584,14 1.4,14ZM12.6,14C12.229,14 11.873,13.852 11.61,13.59C11.347,13.327 11.2,12.971 11.2,12.6V5.6C11.2,5.229 11.348,4.873 11.61,4.61C11.873,4.348 12.229,4.2 12.6,4.2C12.971,4.2 13.327,4.348 13.59,4.61C13.852,4.873 14,5.229 14,5.6V12.6C14,12.971 13.852,13.327 13.59,13.59C13.327,13.852 12.971,14 12.6,14Z"
|
||||
android:fillColor="#FF80F988"/>
|
||||
</vector>
|
||||
@ -16,11 +16,17 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/view"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/title_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/view"
|
||||
|
||||
android:layout_margin="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
@ -39,10 +45,65 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/loadingLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:indeterminateTint="@color/green"
|
||||
android:progressBackgroundTint="@color/green"
|
||||
android:progressTint="@color/green"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/no_content_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/no_content_iv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@mipmap/no_content_img" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:fontFamily="@font/medium_font"
|
||||
android:gravity="center"
|
||||
android:text="@string/content_loading_failed"
|
||||
android:textSize="14dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tryAgainBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/drw_btn_bg"
|
||||
android:fontFamily="@font/medium_font"
|
||||
android:gravity="center"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/try_again"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/title_layout"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
@ -119,4 +180,6 @@
|
||||
android:layout_margin="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="8"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<View
|
||||
@ -40,15 +40,15 @@
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="8"
|
||||
android:background="@drawable/drw_details_bg"
|
||||
android:visibility="gone" />
|
||||
android:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@color/main_bg_color" />
|
||||
android:background="@color/black" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -122,19 +122,42 @@
|
||||
android:progressBackgroundTint="@color/green"
|
||||
android:progressTint="@color/green" />
|
||||
|
||||
<TextView
|
||||
<LinearLayout
|
||||
android:id="@+id/playback_error_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:background="@color/black_60"
|
||||
android:padding="24dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
|
||||
android:fontFamily="@font/medium_font"
|
||||
android:gravity="center"
|
||||
android:text="@string/playback_error"
|
||||
android:textColor="@color/white_80"
|
||||
android:textSize="16dp"
|
||||
android:visibility="gone" />
|
||||
android:textSize="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tryAgainBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/drw_btn_bg"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingTop="8dp"
|
||||
android:fontFamily="@font/medium_font"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:text="@string/try_again"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@ -346,4 +369,50 @@
|
||||
android:orientation="horizontal" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:id="@+id/bottom_blank_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="68dp"
|
||||
android:layout_weight="3" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="5"
|
||||
android:background="@drawable/drw_bottom_layout_bg"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottomCloseBtn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="4dp"
|
||||
android:background="@drawable/drw_bottom_close_btn_bg"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/playListRv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/sv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="-2dp">
|
||||
|
||||
90
app/src/main/res/layout/play_list_item.xml
Normal file
90
app/src/main/res/layout/play_list_item.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="0dp"
|
||||
android:visibility="visible"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/musicoo_logo_img" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/currentPlayingLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black_60"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/playing_small_green_icon" />
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.player.musicoo.view.MarqueeTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/regular_font"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14dp" />
|
||||
|
||||
<com.player.musicoo.view.MarqueeTextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/regular_font"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/white_60"
|
||||
android:textSize="12dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@ -8,4 +8,6 @@
|
||||
<color name="white_80">#CCFFFFFF</color>
|
||||
<color name="main_bg_color">#151718</color>
|
||||
<color name="green">#FF80F988</color>
|
||||
<color name="green_60">#9980F988</color>
|
||||
<color name="bottom_layout_bg_color">#1A1A1A</color>
|
||||
</resources>
|
||||
Loading…
Reference in New Issue
Block a user