This commit is contained in:
ocean 2024-06-25 10:46:31 +08:00
parent 44f827ba21
commit 641e789e2c
5 changed files with 184 additions and 65 deletions

View File

@ -124,16 +124,16 @@ dependencies {
implementation("com.google.ads.mediation:ironsource:8.1.0.0") implementation("com.google.ads.mediation:ironsource:8.1.0.0")
//max //max
implementation("com.applovin:applovin-sdk:12.5.0") // implementation("com.applovin:applovin-sdk:12.5.0")
implementation("com.applovin.mediation:google-adapter:22.1.0.0") // implementation("com.applovin.mediation:google-adapter:22.1.0.0")
implementation("com.applovin.mediation:facebook-adapter:6.11.0.5") // implementation("com.applovin.mediation:facebook-adapter:6.11.0.5")
implementation("com.applovin.mediation:adcolony-adapter:4.8.0.2") // implementation("com.applovin.mediation:adcolony-adapter:4.8.0.2")
implementation("com.applovin.mediation:vungle-adapter:6.12.0.0") // implementation("com.applovin.mediation:vungle-adapter:6.12.0.0")
implementation("com.applovin.mediation:bytedance-adapter:4.7.0.8.0") // implementation("com.applovin.mediation:bytedance-adapter:4.7.0.8.0")
implementation("com.applovin.mediation:mintegral-adapter:16.2.31.0") // implementation("com.applovin.mediation:mintegral-adapter:16.2.31.0")
implementation("androidx.recyclerview:recyclerview:1.3.2")//mintegral 需要 // implementation("androidx.recyclerview:recyclerview:1.3.2")//mintegral 需要
implementation("com.applovin.mediation:unityads-adapter:4.4.1.0") // implementation("com.applovin.mediation:unityads-adapter:4.4.1.0")
implementation("com.applovin.mediation:smaato-adapter:21.8.5.0") // implementation("com.applovin.mediation:smaato-adapter:21.8.5.0")
implementation("com.applovin.mediation:tapjoy-adapter:12.11.0.0") // implementation("com.applovin.mediation:tapjoy-adapter:12.11.0.0")
implementation("com.applovin.mediation:ironsource-adapter:7.3.1.1.0") // implementation("com.applovin.mediation:ironsource-adapter:7.3.1.1.0")
} }

View File

@ -37,18 +37,16 @@ import melody.offline.music.media.MediaControllerManager
import melody.offline.music.sp.AppStore import melody.offline.music.sp.AppStore
import melody.offline.music.util.LogTag import melody.offline.music.util.LogTag
import melody.offline.music.http.getCountryCode import melody.offline.music.http.getCountryCode
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.FileSizeConverter
import melody.offline.music.view.MusicPlayerView import melody.offline.music.view.MusicPlayerView
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), LifecycleOwner {
LifecycleOwner {
private var playerListener: Player.Listener? = null private var playerListener: Player.Listener? = null
enum class Event { enum class Event {
ActivityStart, ActivityStart, ActivityStop, ActivityOnResume, AutomaticallySwitchSongs,
ActivityStop,
ActivityOnResume,
AutomaticallySwitchSongs,
} }
protected val TAG = LogTag.VO_ACT_LOG protected val TAG = LogTag.VO_ACT_LOG
@ -142,9 +140,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
playerListener = object : Player.Listener { playerListener = object : Player.Listener {
override fun onPositionDiscontinuity( override fun onPositionDiscontinuity(
oldPosition: Player.PositionInfo, oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, reason: Int
newPosition: Player.PositionInfo,
reason: Int
) { ) {
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) { if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
if (meController != null) { if (meController != null) {
@ -182,8 +178,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
} }
override fun onPlayWhenReadyChanged( override fun onPlayWhenReadyChanged(
playWhenReady: Boolean, playWhenReady: Boolean, reason: Int
reason: Int
) { ) {
LogTag.LogD(TAG, "base onPlayWhenReadyChanged $playWhenReady") LogTag.LogD(TAG, "base onPlayWhenReadyChanged $playWhenReady")
musicPlayerView.updatePlayState(playWhenReady) musicPlayerView.updatePlayState(playWhenReady)
@ -221,8 +216,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
val content = dialogView.findViewById<TextView>(R.id.dialog_content) val content = dialogView.findViewById<TextView>(R.id.dialog_content)
content.text = description content.text = description
val close = dialogView.findViewById<RelativeLayout>(R.id.closeBtn) val close = dialogView.findViewById<RelativeLayout>(R.id.closeBtn)
val dialogBuilder = AlertDialog.Builder(this) val dialogBuilder = AlertDialog.Builder(this).setView(dialogView)
.setView(dialogView)
val dialog = dialogBuilder.create() val dialog = dialogBuilder.create()
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.show() dialog.show()
@ -251,6 +245,35 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
App.appOfflineDBManager.insertOfflineBean(bean) App.appOfflineDBManager.insertOfflineBean(bean)
} }
suspend fun insertOfflineData(favoriteBean: FavoriteBean) {
val currentDownload = DownloadUtil.getCurrentIdDownload(favoriteBean.videoId)
if (currentDownload != null) {
val bytesDownloaded = currentDownload.bytesDownloaded
val size = FileSizeConverter(currentDownload.bytesDownloaded).formattedSize()
val bean = OfflineBean(
videoId = favoriteBean.videoId,
title = favoriteBean.title,
name = favoriteBean.name,
thumbnail = favoriteBean.thumbnail,
isOffline = true,
isFavorite = favoriteBean.isFavorite,
bytesDownloaded = bytesDownloaded,
size = size
)
App.appOfflineDBManager.insertOfflineBean(bean)
} else {
val bean = OfflineBean(
videoId = favoriteBean.videoId,
title = favoriteBean.title,
name = favoriteBean.name,
thumbnail = favoriteBean.thumbnail,
isOffline = true,
isFavorite = favoriteBean.isFavorite,
)
App.appOfflineDBManager.insertOfflineBean(bean)
}
}
suspend fun insertFavoriteData(mediaItem: MediaItem) { suspend fun insertFavoriteData(mediaItem: MediaItem) {
val bean = FavoriteBean( val bean = FavoriteBean(
videoId = mediaItem.mediaId, videoId = mediaItem.mediaId,
@ -296,15 +319,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
// 不允许的国家代码 // 不允许的国家代码
val restrictedCountries = setOf( val restrictedCountries = setOf(
// "CN", // "CN",
"HK", "HK", "TW", "JP", "KR", "GB", "CH", "BE", "MO", "SG"
"TW",
"JP",
"KR",
"GB",
"CH",
"BE",
"MO",
"SG"
) )
// 检查是否包含当前的国家代码 // 检查是否包含当前的国家代码
LogTag.LogD(TAG, "withPermission ipCountryCode->${appStore.ipCountryCode}") LogTag.LogD(TAG, "withPermission ipCountryCode->${appStore.ipCountryCode}")
@ -326,22 +341,11 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
//206 Belgium //206 Belgium
//455 "Macao, China" //455 "Macao, China"
//525 Singapore (Republic of) //525 Singapore (Republic of)
val restrictedCountryCodes = val restrictedCountryCodes = setOf(
setOf(
// "460", // "460",
// "461", // "461",
"454", "454", "466", "440", "441", "450", "234", "235", "228", "206", "455", "525"
"466", )
"440",
"441",
"450",
"234",
"235",
"228",
"206",
"455",
"525"
)
val currentCountryCode = getCountryCode(this) val currentCountryCode = getCountryCode(this)
LogTag.LogD(TAG, "withPermission currentCountryCode->${currentCountryCode}") LogTag.LogD(TAG, "withPermission currentCountryCode->${currentCountryCode}")
return currentCountryCode !in restrictedCountryCodes return currentCountryCode !in restrictedCountryCodes

View File

@ -1,11 +1,20 @@
package melody.offline.music.activity package melody.offline.music.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.OptIn import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadRequest
import androidx.media3.exoplayer.offline.DownloadService
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
@ -18,8 +27,8 @@ import melody.offline.music.adapter.LikedSongsAdapter
import melody.offline.music.ads.AdPlacement import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityLikedSongsBinding import melody.offline.music.databinding.ActivityLikedSongsBinding
import melody.offline.music.service.MyDownloadService
import melody.offline.music.service.ViewModelMain import melody.offline.music.service.ViewModelMain
import melody.offline.music.util.AnalysisUtil import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.DownloadUtil import melody.offline.music.util.DownloadUtil
@ -36,6 +45,9 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
data object TryAgain : Request() data object TryAgain : Request()
data class UpdateFavorite(val bean: FavoriteBean) : Request() data class UpdateFavorite(val bean: FavoriteBean) : Request()
data class OnFavorites(val bean: FavoriteBean) : Request() data class OnFavorites(val bean: FavoriteBean) : Request()
data class OnDownload(val favoriteBean: FavoriteBean) : Request()
data class OnDownloadRemove(val id: String) : Request()
data class OnUpdateDownloadUi(val id: String) : Request()
} }
private lateinit var binding: ActivityLikedSongsBinding private lateinit var binding: ActivityLikedSongsBinding
@ -51,6 +63,7 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
initView() initView()
initAdapter() initAdapter()
LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST) LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST)
initDownloadFlow()
initData() initData()
onReceive() onReceive()
} }
@ -94,6 +107,88 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
App.appFavoriteDBManager.updateFavoriteBean(it.bean) App.appFavoriteDBManager.updateFavoriteBean(it.bean)
} }
} }
is Request.OnDownload -> {
val id = it.favoriteBean.videoId
LogTag.LogD(TAG,"OnDownload id->${id}")
val currentOfflineBean = App.appOfflineDBManager.getOfflineBeanByID(id)
if (currentOfflineBean != null) {//判断当前数据库是否有这条数据。
if (currentPosition >= 0) {
val videoId = favoriteBeans[currentPosition].videoId
showRemoveDownloadDialogHint(videoId)
}
} else {
//判断是否已经下载了这条数据,已经下载,就直接进行数据库数据存储,反之走下载流程。
if (DownloadUtil.downloadResourceExist(id)) {
insertOfflineData(it.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@MoLikedSongsActivity,
getString(R.string.download_tips),
Toast.LENGTH_LONG
).show()
} else {
DownloadService.sendAddDownload(
this@MoLikedSongsActivity,
MyDownloadService::class.java,
downloadRequest,
false
)
LolAdWrapper.shared.showAdTiming(
this@MoLikedSongsActivity, AdPlacement.INST_DOWNLOAD
)
insertOfflineData(it.favoriteBean)
val jsonObject = JSONObject()
jsonObject.put(
"download_id", "${it.favoriteBean.videoId}"
)
val songMap = mutableMapOf(
Pair(
AnalysisUtil.PARAM_VALUE, jsonObject.toString()
)
)
AnalysisUtil.logEvent(
AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap
)
LolAdWrapper.shared.loadAdIfNotCached(
this@MoLikedSongsActivity, AdPlacement.INST_DOWNLOAD
)
}
}
}
}
is Request.OnDownloadRemove -> {
LogTag.LogD(TAG,"OnDownloadRemove id->${it.id}")
val currentOfflineBean =
App.appOfflineDBManager.getOfflineBeanByID(it.id)
if (currentOfflineBean != null) {
App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean)
}
requests.trySend(Request.OnUpdateDownloadUi(it.id))
}
is Request.OnUpdateDownloadUi -> {
if (App.appOfflineDBManager.getOfflineBeanByID(it.id) != null) {
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.downloadTv.text =
getString(R.string.download_remove_offline)
} else {
binding.downloadImg.setImageResource(R.drawable.more_download_icon)
binding.downloadTv.text = getString(R.string.download_save_offline)
}
}
} }
} }
events.onReceive { events.onReceive {
@ -152,7 +247,27 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
} }
} }
binding.moreDownloadBtn.setOnClickListener { binding.moreDownloadBtn.setOnClickListener {
if (currentPosition >= 0) {
requests.trySend(Request.OnDownload(favoriteBeans[currentPosition]))
}
}
}
private fun showRemoveDownloadDialogHint(id: String) {
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()
} }
} }
@ -175,8 +290,8 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
private fun initDownloadFlow() { private fun initDownloadFlow() {
ViewModelMain.modelDownloadsFlow.observe(this) { downloads -> ViewModelMain.modelDownloadsFlow.observe(this) { downloads ->
if (meController != null && meController.currentMediaItem != null) { if (currentPosition >= 0) {
val id = meController.currentMediaItem?.mediaId val id = favoriteBeans[currentPosition].videoId
val currentScreenDownloads = downloads[id] val currentScreenDownloads = downloads[id]
if (currentScreenDownloads != null) { if (currentScreenDownloads != null) {
updateDownloadUI(currentScreenDownloads) updateDownloadUI(currentScreenDownloads)
@ -205,6 +320,9 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
binding.downloadTv.text = getString(R.string.download_remove_offline) binding.downloadTv.text = getString(R.string.download_remove_offline)
binding.moreDownloadBtn.isClickable = true
binding.moreDownloadBtn.isEnabled = true
val jsonObject = JSONObject() val jsonObject = JSONObject()
jsonObject.put( jsonObject.put(
"download_id", download.request.id "download_id", download.request.id
@ -273,18 +391,11 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites
} }
requests.trySend(Request.UpdateFavorite(bean)) requests.trySend(Request.UpdateFavorite(bean))
if (DownloadUtil.downloadResourceExist(bean.videoId)) {//已经下载,按钮不可点击 requests.trySend(Request.OnUpdateDownloadUi(bean.videoId))
binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
binding.moreDownloadBtn.isClickable = false val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId)
binding.moreDownloadBtn.isEnabled = false if (currentDownload != null) {
binding.downloadTv.text = getString(R.string.download_remove_offline) updateDownloadUI(currentDownload)
} 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)
} }
} }

View File

@ -7,6 +7,7 @@ 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
import melody.offline.music.util.LogTag
class AppOfflineDBManager private constructor(context: Context) { class AppOfflineDBManager private constructor(context: Context) {
@ -36,10 +37,13 @@ class AppOfflineDBManager private constructor(context: Context) {
suspend fun insertOfflineBean(bean: OfflineBean) { suspend fun insertOfflineBean(bean: OfflineBean) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
LogTag.LogD(LogTag.VO_TEST_ONLY, "insertOfflineBean bean.videoId->${bean.videoId}")
val offlineBean = getOfflineBeanByID(bean.videoId) val offlineBean = getOfflineBeanByID(bean.videoId)
if (offlineBean == null) { if (offlineBean == null) {
LogTag.LogD(LogTag.VO_TEST_ONLY, "insertOfflineBean 1")
dao.insertOfflineBean(bean) dao.insertOfflineBean(bean)
} else { } else {
LogTag.LogD(LogTag.VO_TEST_ONLY, "insertOfflineBean 2")
dao.updateOfflineBean(bean) dao.updateOfflineBean(bean)
} }
} }

View File

@ -15,13 +15,13 @@
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.5" android:strokeWidth="1.5"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#80F988" android:strokeColor="#ffffff"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M18,8.5L12,14.5L6,8.5" android:pathData="M18,8.5L12,14.5L6,8.5"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.5" android:strokeWidth="1.5"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#80F988" android:strokeColor="#ffffff"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
</vector> </vector>