新增本地音乐数据库字段。

This commit is contained in:
ocean 2024-06-21 11:12:04 +08:00
parent b159bb178a
commit 9d76dafa47
9 changed files with 172 additions and 31 deletions

View File

@ -238,12 +238,14 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
suspend fun insertOfflineData(mediaItem: MediaItem) { suspend fun insertOfflineData(mediaItem: MediaItem) {
val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(mediaItem.mediaId)
val bean = OfflineBean( val bean = OfflineBean(
videoId = mediaItem.mediaId, videoId = mediaItem.mediaId,
title = mediaItem.mediaMetadata.title.toString(), title = mediaItem.mediaMetadata.title.toString(),
name = mediaItem.mediaMetadata.artist.toString(), name = mediaItem.mediaMetadata.artist.toString(),
thumbnail = mediaItem.mediaMetadata.artworkUri.toString(), thumbnail = mediaItem.mediaMetadata.artworkUri.toString(),
isOffline = true isOffline = true,
isFavorite = favoriteBean?.isFavorite ?: false
) )
LogTag.LogD(TAG, "insertOfflineBean bean->${bean}") LogTag.LogD(TAG, "insertOfflineBean bean->${bean}")
App.appOfflineDBManager.insertOfflineBean(bean) App.appOfflineDBManager.insertOfflineBean(bean)

View File

@ -95,6 +95,10 @@ class MoListDetailsActivity : MoBaseActivity() {
} }
private fun initView() { private fun initView() {
adapter = DetailsListAdapter(this, myList)
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rv.adapter = adapter
binding.backBtn.setOnClickListener { binding.backBtn.setOnClickListener {
finish() finish()
} }
@ -120,13 +124,15 @@ class MoListDetailsActivity : MoBaseActivity() {
} }
} }
@SuppressLint("NotifyDataSetChanged")
private suspend fun initData(browseId: String) { private suspend fun initData(browseId: String) {
showLoadingUi() showLoadingUi()
Innertube.moPlaylistPage(browseId)?.onSuccess { Innertube.moPlaylistPage(browseId)?.onSuccess {
if (this.isDestroyed || this.isFinishing) { if (this.isDestroyed || this.isFinishing) {
return return
} }
LogD(TAG, "moPlaylistPage onSuccess->${it.moPlaylistOrAlbumListBean}")
if (it.moPlaylistOrAlbumListBean.isNotEmpty()) {
showDataUi() showDataUi()
Glide.with(this).load(it.thumbnail).into(binding.imageView) Glide.with(this).load(it.thumbnail).into(binding.imageView)
@ -134,14 +140,12 @@ class MoListDetailsActivity : MoBaseActivity() {
binding.subtitle.text = it.subtitle binding.subtitle.text = it.subtitle
binding.secondSubtitle.text = it.secondSubtitle binding.secondSubtitle.text = it.secondSubtitle
adapter = DetailsListAdapter(this, it.moPlaylistOrAlbumListBean)
binding.rv.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rv.adapter = adapter
myList.clear() myList.clear()
myList.addAll(it.moPlaylistOrAlbumListBean) myList.addAll(it.moPlaylistOrAlbumListBean)
adapter?.notifyDataSetChanged()
} else {
showNoContentUi()
}
}?.onFailure { }?.onFailure {
showNoContentUi() showNoContentUi()
LogD(TAG, "moPlaylistPage onFailure->${it}") LogD(TAG, "moPlaylistPage onFailure->${it}")

View File

@ -2,6 +2,7 @@ package melody.offline.music.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.View import android.view.View
import androidx.media3.common.MediaItem
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
@ -14,12 +15,18 @@ import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper 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.LogTag
import org.json.JSONObject
class MoOfflineSongsActivity : MoBaseActivity() { class MoOfflineSongsActivity : MoBaseActivity() {
private val requests: Channel<Request> = Channel(Channel.UNLIMITED) private val requests: Channel<Request> = Channel(Channel.UNLIMITED)
enum class Request { sealed class Request {
TryAgain, data object TryAgain : Request()
data object OnFavorites : Request()
data class OnDownload(val mediaItem: MediaItem) : Request()
data class UpdateFavorite(val id: String) : Request()
} }
private lateinit var binding: ActivityOfflineSongsBinding private lateinit var binding: ActivityOfflineSongsBinding
@ -54,6 +61,48 @@ class MoOfflineSongsActivity : MoBaseActivity() {
Request.TryAgain -> { Request.TryAgain -> {
initData() initData()
} }
is Request.OnDownload -> {
}
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.UpdateFavorite -> {
}
} }
} }
events.onReceive { events.onReceive {
@ -103,8 +152,12 @@ class MoOfflineSongsActivity : MoBaseActivity() {
private fun initAdapter() { private fun initAdapter() {
adapter = OfflineSongsAdapter(this, offlineList) adapter = OfflineSongsAdapter(this, offlineList)
binding.rv.layoutManager = adapter?.setOnFavoriteClickListener(object : OfflineSongsAdapter.OnFavoriteClickListener {
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) override fun onFavoriteClick(position: Int) {
requests.trySend(Request.OnFavorites)
}
})
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rv.adapter = adapter binding.rv.adapter = adapter
} }
@ -114,8 +167,15 @@ class MoOfflineSongsActivity : MoBaseActivity() {
offlineList.clear() offlineList.clear()
val offlineBeans = App.appOfflineDBManager.getAllOfflineBeans() val offlineBeans = App.appOfflineDBManager.getAllOfflineBeans()
val filteredBeans = // 更新
offlineBeans.filter { it.bytesDownloaded?.let { bytes -> bytes > 0 } == true } offlineBeans.forEach { offlineBean ->
val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(offlineBean.videoId)
if (offlineBean.id == favoriteBean?.id) {
offlineBean.isFavorite = favoriteBean.isFavorite
App.appOfflineDBManager.updateOfflineBean(offlineBean)
}
}
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()

View File

@ -30,12 +30,20 @@ class OfflineSongsAdapter(
val bean = list[position] val bean = list[position]
holder.bind(bean) holder.bind(bean)
holder.binding.favoritedBtn.setOnClickListener {
if (favoriteClickListener != null) {
favoriteClickListener?.onFavoriteClick(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(MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM, MoOfflineSongsActivity::class.java) intent.putExtra(
MoPlayDetailsActivity.PLAY_DETAILS_COME_FROM,
MoOfflineSongsActivity::class.java
)
context.startActivity(intent) context.startActivity(intent)
} }
@ -43,7 +51,7 @@ class OfflineSongsAdapter(
override fun getItemCount(): Int = list.size override fun getItemCount(): Int = list.size
inner class ViewHolder(private val binding: OfflineListItemBinding) : inner class ViewHolder(val binding: OfflineListItemBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@ -76,6 +84,12 @@ 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)
}
} }
} }
} }
@ -89,4 +103,14 @@ class OfflineSongsAdapter(
interface OnItemClickListener { interface OnItemClickListener {
fun onItemClick(position: Int) fun onItemClick(position: Int)
} }
private var favoriteClickListener: OnFavoriteClickListener? = null
fun setOnFavoriteClickListener(listener: OnFavoriteClickListener) {
favoriteClickListener = listener
}
interface OnFavoriteClickListener {
fun onFavoriteClick(position: Int)
}
} }

View File

@ -15,7 +15,8 @@ data class OfflineBean(
@ColumnInfo(name = "thumbnail") var thumbnail: String? = null, @ColumnInfo(name = "thumbnail") var thumbnail: String? = null,
@ColumnInfo(name = "bytesDownloaded") var bytesDownloaded: Long? = null, @ColumnInfo(name = "bytesDownloaded") var bytesDownloaded: Long? = null,
@ColumnInfo(name = "size") var size: String? = null, @ColumnInfo(name = "size") var size: String? = null,
@ColumnInfo(name = "isOffline") var isOffline: Boolean @ColumnInfo(name = "isOffline") var isOffline: Boolean,
@ColumnInfo(name = "isFavorite") var isFavorite: Boolean
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0

View File

@ -2,6 +2,8 @@ package melody.offline.music.database
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import melody.offline.music.bean.OfflineBean import melody.offline.music.bean.OfflineBean
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -19,10 +21,16 @@ class AppOfflineDBManager private constructor(context: Context) {
} }
} }
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
// 在数据库中添加新的列
database.execSQL("ALTER TABLE OfflineBean ADD COLUMN isFavorite INTEGER NOT NULL DEFAULT 0")
}
}
private val database = Room.databaseBuilder( private val database = Room.databaseBuilder(
context.applicationContext, context.applicationContext, AppOfflineDatabase::class.java, "offline_data_base"
AppOfflineDatabase::class.java, "offline_data_base" ).addMigrations(MIGRATION_1_2).build()
).build()
private val dao = database.localOfflineDao() private val dao = database.localOfflineDao()

View File

@ -5,7 +5,7 @@ import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import melody.offline.music.bean.OfflineBean import melody.offline.music.bean.OfflineBean
@Database(entities = [OfflineBean::class], version = 1, exportSchema = false) @Database(entities = [OfflineBean::class], version = 2, exportSchema = false)
abstract class AppOfflineDatabase : RoomDatabase() { abstract class AppOfflineDatabase : RoomDatabase() {
abstract fun localOfflineDao(): OfflineDao abstract fun localOfflineDao(): OfflineDao
} }

View File

@ -0,0 +1,9 @@
<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="M11.944,20C11.532,20 11.136,19.836 10.845,19.544C10.553,19.253 10.389,18.857 10.389,18.444C10.389,18.032 10.553,17.636 10.845,17.345C11.136,17.053 11.532,16.889 11.944,16.889C12.357,16.889 12.753,17.053 13.044,17.345C13.336,17.636 13.5,18.032 13.5,18.444C13.5,18.857 13.336,19.253 13.044,19.544C12.753,19.836 12.357,20 11.944,20ZM11.944,13.556C11.532,13.556 11.136,13.392 10.845,13.1C10.553,12.808 10.389,12.413 10.389,12C10.389,11.587 10.553,11.192 10.845,10.9C11.136,10.608 11.532,10.444 11.944,10.444C12.357,10.444 12.753,10.608 13.044,10.9C13.336,11.192 13.5,11.587 13.5,12C13.5,12.413 13.336,12.808 13.044,13.1C12.753,13.392 12.357,13.556 11.944,13.556ZM11.944,7.111C11.532,7.111 11.136,6.947 10.845,6.655C10.553,6.364 10.389,5.968 10.389,5.556C10.389,5.143 10.553,4.747 10.845,4.456C11.136,4.164 11.532,4 11.944,4C12.357,4 12.753,4.164 13.044,4.456C13.336,4.747 13.5,5.143 13.5,5.556C13.5,5.968 13.336,6.364 13.044,6.655C12.753,6.947 12.357,7.111 11.944,7.111Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -59,8 +59,8 @@
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="vertical"> android:orientation="vertical">
@ -78,8 +78,8 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
@ -111,6 +111,39 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
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: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>