This commit is contained in:
ocean 2024-06-24 13:48:15 +08:00
parent 9d76dafa47
commit 6fe4b96b4e
16 changed files with 977 additions and 92 deletions

View File

@ -95,15 +95,17 @@ class LaunchActivity : MoBaseActivity() {
// if (!withPermission()) { // if (!withPermission()) {
// if (type == 1) {//如果type等于1则是从后台进入的应用不进行跳转直接关闭启动页 // if (type == 1) {//如果type等于1则是从后台进入的应用不进行跳转直接关闭启动页
// finish() // finish()
// return // } else {
// }
// startActivity(Intent(this, MainActivity::class.java)) // startActivity(Intent(this, MainActivity::class.java))
// finish()
// }
// } else { // } else {
if (type == 1) { if (type == 1) {
finish() finish()
return } else {
}
startActivity(Intent(this, PrimaryActivity::class.java)) startActivity(Intent(this, PrimaryActivity::class.java))
finish()
}
// } // }
} }

View File

@ -263,6 +263,18 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
App.appFavoriteDBManager.insertFavoriteBean(bean) App.appFavoriteDBManager.insertFavoriteBean(bean)
} }
suspend fun insertFavoriteData(offlineBean: OfflineBean) {
val bean = FavoriteBean(
videoId = offlineBean.videoId,
title = offlineBean.title,
name = offlineBean.name,
thumbnail = offlineBean.thumbnail,
isFavorite = true
)
LogTag.LogD(TAG, "insertFavoriteBean bean->${bean}")
App.appFavoriteDBManager.insertFavoriteBean(bean)
}
fun withPermission(): Boolean { fun withPermission(): Boolean {
//先判断当前配置的开关是否为true为false的话就直接进入A //先判断当前配置的开关是否为true为false的话就直接进入A
val jsonString = appStore.shouldEnterMusicPageJson//得到配置的json val jsonString = appStore.shouldEnterMusicPageJson//得到配置的json

View File

@ -2,7 +2,12 @@ package melody.offline.music.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.View import android.view.View
import android.view.animation.AnimationUtils
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
@ -13,20 +18,30 @@ import melody.offline.music.adapter.LikedSongsAdapter
import melody.offline.music.ads.AdPlacement import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityLikedSongsBinding import melody.offline.music.databinding.ActivityLikedSongsBinding
import melody.offline.music.service.ViewModelMain
import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.LogTag
import org.json.JSONObject
class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavoritesClickListener { @OptIn(UnstableApi::class)
class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavoritesClickListener,
LikedSongsAdapter.OnMoreClickListener {
private val requests: Channel<Request> = Channel(Channel.UNLIMITED) private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
sealed class Request { sealed class Request {
data object TryAgain : Request() data object TryAgain : Request()
data class UpdateFavorite(val bean: FavoriteBean) : Request() data class UpdateFavorite(val bean: FavoriteBean) : Request()
data class OnFavorites(val bean: FavoriteBean) : Request()
} }
private lateinit var binding: ActivityLikedSongsBinding private lateinit var binding: ActivityLikedSongsBinding
private var adapter: LikedSongsAdapter? = null private var adapter: LikedSongsAdapter? = null
private var favoriteBeans: MutableList<FavoriteBean> = mutableListOf() private var favoriteBeans: MutableList<FavoriteBean> = mutableListOf()
private var currentPosition = -1
override suspend fun main() { override suspend fun main() {
binding = ActivityLikedSongsBinding.inflate(layoutInflater) binding = ActivityLikedSongsBinding.inflate(layoutInflater)
@ -58,9 +73,21 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
} }
is Request.UpdateFavorite -> { is Request.UpdateFavorite -> {
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
if (currentFavoriteBean != null) {
updateFavoriteUi(currentFavoriteBean.isFavorite)
} else {
updateFavoriteUi(false)
}
}
is Request.OnFavorites -> {
it.bean.isFavorite = !it.bean.isFavorite it.bean.isFavorite = !it.bean.isFavorite
adapter?.notifyDataSetChanged() adapter?.notifyDataSetChanged()
updateFavoriteUi(it.bean.isFavorite)
val currentFavoriteBean = val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
if (currentFavoriteBean != null) { if (currentFavoriteBean != null) {
@ -106,24 +133,165 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
} }
private fun initView() { private fun initView() {
binding.layoutInfo.setOnClickListener { }
binding.backBtn.setOnClickListener { binding.backBtn.setOnClickListener {
finish() finish()
} }
binding.tryAgainBtn.setOnClickListener { binding.tryAgainBtn.setOnClickListener {
requests.trySend(Request.TryAgain) requests.trySend(Request.TryAgain)
} }
binding.bottomCloseBtn.setOnClickListener {
hideBottomLayout()
}
binding.bottomBlankLayout.setOnClickListener {
hideBottomLayout()
}
binding.favoritesBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(Request.OnFavorites(favoriteBeans[currentPosition]))
}
}
binding.moreDownloadBtn.setOnClickListener {
}
} }
private fun initAdapter() { private fun initAdapter() {
adapter = LikedSongsAdapter(this, favoriteBeans) adapter = LikedSongsAdapter(this, favoriteBeans)
adapter?.setOnFavoritesItemClickListener(this) adapter?.setOnFavoritesItemClickListener(this)
binding.rv.layoutManager = adapter?.setOnMoreClickListener(this)
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rv.adapter = adapter binding.rv.adapter = adapter
} }
override fun onFavoritesItemClick(position: Int) { override fun onFavoritesItemClick(position: Int) {
requests.trySend(Request.UpdateFavorite(favoriteBeans[position])) requests.trySend(Request.OnFavorites(favoriteBeans[position]))
}
override fun onMoreClick(position: Int) {
currentPosition = position
toggleBottomLayout(position)
}
private fun initDownloadFlow() {
ViewModelMain.modelDownloadsFlow.observe(this) { downloads ->
if (meController != null && meController.currentMediaItem != null) {
val id = meController.currentMediaItem?.mediaId
val currentScreenDownloads = downloads[id]
if (currentScreenDownloads != null) {
updateDownloadUI(currentScreenDownloads)
}
}
}
}
private fun updateDownloadUI(download: Download) {
when (download.state) {
Download.STATE_DOWNLOADING -> {
binding.downloadLoading.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadImg.visibility = View.GONE
binding.downloadTv.text = getString(R.string.download_saving)
binding.moreDownloadBtn.isClickable = false
binding.moreDownloadBtn.isEnabled = false
}
Download.STATE_COMPLETED -> {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.downloadImg.visibility = View.VISIBLE
binding.downloadTv.text = getString(R.string.download_remove_offline)
val jsonObject = JSONObject()
jsonObject.put(
"download_id", download.request.id
)
val songMap = mutableMapOf(
Pair(
AnalysisUtil.PARAM_VALUE, jsonObject.toString()
)
)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_DOWNLOAD_SUCCESS_ACTION, songMap)
}
Download.STATE_FAILED -> {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.setImageResource(R.drawable.error)
binding.downloadImg.visibility = View.VISIBLE
binding.downloadTv.text = getString(R.string.download_save_offline)
binding.moreDownloadBtn.isClickable = true
binding.moreDownloadBtn.isEnabled = true
}
else -> {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.setImageResource(R.drawable.download_icon)
binding.downloadImg.visibility = View.VISIBLE
binding.downloadTv.text = getString(R.string.download_save_offline)
binding.moreDownloadBtn.isClickable = true
binding.moreDownloadBtn.isEnabled = true
}
}
}
private fun updateFavoriteUi(b: Boolean) {
if (b) {
binding.favoritesImg.setImageResource(R.drawable.favorited_icon)
} else {
binding.favoritesImg.setImageResource(R.drawable.not_favorited_icon)
}
}
private fun toggleBottomLayout(position: Int) {
if (binding.bottomLayout.visibility == View.VISIBLE) {
hideBottomLayout()
} else {
showBottomLayout(position)
}
}
private fun showBottomLayout(position: Int) {
val slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_up)
binding.bottomLayout.startAnimation(slideUpAnimation)
binding.bottomLayout.visibility = View.VISIBLE
val bean = favoriteBeans[position]
Glide.with(this).load(bean.thumbnail).into(binding.songImg)
binding.title.text = bean.title
if (bean.name.isEmpty()) {
binding.name.visibility = View.GONE
} else {
binding.name.visibility = View.VISIBLE
binding.name.text = bean.name
}
requests.trySend(Request.UpdateFavorite(bean))
if (DownloadUtil.downloadResourceExist(bean.videoId)) {//已经下载,按钮不可点击
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.moreDownloadBtn.isClickable = false
binding.moreDownloadBtn.isEnabled = false
binding.downloadTv.text = getString(R.string.download_remove_offline)
} else {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadImg.visibility = View.VISIBLE
binding.moreDownloadBtn.isClickable = true
binding.moreDownloadBtn.isEnabled = true
binding.downloadTv.text = getString(R.string.download_save_offline)
}
}
private fun hideBottomLayout() {
val slideDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_down)
binding.bottomLayout.startAnimation(slideDownAnimation)
binding.bottomLayout.visibility = View.GONE
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@ -157,5 +325,4 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
binding.loadingLayout.visibility = View.GONE binding.loadingLayout.visibility = View.GONE
binding.noContentLayout.visibility = View.VISIBLE binding.noContentLayout.visibility = View.VISIBLE
} }
} }

View File

@ -1,9 +1,18 @@
package melody.offline.music.activity package melody.offline.music.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.media3.common.MediaItem import android.view.animation.AnimationUtils
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
@ -16,16 +25,18 @@ import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.OfflineBean import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityOfflineSongsBinding import melody.offline.music.databinding.ActivityOfflineSongsBinding
import melody.offline.music.util.AnalysisUtil import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.LogTag import melody.offline.music.util.LogTag
import org.json.JSONObject import org.json.JSONObject
@OptIn(UnstableApi::class)
class MoOfflineSongsActivity : MoBaseActivity() { class MoOfflineSongsActivity : MoBaseActivity() {
private val requests: Channel<Request> = Channel(Channel.UNLIMITED) private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
sealed class Request { sealed class Request {
data object TryAgain : Request() data object TryAgain : Request()
data object OnFavorites : Request() data class OnFavorites(val bean: OfflineBean) : Request()
data class OnDownload(val mediaItem: MediaItem) : Request() data class OnDownloadRemove(val id: String) : Request()
data class UpdateFavorite(val id: String) : Request() data class UpdateFavorite(val id: String) : Request()
} }
@ -33,6 +44,8 @@ class MoOfflineSongsActivity : MoBaseActivity() {
private var adapter: OfflineSongsAdapter? = null private var adapter: OfflineSongsAdapter? = null
private var offlineList: MutableList<OfflineBean> = mutableListOf() private var offlineList: MutableList<OfflineBean> = mutableListOf()
private var currentPosition = -1
override suspend fun main() { override suspend fun main() {
binding = ActivityOfflineSongsBinding.inflate(layoutInflater) binding = ActivityOfflineSongsBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@ -62,16 +75,10 @@ class MoOfflineSongsActivity : MoBaseActivity() {
initData() initData()
} }
is Request.OnDownload -> { is Request.OnFavorites -> {
}
Request.OnFavorites -> {
if (meController != null && meController.currentMediaItem != null) {
val currentMediaItem = meController.currentMediaItem
val jsonObject = JSONObject() val jsonObject = JSONObject()
jsonObject.put( jsonObject.put(
"song_title", "${currentMediaItem?.mediaMetadata?.title}" "song_title", it.bean.title
) )
val songMap = mutableMapOf( val songMap = mutableMapOf(
Pair( Pair(
@ -79,7 +86,7 @@ class MoOfflineSongsActivity : MoBaseActivity() {
) )
) )
val currentFavoriteBean = val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!) App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
if (currentFavoriteBean != null) { if (currentFavoriteBean != null) {
currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite
App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean) App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean)
@ -93,17 +100,38 @@ class MoOfflineSongsActivity : MoBaseActivity() {
) )
} }
} else { } else {
insertFavoriteData(currentMediaItem) insertFavoriteData(it.bean)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap) AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap)
} }
requests.trySend(Request.UpdateFavorite(currentMediaItem.mediaId)) requests.trySend(Request.UpdateFavorite(it.bean.videoId))
} }
is Request.OnDownloadRemove -> {
val currentOfflineBean =
App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (currentOfflineBean != null) {
App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean)
}
if (currentPosition >= 0) {
offlineList.remove(offlineList[currentPosition])
}
adapter?.notifyDataSetChanged()
hideBottomLayout()
} }
is Request.UpdateFavorite -> { is Request.UpdateFavorite -> {
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.id)
if (currentFavoriteBean != null) {
updateFavoriteUi(currentFavoriteBean.isFavorite)
} else {
updateFavoriteUi(false)
} }
} }
}
} }
events.onReceive { events.onReceive {
when (it) { when (it) {
@ -142,19 +170,41 @@ class MoOfflineSongsActivity : MoBaseActivity() {
} }
private fun initView() { private fun initView() {
binding.layoutInfo.setOnClickListener { }
binding.backBtn.setOnClickListener { binding.backBtn.setOnClickListener {
finish() finish()
} }
binding.tryAgainBtn.setOnClickListener { binding.tryAgainBtn.setOnClickListener {
requests.trySend(Request.TryAgain) requests.trySend(Request.TryAgain)
} }
binding.bottomCloseBtn.setOnClickListener {
hideBottomLayout()
}
binding.bottomBlankLayout.setOnClickListener {
hideBottomLayout()
}
binding.moreDownloadBtn.setOnClickListener {
if (currentPosition >= 0) {
val videoId = offlineList[currentPosition].videoId
showRemoveDownloadDialogHint(videoId)
}
}
binding.moreAddPlaylistBtn.setOnClickListener {
}
binding.favoritesBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(Request.OnFavorites(offlineList[currentPosition]))
}
}
} }
private fun initAdapter() { private fun initAdapter() {
adapter = OfflineSongsAdapter(this, offlineList) adapter = OfflineSongsAdapter(this, offlineList)
adapter?.setOnFavoriteClickListener(object : OfflineSongsAdapter.OnFavoriteClickListener { adapter?.setOnMoreClickListener(object : OfflineSongsAdapter.OnMoreClickListener {
override fun onFavoriteClick(position: Int) { override fun onMoreClick(position: Int) {
requests.trySend(Request.OnFavorites) currentPosition = position
toggleBottomLayout(position)
} }
}) })
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
@ -170,12 +220,15 @@ class MoOfflineSongsActivity : MoBaseActivity() {
// 更新 // 更新
offlineBeans.forEach { offlineBean -> offlineBeans.forEach { offlineBean ->
val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(offlineBean.videoId) val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(offlineBean.videoId)
if (offlineBean.id == favoriteBean?.id) { if (favoriteBean != null) {
if (offlineBean.id == favoriteBean.id) {
offlineBean.isFavorite = favoriteBean.isFavorite offlineBean.isFavorite = favoriteBean.isFavorite
App.appOfflineDBManager.updateOfflineBean(offlineBean) App.appOfflineDBManager.updateOfflineBean(offlineBean)
} }
} }
val filteredBeans = offlineBeans.filter { it.bytesDownloaded?.let { bytes -> bytes > 0 } == true } }
val filteredBeans =
offlineBeans.filter { it.bytesDownloaded?.let { bytes -> bytes > 0 } == true }
offlineList.addAll(filteredBeans) offlineList.addAll(filteredBeans)
if (offlineList.size > 0) { if (offlineList.size > 0) {
showDataUi() showDataUi()
@ -188,6 +241,64 @@ class MoOfflineSongsActivity : MoBaseActivity() {
} }
private fun showRemoveDownloadDialogHint(id: String) {
LogTag.LogD(TAG, "showRemoveDownloadDialogHint")
val inflater = LayoutInflater.from(this)
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(this).setView(dialogView)
val dialog = dialogBuilder.create()
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.show()
okBtn.setOnClickListener {
dialog.dismiss()
requests.trySend(Request.OnDownloadRemove(id))
}
cancelBtn.setOnClickListener {
dialog.dismiss()
}
}
private fun updateFavoriteUi(b: Boolean) {
if (b) {
binding.favoritesImg.setImageResource(R.drawable.favorited_icon)
} else {
binding.favoritesImg.setImageResource(R.drawable.not_favorited_icon)
}
}
private fun toggleBottomLayout(position: Int) {
if (binding.bottomLayout.visibility == View.VISIBLE) {
hideBottomLayout()
} else {
showBottomLayout(position)
}
}
private fun showBottomLayout(position: Int) {
val slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_up)
binding.bottomLayout.startAnimation(slideUpAnimation)
binding.bottomLayout.visibility = View.VISIBLE
val bean = offlineList[position]
Glide.with(this).load(bean.thumbnail).into(binding.songImg)
binding.title.text = bean.title
if (bean.name.isEmpty()) {
binding.name.visibility = View.GONE
} else {
binding.name.visibility = View.VISIBLE
binding.name.text = bean.name
}
requests.trySend(Request.UpdateFavorite(bean.videoId))
}
private fun hideBottomLayout() {
val slideDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_down)
binding.bottomLayout.startAnimation(slideDownAnimation)
binding.bottomLayout.visibility = View.GONE
}
private fun showDataUi() { private fun showDataUi() {
binding.loadingLayout.visibility = View.GONE binding.loadingLayout.visibility = View.GONE
binding.noContentLayout.visibility = View.GONE binding.noContentLayout.visibility = View.GONE

View File

@ -46,6 +46,11 @@ class LikedSongsAdapter(
itemFavoritesClickListener?.onFavoritesItemClick(position) itemFavoritesClickListener?.onFavoritesItemClick(position)
} }
} }
holder.binding.moreBtn.setOnClickListener {
if (moreClickListener != null) {
moreClickListener?.onMoreClick(position)
}
}
} }
override fun getItemCount(): Int = list.size override fun getItemCount(): Int = list.size
@ -107,4 +112,14 @@ class LikedSongsAdapter(
interface OnItemFavoritesClickListener { interface OnItemFavoritesClickListener {
fun onFavoritesItemClick(position: Int) fun onFavoritesItemClick(position: Int)
} }
private var moreClickListener: OnMoreClickListener? = null
fun setOnMoreClickListener(listener: OnMoreClickListener) {
moreClickListener = listener
}
interface OnMoreClickListener {
fun onMoreClick(position: Int)
}
} }

View File

@ -18,8 +18,7 @@ import melody.offline.music.media.MediaControllerManager
class OfflineSongsAdapter( class OfflineSongsAdapter(
private val context: Context, private val context: Context,
private val list: List<OfflineBean>, private val list: List<OfflineBean>,
) : ) : RecyclerView.Adapter<OfflineSongsAdapter.ViewHolder>() {
RecyclerView.Adapter<OfflineSongsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = OfflineListItemBinding.inflate(LayoutInflater.from(context), parent, false) val binding = OfflineListItemBinding.inflate(LayoutInflater.from(context), parent, false)
@ -30,19 +29,19 @@ class OfflineSongsAdapter(
val bean = list[position] val bean = list[position]
holder.bind(bean) holder.bind(bean)
holder.binding.favoritedBtn.setOnClickListener { holder.binding.moreBtn.setOnClickListener {
if (favoriteClickListener != null) { if (moreClickListener != null) {
favoriteClickListener?.onFavoriteClick(position) moreClickListener?.onMoreClick(position)
} }
} }
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
val intent = Intent(context, MoPlayDetailsActivity::class.java) val intent = Intent(context, MoPlayDetailsActivity::class.java)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, bean.videoId) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, bean.videoId)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.title) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.title)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.name) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.name)
intent.putExtra( intent.putExtra(
MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoOfflineSongsActivity::class.java
MoOfflineSongsActivity::class.java
) )
context.startActivity(intent) context.startActivity(intent)
@ -58,9 +57,7 @@ class OfflineSongsAdapter(
fun bind(bean: OfflineBean) { fun bind(bean: OfflineBean) {
binding.apply { binding.apply {
Glide.with(context) Glide.with(context).load(bean.thumbnail).into(image)
.load(bean.thumbnail)
.into(image)
title.text = bean.title title.text = bean.title
if (bean.name.isEmpty()) { if (bean.name.isEmpty()) {
name.visibility = View.GONE name.visibility = View.GONE
@ -84,12 +81,6 @@ class OfflineSongsAdapter(
binding.listPlayView.visibility = View.GONE binding.listPlayView.visibility = View.GONE
} }
} }
if (bean.isFavorite) {
binding.favoritedImg.setImageResource(R.drawable.favorited_icon)
} else {
binding.favoritedImg.setImageResource(R.drawable.not_favorited_icon)
}
} }
} }
} }
@ -104,13 +95,13 @@ class OfflineSongsAdapter(
fun onItemClick(position: Int) fun onItemClick(position: Int)
} }
private var favoriteClickListener: OnFavoriteClickListener? = null private var moreClickListener: OnMoreClickListener? = null
fun setOnFavoriteClickListener(listener: OnFavoriteClickListener) { fun setOnMoreClickListener(listener: OnMoreClickListener) {
favoriteClickListener = listener moreClickListener = listener
} }
interface OnFavoriteClickListener { interface OnMoreClickListener {
fun onFavoriteClick(position: Int) fun onMoreClick(position: Int)
} }
} }

View File

@ -0,0 +1,48 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4,14H12"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M4,18.5H12"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M4,9.5H20"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M4,5H20"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M15,16.5H20"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
<path
android:pathData="M17.5,14V19"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M21,12C21,15.375 19,21 12,21C5,21 3,15.375 3,12"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M11.996,14.449L12,2"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
<path
android:pathData="M18,8.5L12,14.5L6,8.5"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M21,12C21,15.375 19,21 12,21C5,21 3,15.375 3,12"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
<path
android:pathData="M11.996,14.449L12,2"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
<path
android:pathData="M18,8.5L12,14.5L6,8.5"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#80F988"
android:strokeLineCap="round"/>
</vector>

View File

@ -1,4 +1,5 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/main_bg_color" android:background="@color/main_bg_color"
@ -153,4 +154,198 @@
</LinearLayout> </LinearLayout>
<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:id="@+id/layout_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/drw_bottom_layout_bg"
android:orientation="vertical"
android:paddingBottom="32dp"
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>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="18dp"
android:paddingEnd="18dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="0dp"
app:cardBackgroundColor="@color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/songImg"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/app_logo" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<melody.offline.music.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" />
<melody.offline.music.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
android:id="@+id/favoritesBtn"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="@drawable/drw_round_48_bg"
android:gravity="center">
<ImageView
android:id="@+id/favoritesImg"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/not_favorited_icon" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/liner_color" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/moreDownloadBtn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/downloadImg"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/more_download_icon" />
<ProgressBar
android:id="@+id/downloadLoading"
android:layout_width="24dp"
android:layout_height="24dp"
android:indeterminateTint="@color/green"
android:progressBackgroundTint="@color/green"
android:progressTint="@color/green"
android:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/downloadTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/download"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/moreAddPlaylistBtn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/more_add_playlist_icon" />
<TextView
android:id="@+id/addPlaylistTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/add_to_playlist"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -147,10 +147,201 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:orientation="vertical" /> android:orientation="vertical" />
</RelativeLayout>
</LinearLayout>
<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:id="@+id/layout_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/drw_bottom_layout_bg"
android:orientation="vertical"
android:paddingBottom="32dp"
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>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="18dp"
android:paddingEnd="18dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="0dp"
app:cardBackgroundColor="@color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/songImg"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/app_logo" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<melody.offline.music.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" />
<melody.offline.music.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
android:id="@+id/favoritesBtn"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="@drawable/drw_round_48_bg"
android:gravity="center">
<ImageView
android:id="@+id/favoritesImg"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/not_favorited_icon" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/liner_color" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/moreDownloadBtn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/downloadImg"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/more_downloaded_icon" />
<ProgressBar
android:id="@+id/downloadLoading"
android:layout_width="24dp"
android:layout_height="24dp"
android:indeterminateTint="@color/green"
android:progressBackgroundTint="@color/green"
android:progressTint="@color/green"
android:visibility="gone" />
</RelativeLayout> </RelativeLayout>
<TextView
android:id="@+id/downloadTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/download_remove_offline"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/moreAddPlaylistBtn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/more_add_playlist_icon" />
<TextView
android:id="@+id/addPlaylistTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/add_to_playlist"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,93 @@
<!-- custom_dialog_layout.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/drw_dialog_bg"
android:orientation="vertical"
android:padding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@mipmap/app_logo" />
<TextView
android:id="@+id/dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:fontFamily="@font/medium_font"
android:text="@string/download_remove_offline"
android:textColor="@color/white"
android:textSize="16dp" />
</LinearLayout>
</RelativeLayout>
<TextView
android:id="@+id/dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:fontFamily="@font/regular_font"
android:text="@string/download_remove_hint"
android:textColor="@color/white_60"
android:textSize="14dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center_vertical"
android:visibility="visible">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<TextView
android:id="@+id/dialog_cancel_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fontFamily="@font/medium_font"
android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/cancel"
android:textColor="@color/white_60"
android:textSize="16dp"
android:visibility="visible" />
<TextView
android:id="@+id/dialog_ok_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:fontFamily="@font/medium_font"
android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/ok"
android:textColor="@color/white"
android:textSize="16dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -112,6 +112,20 @@
android:layout_height="24dp" android:layout_height="24dp"
android:src="@drawable/not_favorited_icon" /> android:src="@drawable/not_favorited_icon" />
</RelativeLayout> </RelativeLayout>
<LinearLayout
android:id="@+id/moreBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/three_dots_icon" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -117,24 +117,10 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<LinearLayout
android:id="@+id/favoritedBtn"
android:layout_width="36dp"
android:layout_height="36dp"
android:gravity="center">
<ImageView
android:id="@+id/favoritedImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/not_favorited_icon" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/moreBtn" android:id="@+id/moreBtn"
android:layout_width="36dp" android:layout_width="40dp"
android:layout_height="36dp" android:layout_height="40dp"
android:gravity="center"> android:gravity="center">
<ImageView <ImageView

View File

@ -15,4 +15,5 @@
<color name="transparent">#00000000</color> <color name="transparent">#00000000</color>
<color name="car_bg_color">#3A3D3B</color> <color name="car_bg_color">#3A3D3B</color>
<color name="car_bg_color_60">#993A3D3B</color> <color name="car_bg_color_60">#993A3D3B</color>
<color name="liner_color">#FF444444</color>
</resources> </resources>

View File

@ -40,4 +40,9 @@
<string name="prompt">Prompt</string> <string name="prompt">Prompt</string>
<string name="play">PLAY</string> <string name="play">PLAY</string>
<string name="download_tips">There are additional download tasks in progress, please wait a moment.</string> <string name="download_tips">There are additional download tasks in progress, please wait a moment.</string>
<string name="add_to_playlist">Add to playlist</string>
<string name="download_saving">Saving</string>
<string name="download_save_offline">Save to Offline</string>
<string name="download_remove_offline">Remove from offline</string>
<string name="download_remove_hint">Are you sure you want to delete this downloaded music file?</string>
</resources> </resources>