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 (type == 1) {//如果type等于1则是从后台进入的应用不进行跳转直接关闭启动页
// finish()
// return
// } else {
// startActivity(Intent(this, MainActivity::class.java))
// finish()
// }
// startActivity(Intent(this, MainActivity::class.java))
// } else {
if (type == 1) {
finish()
return
} else {
startActivity(Intent(this, PrimaryActivity::class.java))
finish()
}
startActivity(Intent(this, PrimaryActivity::class.java))
// }
}

View File

@ -263,6 +263,18 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
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 {
//先判断当前配置的开关是否为true为false的话就直接进入A
val jsonString = appStore.shouldEnterMusicPageJson//得到配置的json

View File

@ -2,7 +2,12 @@ package melody.offline.music.activity
import android.annotation.SuppressLint
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 com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel
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.LolAdWrapper
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
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)
sealed class Request {
data object TryAgain : Request()
data class UpdateFavorite(val bean: FavoriteBean) : Request()
data class OnFavorites(val bean: FavoriteBean) : Request()
}
private lateinit var binding: ActivityLikedSongsBinding
private var adapter: LikedSongsAdapter? = null
private var favoriteBeans: MutableList<FavoriteBean> = mutableListOf()
private var currentPosition = -1
override suspend fun main() {
binding = ActivityLikedSongsBinding.inflate(layoutInflater)
@ -58,9 +73,21 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
}
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
adapter?.notifyDataSetChanged()
updateFavoriteUi(it.bean.isFavorite)
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
if (currentFavoriteBean != null) {
@ -106,24 +133,165 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
}
private fun initView() {
binding.layoutInfo.setOnClickListener { }
binding.backBtn.setOnClickListener {
finish()
}
binding.tryAgainBtn.setOnClickListener {
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() {
adapter = LikedSongsAdapter(this, favoriteBeans)
adapter?.setOnFavoritesItemClickListener(this)
binding.rv.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
adapter?.setOnMoreClickListener(this)
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rv.adapter = adapter
}
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")
@ -157,5 +325,4 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
binding.loadingLayout.visibility = View.GONE
binding.noContentLayout.visibility = View.VISIBLE
}
}

View File

@ -1,9 +1,18 @@
package melody.offline.music.activity
import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import 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 com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
@ -16,16 +25,18 @@ import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityOfflineSongsBinding
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 MoOfflineSongsActivity : MoBaseActivity() {
private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
sealed class Request {
data object TryAgain : Request()
data object OnFavorites : Request()
data class OnDownload(val mediaItem: MediaItem) : Request()
data class OnFavorites(val bean: OfflineBean) : Request()
data class OnDownloadRemove(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 offlineList: MutableList<OfflineBean> = mutableListOf()
private var currentPosition = -1
override suspend fun main() {
binding = ActivityOfflineSongsBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -62,47 +75,62 @@ class MoOfflineSongsActivity : MoBaseActivity() {
initData()
}
is Request.OnDownload -> {
is Request.OnFavorites -> {
val jsonObject = JSONObject()
jsonObject.put(
"song_title", it.bean.title
)
val songMap = mutableMapOf(
Pair(
AnalysisUtil.PARAM_VALUE, jsonObject.toString()
)
)
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
if (currentFavoriteBean != null) {
currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite
App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean)
if (currentFavoriteBean.isFavorite) {
AnalysisUtil.logEvent(
AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap
)
} else {
AnalysisUtil.logEvent(
AnalysisUtil.PLAYER_B_UN_LOVE_CLICK, songMap
)
}
} else {
insertFavoriteData(it.bean)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap)
}
requests.trySend(Request.UpdateFavorite(it.bean.videoId))
}
Request.OnFavorites -> {
if (meController != null && meController.currentMediaItem != null) {
val currentMediaItem = meController.currentMediaItem
val jsonObject = JSONObject()
jsonObject.put(
"song_title", "${currentMediaItem?.mediaMetadata?.title}"
)
val songMap = mutableMapOf(
Pair(
AnalysisUtil.PARAM_VALUE, jsonObject.toString()
)
)
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!)
if (currentFavoriteBean != null) {
currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite
App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean)
if (currentFavoriteBean.isFavorite) {
AnalysisUtil.logEvent(
AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap
)
} else {
AnalysisUtil.logEvent(
AnalysisUtil.PLAYER_B_UN_LOVE_CLICK, songMap
)
}
} else {
insertFavoriteData(currentMediaItem)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap)
}
requests.trySend(Request.UpdateFavorite(currentMediaItem.mediaId))
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 -> {
val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(it.id)
if (currentFavoriteBean != null) {
updateFavoriteUi(currentFavoriteBean.isFavorite)
} else {
updateFavoriteUi(false)
}
}
}
}
events.onReceive {
@ -142,19 +170,41 @@ class MoOfflineSongsActivity : MoBaseActivity() {
}
private fun initView() {
binding.layoutInfo.setOnClickListener { }
binding.backBtn.setOnClickListener {
finish()
}
binding.tryAgainBtn.setOnClickListener {
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() {
adapter = OfflineSongsAdapter(this, offlineList)
adapter?.setOnFavoriteClickListener(object : OfflineSongsAdapter.OnFavoriteClickListener {
override fun onFavoriteClick(position: Int) {
requests.trySend(Request.OnFavorites)
adapter?.setOnMoreClickListener(object : OfflineSongsAdapter.OnMoreClickListener {
override fun onMoreClick(position: Int) {
currentPosition = position
toggleBottomLayout(position)
}
})
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
@ -170,12 +220,15 @@ class MoOfflineSongsActivity : MoBaseActivity() {
// 更新
offlineBeans.forEach { offlineBean ->
val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(offlineBean.videoId)
if (offlineBean.id == favoriteBean?.id) {
offlineBean.isFavorite = favoriteBean.isFavorite
App.appOfflineDBManager.updateOfflineBean(offlineBean)
if (favoriteBean != null) {
if (offlineBean.id == favoriteBean.id) {
offlineBean.isFavorite = favoriteBean.isFavorite
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)
if (offlineList.size > 0) {
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() {
binding.loadingLayout.visibility = View.GONE
binding.noContentLayout.visibility = View.GONE

View File

@ -46,6 +46,11 @@ class LikedSongsAdapter(
itemFavoritesClickListener?.onFavoritesItemClick(position)
}
}
holder.binding.moreBtn.setOnClickListener {
if (moreClickListener != null) {
moreClickListener?.onMoreClick(position)
}
}
}
override fun getItemCount(): Int = list.size
@ -107,4 +112,14 @@ class LikedSongsAdapter(
interface OnItemFavoritesClickListener {
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(
private val context: Context,
private val list: List<OfflineBean>,
) :
RecyclerView.Adapter<OfflineSongsAdapter.ViewHolder>() {
) : RecyclerView.Adapter<OfflineSongsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = OfflineListItemBinding.inflate(LayoutInflater.from(context), parent, false)
@ -30,19 +29,19 @@ class OfflineSongsAdapter(
val bean = list[position]
holder.bind(bean)
holder.binding.favoritedBtn.setOnClickListener {
if (favoriteClickListener != null) {
favoriteClickListener?.onFavoriteClick(position)
holder.binding.moreBtn.setOnClickListener {
if (moreClickListener != null) {
moreClickListener?.onMoreClick(position)
}
}
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
MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoOfflineSongsActivity::class.java
)
context.startActivity(intent)
@ -58,9 +57,7 @@ class OfflineSongsAdapter(
fun bind(bean: OfflineBean) {
binding.apply {
Glide.with(context)
.load(bean.thumbnail)
.into(image)
Glide.with(context).load(bean.thumbnail).into(image)
title.text = bean.title
if (bean.name.isEmpty()) {
name.visibility = View.GONE
@ -84,12 +81,6 @@ class OfflineSongsAdapter(
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)
}
private var favoriteClickListener: OnFavoriteClickListener? = null
private var moreClickListener: OnMoreClickListener? = null
fun setOnFavoriteClickListener(listener: OnFavoriteClickListener) {
favoriteClickListener = listener
fun setOnMoreClickListener(listener: OnMoreClickListener) {
moreClickListener = listener
}
interface OnFavoriteClickListener {
fun onFavoriteClick(position: Int)
interface OnMoreClickListener {
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_bg_color"
@ -153,4 +154,198 @@
</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>

View File

@ -147,10 +147,201 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
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>
<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>

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:src="@drawable/not_favorited_icon" />
</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>

View File

@ -117,24 +117,10 @@
android:gravity="center_vertical"
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
android:id="@+id/moreBtn"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView

View File

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

View File

@ -40,4 +40,9 @@
<string name="prompt">Prompt</string>
<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="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>