This commit is contained in:
ocean 2024-05-30 14:49:16 +08:00
parent 3eaccb2e67
commit 77f316faef
23 changed files with 225 additions and 26 deletions

View File

@ -23,6 +23,7 @@ import relax.offline.music.database.AppFavoriteDBManager
import relax.offline.music.firebase.RemoteConfig import relax.offline.music.firebase.RemoteConfig
import relax.offline.music.http.CommonIpInfoUtil import relax.offline.music.http.CommonIpInfoUtil
import relax.offline.music.http.UploadEventName import relax.offline.music.http.UploadEventName
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.AppLifecycleHandler import relax.offline.music.util.AppLifecycleHandler
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
@ -114,6 +115,7 @@ class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
AnalysisUtil.logEvent(AnalysisUtil.USER_LAUNCH)
app = this app = this
AppLifecycleHandler(this) AppLifecycleHandler(this)
CommonIpInfoUtil.shared.initIPInfo() CommonIpInfoUtil.shared.initIPInfo()

View File

@ -5,6 +5,7 @@ import android.os.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
import relax.offline.music.databinding.ActivityLaunchBinding import relax.offline.music.databinding.ActivityLaunchBinding
import relax.offline.music.util.AnalysisUtil
class LaunchActivity : MoBaseActivity() { class LaunchActivity : MoBaseActivity() {
private lateinit var binding: ActivityLaunchBinding private lateinit var binding: ActivityLaunchBinding
@ -46,6 +47,7 @@ class LaunchActivity : MoBaseActivity() {
} else { } else {
startActivity(Intent(this, PrimaryActivity::class.java)) startActivity(Intent(this, PrimaryActivity::class.java))
} }
AnalysisUtil.logEvent(AnalysisUtil.LAUNCH_PV)
finish() finish()
} }
} }

View File

@ -18,6 +18,7 @@ import relax.offline.music.databinding.ActivityMainBinding
import relax.offline.music.fragment.HomeFragment import relax.offline.music.fragment.HomeFragment
import relax.offline.music.fragment.ImportFragment import relax.offline.music.fragment.ImportFragment
import relax.offline.music.media.LocalMediaControllerManager import relax.offline.music.media.LocalMediaControllerManager
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.getAudioDurationFromAssets import relax.offline.music.util.getAudioDurationFromAssets
@ -192,7 +193,9 @@ class MainActivity : BaseActivity() {
binding.apply { binding.apply {
homeImg.setImageResource( homeImg.setImageResource(
when (index) { when (index) {
0 -> R.drawable.home_select_icon 0 ->{
R.drawable.home_select_icon
}
else -> R.drawable.home_unselect_icon else -> R.drawable.home_unselect_icon
} }
) )

View File

@ -120,7 +120,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
} }
private fun initPlayerListener() { private fun initPlayerListener() {
if (this !is MoPlayDetailsActivity) { if (this !is MoPlayDetailsActivity && this !is LaunchActivity) {
if (playerListener == null) { if (playerListener == null) {
LogTag.LogD(TAG, "MoBaseActivity initPlayerListener") LogTag.LogD(TAG, "MoBaseActivity initPlayerListener")
meController?.addListener(getPlayerListener()) meController?.addListener(getPlayerListener())
@ -161,7 +161,16 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
musicPlayerView.updateProgressState(meController) musicPlayerView.updateProgressState(meController)
when (playbackState) { when (playbackState) {
Player.STATE_IDLE -> {
LogTag.LogD(TAG, "base STATE_IDLE")
}
Player.STATE_BUFFERING -> {
LogTag.LogD(TAG, "base STATE_BUFFERING")
}
Player.STATE_READY -> { Player.STATE_READY -> {
LogTag.LogD(TAG, "base STATE_READY")
musicPlayerView.updateSetProgress(meController) musicPlayerView.updateSetProgress(meController)
} }
@ -174,6 +183,7 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
playWhenReady: Boolean, playWhenReady: Boolean,
reason: Int reason: Int
) { ) {
LogTag.LogD(TAG, "base onPlayWhenReadyChanged $playWhenReady")
musicPlayerView.updatePlayState(playWhenReady) musicPlayerView.updatePlayState(playWhenReady)
val meController = MediaControllerManager.getController() val meController = MediaControllerManager.getController()
if (meController != null) { if (meController != null) {
@ -266,7 +276,8 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
"CH", "CH",
"BE", "BE",
"MO", "MO",
"SG") "SG"
)
// 检查是否包含当前的国家代码 // 检查是否包含当前的国家代码
LogTag.LogD(TAG, "withPermission ipCountryCode->${appStore.ipCountryCode}") LogTag.LogD(TAG, "withPermission ipCountryCode->${appStore.ipCountryCode}")
if (appStore.ipCountryCode in restrictedCountries) { if (appStore.ipCountryCode in restrictedCountries) {

View File

@ -42,8 +42,11 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select import kotlinx.coroutines.selects.select
import org.json.JSONObject
import relax.offline.music.App import relax.offline.music.App
import relax.offline.music.bean.FavoriteBean import relax.offline.music.bean.FavoriteBean
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.LogTag
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
@ -74,6 +77,8 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
private var comeFrom: Class<*>? = null private var comeFrom: Class<*>? = null
private var playListAdapter: PlayListAdapter? = null private var playListAdapter: PlayListAdapter? = null
private var startPlayTime = 0L
private fun initImmersionBar() { private fun initImmersionBar() {
immersionBar { immersionBar {
statusBarDarkFont(false) statusBarDarkFont(false)
@ -199,13 +204,36 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
is Request.OnFavorites -> { is Request.OnFavorites -> {
if (meController != null && meController.currentMediaItem != null) { if (meController != null && meController.currentMediaItem != null) {
val currentMediaItem = meController.currentMediaItem 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 = val currentFavoriteBean =
App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!) App.appFavoriteDBManager.getFavoriteBeanByID(currentMediaItem?.mediaId!!)
if (currentFavoriteBean != null) { if (currentFavoriteBean != null) {
currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite
App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean) 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 { } else {
insertFavoriteData(currentMediaItem) insertFavoriteData(currentMediaItem)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap)
} }
requests.trySend(Request.UpdateFavorite(currentMediaItem.mediaId)) requests.trySend(Request.UpdateFavorite(currentMediaItem.mediaId))
} }
@ -213,6 +241,18 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
is Request.OnDownload -> { is Request.OnDownload -> {
insertOfflineData(it.mediaItem) insertOfflineData(it.mediaItem)
val jsonObject = JSONObject()
jsonObject.put(
"download_id",
"${it.mediaItem.mediaId}"
)
val songMap = mutableMapOf(
Pair(
AnalysisUtil.PARAM_VALUE,
jsonObject.toString()
)
)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap)
} }
is Request.UpdateFavorite -> { is Request.UpdateFavorite -> {
@ -272,6 +312,19 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
binding.downloadLoading.visibility = View.GONE binding.downloadLoading.visibility = View.GONE
binding.downloadImg.setImageResource(R.drawable.download_done_icon) binding.downloadImg.setImageResource(R.drawable.download_done_icon)
binding.downloadImg.visibility = View.VISIBLE binding.downloadImg.visibility = View.VISIBLE
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 -> { Download.STATE_FAILED -> {
@ -644,12 +697,21 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
when (playbackState) { when (playbackState) {
Player.STATE_BUFFERING -> { Player.STATE_BUFFERING -> {
startPlayTime = System.currentTimeMillis()
LogD(TAG, "details STATE_BUFFERING")
binding.loadingView.visibility = View.VISIBLE binding.loadingView.visibility = View.VISIBLE
binding.disableClicksLayout.visibility = View.VISIBLE binding.disableClicksLayout.visibility = View.VISIBLE
binding.playbackErrorLayout.visibility = View.GONE binding.playbackErrorLayout.visibility = View.GONE
} }
Player.STATE_READY -> { Player.STATE_READY -> {
val jsonObject = JSONObject()
jsonObject.put("play_time", System.currentTimeMillis() - startPlayTime)
val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, jsonObject.toString()))
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_DELAY_ACTION, map)
startPlayTime = 0L
LogD(TAG, "details STATE_READY")
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_SUCCESS_ACTION)
binding.playbackErrorLayout.visibility = View.GONE binding.playbackErrorLayout.visibility = View.GONE
binding.loadingView.visibility = View.GONE binding.loadingView.visibility = View.GONE
binding.disableClicksLayout.visibility = View.GONE binding.disableClicksLayout.visibility = View.GONE
@ -677,6 +739,8 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
meController?.removeListener(playerListener) meController?.removeListener(playerListener)
AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_PV)
} }
private fun updateProgressUi() { private fun updateProgressUi() {

View File

@ -11,6 +11,7 @@ import relax.offline.music.fragment.MoMeFragment
import relax.offline.music.fragment.SearchFragment import relax.offline.music.fragment.SearchFragment
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select import kotlinx.coroutines.selects.select
import relax.offline.music.util.AnalysisUtil
class PrimaryActivity : MoBaseActivity(), SearchFragment.SearchFragmentCancelClickListener { class PrimaryActivity : MoBaseActivity(), SearchFragment.SearchFragmentCancelClickListener {
/** /**
@ -87,7 +88,9 @@ class PrimaryActivity : MoBaseActivity(), SearchFragment.SearchFragmentCancelCli
binding.apply { binding.apply {
homeImg.setImageResource( homeImg.setImageResource(
when (index) { when (index) {
0 -> R.drawable.home_select_icon 0 -> {
R.drawable.home_select_icon
}
else -> R.drawable.home_unselect_icon else -> R.drawable.home_unselect_icon
} }
) )

View File

@ -10,6 +10,7 @@ import relax.offline.music.R
import relax.offline.music.activity.PlayDetailsActivity import relax.offline.music.activity.PlayDetailsActivity
import relax.offline.music.bean.Audio import relax.offline.music.bean.Audio
import relax.offline.music.databinding.RealHumanVoiceLayoutBinding import relax.offline.music.databinding.RealHumanVoiceLayoutBinding
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.convertMillisToMinutesAndSecondsString import relax.offline.music.util.convertMillisToMinutesAndSecondsString
import relax.offline.music.util.getAudioDurationFromAssets import relax.offline.music.util.getAudioDurationFromAssets
@ -32,6 +33,8 @@ class RealHumanVoiceAdapter(
val intent = Intent(context, PlayDetailsActivity::class.java); val intent = Intent(context, PlayDetailsActivity::class.java);
intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio) intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio)
context.startActivity(intent) context.startActivity(intent)
AnalysisUtil.logEvent(AnalysisUtil.HOME_A_PV)
} }
} }

View File

@ -12,6 +12,7 @@ import relax.offline.music.activity.MoPlayDetailsActivity
import relax.offline.music.databinding.MusicResponsiveItemBinding import relax.offline.music.databinding.MusicResponsiveItemBinding
import relax.offline.music.innertube.models.MusicCarouselShelfRenderer import relax.offline.music.innertube.models.MusicCarouselShelfRenderer
import relax.offline.music.media.MediaControllerManager import relax.offline.music.media.MediaControllerManager
import relax.offline.music.util.AnalysisUtil
class ResponsiveListAdapter( class ResponsiveListAdapter(
private val context: Context, private val context: Context,
@ -68,6 +69,9 @@ class ResponsiveListAdapter(
holder.bind(url, name, desc, videoId) holder.bind(url, name, desc, videoId)
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
//离开上报,那就跳走上报。
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_PV)
val intent = Intent(context, MoPlayDetailsActivity::class.java) val intent = Intent(context, MoPlayDetailsActivity::class.java)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_ID, playlistId) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_ID, playlistId)
@ -81,6 +85,10 @@ class ResponsiveListAdapter(
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, name) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, name)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, desc)
context.startActivity(intent) context.startActivity(intent)
if(itemClickListener!=null){
itemClickListener?.onItemClick(position)
}
} }
} }

View File

@ -31,6 +31,9 @@ class SearchResultOtherAdapter(
holder.bind(bean) holder.bind(bean)
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
if (itemClickListener != null) {
itemClickListener?.onItemClick(position)
}
LogTag.LogD( LogTag.LogD(
LogTag.VO_ACT_LOG, LogTag.VO_ACT_LOG,
"SearchResultOtherAdapter bean.pageType->${bean.pageType}" "SearchResultOtherAdapter bean.pageType->${bean.pageType}"

View File

@ -11,6 +11,7 @@ import relax.offline.music.R
import relax.offline.music.activity.PlayDetailsActivity import relax.offline.music.activity.PlayDetailsActivity
import relax.offline.music.bean.Audio import relax.offline.music.bean.Audio
import relax.offline.music.databinding.SoundsOfAppliancesLayoutBinding import relax.offline.music.databinding.SoundsOfAppliancesLayoutBinding
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.convertMillisToMinutesAndSecondsString import relax.offline.music.util.convertMillisToMinutesAndSecondsString
import relax.offline.music.util.getAudioDurationFromAssets import relax.offline.music.util.getAudioDurationFromAssets
@ -34,6 +35,8 @@ class SoundsOfAppliancesAdapter(
intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio) intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio)
context.startActivity(intent) context.startActivity(intent)
// mediaPlayer.setDataSource(this, Uri.parse("file:///android_asset/${audio.file}")) // mediaPlayer.setDataSource(this, Uri.parse("file:///android_asset/${audio.file}"))
AnalysisUtil.logEvent(AnalysisUtil.HOME_A_PV)
} }
} }

View File

@ -11,6 +11,7 @@ import relax.offline.music.R
import relax.offline.music.activity.PlayDetailsActivity import relax.offline.music.activity.PlayDetailsActivity
import relax.offline.music.bean.Audio import relax.offline.music.bean.Audio
import relax.offline.music.databinding.SoundsOfNatureLayoutBinding import relax.offline.music.databinding.SoundsOfNatureLayoutBinding
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.convertMillisToMinutesAndSecondsString import relax.offline.music.util.convertMillisToMinutesAndSecondsString
import relax.offline.music.util.getAudioDurationFromAssets import relax.offline.music.util.getAudioDurationFromAssets
@ -34,6 +35,8 @@ class SoundsOfNatureAdapter(
intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio) intent.putExtra(PlayDetailsActivity.KEY_DETAILS_AUDIO, audio)
context.startActivity(intent) context.startActivity(intent)
// mediaPlayer.setDataSource(this, Uri.parse("file:///android_asset/${audio.file}")) // mediaPlayer.setDataSource(this, Uri.parse("file:///android_asset/${audio.file}"))
AnalysisUtil.logEvent(AnalysisUtil.HOME_A_PV)
} }
} }

View File

@ -11,6 +11,7 @@ import relax.offline.music.activity.MoPlayDetailsActivity
import relax.offline.music.activity.MoSingerDetailsActivity import relax.offline.music.activity.MoSingerDetailsActivity
import relax.offline.music.databinding.MusicTowRowItemBinding import relax.offline.music.databinding.MusicTowRowItemBinding
import relax.offline.music.innertube.models.MusicCarouselShelfRenderer import relax.offline.music.innertube.models.MusicCarouselShelfRenderer
import relax.offline.music.util.AnalysisUtil
class TowRowListAdapter( class TowRowListAdapter(
private val context: Activity, private val context: Activity,
@ -69,6 +70,12 @@ class TowRowListAdapter(
holder.bind(url = url, name = name, desc = desc) holder.bind(url = url, name = name, desc = desc)
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
//离开上报,那就跳走上报。
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_PV)
if (itemClickListener != null) {
itemClickListener?.onItemClick(position)
}
if (browseId.isNullOrEmpty()) { if (browseId.isNullOrEmpty()) {
val intent = Intent(context, MoPlayDetailsActivity::class.java) val intent = Intent(context, MoPlayDetailsActivity::class.java)
intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId) intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, videoId)

View File

@ -13,6 +13,7 @@ import relax.offline.music.adapter.RealHumanVoiceAdapter
import relax.offline.music.adapter.SoundsOfAppliancesAdapter import relax.offline.music.adapter.SoundsOfAppliancesAdapter
import relax.offline.music.adapter.SoundsOfNatureAdapter import relax.offline.music.adapter.SoundsOfNatureAdapter
import relax.offline.music.databinding.FragmentHomeBinding import relax.offline.music.databinding.FragmentHomeBinding
import relax.offline.music.util.AnalysisUtil
import relax.offline.music.util.GridSpacingItemDecoration import relax.offline.music.util.GridSpacingItemDecoration
class HomeFragment : Fragment() { class HomeFragment : Fragment() {
@ -106,9 +107,16 @@ class HomeFragment : Fragment() {
super.onHiddenChanged(hidden) super.onHiddenChanged(hidden)
if (!hidden) { if (!hidden) {
initImmersionBar() initImmersionBar()
AnalysisUtil.logEvent(AnalysisUtil.HOME_A_PV)
} }
} }
override fun onDestroy() {
AnalysisUtil.logEvent(AnalysisUtil.HOME_A_PV)
super.onDestroy()
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
private fun notifyDataSetChanged() { private fun notifyDataSetChanged() {
soundsOfAppliancesAdapter?.notifyDataSetChanged() soundsOfAppliancesAdapter?.notifyDataSetChanged()

View File

@ -15,6 +15,7 @@ import relax.offline.music.view.MusicTowRowListView
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select import kotlinx.coroutines.selects.select
import relax.offline.music.util.AnalysisUtil
class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() { class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
@ -70,6 +71,7 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
private suspend fun initData() { private suspend fun initData() {
showLoadingUi() showLoadingUi()
Innertube.homePage(appStore.myVisitorData)?.onSuccess { Innertube.homePage(appStore.myVisitorData)?.onSuccess {
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_MODULE_SHOW_SUCCESS_ACTION)
showDataUi() showDataUi()
if (it.homePage.isNotEmpty()) { if (it.homePage.isNotEmpty()) {
for (home: Innertube.HomePage in it.homePage) { for (home: Innertube.HomePage in it.homePage) {
@ -134,7 +136,7 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
} }
} }
private fun fragmentOnResume(){ private fun fragmentOnResume() {
refreshAdapters() refreshAdapters()
} }
@ -146,6 +148,7 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
} }
} }
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
initImmersionBar() initImmersionBar()
@ -155,9 +158,18 @@ class MoHomeFragment : MoBaseFragment<FragmentMoHomeBinding>() {
super.onHiddenChanged(hidden) super.onHiddenChanged(hidden)
if (!hidden) { if (!hidden) {
initImmersionBar() initImmersionBar()
} else {
//离开上报,那就隐藏上报。
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_PV)
} }
} }
override fun onDestroy() {
//离开上报
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_PV)
super.onDestroy()
}
private fun showDataUi() { private fun showDataUi() {
binding.loadingLayout.visibility = View.GONE binding.loadingLayout.visibility = View.GONE
binding.noContentLayout.visibility = View.GONE binding.noContentLayout.visibility = View.GONE

View File

@ -14,6 +14,7 @@ import relax.offline.music.activity.MoLikedSongsActivity
import relax.offline.music.activity.MoOfflineSongsActivity import relax.offline.music.activity.MoOfflineSongsActivity
import relax.offline.music.activity.SettingsActivity import relax.offline.music.activity.SettingsActivity
import relax.offline.music.databinding.FragmentMoMeBinding import relax.offline.music.databinding.FragmentMoMeBinding
import relax.offline.music.util.AnalysisUtil
class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>() { class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>() {
@ -61,12 +62,14 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>() {
val intent = Intent(requireActivity(), SettingsActivity::class.java) val intent = Intent(requireActivity(), SettingsActivity::class.java)
intent.putExtra(SettingsActivity.FROM_TO_SETTING, MoMeFragment::class.java) intent.putExtra(SettingsActivity.FROM_TO_SETTING, MoMeFragment::class.java)
startActivity(intent) startActivity(intent)
AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV)
} }
binding.likedSongsBtn.setOnClickListener { binding.likedSongsBtn.setOnClickListener {
val count = binding.likedSongsTv.text.toString().trim().toInt() val count = binding.likedSongsTv.text.toString().trim().toInt()
if (count > 0) { if (count > 0) {
val intent = Intent(context, MoLikedSongsActivity::class.java) val intent = Intent(context, MoLikedSongsActivity::class.java)
startActivity(intent) startActivity(intent)
AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV)
} else { } else {
Toast.makeText( Toast.makeText(
activity, activity,
@ -80,6 +83,7 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>() {
if (count > 0) { if (count > 0) {
val intent = Intent(context, MoOfflineSongsActivity::class.java) val intent = Intent(context, MoOfflineSongsActivity::class.java)
startActivity(intent) startActivity(intent)
AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV)
} else { } else {
Toast.makeText( Toast.makeText(
activity, activity,
@ -111,6 +115,8 @@ class MoMeFragment : MoBaseFragment<FragmentMoMeBinding>() {
super.onHiddenChanged(hidden) super.onHiddenChanged(hidden)
if (!hidden) { if (!hidden) {
initImmersionBar() initImmersionBar()
} else {
AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV)
} }
} }
} }

View File

@ -34,6 +34,8 @@ import relax.offline.music.view.SearchResultOtherView
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select import kotlinx.coroutines.selects.select
import org.json.JSONObject
import relax.offline.music.util.AnalysisUtil
class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher, class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
View.OnFocusChangeListener, SearchSuggestionsAdapter.OnItemClickListener, View.OnFocusChangeListener, SearchSuggestionsAdapter.OnItemClickListener,
@ -150,6 +152,7 @@ class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
?.onSuccess { suggestionsList -> ?.onSuccess { suggestionsList ->
LogTag.LogD(TAG, "suggestionsList->${suggestionsList?.size}") LogTag.LogD(TAG, "suggestionsList->${suggestionsList?.size}")
if (suggestionsList != null) { if (suggestionsList != null) {
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_SUG_SHOW)
showSearchSuggestions() showSearchSuggestions()
searchSuggestionsList.clear() searchSuggestionsList.clear()
searchSuggestionsList.addAll(suggestionsList) searchSuggestionsList.addAll(suggestionsList)
@ -164,9 +167,9 @@ class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
} }
is Request.SearchData -> { is Request.SearchData -> {
showLoadingLayout()
binding.contentLayout.removeAllViews() binding.contentLayout.removeAllViews()
binding.searchEdit.clearFocus() binding.searchEdit.clearFocus()
showLoadingLayout()
val input = it.input val input = it.input
if (input.isNotEmpty()) { if (input.isNotEmpty()) {
searchHistorySet.clear() searchHistorySet.clear()
@ -176,29 +179,34 @@ class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
} }
appStore.searchHistoryStore = searchHistorySet appStore.searchHistoryStore = searchHistorySet
updateHistoryUi() updateHistoryUi()
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_RESULT_PV)
Innertube.moSearchPage(SearchBody(query = input))?.onSuccess { result -> Innertube.moSearchPage(SearchBody(query = input))
showResultContent() ?.onSuccess { result ->
for (dataPage: Innertube.SearchDataPage in result) { AnalysisUtil.logEvent(AnalysisUtil.SEARCH_RESULT_SUCCESS_ACTION)
LogTag.LogD(TAG,"moSearchPage dataPage->$dataPage") showResultContent()
if (dataPage.type == 1) {//type为1的是最佳结果。 for (dataPage: Innertube.SearchDataPage in result) {
binding.contentLayout.addView( LogTag.LogD(TAG, "moSearchPage dataPage->$dataPage")
SearchResultOptimalView(requireActivity(), dataPage) if (dataPage.type == 1) {//type为1的是最佳结果。
)
} else if (dataPage.type == 2) {//type为2的是其他搜索结果。
if (dataPage.searchResultList.isNotEmpty()) {//如何数据集合为空就不添加view
binding.contentLayout.addView( binding.contentLayout.addView(
SearchResultOtherView( SearchResultOptimalView(
requireActivity(), requireActivity(),
dataPage dataPage
) )
) )
} else if (dataPage.type == 2) {//type为2的是其他搜索结果。
if (dataPage.searchResultList.isNotEmpty()) {//如何数据集合为空就不添加view
binding.contentLayout.addView(
SearchResultOtherView(
requireActivity(),
dataPage
)
)
}
} }
} }
}?.onFailure {
showNoContentLayout()
} }
}?.onFailure {
showNoContentLayout()
}
} }
} }
} }
@ -215,6 +223,9 @@ class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
binding.searchEdit.clearFocus() binding.searchEdit.clearFocus()
binding.searchEdit.text.clear() binding.searchEdit.text.clear()
binding.contentLayout.removeAllViews() binding.contentLayout.removeAllViews()
//隐藏上报
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_PV)
} }
} }
@ -225,6 +236,12 @@ class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
override fun onItemClick(position: Int) { override fun onItemClick(position: Int) {
binding.searchEdit.setText(searchSuggestionsList[position]) binding.searchEdit.setText(searchSuggestionsList[position])
val jsonObject = JSONObject()
jsonObject.put("search_sug_string", searchSuggestionsList[position])
val map = mutableMapOf(
Pair(AnalysisUtil.PARAM_VALUE, jsonObject.toString())
)
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_SUG_CLICK, map)
requests.trySend(Request.SearchData(searchSuggestionsList[position])) requests.trySend(Request.SearchData(searchSuggestionsList[position]))
} }

View File

@ -3,6 +3,7 @@ package relax.offline.music.media
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.annotation.OptIn
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player import androidx.media3.common.Player
@ -20,7 +21,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@UnstableApi @OptIn(UnstableApi::class)
object LocalMediaControllerManager { object LocalMediaControllerManager {
private var mediaController: MediaController? = null private var mediaController: MediaController? = null
private var controllerFuture: ListenableFuture<MediaController>? = null private var controllerFuture: ListenableFuture<MediaController>? = null

View File

@ -12,9 +12,23 @@ object AnalysisUtil {
const val USER_LAUNCH = "user_launch"//用户启动 const val USER_LAUNCH = "user_launch"//用户启动
const val LAUNCH_PV = "launch_pv"//启动页曝光 const val LAUNCH_PV = "launch_pv"//启动页曝光
const val home_a_pv = "home_a_pv"//A面首页曝光 const val HOME_A_PV = "home_a_pv"//A面首页曝光
const val home_b_pv = "home_b_pv"//B面首页曝光 const val HOME_B_PV = "home_b_pv"//B面首页曝光
const val HOME_B_MODULE_SHOW_SUCCESS_ACTION = "home_b_module_show_success_action"//首页资源曝光成功
const val HOME_B_MODULE_CLICK = "home_b_module_click"//点击首页模块
const val ME_B_PV = "me_b_pv"//B面我的曝光
const val PLAYER_B_PV = "player_b_pv"//B面播放器曝光
const val PLAYER_B_DELAY_ACTION = "player_b_delay_action"//统计加载时间
const val PLAYER_B_SUCCESS_ACTION = "player_b_success_action"//播放成功
const val PLAYER_B_LOVE_CLICK = "player_b_love_click"//点击收藏
const val PLAYER_B_UN_LOVE_CLICK = "player_b_un_love_click"//点击收藏
const val PLAYER_B_DOWNLOAD_CLICK = "player_b_download_click"//点击下载
const val PLAYER_B_DOWNLOAD_SUCCESS_ACTION = "player_b_download_success_action"//下载成功
const val SEARCH_PV = "search_pv"//B面搜索曝光
const val SEARCH_SUG_SHOW = "search_sug_show"//搜索SUG曝光
const val SEARCH_SUG_CLICK = "search_sug_click"//点击sug结果
const val SEARCH_RESULT_PV = "search_result_pv"//搜索结果曝光
const val SEARCH_RESULT_SUCCESS_ACTION = "search_result_success_action"//搜索有结果
private var firebaseAnalytics: FirebaseAnalytics? = null private var firebaseAnalytics: FirebaseAnalytics? = null
@ -25,7 +39,6 @@ object AnalysisUtil {
} }
} catch (ignore: Exception) { } catch (ignore: Exception) {
} }
if (myParam != null) { if (myParam != null) {
val bundle = Bundle() val bundle = Bundle()
try { try {

View File

@ -19,6 +19,7 @@ import relax.offline.music.R
import relax.offline.music.activity.MoPlayDetailsActivity import relax.offline.music.activity.MoPlayDetailsActivity
import relax.offline.music.activity.PrimaryActivity import relax.offline.music.activity.PrimaryActivity
import relax.offline.music.media.MediaControllerManager import relax.offline.music.media.MediaControllerManager
import relax.offline.music.util.AnalysisUtil
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class MusicPlayerView( class MusicPlayerView(

View File

@ -5,9 +5,11 @@ import android.content.Context
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.json.JSONObject
import relax.offline.music.R import relax.offline.music.R
import relax.offline.music.adapter.ResponsiveListAdapter import relax.offline.music.adapter.ResponsiveListAdapter
import relax.offline.music.innertube.Innertube import relax.offline.music.innertube.Innertube
import relax.offline.music.util.AnalysisUtil
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) : class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) :
@ -23,6 +25,14 @@ class MusicResponsiveListView(context: Context, homePage: Innertube.HomePage) :
val rv = contentView?.findViewById<RecyclerView>(R.id.rv) val rv = contentView?.findViewById<RecyclerView>(R.id.rv)
adapter = ResponsiveListAdapter(context, homePage.contents) adapter = ResponsiveListAdapter(context, homePage.contents)
adapter?.setOnItemClickListener(object : ResponsiveListAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val jsonObject = JSONObject()
jsonObject.put("moduleName", homePage.title)
val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, jsonObject.toString()))
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_MODULE_CLICK, map)
}
})
rv?.layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false) rv?.layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false)
rv?.adapter = adapter rv?.adapter = adapter
} }

View File

@ -5,9 +5,11 @@ import android.app.Activity
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.json.JSONObject
import relax.offline.music.R import relax.offline.music.R
import relax.offline.music.adapter.TowRowListAdapter import relax.offline.music.adapter.TowRowListAdapter
import relax.offline.music.innertube.Innertube import relax.offline.music.innertube.Innertube
import relax.offline.music.util.AnalysisUtil
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class MusicTowRowListView(context: Activity, homePage: Innertube.HomePage) : ModuleView(context) { class MusicTowRowListView(context: Activity, homePage: Innertube.HomePage) : ModuleView(context) {
@ -19,6 +21,14 @@ class MusicTowRowListView(context: Activity, homePage: Innertube.HomePage) : Mod
val rv = contentView?.findViewById<RecyclerView>(R.id.rv) val rv = contentView?.findViewById<RecyclerView>(R.id.rv)
val adapter = TowRowListAdapter(context, homePage.contents) val adapter = TowRowListAdapter(context, homePage.contents)
adapter.setOnItemClickListener(object : TowRowListAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val jsonObject = JSONObject()
jsonObject.put("moduleName", homePage.title)
val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, jsonObject.toString()))
AnalysisUtil.logEvent(AnalysisUtil.HOME_B_MODULE_CLICK, map)
}
})
rv?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) rv?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
rv?.adapter = adapter rv?.adapter = adapter
} }

View File

@ -12,6 +12,7 @@ import relax.offline.music.activity.MoListDetailsActivity
import relax.offline.music.activity.MoPlayDetailsActivity import relax.offline.music.activity.MoPlayDetailsActivity
import relax.offline.music.activity.MoSingerDetailsActivity import relax.offline.music.activity.MoSingerDetailsActivity
import relax.offline.music.innertube.Innertube import relax.offline.music.innertube.Innertube
import relax.offline.music.util.AnalysisUtil
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class SearchResultOptimalView(context: Context, data: Innertube.SearchDataPage) : class SearchResultOptimalView(context: Context, data: Innertube.SearchDataPage) :
@ -37,6 +38,7 @@ class SearchResultOptimalView(context: Context, data: Innertube.SearchDataPage)
val playBtn = contentView?.findViewById<LinearLayout>(R.id.playBtn) val playBtn = contentView?.findViewById<LinearLayout>(R.id.playBtn)
playBtn?.setOnClickListener { playBtn?.setOnClickListener {
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_PV)
if (optimalBean != null) { if (optimalBean != null) {
if (!optimalBean.videoId.isNullOrEmpty()) { if (!optimalBean.videoId.isNullOrEmpty()) {
val intent = Intent(context, MoPlayDetailsActivity::class.java) val intent = Intent(context, MoPlayDetailsActivity::class.java)

View File

@ -11,6 +11,7 @@ import relax.offline.music.R
import relax.offline.music.activity.MoSearchMoreActivity import relax.offline.music.activity.MoSearchMoreActivity
import relax.offline.music.adapter.SearchResultOtherAdapter import relax.offline.music.adapter.SearchResultOtherAdapter
import relax.offline.music.innertube.Innertube import relax.offline.music.innertube.Innertube
import relax.offline.music.util.AnalysisUtil
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class SearchResultOtherView(context: Context, data: Innertube.SearchDataPage) : class SearchResultOtherView(context: Context, data: Innertube.SearchDataPage) :
@ -22,6 +23,7 @@ class SearchResultOtherView(context: Context, data: Innertube.SearchDataPage) :
val moreBtn = contentView?.findViewById<LinearLayout>(R.id.moreBtn) val moreBtn = contentView?.findViewById<LinearLayout>(R.id.moreBtn)
moreBtn?.setOnClickListener { moreBtn?.setOnClickListener {
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_PV)
val intent = Intent(context, MoSearchMoreActivity::class.java) val intent = Intent(context, MoSearchMoreActivity::class.java)
intent.putExtra(MoSearchMoreActivity.SEARCH_MORE_QUERY, data.query) intent.putExtra(MoSearchMoreActivity.SEARCH_MORE_QUERY, data.query)
intent.putExtra(MoSearchMoreActivity.SEARCH_MORE_PARAMS, data.params) intent.putExtra(MoSearchMoreActivity.SEARCH_MORE_PARAMS, data.params)
@ -30,6 +32,11 @@ class SearchResultOtherView(context: Context, data: Innertube.SearchDataPage) :
val rv = contentView?.findViewById<RecyclerView>(R.id.rv) val rv = contentView?.findViewById<RecyclerView>(R.id.rv)
val adapter = SearchResultOtherAdapter(context, data.searchResultList) val adapter = SearchResultOtherAdapter(context, data.searchResultList)
adapter.setOnItemClickListener(object :SearchResultOtherAdapter.OnItemClickListener{
override fun onItemClick(position: Int) {
AnalysisUtil.logEvent(AnalysisUtil.SEARCH_PV)
}
})
rv?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) rv?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
rv?.adapter = adapter rv?.adapter = adapter