From 99e5382a5b27f0127c8a2ed3defc3814faf6a361 Mon Sep 17 00:00:00 2001 From: ocean <503259349@qq.com> Date: Mon, 27 May 2024 17:32:26 +0800 Subject: [PATCH] update --- app/src/main/AndroidManifest.xml | 3 + app/src/main/java/relax/offline/music/App.kt | 4 + .../offline/music/activity/MoBaseActivity.kt | 36 +++-- .../music/activity/MoLikedSongsActivity.kt | 148 ++++++++++++++++++ .../music/activity/MoPlayDetailsActivity.kt | 97 +++++++++++- .../music/adapter/LikedSongsAdapter.kt | 110 +++++++++++++ .../relax/offline/music/bean/FavoriteBean.kt | 20 +++ .../music/database/AppFavoriteDBManager.kt | 81 ++++++++++ .../music/database/AppFavoriteDatabase.kt | 10 ++ .../offline/music/database/FavoriteDao.kt | 30 ++++ .../offline/music/fragment/MoMeFragment.kt | 25 ++- .../music/media/MediaControllerManager.kt | 1 - .../offline/music/service/PlaybackService.kt | 4 +- .../java/relax/offline/music/util/Utils.kt | 16 ++ .../main/res/layout/activity_liked_songs.xml | 145 +++++++++++++++++ app/src/main/res/layout/liked_list_item.xml | 117 ++++++++++++++ 16 files changed, 821 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/relax/offline/music/activity/MoLikedSongsActivity.kt create mode 100644 app/src/main/java/relax/offline/music/adapter/LikedSongsAdapter.kt create mode 100644 app/src/main/java/relax/offline/music/bean/FavoriteBean.kt create mode 100644 app/src/main/java/relax/offline/music/database/AppFavoriteDBManager.kt create mode 100644 app/src/main/java/relax/offline/music/database/AppFavoriteDatabase.kt create mode 100644 app/src/main/java/relax/offline/music/database/FavoriteDao.kt create mode 100644 app/src/main/res/layout/activity_liked_songs.xml create mode 100644 app/src/main/res/layout/liked_list_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f04ecef..08cf6d3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -69,6 +69,9 @@ + ${bean}") - relax.offline.music.App.appOfflineDBManager.insertOfflineBean(bean) - } + suspend fun insertOfflineData(mediaItem: MediaItem) { + val bean = OfflineBean( + videoId = mediaItem.mediaId, + title = mediaItem.mediaMetadata.title.toString(), + name = mediaItem.mediaMetadata.artist.toString(), + thumbnail = mediaItem.mediaMetadata.artworkUri.toString(), + isOffline = true + ) + LogTag.LogD(Innertube.TAG, "insertOfflineBean bean->${bean}") + relax.offline.music.App.appOfflineDBManager.insertOfflineBean(bean) + } + + suspend fun insertFavoriteData(mediaItem: MediaItem) { + val bean = FavoriteBean( + videoId = mediaItem.mediaId, + title = mediaItem.mediaMetadata.title.toString(), + name = mediaItem.mediaMetadata.artist.toString(), + thumbnail = mediaItem.mediaMetadata.artworkUri.toString(), + isFavorite = true + ) + LogTag.LogD(Innertube.TAG, "insertFavoriteBean bean->${bean}") + App.appFavoriteDBManager.insertFavoriteBean(bean) } } \ No newline at end of file diff --git a/app/src/main/java/relax/offline/music/activity/MoLikedSongsActivity.kt b/app/src/main/java/relax/offline/music/activity/MoLikedSongsActivity.kt new file mode 100644 index 0000000..1b58f2b --- /dev/null +++ b/app/src/main/java/relax/offline/music/activity/MoLikedSongsActivity.kt @@ -0,0 +1,148 @@ +package relax.offline.music.activity + +import android.annotation.SuppressLint +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import com.gyf.immersionbar.ktx.immersionBar +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.isActive +import kotlinx.coroutines.selects.select +import relax.offline.music.App +import relax.offline.music.adapter.LikedSongsAdapter +import relax.offline.music.bean.FavoriteBean +import relax.offline.music.databinding.ActivityLikedSongsBinding + +class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavoritesClickListener { + + private val requests: Channel = Channel(Channel.UNLIMITED) + + sealed class Request { + data object TryAgain : Request() + data class UpdateFavorite(val bean: FavoriteBean) : Request() + } + + private lateinit var binding: ActivityLikedSongsBinding + private var adapter: LikedSongsAdapter? = null + private var favoriteBeans: MutableList = mutableListOf() + + override suspend fun main() { + binding = ActivityLikedSongsBinding.inflate(layoutInflater) + setContentView(binding.root) + initImmersionBar() + initView() + initAdapter() + initData() + onReceive() + } + + private fun initImmersionBar() { + immersionBar { + statusBarDarkFont(false) + statusBarView(binding.view) + } + } + + @SuppressLint("NotifyDataSetChanged") + private suspend fun onReceive() { + while (isActive) { + select { + requests.onReceive { + when (it) { + is Request.TryAgain -> { + initData() + } + + is Request.UpdateFavorite -> { + it.bean.isFavorite = !it.bean.isFavorite + adapter?.notifyDataSetChanged() + + val currentFavoriteBean = + App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) + if (currentFavoriteBean != null) { + App.appFavoriteDBManager.updateFavoriteBean(it.bean) + } + } + } + } + events.onReceive { + when (it) { + Event.ActivityOnResume -> { + activityOnResume() + } + + Event.AutomaticallySwitchSongs -> { + if (adapter != null) { + adapter?.notifyDataSetChanged() + } + } + + else -> {} + } + } + } + } + } + + @SuppressLint("NotifyDataSetChanged") + private fun activityOnResume() { + addMusicPlayerViewToLayout(binding.playMusicLayout) + + if (adapter != null) { + adapter?.notifyDataSetChanged() + } + } + + private fun initView() { + binding.backBtn.setOnClickListener { + finish() + } + binding.tryAgainBtn.setOnClickListener { + requests.trySend(Request.TryAgain) + } + } + + private fun initAdapter() { + adapter = LikedSongsAdapter(this, favoriteBeans) + adapter?.setOnFavoritesItemClickListener(this) + binding.rv.layoutManager = + LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + binding.rv.adapter = adapter + } + + override fun onFavoritesItemClick(position: Int) { + requests.trySend(Request.UpdateFavorite(favoriteBeans[position])) + } + + @SuppressLint("NotifyDataSetChanged") + private suspend fun initData() { + showLoadingUi() + favoriteBeans.clear() + val beans = App.appFavoriteDBManager.getAllFavoriteBeans() + val filteredBeans = beans.filter { it.isFavorite } + favoriteBeans.addAll(filteredBeans) + if (favoriteBeans.size > 0) { + showDataUi() + } else { + showNoContentUi() + } + if (adapter != null) { + adapter?.notifyDataSetChanged() + } + } + + private fun showDataUi() { + binding.loadingLayout.visibility = View.GONE + binding.noContentLayout.visibility = View.GONE + } + + private fun showLoadingUi() { + binding.loadingLayout.visibility = View.VISIBLE + binding.noContentLayout.visibility = View.GONE + } + + private fun showNoContentUi() { + binding.loadingLayout.visibility = View.GONE + binding.noContentLayout.visibility = View.VISIBLE + } + +} \ No newline at end of file diff --git a/app/src/main/java/relax/offline/music/activity/MoPlayDetailsActivity.kt b/app/src/main/java/relax/offline/music/activity/MoPlayDetailsActivity.kt index a47518c..5ce97b5 100644 --- a/app/src/main/java/relax/offline/music/activity/MoPlayDetailsActivity.kt +++ b/app/src/main/java/relax/offline/music/activity/MoPlayDetailsActivity.kt @@ -38,14 +38,25 @@ import relax.offline.music.util.PlayMode import relax.offline.music.util.asMediaItem import relax.offline.music.util.convertMillisToMinutesAndSecondsString import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.selects.select import relax.offline.music.App +import relax.offline.music.bean.FavoriteBean @OptIn(UnstableApi::class) class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { + private val requests: Channel = Channel(Channel.UNLIMITED) + + sealed class Request { + data object OnFavorites : Request() + data class OnDownload(val mediaItem: MediaItem) : Request() + data class UpdateFavorite(val id: String) : Request() + } + + companion object { const val PLAY_DETAILS_VIDEO_ID = "play_details_videoId" const val PLAY_DETAILS_PLAY_LIST_ID = "play_details_playlistId" @@ -120,6 +131,32 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } else { binding.playbackErrorLayout.visibility = View.VISIBLE } + } else if (comeFrom != null && comeFrom == MoLikedSongsActivity::class.java) { + LogD(TAG, "从liked songs 进入") + binding.nameTv.text = intent.getStringExtra(PLAY_DETAILS_NAME) + binding.descTv.text = intent.getStringExtra(PLAY_DETAILS_DESC) + val favoriteBeans = App.appFavoriteDBManager.getAllFavoriteBeans() + val allFilteredBeans = favoriteBeans.filter { it.isFavorite}//过滤只有为true的值 + //找到当前点击进来的歌曲media + val findCurrentMedia = allFilteredBeans.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 = allFilteredBeans + .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) @@ -157,13 +194,52 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { else -> {} } } + requests.onReceive { + when (it) { + is Request.OnFavorites -> { + if (meController != null && meController.currentMediaItem != null) { + val currentMediaItem = meController.currentMediaItem + val currentFavoriteBean = + App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!) + if (currentFavoriteBean != null) { + currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite + App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean) + } else { + insertFavoriteData(currentMediaItem) + } + requests.trySend(Request.UpdateFavorite(currentMediaItem.mediaId)) + } + } + + is Request.OnDownload -> { + insertOfflineData(it.mediaItem) + } + + is Request.UpdateFavorite -> { + val currentFavoriteBean = + App.appFavoriteDBManager.getFavoriteBeanByID(it.id) + LogD(TAG, "UpdateFavorite->${currentFavoriteBean}") + if (currentFavoriteBean != null) { + updateFavoriteUi(currentFavoriteBean.isFavorite) + } else { + updateFavoriteUi(false) + } + } + } + } } } } - private fun activityOnResume() { + private suspend fun activityOnResume() { + //更新收藏按钮状态 // if (meController != null && meController.currentMediaItem != null) { -// updateInfoUi(meController.currentMediaItem) +// val currentMediaItem = meController.currentMediaItem +// val currentFavoriteBean = +// App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!) +// if (currentFavoriteBean != null) { +// updateFavoriteUi(currentFavoriteBean.isFavorite) +// } // } } @@ -236,6 +312,13 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } } + 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 initPlayerListener() { meController?.addListener(playerListener) @@ -401,7 +484,9 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } } } - + binding.favoritesBtn.setOnClickListener { + requests.trySend(Request.OnFavorites) + } binding.downloadBtn.setOnClickListener { if (meController != null && meController.currentMediaItem != null) { val currentMediaItem = meController.currentMediaItem @@ -411,8 +496,6 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { return@setOnClickListener } - insertOfflineData(currentMediaItem!!) - val downloadRequest = DownloadRequest .Builder(contentId, contentId.toUri()) .setCustomCacheKey(contentId) @@ -423,8 +506,9 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { downloadRequest, false ) - } + requests.trySend(Request.OnDownload(currentMediaItem!!)) + } } } @@ -610,6 +694,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } // currentVideoID = mediaItem.mediaId updateDownloadUi(mediaItem.mediaId) + requests.trySend(Request.UpdateFavorite(mediaItem.mediaId))//更新喜欢状态 Glide.with(this) .asBitmap() diff --git a/app/src/main/java/relax/offline/music/adapter/LikedSongsAdapter.kt b/app/src/main/java/relax/offline/music/adapter/LikedSongsAdapter.kt new file mode 100644 index 0000000..419fcb5 --- /dev/null +++ b/app/src/main/java/relax/offline/music/adapter/LikedSongsAdapter.kt @@ -0,0 +1,110 @@ +package relax.offline.music.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import relax.offline.music.R +import relax.offline.music.activity.MoLikedSongsActivity +import relax.offline.music.activity.MoPlayDetailsActivity +import relax.offline.music.bean.FavoriteBean +import relax.offline.music.databinding.LikedListItemBinding +import relax.offline.music.media.MediaControllerManager + +class LikedSongsAdapter( + private val context: Context, + private val list: List, +) : + RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = LikedListItemBinding.inflate(LayoutInflater.from(context), parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val bean = list[position] + holder.bind(bean) + + holder.itemView.setOnClickListener { + val 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, + MoLikedSongsActivity::class.java + ) + context.startActivity(intent) + } + holder.binding.favoritesBtn.setOnClickListener { + if (itemFavoritesClickListener != null) { + itemFavoritesClickListener?.onFavoritesItemClick(position) + } + } + } + + override fun getItemCount(): Int = list.size + + inner class ViewHolder(val binding: LikedListItemBinding) : + RecyclerView.ViewHolder(binding.root) { + + @SuppressLint("SetTextI18n") + fun bind(bean: FavoriteBean) { + + binding.apply { + Glide.with(context) + .load(bean.thumbnail) + .into(image) + title.text = bean.title + if (bean.name.isEmpty()) { + name.visibility = View.GONE + } else { + name.visibility = View.VISIBLE + name.text = bean.name + } + if (bean.isFavorite) { + binding.favoritesImg.setImageResource(R.drawable.favorited_icon) + } else { + binding.favoritesImg.setImageResource(R.drawable.not_favorited_icon) + } + val meController = MediaControllerManager.getController() + if (meController != null && meController.currentMediaItem != null) { + if (meController.currentMediaItem?.mediaId == bean.videoId) { + binding.listPlayView.visibility = View.VISIBLE + binding.title.setTextColor(context.getColor(R.color.green)) + binding.name.setTextColor(context.getColor(R.color.green_60)) + } else { + binding.title.setTextColor(context.getColor(R.color.white)) + binding.name.setTextColor(context.getColor(R.color.white_60)) + binding.listPlayView.visibility = View.GONE + } + } + } + } + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(listener: OnItemClickListener) { + itemClickListener = listener + } + + interface OnItemClickListener { + fun onItemClick(position: Int) + } + + private var itemFavoritesClickListener: OnItemFavoritesClickListener? = null + + fun setOnFavoritesItemClickListener(listener: OnItemFavoritesClickListener) { + itemFavoritesClickListener = listener + } + + interface OnItemFavoritesClickListener { + fun onFavoritesItemClick(position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/relax/offline/music/bean/FavoriteBean.kt b/app/src/main/java/relax/offline/music/bean/FavoriteBean.kt new file mode 100644 index 0000000..d0b5e1a --- /dev/null +++ b/app/src/main/java/relax/offline/music/bean/FavoriteBean.kt @@ -0,0 +1,20 @@ +package relax.offline.music.bean + +import androidx.annotation.Keep +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.io.Serializable + +@Keep +@Entity +data class FavoriteBean( + @ColumnInfo(name = "videoId") var videoId: String, + @ColumnInfo(name = "title") var title: String, + @ColumnInfo(name = "name") var name: String, + @ColumnInfo(name = "thumbnail") var thumbnail: String? = null, + @ColumnInfo(name = "isFavorite") var isFavorite: Boolean +) : Serializable { + @PrimaryKey(autoGenerate = true) + var id: Long = 0 +} \ No newline at end of file diff --git a/app/src/main/java/relax/offline/music/database/AppFavoriteDBManager.kt b/app/src/main/java/relax/offline/music/database/AppFavoriteDBManager.kt new file mode 100644 index 0000000..83985f9 --- /dev/null +++ b/app/src/main/java/relax/offline/music/database/AppFavoriteDBManager.kt @@ -0,0 +1,81 @@ +package relax.offline.music.database + +import android.content.Context +import androidx.room.Room +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import relax.offline.music.bean.FavoriteBean +import relax.offline.music.util.LogTag + +class AppFavoriteDBManager private constructor(context: Context) { + + companion object { + @Volatile + private var instance: AppFavoriteDBManager? = null + + fun getInstance(context: Context): AppFavoriteDBManager { + return instance ?: synchronized(this) { + instance ?: AppFavoriteDBManager(context).also { instance = it } + } + } + } + + private val database = Room.databaseBuilder( + context.applicationContext, + AppFavoriteDatabase::class.java, "favorite_data_base" + ).build() + + private val dao = database.localFavoriteDao() + + suspend fun insertFavoriteBean(bean: FavoriteBean) { + withContext(Dispatchers.IO) { + val offlineBean = getFavoriteBeanByID(bean.videoId) + if (offlineBean == null) { + dao.insertFavoriteBean(bean) + } else { + dao.updateFavoriteBean(bean) + } + } + } + + suspend fun insertOfflineListBean(list: List) { + withContext(Dispatchers.IO) { + for (bean in list) { + val offlineBean = getFavoriteBeanByID(bean.videoId) + if (offlineBean == null) { + dao.insertFavoriteBean(bean) + } else { + dao.updateFavoriteBean(bean) + } + } + } + } + + suspend fun getAllFavoriteBeans(): List { + return withContext(Dispatchers.IO) { + dao.getAllFavoriteBeans() + } + } + + suspend fun deleteFavoriteBean(bean: FavoriteBean) { + withContext(Dispatchers.IO) { + dao.deleteFavoriteBean(bean) + } + } + + suspend fun deleteAllFavoriteBean() { + withContext(Dispatchers.IO) { + dao.deleteAllFavoriteBean() + } + } + + suspend fun updateFavoriteBean(bean: FavoriteBean) { + withContext(Dispatchers.IO) { + dao.updateFavoriteBean(bean) + } + } + + suspend fun getFavoriteBeanByID(id: String): FavoriteBean? { + return dao.getFavoriteBeanByID(id) + } +} diff --git a/app/src/main/java/relax/offline/music/database/AppFavoriteDatabase.kt b/app/src/main/java/relax/offline/music/database/AppFavoriteDatabase.kt new file mode 100644 index 0000000..7627fe4 --- /dev/null +++ b/app/src/main/java/relax/offline/music/database/AppFavoriteDatabase.kt @@ -0,0 +1,10 @@ +package relax.offline.music.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import relax.offline.music.bean.FavoriteBean + +@Database(entities = [FavoriteBean::class], version = 1, exportSchema = false) +abstract class AppFavoriteDatabase : RoomDatabase() { + abstract fun localFavoriteDao(): FavoriteDao +} \ No newline at end of file diff --git a/app/src/main/java/relax/offline/music/database/FavoriteDao.kt b/app/src/main/java/relax/offline/music/database/FavoriteDao.kt new file mode 100644 index 0000000..e6e7701 --- /dev/null +++ b/app/src/main/java/relax/offline/music/database/FavoriteDao.kt @@ -0,0 +1,30 @@ +package relax.offline.music.database + +import androidx.room.* +import relax.offline.music.bean.FavoriteBean + +@Dao +interface FavoriteDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertFavoriteBean(bean: FavoriteBean) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertFavoriteBeans(beans: List) + + @Query("SELECT * FROM FavoriteBean") + suspend fun getAllFavoriteBeans(): List + + @Delete + suspend fun deleteFavoriteBean(bean: FavoriteBean) + + @Query("DELETE FROM FavoriteBean") + suspend fun deleteAllFavoriteBean() + + @Update + suspend fun updateFavoriteBean(bean: FavoriteBean) + + @Query("SELECT * FROM FavoriteBean WHERE videoId = :id LIMIT 1") + suspend fun getFavoriteBeanByID(id: String): FavoriteBean? + +} diff --git a/app/src/main/java/relax/offline/music/fragment/MoMeFragment.kt b/app/src/main/java/relax/offline/music/fragment/MoMeFragment.kt index fea66fc..5b38f73 100644 --- a/app/src/main/java/relax/offline/music/fragment/MoMeFragment.kt +++ b/app/src/main/java/relax/offline/music/fragment/MoMeFragment.kt @@ -5,14 +5,14 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.Toast import com.gyf.immersionbar.ktx.immersionBar -import relax.offline.music.R -import relax.offline.music.activity.MoOfflineSongsActivity -import relax.offline.music.databinding.FragmentMoMeBinding -import relax.offline.music.util.DownloadUtil import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select import relax.offline.music.App +import relax.offline.music.R +import relax.offline.music.activity.MoLikedSongsActivity +import relax.offline.music.activity.MoOfflineSongsActivity +import relax.offline.music.databinding.FragmentMoMeBinding class MoMeFragment : MoBaseFragment() { @@ -57,7 +57,17 @@ class MoMeFragment : MoBaseFragment() { private fun initView() { binding.likedSongsBtn.setOnClickListener { - + val count = binding.likedSongsTv.text.toString().trim().toInt() + if (count > 0) { + val intent = Intent(context, MoLikedSongsActivity::class.java) + startActivity(intent) + } else { + Toast.makeText( + activity, + getString(R.string.liked_songs_no_data_prompt), + Toast.LENGTH_LONG + ).show() + } } binding.offlineSongsBtn.setOnClickListener { val count = binding.offlineSongsTv.text.toString().trim().toInt() @@ -79,6 +89,11 @@ class MoMeFragment : MoBaseFragment() { val offlineBeans = App.appOfflineDBManager.getAllOfflineBeans() val count = offlineBeans.count { it.bytesDownloaded?.let { bytes -> bytes > 0 } == true } binding.offlineSongsTv.text = "$count" + + //过滤只有为true的才计数 + val favoriteBeans = App.appFavoriteDBManager.getAllFavoriteBeans() + val favorites = favoriteBeans.count { it.isFavorite } + binding.likedSongsTv.text = "$favorites" } override fun onResume() { diff --git a/app/src/main/java/relax/offline/music/media/MediaControllerManager.kt b/app/src/main/java/relax/offline/music/media/MediaControllerManager.kt index 3fe0c21..2976e42 100644 --- a/app/src/main/java/relax/offline/music/media/MediaControllerManager.kt +++ b/app/src/main/java/relax/offline/music/media/MediaControllerManager.kt @@ -9,7 +9,6 @@ import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.MoreExecutors import relax.offline.music.service.PlaybackService -@UnstableApi object MediaControllerManager { private var mediaController: MediaController? = null private var controllerFuture: ListenableFuture? = null diff --git a/app/src/main/java/relax/offline/music/service/PlaybackService.kt b/app/src/main/java/relax/offline/music/service/PlaybackService.kt index 9f15552..57a67af 100644 --- a/app/src/main/java/relax/offline/music/service/PlaybackService.kt +++ b/app/src/main/java/relax/offline/music/service/PlaybackService.kt @@ -3,6 +3,7 @@ package relax.offline.music.service import android.content.Intent import android.net.Uri import android.os.Handler +import androidx.annotation.OptIn import androidx.core.net.toUri import androidx.media3.common.AudioAttributes import androidx.media3.common.C @@ -42,8 +43,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import relax.offline.music.util.RingBuffer - -@UnstableApi +@OptIn(UnstableApi::class) class PlaybackService : MediaSessionService(), Player.Listener { private val TAG = LogTag.VO_SERVICE_LOG private var mediaSession: MediaSession? = null diff --git a/app/src/main/java/relax/offline/music/util/Utils.kt b/app/src/main/java/relax/offline/music/util/Utils.kt index ca75cac..b853135 100644 --- a/app/src/main/java/relax/offline/music/util/Utils.kt +++ b/app/src/main/java/relax/offline/music/util/Utils.kt @@ -9,6 +9,7 @@ import androidx.core.os.bundleOf import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata import androidx.media3.common.util.UnstableApi +import relax.offline.music.bean.FavoriteBean import relax.offline.music.bean.OfflineBean import relax.offline.music.innertube.Innertube import relax.offline.music.innertube.models.bodies.ContinuationBody @@ -30,6 +31,21 @@ val OfflineBean.asMediaItem: MediaItem ) .build() +val FavoriteBean.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() diff --git a/app/src/main/res/layout/activity_liked_songs.xml b/app/src/main/res/layout/activity_liked_songs.xml new file mode 100644 index 0000000..1d4a0ea --- /dev/null +++ b/app/src/main/res/layout/activity_liked_songs.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/liked_list_item.xml b/app/src/main/res/layout/liked_list_item.xml new file mode 100644 index 0000000..b9bd04e --- /dev/null +++ b/app/src/main/res/layout/liked_list_item.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file