This commit is contained in:
ocean 2024-06-27 16:33:31 +08:00
parent 55df7e9988
commit 6aea370d98
13 changed files with 367 additions and 34 deletions

View File

@ -81,6 +81,7 @@ dependencies {
implementation("androidx.media3:media3-ui:1.3.1")
implementation("androidx.media3:media3-common:1.3.1")
implementation("androidx.media3:media3-datasource-cronet:1.3.1")
implementation("androidx.media3:media3-datasource-okhttp:1.3.1")
implementation("io.coil-kt:coil-compose:2.6.0")
implementation("io.ktor:ktor-client-core:2.3.8")

View File

@ -117,7 +117,7 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
val id = it.favoriteBean.videoId
LogTag.LogD(TAG, "OnDownload id->${id}")
val currentOfflineBean = App.appOfflineDBManager.getOfflineBeanByID(id)
if (currentOfflineBean != null) {//判断当前数据库是否有这条数据。
if (currentOfflineBean != null && currentOfflineBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {//判断当前数据库是否有这条数据。
if (currentPosition >= 0) {
val videoId = favoriteBeans[currentPosition].videoId
showRemoveDownloadDialogHint(videoId)
@ -185,11 +185,16 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
}
is Request.OnUpdateDownloadUi -> {
if (App.appOfflineDBManager.getOfflineBeanByID(it.id) != null) {
val offBean = App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.downloadTv.text =
getString(R.string.download_remove_offline)
} else {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadTv.text = getString(R.string.download_save_offline)
}
@ -406,8 +411,6 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
}
requests.trySend(Request.UpdateFavorite(bean))
requests.trySend(Request.OnUpdateDownloadUi(bean.videoId))
val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId)
if (currentDownload != null) {
updateDownloadUI(currentDownload)

View File

@ -28,7 +28,6 @@ import melody.offline.music.adapter.DetailsListAdapter
import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityDetailsBinding
import melody.offline.music.innertube.Innertube
import melody.offline.music.innertube.requests.moPlaylistPage
@ -36,7 +35,6 @@ import melody.offline.music.service.MyDownloadService
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 melody.offline.music.util.LogTag.LogD
import org.json.JSONObject
@ -162,9 +160,8 @@ class MoListDetailsActivity : MoBaseActivity(), DetailsListAdapter.OnItemMoreCli
is Request.OnDownload -> {
val id = it.bean.videoId
val currentOfflineBean =
App.appOfflineDBManager.getOfflineBeanByID(id!!)
if (currentOfflineBean != null) {//判断当前数据库是否有这条数据。
val offBean = App.appOfflineDBManager.getOfflineBeanByID(id!!)
if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {//判断当前数据库是否有这条数据。
if (currentPosition >= 0) {
showRemoveDownloadDialogHint(id)
}
@ -244,11 +241,16 @@ class MoListDetailsActivity : MoBaseActivity(), DetailsListAdapter.OnItemMoreCli
}
is Request.OnUpdateDownloadUi -> {
if (App.appOfflineDBManager.getOfflineBeanByID(it.id) != null) {
val offBean = App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.downloadTv.text =
getString(R.string.download_remove_offline)
} else {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadTv.text = getString(R.string.download_save_offline)
}
@ -436,6 +438,7 @@ class MoListDetailsActivity : MoBaseActivity(), DetailsListAdapter.OnItemMoreCli
}
private fun updateDownloadUI(download: Download) {
LogD(TAG, "download.state->${download.state}")
when (download.state) {
Download.STATE_DOWNLOADING -> {
binding.downloadLoading.visibility = View.VISIBLE
@ -527,11 +530,11 @@ class MoListDetailsActivity : MoBaseActivity(), DetailsListAdapter.OnItemMoreCli
}
requests.trySend(Request.UpdateFavorite(bean))
requests.trySend(Request.OnUpdateDownloadUi(bean.videoId!!))
val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId)
val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId!!)
if (currentDownload != null) {
updateDownloadUI(currentDownload)
} else {
requests.trySend(Request.OnUpdateDownloadUi(bean.videoId))
}
}

View File

@ -68,6 +68,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
const val PLAY_DETAILS_NAME = "play_details_name"
const val PLAY_DETAILS_DESC = "play_details_desc"
const val PLAY_DETAILS_COME_FROM = "PLAY_DETAILS_COME_FROM"
const val PLAY_LIST_ID = "play_list_id"
}
private lateinit var binding: ActivityMoPlayDetailsBinding
@ -164,6 +165,34 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
} else {
binding.playbackErrorLayout.visibility = View.VISIBLE
}
} else if (comeFrom != null && comeFrom == MoPlaylistSongsActivity::class.java) {
LogD(TAG, "从 playlist songs 进入")
binding.nameTv.text = intent.getStringExtra(PLAY_DETAILS_NAME)
binding.descTv.text = intent.getStringExtra(PLAY_DETAILS_DESC)
val playlistID = intent.getIntExtra(PLAY_LIST_ID, -1)
val playlistItems = App.appPlaylistDBManager.getPlaylistItems(playlistID)
//找到当前点击进来的歌曲media
val findCurrentMedia = playlistItems.find { it.videoId == videoId }?.asMediaItem
if (findCurrentMedia != null) {
binding.likeAndDownloadLayout.visibility = View.VISIBLE
updateInfoUi(findCurrentMedia)
binding.playbackErrorLayout.visibility = View.GONE
binding.totalDurationTv.visibility = View.GONE
meController?.let {
it.setMediaItem(findCurrentMedia, true)
it.prepare()
it.play()
val mediaItems =
playlistItems.map { mapAll -> mapAll.asMediaItem }//转换成MediaItem
.filter { filter -> filter.mediaId != videoId }//过滤掉id相等的。
it.addMediaItems(mediaItems)
}
updatePlayListDataAndAdapter()
} else {
binding.playbackErrorLayout.visibility = View.VISIBLE
}
} else {
LogD(TAG, "从点击任意歌曲进入")
binding.nameTv.text = intent.getStringExtra(PLAY_DETAILS_NAME)

View File

@ -7,9 +7,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
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 com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar
@ -21,8 +26,15 @@ import melody.offline.music.R
import melody.offline.music.adapter.PlaylistSongsAdapter
import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.PlaylistItem
import melody.offline.music.databinding.ActivityPlaylistSongsBinding
import melody.offline.music.service.MyDownloadService
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
@OptIn(UnstableApi::class)
class MoPlaylistSongsActivity : MoBaseActivity() {
@ -35,6 +47,22 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
sealed class Request {
data object TryAgain : 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 id: String) : Request()
data class OnUpdateDownloadUi(val id: String) : Request()
data class OnRemovePlaylist(
val bean: PlaylistItem
) : Request()
}
private lateinit var binding: ActivityPlaylistSongsBinding
@ -54,6 +82,7 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
initView()
initAdapter()
LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST)
initDownloadFlow()
initData()
onReceive()
}
@ -74,6 +103,158 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
Request.TryAgain -> {
initData()
}
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)
if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {//判断当前数据库是否有这条数据。
if (currentPosition >= 0) {
showRemoveDownloadDialogHint(id)
}
} else {
val isFavorite =
App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId.toString()) != null
//判断是否已经下载了这条数据,已经下载,就直接进行数据库数据存储,反之走下载流程。
if (DownloadUtil.downloadResourceExist(id)) {
val favoriteBean = FavoriteBean(
id,
it.bean.title,
it.bean.name,
it.bean.thumbnail,
isFavorite
)
insertOfflineData(favoriteBean)
requests.trySend(Request.OnUpdateDownloadUi(id))
} else {
val downloadRequest = DownloadRequest.Builder(id, id.toUri())
.setCustomCacheKey(id).build()
val downloadCount = DownloadUtil.getCurrentDownloads()
if (downloadCount >= 3) {
Toast.makeText(
this@MoPlaylistSongsActivity,
getString(R.string.download_tips),
Toast.LENGTH_LONG
).show()
} else {
DownloadService.sendAddDownload(
this@MoPlaylistSongsActivity,
MyDownloadService::class.java,
downloadRequest,
false
)
LolAdWrapper.shared.showAdTiming(
this@MoPlaylistSongsActivity, AdPlacement.INST_DOWNLOAD
)
val favoriteBean = FavoriteBean(
id,
it.bean.title,
it.bean.name,
it.bean.thumbnail,
isFavorite
)
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(
this@MoPlaylistSongsActivity, AdPlacement.INST_DOWNLOAD
)
}
}
}
}
is Request.OnDownloadRemove -> {
val currentOfflineBean =
App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (currentOfflineBean != null) {
App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean)
}
requests.trySend(Request.OnUpdateDownloadUi(it.id))
}
is Request.OnUpdateDownloadUi -> {
val offBean = App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.downloadTv.text =
getString(R.string.download_remove_offline)
} else {
binding.downloadLoading.visibility = View.GONE
binding.downloadImg.visibility = View.VISIBLE
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadTv.text = getString(R.string.download_save_offline)
}
}
is Request.OnRemovePlaylist -> {
playlistItems.remove(it.bean)
adapter?.notifyDataSetChanged()
App.appPlaylistDBManager.deletePlaylistItem(it.bean)
}
}
}
events.onReceive {
@ -132,17 +313,32 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
binding.bottomBlankLayout.setOnClickListener {
hideBottomLayout()
}
binding.favoritesBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(
Request.OnFavorites(
playlistItems[currentPosition]
)
)
}
}
binding.moreDownloadBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(
Request.OnDownload(
playlistItems[currentPosition]
)
)
}
}
binding.moreAddPlaylistBtn.setOnClickListener {
if (currentPosition >= 0) {
}
}
binding.favoritesBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(
Request.OnRemovePlaylist(
playlistItems[currentPosition]
)
)
hideBottomLayout()
}
}
}
@ -185,12 +381,85 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
dialog.show()
okBtn.setOnClickListener {
dialog.dismiss()
requests.trySend(Request.OnDownloadRemove(id))
}
cancelBtn.setOnClickListener {
dialog.dismiss()
}
}
private fun initDownloadFlow() {
ViewModelMain.modelDownloadsFlow.observe(this) { downloads ->
if (currentPosition >= 0) {
val id = playlistItems[currentPosition].videoId
val currentScreenDownloads = downloads[id]
if (currentScreenDownloads != null) {
updateDownloadUI(currentScreenDownloads)
}
}
}
}
private fun updateDownloadUI(download: Download) {
LogTag.LogD(TAG, "download.state->${download.state}")
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)
binding.moreDownloadBtn.isClickable = true
binding.moreDownloadBtn.isEnabled = true
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.more_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)
@ -221,6 +490,15 @@ class MoPlaylistSongsActivity : MoBaseActivity() {
binding.name.visibility = View.VISIBLE
binding.name.text = bean.name
}
requests.trySend(Request.UpdateFavorite(bean))
val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId)
if (currentDownload != null) {
updateDownloadUI(currentDownload)
} else {
requests.trySend(Request.OnUpdateDownloadUi(bean.videoId))
}
}
private fun hideBottomLayout() {

View File

@ -9,12 +9,10 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import melody.offline.music.R
import melody.offline.music.activity.MoOfflineSongsActivity
import melody.offline.music.activity.MoPlayDetailsActivity
import melody.offline.music.bean.OfflineBean
import melody.offline.music.activity.MoPlaylistSongsActivity
import melody.offline.music.bean.PlaylistItem
import melody.offline.music.databinding.PlayListItemBinding
import melody.offline.music.media.MediaControllerManager
class PlaylistSongsAdapter(
private val context: Context,
@ -43,14 +41,15 @@ class PlaylistSongsAdapter(
}
holder.itemView.setOnClickListener {
// val intent = Intent(context, MoPlayDetailsActivity::class.java)
// intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, bean.videoId)
// intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.title)
// intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.name)
// intent.putExtra(
// MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoOfflineSongsActivity::class.java
// )
// context.startActivity(intent)
val intent = Intent(context, MoPlayDetailsActivity::class.java)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, bean.videoId)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.title)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.name)
intent.putExtra(
MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoPlaylistSongsActivity::class.java
)
intent.putExtra(MoPlayDetailsActivity.PLAY_LIST_ID, bean.playlistId)
context.startActivity(intent)
}
}

View File

@ -159,8 +159,8 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
requireActivity(),
AdPlacement.NATIVE_ME_PAGE_LIST,
binding.frameAd,
R.layout.ad_layout_admob_result,
R.layout.ad_layout_max_result
R.layout.ad_layout_admob_banner,
R.layout.ad_layout_max_banner
)
}
@ -189,6 +189,7 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>(), NewPlayListAdapter.O
override fun onItemClick(position: Int) {
val intent = Intent(requireActivity(), MoPlaylistSongsActivity::class.java)
intent.putExtra(MoPlaylistSongsActivity.PLAYLIST_ID, playlist[position].id)
intent.putExtra(MoPlaylistSongsActivity.PLAYLIST_TITLE, playlist[position].title)
startActivity(intent)
}

View File

@ -11,6 +11,7 @@ import androidx.media3.common.MediaMetadata
import androidx.media3.common.util.UnstableApi
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
import melody.offline.music.bean.PlaylistItem
import melody.offline.music.innertube.Innertube
import melody.offline.music.innertube.models.bodies.ContinuationBody
import melody.offline.music.innertube.requests.playlistPage
@ -46,6 +47,21 @@ val FavoriteBean.asMediaItem: MediaItem
)
.build()
val PlaylistItem.asMediaItem: MediaItem
@OptIn(UnstableApi::class)
get() = MediaItem.Builder()
.setMediaId(videoId)
.setUri(videoId)
.setCustomCacheKey(videoId)
.setMediaMetadata(
MediaMetadata.Builder()
.setTitle(title)
.setArtist(name)
.setArtworkUri(thumbnail?.toUri())
.build()
)
.build()
val Innertube.SongItem.asMediaItem: MediaItem
@OptIn(UnstableApi::class)
get() = MediaItem.Builder()

View File

@ -383,7 +383,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/download"
android:text="@string/download_save_offline"
android:textColor="@color/white"
android:textSize="14dp" />

View File

@ -57,6 +57,7 @@
android:textSize="18dp" />
<RelativeLayout
android:visibility="gone"
android:id="@+id/playlist_title_more_btn"
android:layout_width="42dp"
android:layout_height="42dp">
@ -347,7 +348,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/add_to_playlist"
android:text="@string/remove_from_playlist"
android:textColor="@color/white"
android:textSize="14dp" />

View File

@ -94,7 +94,7 @@
<RelativeLayout
android:id="@+id/downloadBtn"
android:layout_width="40dp"
android:visibility="visible"
android:visibility="gone"
android:layout_height="40dp">
<ImageView

View File

@ -119,6 +119,7 @@
android:orientation="horizontal">
<LinearLayout
android:visibility="gone"
android:id="@+id/downloadBtn"
android:layout_width="40dp"
android:layout_height="40dp"

View File

@ -44,6 +44,7 @@
<string name="play">PLAY</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="remove_from_playlist">Remove from 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>