Commit 4e7da677 by 王佳洋

1,音频播放页从老的音视频页面移过来的逻辑bug修正

2,音频播放页接口接入
3,老的悬浮窗代码优化
4,老的悬浮窗缺省逻辑补充
5,AudioPlay逻辑梳理
parent d79b500f
......@@ -91,17 +91,22 @@ public class PlayFragment extends Fragment implements View.OnClickListener,
}
@Override
public boolean onPreLoad(int playPosition) {
return true;
}
@Override
public void onLoad(Music music) {
onChangeImpl(music);
}
@Override
public void onPlayerStart() {
public void onStartPlay() {
ivPlay.setSelected(true);
}
@Override
public void onPlayerPause() {
public void onPausePlay() {
ivPlay.setSelected(false);
}
......@@ -206,7 +211,7 @@ public class PlayFragment extends Fragment implements View.OnClickListener,
}
void play() {
AudioPlayer.Companion.get().playPause();
AudioPlayer.Companion.get().playOrPause();
}
void next() {
......
......@@ -148,7 +148,7 @@ class ConfideHomeEventImpl(context: Context, var confideHomeView: IConfideHomeCo
override fun videoShowClick(index: Int, data: List<ConfideHomeBodyBean>?) {
val dataJson = if (data != null) JSON.toJSONString(data) else null
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
PlayerFloatHelper.updatePlayState()
route(mContext, ConfideRoute.R_VIDEO_SHOW, "initPos" to index, "initData" to dataJson)
}
......@@ -255,7 +255,7 @@ class ConfideHomeEventImpl(context: Context, var confideHomeView: IConfideHomeCo
if (TextUtils.isEmpty(cachePlayUrl)) {
return
}
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
confideHomeView.updataPlayStatu(cacheType, cacheIndex!!, cacheSubIndex, true)
}
......@@ -263,7 +263,7 @@ class ConfideHomeEventImpl(context: Context, var confideHomeView: IConfideHomeCo
* 暂停播放音频文件
*/
override fun pauseVoice() {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
PlayerFloatHelper.updatePlayState()
//因为9999 类型不存在 所以就能把状态全部置为暂停状态了 偷个懒
confideHomeView.updataPlayStatu(9999, 0, 0, false)
......@@ -272,7 +272,7 @@ class ConfideHomeEventImpl(context: Context, var confideHomeView: IConfideHomeCo
override fun destoryPlayer() {
PlayerFloatHelper.hide()
PlayerFloatHelper.playTempData = hashMapOf<String,String>()
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
floatViewClickListener?.let { PlayerFloatHelper.removeClickListener(it) };
}
......
......@@ -14,6 +14,7 @@ tv.danmaku.ijk.media.player_arm64
"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
<!--课程首页-->
......
package com.yidianling.course.bean
/**
* 咨询师上线状态
*/
data class CourseConsultant(var doctorId: Int,
var doctorUid: Int,
var doctorName: String,
var doctorHead: String,
var isOnline: Int // 1在线 0不在线
)
\ No newline at end of file
......@@ -740,7 +740,7 @@ class CourseListContainerActivity : BaseActivity(), PtrHandler, LoadMoreHandler
if (!PlayerFloatHelper.isCanClick) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(this)
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......
......@@ -16,7 +16,6 @@ import com.ydl.media.audio.model.Music
import com.ydl.media.view.PlayerFloatHelper
import com.ydl.webview.H5Params
import com.ydl.webview.NewH5Activity
import com.ydl.ydl_image.module.GlideApp
import com.ydl.ydlcommon.base.BaseMvpActivity
import com.ydl.ydlcommon.bean.ShareData
import com.ydl.ydlcommon.data.PlatformDataManager
......@@ -31,12 +30,10 @@ import com.yidianling.course.BuildConfig
import com.yidianling.course.CourseConstants
import com.yidianling.course.R
import com.yidianling.course.bean.CourseExtraBean
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.coursePlay.presenter.AudioPlayPresenter
import com.yidianling.course.coursePlay.presenter.IAudioPlayContract
import com.yidianling.course.router.CourseIn
import com.yidianling.course.widget.CourseListDialog
import com.yidianling.course.widget.CourseListListener
import com.yidianling.course.widget.CourseSpeedDialog
import com.yidianling.ydl_pay.common.CommonPayDialog
import jp.wasabeef.glide.transformations.BlurTransformation
......@@ -88,7 +85,7 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
mPresenter.share()
}
audio_play.mListener = { playPosition ->
mPresenter.togglePlaying(playPosition)
mPresenter.isCanLoad(playPosition)
}
}
......@@ -96,6 +93,11 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
CourseIn.loginByOneKeyLogin(mContext, true)
}
override fun goToConsultantInfo(url: String) {
mPresenter.showFloatView()
NewH5Activity.start(this, H5Params(url, ""))
}
override fun commonPayDialog(userInfo: YdlUserInfo, courseId: String) {
CommonPayDialog.Build(mContext)
.setCourseId(courseId)
......@@ -114,8 +116,12 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
.setIsTestEnvironment(BuildConfig.DEBUG).build().show()
}
override fun play(playPosition: Int) {
audio_play.play(playPosition)
override fun setTitle(title: String) {
tv_title.text = title
}
override fun load() {
audio_play.load(mPresenter.getPlayPosition())
}
override fun buyCourseTipDialog() {
......@@ -171,7 +177,7 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
}
}
override fun updateView(bean: CourseExtraBean, currentPosition: Int, list: List<CourseMediaBean>, from: Int) {
override fun updateView(bean: CourseExtraBean, from: Int) {
bean.let {
Glide.with(this)
.load(it.pic)
......@@ -187,18 +193,20 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
.transition(DrawableTransitionOptions.withCrossFade())
.apply(RequestOptions.bitmapTransform(RoundedCorners(RxImageTool.dp2px(8f))))
.into(iv_pic)
GlideApp.with(this).load(it.doctorHead).error(R.drawable.course_head_place_hold_pic)
Glide.with(this).load(it.doctorHead).error(R.drawable.course_head_place_hold_pic)
.into(iv_icon)
tv_title.text = it.title
tv_title.text = mPresenter.getPlayList().elementAtOrNull(mPresenter.getPlayPosition())?.title.orEmpty()
tv_name.text = it.doctorName
iv_icon.setOnClickListener { consultantClick() }
tv_name.setOnClickListener { consultantClick() }
tv_detail.setOnClickListener { _ -> detailClick(it) }
iv_detail.setOnClickListener { _ -> detailClick(it) }
tv_speed.setOnClickListener { speedClick() }
iv_speed.setOnClickListener { speedClick() }
tv_list.setOnClickListener { _ -> listClick(it, currentPosition, list) }
iv_list.setOnClickListener { _ -> listClick(it, currentPosition, list) }
tv_list.setOnClickListener { _ -> listClick(it) }
iv_list.setOnClickListener { _ -> listClick(it) }
audio_play.setData(mPresenter.getPlayPosition(), mPresenter.convertToMusics(), from)
}
audio_play.setData(currentPosition, mPresenter.convertToMusics(list), bean.isBuy, from)
}
override fun setNonWifiTips(show: Boolean) {
......@@ -209,13 +217,9 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
override fun audioPausePlay() = audio_play.pausePlay()
override fun getAudioPath(): String = audio_play.getAudioMusic()?.path.orEmpty()
override fun getAudioMusic(): Music? = audio_play.getAudioMusic()
override fun close() {
finish()
}
override fun close() = finish()
private fun detailClick(extra: CourseExtraBean) {
if (TextUtils.isEmpty(extra.id)) {
......@@ -239,27 +243,23 @@ class AudioPlayActivity : BaseMvpActivity<IAudioPlayContract.View, IAudioPlayCon
}, "courseSpeed")
}
private fun listClick(extra: CourseExtraBean, currentPosition: Int, playList: List<CourseMediaBean>) {
private fun listClick(extra: CourseExtraBean) {
extra.let {
showFragment(mCourseListDialog?.also {
it.setCurrentPosition(currentPosition)
it.setCurrentPosition(mPresenter.getPlayPosition())
} ?: CourseListDialog().also { dialog ->
mCourseListDialog = dialog
mCourseListDialog?.setData(it.isBuy, currentPosition, playList)
dialog.mListener = object : CourseListListener {
override fun addCourseOrder() {
mPresenter.addCourseOrder()
}
override fun togglePlaying(position: Int) {
mPresenter.togglePlaying(position)
}
}
dialog.setData(it.isBuy, mPresenter.getPlayPosition(), mPresenter.getPlayList())
dialog.mView = this
dialog.mPresenter = mPresenter
}, "courseList")
}
}
private fun consultantClick() {
mPresenter.getConsultantInfo()
}
override fun onResume() {
super.onResume()
if (PlayerFloatHelper.isShow(this)) {
......
......@@ -392,12 +392,12 @@ class CoursePlayActivity : BaseActivity() {
try {
if (play_type == 1) {
//视频播放销毁音频服务
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
if (PlayerFloatHelper.playingType == PlayTypeEnum.PLAY_TYPE_CONFIDE || PlayerFloatHelper.playingType == PlayTypeEnum.PLAY_TYPE_FM) {
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -484,7 +484,7 @@ class CoursePlayActivity : BaseActivity() {
if (index < playList.size && this.index != index) {
if (!playList[index].isDemo && !courPlayBean!!.courseExtra.isBuy) {
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
if (videoView != null) {
......@@ -521,7 +521,7 @@ class CoursePlayActivity : BaseActivity() {
frame_video_play.visibility = View.VISIBLE
frame_audio_play.visibility = View.GONE
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
(playVideoView as CoursePlayItemViewVideo)?.play(index)
}
......
......@@ -2,6 +2,7 @@ package com.yidianling.course.coursePlay.model
import com.ydl.ydlcommon.data.http.BaseResponse
import com.ydl.ydlcommon.mvp.base.BaseModel
import com.yidianling.course.bean.CourseConsultant
import com.yidianling.course.bean.CourseMediaDetailBean
import com.yidianling.course.coursePlay.presenter.IAudioPlayContract
import com.yidianling.course.net.CourseRetrofitUtils
......@@ -13,4 +14,8 @@ class AudioPlayModelImpl : BaseModel(), IAudioPlayContract.Model {
return CourseRetrofitUtils.getCoursePlayData(courseId.toString())
}
override fun getConsultantInfo(courseId: Int): Observable<BaseResponse<CourseConsultant>> {
return CourseRetrofitUtils.getConsultantInfo(courseId.toString())
}
}
\ No newline at end of file
......@@ -10,9 +10,11 @@ import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.mvp.base.BasePresenter
import com.ydl.ydlcommon.router.IYDLRouterConstant
import com.ydl.ydlcommon.router.YdlCommonRouterManager
import com.ydl.ydlcommon.utils.extend.ifNotNull
import com.ydl.ydlnet.client.observer.CommonObserver
import com.yidianling.common.tools.ToastUtil
import com.yidianling.course.bean.COURSE_AUDIO
import com.yidianling.course.bean.CourseConsultant
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.bean.CourseMediaDetailBean
import com.yidianling.course.coursePlay.model.AudioPlayModelImpl
......@@ -26,8 +28,7 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
private val ROUTER_PARAMS = "routerParam"
private var mFrom: Int = 0
private var mReceiverPlayUrl: String? = null // 外部选中要播放的音/视频文件地址
private var mIsFromFloatView = false // 是否是悬浮窗进入
private var mPlayUrl: String? = null // 外部选中要播放的音频文件地址
private var mCourPlayBean: CourseMediaDetailBean? = null
private val mPlayList: ArrayList<CourseMediaBean> = ArrayList() // 播放列表
private var mCurrentPosition = 0
......@@ -51,19 +52,9 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
}
//正常跳转所传参数
mCourseId = it.getIntExtra("course_id", 0)
mReceiverPlayUrl = it.getStringExtra("coursePlayUrl")
mIsFromFloatView = it.getBooleanExtra("isFromFloatView", false)
if (!TextUtils.isEmpty(mReceiverPlayUrl) && mIsFromFloatView)
mView.setNonWifiTips(false)
try {
if (PlayerFloatHelper.playingType == PlayTypeEnum.PLAY_TYPE_COURSE
&& mView.audioIsPlaying()
&& TextUtils.isEmpty(mReceiverPlayUrl)
) {
mReceiverPlayUrl = mView.getAudioPath()
}
} catch (e: Exception) {
}
mPlayUrl = it.getStringExtra("coursePlayUrl")
val isFromFloatView = it.getBooleanExtra("isFromFloatView", false)
mView.setNonWifiTips(!isFromFloatView)
mFrom = it.getIntExtra("from", 0)
if (mCourseId == 0) {
ToastUtil.toastShort("参数错误")
......@@ -99,17 +90,42 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
response.data?.let { bean ->
mCourPlayBean = bean
setPlayList(bean)
if (!TextUtils.isEmpty(mReceiverPlayUrl)) {
mCurrentPosition = mPlayList.indexOfLast {
TextUtils.equals(mReceiverPlayUrl, it.url) || TextUtils.equals(
mReceiverPlayUrl!!.replace(
"http",
"https"
), it.url
)
if (!mPlayUrl.isNullOrEmpty()) {
val regex = Regex("(?<=video).*?(?=&token)")
val playUrl = regex.find(mPlayUrl!!)?.value
val position = mPlayList.indexOfLast {
playUrl == regex.find(it.url)?.value
}
mCurrentPosition = if (-1 == position) 0 else position
}
mView.updateView(bean.courseExtra, mFrom)
} ?: let {
ToastUtil.toastShort("解析出错")
}
} else {
ToastUtil.toastShort(response.msg)
}
}
}
})
}
override fun getConsultantInfo() {
mModel.getConsultantInfo(mCourseId)
.compose(RxUtils.applySchedulers())
.subscribe(object : CommonObserver<BaseResponse<CourseConsultant>>() {
override fun onError(s: String?) {}
override fun onSuccess(resp: BaseResponse<CourseConsultant>?) {
resp?.let { response ->
if (response.code == 200) {
response.data?.let { info ->
if (1 == info.isOnline) {
mView.goToConsultantInfo(info.doctorHead)
} else {
ToastUtil.toastShort("该咨询师未上线")
}
mView.updateView(bean.courseExtra, mCurrentPosition, mPlayList, mFrom)
} ?: let {
ToastUtil.toastShort("解析出错")
}
......@@ -138,19 +154,18 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
}
}
override fun convertToMusics(list: List<CourseMediaBean>): ArrayList<Music> {
override fun convertToMusics(): ArrayList<Music> {
val musics = ArrayList<Music>()
try {
for (i in list.indices) {
mCourPlayBean?.courseExtra?.let { extra ->
mPlayList.forEach { bean ->
musics.add(Music().apply {
path = list[i].url
coverPath = mCourPlayBean?.courseExtra?.pic
title = list[i].title
artist = list[i].doctorName
path = bean.url
coverPath = extra.pic
title = bean.title
artist = bean.doctorName
canPlay = extra.isBuy || bean.isDemo
})
}
} catch (e: Exception) {
e.printStackTrace()
}
return musics
}
......@@ -168,23 +183,26 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
mView.commonPayDialog(userInfo, mCourseId.toString())
}
override fun togglePlaying(playPosition: Int) {
if (playPosition >= mPlayList.size || playPosition < 0) {
ToastUtil.toastShort("暂无内容")
} else if (mCurrentPosition != playPosition) {
mCurrentPosition = playPosition
mCourPlayBean?.courseExtra?.let {
if (isCanPlay(it.isBuy)) mView.play(mCurrentPosition)
}
override fun getPlayPosition(): Int = mCurrentPosition
override fun getPlayList(): List<CourseMediaBean> = mPlayList
override fun togglePlay(playPosition: Int) {
if (isCanLoad(playPosition)) {
mView.load()
}
}
private fun isCanPlay(isBuy: Boolean): Boolean {
mPlayList.elementAtOrNull(mCurrentPosition)?.let {
if (!it.isDemo && !isBuy) {
override fun isCanLoad(playPosition: Int): Boolean {
ifNotNull(
mCourPlayBean?.courseExtra,
mPlayList.elementAtOrNull(playPosition)
) { extra, bean ->
if (!bean.isDemo && !extra.isBuy) {
if (mView.audioIsPlaying()) mView.audioPausePlay()
mView.buyCourseTipDialog()
} else if (it.mediaType == COURSE_AUDIO) {
} else if (bean.mediaType == COURSE_AUDIO) {
mCurrentPosition = playPosition
mView.setTitle(bean.title)
return true
}
}
......@@ -197,11 +215,7 @@ class AudioPlayPresenter : BasePresenter<IAudioPlayContract.View, IAudioPlayCont
override fun showFloatView() {
if (mView.audioIsPlaying() && PlayerFloatHelper.playingType == PlayTypeEnum.PLAY_TYPE_COURSE) {
mView.getAudioMusic()?.coverPath = mCourPlayBean?.courseExtra?.pic
mView.getAudioMusic()?.artist = mCourPlayBean?.courseExtra?.doctorName
PlayerFloatHelper.playTempData.clear()
val hashMap = HashMap<String, String>()
hashMap["course_id"] = mCourseId.toString()
hashMap["media_type"] = COURSE_AUDIO.toString()
......
......@@ -8,6 +8,7 @@ import com.ydl.ydlcommon.mvp.base.IModel
import com.ydl.ydlcommon.mvp.base.IPresenter
import com.ydl.ydlcommon.mvp.base.IView
import com.ydl.ydlcommon.router.YdlUserInfo
import com.yidianling.course.bean.CourseConsultant
import com.yidianling.course.bean.CourseExtraBean
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.bean.CourseMediaDetailBean
......@@ -22,7 +23,7 @@ interface IAudioPlayContract {
fun dismissProgressDialog()
fun updateView(bean: CourseExtraBean, currentPosition: Int, list: List<CourseMediaBean>, from: Int)
fun updateView(bean: CourseExtraBean, from: Int)
fun setNonWifiTips(show: Boolean)
......@@ -30,19 +31,21 @@ interface IAudioPlayContract {
fun audioPausePlay()
fun getAudioPath(): String
fun getAudioMusic(): Music?
fun loginByOneKeyLogin()
fun goToConsultantInfo(url: String)
fun commonPayDialog(userInfo: YdlUserInfo, courseId: String)
fun buyCourseTipDialog()
fun shareDialog(share: ShareData?)
fun play(playPosition: Int)
fun setTitle(title: String)
fun load()
fun close()
}
......@@ -56,21 +59,31 @@ interface IAudioPlayContract {
fun getCoursePlayData()
fun getConsultantInfo()
fun addCourseOrder()
fun togglePlaying(playPosition: Int)
fun getPlayPosition(): Int
fun getPlayList(): List<CourseMediaBean>
fun togglePlay(playPosition: Int)
fun isCanLoad(playPosition: Int): Boolean
fun share()
fun showFloatView()
fun convertToMusics(list: List<CourseMediaBean>): ArrayList<Music>
fun convertToMusics(): ArrayList<Music>
}
interface Model : IModel {
fun getCoursePlayData(courseId: Int) : Observable<BaseResponse<CourseMediaDetailBean>>
fun getCoursePlayData(courseId: Int): Observable<BaseResponse<CourseMediaDetailBean>>
fun getConsultantInfo(courseId: Int): Observable<BaseResponse<CourseConsultant>>
}
......
......@@ -124,7 +124,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
NewH5Activity.start(mFragment!!.activity, h5Params)
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
CourseSendPlugin.sendMsg(false)
return
}
......@@ -166,7 +166,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
}
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
CourseSendPlugin.sendMsg(false)
}
}
......@@ -177,7 +177,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
}
PAUSECOURSEPLAY -> {
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
PlayerFloatHelper.updatePlayState()
}
}
......@@ -196,7 +196,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
IOSPOP -> {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
CourseSendPlugin.sendMsg(false)
mFragment!!.activity?.finish()
}
......@@ -207,7 +207,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
if (PlayerFloatHelper.isShow(mFragment!!.requireActivity())) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
} else {
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
}
......@@ -248,7 +248,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
if (PlayerFloatHelper.isShow(mFragment!!.requireActivity())) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mFragment!!.requireActivity())
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -263,7 +263,7 @@ class CoursePlugin : MethodChannel.MethodCallHandler {
override fun onPlayFinish() {
PlayerFloatHelper.hide()
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
CourseSendPlugin.sendMsg(false)
}
......
......@@ -24,7 +24,7 @@ class CoursePlayLifecycle : Application.ActivityLifecycleCallbacks {
if (!PlayerFloatHelper.isCanClick) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(activity!!)
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
} else {
PlayerFloatHelper.showIfPlaying(activity!!)
if (!TextUtils.isEmpty(PlayerFloatHelper.playTempData["course_id"])) {
......
......@@ -8,7 +8,6 @@ import com.alibaba.android.arouter.facade.annotation.Route
import com.ydl.course.api.ICourseService
import com.ydl.media.audio.AudioPlayer
import com.ydl.media.view.PlayerFloatHelper
import com.yidianling.course.bean.COURSE_AUDIO
import com.yidianling.course.courseNew.CourseTopicActivity
import com.yidianling.course.courseNew.mine.MyCourseActivity
import com.yidianling.course.coursePlay.AudioPlayActivity
......@@ -33,7 +32,7 @@ class CourseServiceImp : ICourseService {
override fun closePlayer() {
if (AudioPlayer.get().isPlaying){
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -50,7 +49,7 @@ class CourseServiceImp : ICourseService {
}
override fun pause() {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
override fun sendLoginStatusToFlutter() {
......
......@@ -100,6 +100,13 @@ public class CourseRetrofitUtils {
return YDLHttpUtils.Companion.obtainApi(NetApiStore.class).getCoursePlayData(courseId);
}
/**
* 获取咨询师上线状态
*/
public static Observable<BaseResponse<CourseConsultant>> getConsultantInfo(String courseId) {
return YDLHttpUtils.Companion.obtainApi(NetApiStore.class).getConsultantInfo(courseId);
}
public static Observable<BaseAPIResponse<CourseSpecialListBean>> specialListRequest(CourseSpecialListParam param) {
List<FormatText> list = NetworkParamsUtils.getPostList(param);
return YDLHttpUtils.Companion.obtainApi(NetApiStore.class).courseSpecialList(NetworkParamsUtils.getMaps(list));
......
......@@ -5,6 +5,7 @@ import com.ydl.ydlcommon.data.http.BaseResponse;
import com.yidianling.course.bean.CouponHintResponseBean;
import com.yidianling.course.bean.Course;
import com.yidianling.course.bean.CourseAddOrderBean;
import com.yidianling.course.bean.CourseConsultant;
import com.yidianling.course.bean.CourseCouponBean;
import com.yidianling.course.bean.CourseListDataBean;
import com.yidianling.course.bean.CourseMediaDetailBean;
......@@ -131,6 +132,11 @@ public interface NetApiStore {
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
Observable<BaseResponse<CourseMediaDetailBean>> getCoursePlayData(@Query("courseId") String courseId);
//获取咨询师上线状态
@GET("auth/course/getCourseDoctorInfo")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
Observable<BaseResponse<CourseConsultant>> getConsultantInfo(@Query("courseId") String courseId);
//课程专题列表
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
......
......@@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import android.widget.SeekBar
......@@ -31,18 +30,16 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
private var mSeekBarIsTouch = false
private var mProgress = 0
var mNonWifiTips = true
/**
* 切换前调用 -> 判断切换后 音频 是否符合业务条件
* 切换后调用 -> 若 音频 失效,自动切换至下一个,此时仍需判断是否符合业务条件
*/
var mListener: ((playPosition: Int) -> Unit)? = null
var mListener: ((playPosition: Int) -> Boolean)? = null
init {
AudioPlayer.get().addOnPlayEventListener(this)
View.inflate(context, R.layout.audio_play_view, this)
iv_bg.setOnClickListener {
AudioPlayer.get().playPause()
if (AudioPlayer.get().isPlaying)
AudioPlayer.get().pausePlayer()
else if (AudioPlayer.get().isPausing)
AudioPlayer.get().startPlayer()
}
iv_rewind.setOnClickListener {
AudioPlayer.get().seekTo(position = AudioPlayer.get().currentPosition.minus(15000))
......@@ -51,15 +48,15 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
AudioPlayer.get().seekTo(position = AudioPlayer.get().currentPosition.plus(15000))
}
iv_pre.setOnClickListener {
mListener?.invoke(AudioPlayer.get().playPosition - 1)
AudioPlayer.get().prev()
}
iv_next.setOnClickListener {
mListener?.invoke(AudioPlayer.get().playPosition + 1)
AudioPlayer.get().next()
}
seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser) {
tv_start.text = getStringTime(progress)
tv_progress.text = getStringTime(progress)
mProgress = progress
}
}
......@@ -79,21 +76,21 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
})
}
fun setData(playPosition: Int, playList: ArrayList<Music>, isAuto: Boolean, from: Int) {
fun setData(playPosition: Int, playList: ArrayList<Music>, from: Int) {
if (playList.isEmpty()) return
setAutoNext(isAuto)
AudioPlayer.get().playMode = PlayModeEnum.LIST
AudioPlayer.get().addPlayList(playList)
if (isPlaying()) mNonWifiTips = false
if (RxNetTool.isWifi(context)) {
playAudio(from, playPosition, playList)
loadAudio(from, playPosition, playList)
} else {
if (mNonWifiTips) {
showNonWifiTips {
mNonWifiTips = false
playAudio(from, playPosition, playList)
loadAudio(from, playPosition, playList)
}
} else {
playAudio(from, playPosition, playList)
loadAudio(from, playPosition, playList)
}
}
}
......@@ -102,16 +99,17 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
block.invoke()
}
private fun playAudio(from: Int, playPosition: Int, playList: ArrayList<Music>) {
private fun loadAudio(from: Int, playPosition: Int, playList: ArrayList<Music>) {
if (isPlaying() && (from == 1 || from == 2)) {
if (TextUtils.equals(getCurrentUrl(), playList[playPosition].path)) {
seekbar.max = AudioPlayer.get().getDuration().toInt()
tv_duration.text = getStringTime(seekbar.max)
displayPlayStatus(R.drawable.course_pause)
} else {
play(playPosition)
load(playPosition)
}
} else {
play(playPosition)
load(playPosition)
}
}
......@@ -122,36 +120,31 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
return AudioPlayer.get().playMusic?.path.orEmpty()
}
fun play(index: Int) {
fun load(index: Int) {
PlayerFloatHelper.playingType = PlayTypeEnum.PLAY_TYPE_COURSE
AudioPlayer.get().load(index)
}
/**
* 设置自动播放下一曲
*/
fun setAutoNext(auto: Boolean) {
if (!auto) {
AudioPlayer.get().playMode = PlayModeEnum.SINGLE
} else {
AudioPlayer.get().playMode = PlayModeEnum.LIST_LOOP
}
override fun onPreLoad(playPosition: Int): Boolean {
return mListener?.invoke(playPosition) ?: true
}
@SuppressLint("SetTextI18n")
override fun onLoad(music: Music) {
displayPlayStatus(R.drawable.course_loading5, true)
seekbar.progress = 0
tv_start.text = "00:00"
tv_progress.text = "00:00"
}
override fun onPlayerStart() {
override fun onStartPlay() {
postDelayed({
displayPlayStatus(R.drawable.course_pause)
}, 200) // 为了列表切换结束后还能看到loading效果
}
override fun onPrepared(duration: Long) {
seekbar.max = duration.toInt()
tv_duration.text = getStringTime(seekbar.max)
mListener?.invoke(AudioPlayer.get().playPosition)
}
override fun onBufferingUpdate(percent: Int) {
......@@ -160,21 +153,19 @@ class AudioPlayView(context: Context, attrs: AttributeSet?) :
override fun onPublish(percent: Int, currentPosition: Long) {
if (!mSeekBarIsTouch) {
displayPlayStatus(R.drawable.course_pause)
seekbar.progress = currentPosition.toInt()
tv_start.text = getStringTime(currentPosition.toInt())
val currentProgress = currentPosition.toInt()
seekbar.progress =
if (seekbar.max - currentProgress < 1000) seekbar.max else currentProgress
tv_progress.text = getStringTime(seekbar.progress)
}
}
override fun onComplete() {
tv_progress.text = getStringTime(seekbar.max)
}
override fun onPlayerPause() {
if (isPlaying()) {
displayPlayStatus(R.drawable.course_pause)
} else {
displayPlayStatus(R.drawable.course_play)
}
override fun onPausePlay() {
displayPlayStatus(R.drawable.course_play)
}
private fun displayPlayStatus(
......
......@@ -276,7 +276,7 @@ class CourseItemNewView : ConstraintLayout {
if (PlayerFloatHelper.isShow(mContext)) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mContext)
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
} else {
PlayerFloatHelper.removeView(mContext)
}
......@@ -313,7 +313,7 @@ class CourseItemNewView : ConstraintLayout {
if (PlayerFloatHelper.isShow(mContext)) {
PlayerFloatHelper.hide()
PlayerFloatHelper.removeView(mContext)
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -325,7 +325,7 @@ class CourseItemNewView : ConstraintLayout {
override fun onPlayFinish() {
PlayerFloatHelper.hide()
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
override fun onPauseClick() {
......
......@@ -12,9 +12,9 @@ import com.ydl.ydlcommon.base.BaseDialogFragment
import com.ydl.ydlcommon.utils.extend.gone
import com.ydl.ydlcommon.utils.extend.invisible
import com.ydl.ydlcommon.utils.extend.visible
import com.ydl.ydlcommon.view.dialog.CommonDialog
import com.yidianling.course.R
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.coursePlay.presenter.IAudioPlayContract
import kotlinx.android.synthetic.main.dialog_course_list.*
import kotlinx.android.synthetic.main.item_course_playlist.view.*
......@@ -23,7 +23,8 @@ import kotlinx.android.synthetic.main.item_course_playlist.view.*
*/
class CourseListDialog : BaseDialogFragment() {
var mListener: CourseListListener? = null
var mView: IAudioPlayContract.View? = null
var mPresenter: IAudioPlayContract.Presenter? = null
var mCurrentPosition = 0
private var mAdapter: CourseListDialog.CourseListAdapter? = null
private val mCourseList = mutableListOf<CourseMediaBean>()
......@@ -88,17 +89,12 @@ class CourseListDialog : BaseDialogFragment() {
tv_title.text = bean.title
setOnClickListener {
if (mCurrentPosition == position) return@setOnClickListener
if (mCurrentPosition == position) {
dismissAllowingStateLoss()
return@setOnClickListener
}
if (!bean.isDemo && !mIsBuy) {
CommonDialog(context)
.setMessage("\n购买课程,获取完整课程内容\n")
.setLeftOnclick("放弃") {}
.setRightClick("购买") {
//跳转支付页
mListener?.addCourseOrder()
}
.setCancelAble(false)
.show()
mView?.buyCourseTipDialog()
} else {
PlayProgressUtil.saveProgress(
context,
......@@ -107,7 +103,7 @@ class CourseListDialog : BaseDialogFragment() {
)
mCurrentPosition = position
notifyDataSetChanged()
mListener?.togglePlaying(position)
mPresenter?.togglePlay(position)
dismissAllowingStateLoss()
}
}
......@@ -119,8 +115,3 @@ class CourseListDialog : BaseDialogFragment() {
}
}
interface CourseListListener {
fun addCourseOrder()
fun togglePlaying(position: Int)
}
\ No newline at end of file
......@@ -47,11 +47,11 @@ class HPlayView : RelativeLayout, OnPlayerEventListener {
AudioPlayer.get().addOnPlayEventListener(this)
course_audio_play_icon.setOnClickListener {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
img_gif.setOnClickListener {
if (!AudioPlayer.get().isPlaying) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
}
......@@ -138,6 +138,7 @@ class HPlayView : RelativeLayout, OnPlayerEventListener {
}
}
override fun onPreLoad(playPosition: Int): Boolean = true
@SuppressLint("SetTextI18n")
override fun onLoad(music: Music) {
......@@ -150,11 +151,11 @@ class HPlayView : RelativeLayout, OnPlayerEventListener {
text_start_time.text = "00:00"
}
override fun onPlayerStart() {
override fun onStartPlay() {
setGifVisibity(true)
}
override fun onPlayerPause() {
override fun onPausePlay() {
if (AudioPlayer.get().isPlaying) {
setGifVisibity(true)
} else {
......
......@@ -83,7 +83,7 @@
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingStart="8dp"
android:textColor="@android:color/white"
android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="@id/iv_icon"
......
......@@ -39,7 +39,7 @@
android:progress="0" />
<TextView
android:id="@+id/tv_start"
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="00:00"
......@@ -64,7 +64,7 @@
android:layout_height="66dp"
app:roundPercent="1"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@id/tv_start"
app:layout_constraintTop_toBottomOf="@id/tv_progress"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/white"/>
......
......@@ -591,18 +591,23 @@ public class FMDetailActivity extends BaseActivity implements View.OnClickListen
}
@Override
public boolean onPreLoad(int playPosition) {
return true;
}
@Override
public void onLoad(@NotNull Music music) {
}
@Override
public void onPlayerStart() {
public void onStartPlay() {
iv_play.setImageResource(R.drawable.fm_stop_2);
fmSurfaceView.playTimer();
}
@Override
public void onPlayerPause() {
public void onPausePlay() {
iv_play.setImageResource(R.drawable.fm_play_2);
fmSurfaceView.stopTimer();
}
......
......@@ -55,7 +55,7 @@ class FMServiceImpl : IFMService {
*/
override fun closePlayer() {
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......
......@@ -27,7 +27,7 @@ class MuseActivity : BaseFlutterActivity() {
* 如果正在播放音乐,则停止播放所有音乐
*/
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -36,6 +36,6 @@ class MuseActivity : BaseFlutterActivity() {
/**
* 退出冥想模块的时候,关闭音乐播放
*/
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
}
......@@ -111,7 +111,7 @@ class PlayMeditationActivity : BaseActivity() {
PlayerFloatHelper.removeView(mContext)
PlayerFloatHelper.playTempData.clear()
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
mMediaPlayer = MediaPlayerManager.getInstance(this)?.getMediaPlayer()
......
......@@ -93,7 +93,7 @@ class MusePlugin : MethodChannel.MethodCallHandler {
}
// 暂停(销毁)音乐
ACTION_STOP_MUSIC -> {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
// 设置默认时间
ACTION_SET_DEFAULT_TIME -> {
......
package com.yidianling.muse.helper
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.PixelFormat
import android.graphics.Point
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import androidx.core.view.ViewCompat
import com.alibaba.android.arouter.launcher.ARouter
import com.ydl.media.audio.AudioPlayer
import com.ydl.media.view.PlayTypeEnum
import com.yidianling.common.tools.RxImageTool
class MeditationPlayWindowController {
companion object {
@SuppressLint("StaticFieldLeak")
private var mPlayerFloatView: MeditationFloatWindow? = null
//已添加悬浮窗页面全路径名
private var showingPageName: String? = null
private var wm: WindowManager? = null
var isCanClick = true
var playingType = PlayTypeEnum.PLAY_TYPE_NONE
var playTempData = hashMapOf<String, String>()
/**
* 如果有音频正在播放则显示
*/
fun showIfPlaying(context: Context) {
if (MediaPlayerManager.getInstance(context)?.isPlaying() == true) {
show(context)
mPlayerFloatView?.updatePlayState()
} else {
hide()
}
}
/**
* 显示悬浮控件
*/
fun show(
context: Context,
playTypeEnum: PlayTypeEnum = PlayTypeEnum.PLAY_TYPE_NONE,
playData: HashMap<String, String> = hashMapOf<String, String>()
) {
playingType = playTypeEnum
if (playData.size > 0) {
this.playTempData.putAll(playData)
}
if (mPlayerFloatView == null) {
mPlayerFloatView = MeditationFloatWindow(context)
mPlayerFloatView?.addFloatClickListener(object :
MeditationFloatWindow.FloatViewPlayListener {
override fun onPauseClick() {
}
override fun onStartClick() {
}
override fun onPlayFinish() {
}
})
}
if (showingPageName != context::class.qualifiedName) {
mPlayerFloatView?.resetWm(context)
addFloatToWm(context)
}
mPlayerFloatView?.resetView()
mPlayerFloatView?.visibility = View.VISIBLE
mPlayerFloatView?.setPlayingState()
}
fun hide() {
mPlayerFloatView?.visibility = View.GONE
}
fun addClickListener(listener: MeditationFloatWindow.FloatViewPlayListener) {
mPlayerFloatView?.addFloatClickListener(listener)
}
fun removeClickListener(listener: MeditationFloatWindow.FloatViewPlayListener) {
mPlayerFloatView?.removeFloatClickListener(listener)
}
fun isShow(context: Context): Boolean {
return !TextUtils.isEmpty(showingPageName) && showingPageName == context::class.qualifiedName && mPlayerFloatView?.visibility == View.VISIBLE
}
fun removeView(context: Context) {
if (TextUtils.isEmpty(showingPageName) || showingPageName != context::class.qualifiedName) {
return
}
mPlayerFloatView?.visibility = View.GONE
wm?.removeViewImmediate(mPlayerFloatView)
showingPageName = ""
wm = null
}
fun onDestroy() {
if (mPlayerFloatView != null) {
if (!TextUtils.isEmpty(showingPageName)) {
wm?.removeViewImmediate(mPlayerFloatView)
showingPageName = ""
}
mPlayerFloatView?.onDestroy()
mPlayerFloatView?.removeAllViews()
}
}
fun setPlayingState(context: Context) {
show(context)
mPlayerFloatView?.setPlayingState()
}
fun updatePlayState() {
mPlayerFloatView?.updatePlayState()
}
private fun addFloatToWm(context: Context) {
if (wm != null && !TextUtils.isEmpty(showingPageName)) {
if (ViewCompat.isAttachedToWindow(mPlayerFloatView!!)) {
// if (context is Activity && !(context.isFinishing)){
// wm?.removeViewImmediate(mPlayerFloatView)
// }
wm?.removeViewImmediate(mPlayerFloatView)
}
wm = null
}
//获取WindowManager
wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
//设置LayoutParams(全局变量)相关参数
val wmParams = mPlayerFloatView?.wmParams
wmParams?.type = WindowManager.LayoutParams.TYPE_APPLICATION //设置window type
wmParams?.format = PixelFormat.RGBA_8888 //设置图片格式,效果为背景透明
//设置Window flag
wmParams?.flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
wmParams?.gravity = Gravity.LEFT or Gravity.TOP //调整悬浮窗口至左上角
//以屏幕左上角为原点,设置x、y初始值
val size = Point()
wm?.defaultDisplay?.getSize(size)
wmParams?.x = 0
wmParams?.y = size.y * 5 / 6
//设置悬浮窗口长宽数据
wmParams?.width = WindowManager.LayoutParams.MATCH_PARENT
wmParams?.height = RxImageTool.dp2px(56f)
//显示myFloatView图像
wm?.addView(mPlayerFloatView, wmParams)
showingPageName = context::class.qualifiedName!!
}
/**
* 打开播放中的页面详情
*/
fun startPlayingActivity(context: Context?, fullScreen: Int = 0) {
if (playingType == PlayTypeEnum.PLAY_TYPE_FM) {
//FM播放页
startFMPlayActivity(context)
} else if (playingType == PlayTypeEnum.PLAY_TYPE_COURSE) {
var url = AudioPlayer.get().playMusic?.path
//课程播放页
startCoursePlayActivity(context, 1, fullScreen, url, true)
}
}
fun startCoursePlayActivity(
context: Context?,
from: Int,
fullScreen: Int = 0,
coursePlayUrl: String? = "",
isFromFloatView: Boolean = false
) {
ARouter.getInstance()
.build("/course/play")
.withInt("course_id", playTempData["course_id"]?.toInt() ?: 0)
.withInt("course_type", 0)
.withString("coursePlayUrl", coursePlayUrl)
.withInt("from", from)
.withBoolean("isFromFloatView", isFromFloatView)
.withInt("fullScreen", fullScreen)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.navigation()
}
fun startFMPlayActivity(context: Context?) {
val bundle = Bundle()
bundle.putInt("id", playTempData["fmId"]?.toInt() ?: 0)
ARouter.getInstance().build("/fm/detail")
.withBundle("bundle", bundle)
.navigation()
}
/**
* 获取FM播放Id
*/
fun getFmId(): Int {
return playTempData["fmId"]?.toInt() ?: 0
}
}
}
\ No newline at end of file
......@@ -63,7 +63,7 @@ class AudioPlayer private constructor() {
}
val audioSessionId: Int
get() = if (mediaPlayer != null)mediaPlayer!!.audioSessionId else 0
get() = if (mediaPlayer != null) mediaPlayer!!.audioSessionId else 0
val currentPosition: Long
get() = if (isPlaying || isPausing) {
......@@ -89,8 +89,7 @@ class AudioPlayer private constructor() {
val isIdle: Boolean
get() = state == STATE_IDLE
var playPosition: Int = 0
private set
private var playPosition: Int = 0
get() {
if (field < 0 || field >= musicList.size) {
field = 0
......@@ -103,10 +102,12 @@ class AudioPlayer private constructor() {
* 默认为列表循环
*/
var playMode = PlayModeEnum.LIST_LOOP
/**
* 是否自动保存播放进度
*/
var autoSaveProgress = false
/**
* 是否显示通知栏
*/
......@@ -131,6 +132,7 @@ class AudioPlayer private constructor() {
LogUtil.e(e.message)
}
mediaPlayer!!.setOnPreparedListener {
// TODO: 2022/8/4 startPlayer 和 onPrepared 调用顺序不对
if (isPreparing) {
if (autoSaveProgress) {
//自动播放
......@@ -163,13 +165,17 @@ class AudioPlayer private constructor() {
listener.onComplete()
}
if (playMode == PlayModeEnum.SINGLE) {
stopPlayer()
playMode = PlayModeEnum.LIST_LOOP
return@setOnCompletionListener
when (playMode) {
PlayModeEnum.SINGLE -> { // 这是老逻辑
resetPlayer()
playMode = PlayModeEnum.LIST_LOOP
}
PlayModeEnum.LIST -> {
if (playPosition >= musicList.lastIndex) pausePlayer()
else next()
}
else -> next()
}
next()
}
handler = Handler(Looper.getMainLooper())
noisyReceiver = NoisyAudioStreamReceiver()
......@@ -202,7 +208,6 @@ class AudioPlayer private constructor() {
}
musicList.clear()
musicList.addAll(music)
playMode = PlayModeEnum.LIST_LOOP
autoSaveProgress = false
}
......@@ -251,19 +256,17 @@ class AudioPlayer private constructor() {
* 加载指定索引的音乐
*/
fun load(index: Int) {
if (musicList.isEmpty()) return
var position = index
if (musicList.isEmpty()) {
return
}
if (position < 0) {
position = musicList.size - 1
} else if (position >= musicList.size) {
position = 0
}
listeners.forEach {
if (!it.onPreLoad(position)) return
}
playPosition = position
val music = playMusic
try {
......@@ -298,7 +301,7 @@ class AudioPlayer private constructor() {
playPosition -= 1
next()
} else {
stopPlayer()
resetPlayer()
for (listener in listeners) {
listener.onLoad(playMusic!!)
}
......@@ -309,10 +312,10 @@ class AudioPlayer private constructor() {
/**
* 暂停或者播放音乐
*/
fun playPause() {
fun playOrPause() {
when {
isPreparing -> {
stopPlayer()
resetPlayer()
}
isPlaying -> {
pausePlayer()
......@@ -343,7 +346,7 @@ class AudioPlayer private constructor() {
}
context!!.registerReceiver(noisyReceiver, noisyFilter)
for (listener in listeners) {
listener.onPlayerStart()
listener.onStartPlay()
}
}
......@@ -374,14 +377,14 @@ class AudioPlayer private constructor() {
}
for (listener in listeners) {
listener.onPlayerPause()
listener.onPausePlay()
}
}
/**
* 停止播放器
*/
fun stopPlayer() {
fun resetPlayer() {
if (isIdle) {
return
}
......@@ -395,16 +398,21 @@ class AudioPlayer private constructor() {
/**
* 下一首
*/
operator fun next() {
fun next() {
if (musicList.isEmpty()) {
return
}
val position = when (playMode) {
PlayModeEnum.SHUFFLE -> Random().nextInt(musicList.size)
PlayModeEnum.SINGLE_LOOP -> playPosition
PlayModeEnum.LIST_LOOP -> playPosition + 1
PlayModeEnum.LIST_LOOP -> if (playPosition >= musicList.lastIndex) 0 else playPosition + 1
PlayModeEnum.LIST -> if (playPosition >= musicList.lastIndex) -1 else playPosition + 1
else -> playPosition + 1
}
if (-1 == position) {
ToastUtil.toastShort("暂无内容")
return
}
load(position)
}
......@@ -415,13 +423,18 @@ class AudioPlayer private constructor() {
if (musicList.isEmpty()) {
return
}
val playPosition = when (playMode) {
val position = when (playMode) {
PlayModeEnum.SHUFFLE -> Random().nextInt(musicList.size)
PlayModeEnum.SINGLE_LOOP -> playPosition
PlayModeEnum.LIST_LOOP -> playPosition - 1
PlayModeEnum.LIST_LOOP -> if (playPosition <= 0) musicList.lastIndex else playPosition - 1
PlayModeEnum.LIST -> if (playPosition <= 0) -1 else playPosition - 1
else -> playPosition - 1
}
load(playPosition)
if (-1 == position) {
ToastUtil.toastShort("暂无内容")
return
}
load(position)
}
/**
......@@ -479,6 +492,8 @@ class AudioPlayer private constructor() {
}
companion object {
// TODO: 2022/8/4 缺少完成状态和出错状态,目前看代码逻辑是
// TODO: 2022/8/4 正常播放完,到下一首加载前都是 STATE_PLAYING 状态,如果播放链接出错,则到下一首加载前是 STATE_PREPARING 状态
private val STATE_IDLE = 0
private val STATE_PREPARING = 1
private val STATE_PLAYING = 2
......
......@@ -6,18 +6,27 @@ import com.ydl.media.audio.model.Music
/**
* Created by haorui on 2019-10-27 .
* Des:播放进度监听器
*
* todo: [onStartPlay]和[onPrepared]调用顺序有问题,不改是因为多处调用
*/
interface OnPlayerEventListener {
/**
* 加载歌曲
* 加载之前
* @return true: 可加载
*/
fun onPreLoad(playPosition: Int): Boolean = true
/**
* 加载之后
*/
fun onLoad(music: Music)
/**
* 开始播放
*
*/
fun onPlayerStart()
fun onStartPlay()
/**
* 准备完成
......@@ -39,12 +48,12 @@ interface OnPlayerEventListener {
fun onPublish(percent: Int,currentPosition: Long)
/**
* 单曲播放完成
* 播放完成
*/
fun onComplete()
/**
* 暂停播放
*/
fun onPlayerPause()
fun onPausePlay()
}
......@@ -56,7 +56,7 @@ class PlayService : Service() {
}
private fun stop() {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
NotifyManager.get().cancelAll()
}
......
......@@ -5,6 +5,8 @@ package com.ydl.media.audio.enums
* Des: 播放模式
*/
enum class PlayModeEnum(private val value: Int) {
//列表
LIST(-1),
//列表循环
LIST_LOOP(0),
//随机播放
......
......@@ -23,11 +23,11 @@ class MediaSessionManager private constructor() {
private val callback = object : MediaSessionCompat.Callback() {
override fun onPlay() {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
override fun onPause() {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
override fun onSkipToNext() {
......@@ -39,7 +39,7 @@ class MediaSessionManager private constructor() {
}
override fun onStop() {
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
override fun onSeekTo(pos: Long) {
......
......@@ -22,6 +22,7 @@ import com.ydl.media.audio.PlayService
import com.ydl.media.audio.constants.Extras
import com.ydl.media.audio.model.Music
import com.ydl.media.audio.receiver.StatusBarReceiver
import com.ydl.ydlcommon.router.YdlCommonOut
import java.util.*
......@@ -77,20 +78,18 @@ class NotifyManager private constructor() {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val pendingIntent =
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
var remoteViews = getRemoteViews(context, music, isPlaying)
val remoteViews = getRemoteViews(context, music, isPlaying)
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= 26) {
val builder: NotificationCompat.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "app_play_intent_service_channel_id"
val channelName = "壹点灵心理咨询"
val notificationManager =
context.getSystemService("notification") as NotificationManager
val notificationChannel = NotificationChannel(channelId, channelName, 2)
notificationManager.createNotificationChannel(notificationChannel)
builder = NotificationCompat.Builder(context, channelId)
NotificationCompat.Builder(context, channelId)
} else {
builder = NotificationCompat.Builder(context)
NotificationCompat.Builder(context)
}
builder
......@@ -112,7 +111,7 @@ class NotifyManager private constructor() {
private fun getRemoteViews(context: Context, music: Music, isPlaying: Boolean): RemoteViews {
val title = music.title
val subtitle = music.artist + "-" + music.album
val subtitle = music.artist + if (null == music.album) "" else "-" + music.album
val remoteViews = RemoteViews(context.packageName, R.layout.notification)
......@@ -122,7 +121,7 @@ class NotifyManager private constructor() {
val isLightNotificationTheme = isLightNotificationTheme(playService)
val playIntent = Intent(StatusBarReceiver.ACTION_STATUS_BAR)
playIntent.setPackage("com.cxzapp.xinlizixun")
playIntent.setPackage(YdlCommonOut.getApp().packageName)
playIntent.putExtra(StatusBarReceiver.EXTRA, StatusBarReceiver.EXTRA_PLAY_PAUSE)
val playPendingIntent =
PendingIntent.getBroadcast(context, 0, playIntent, PendingIntent.FLAG_UPDATE_CURRENT)
......@@ -133,7 +132,7 @@ class NotifyManager private constructor() {
remoteViews.setOnClickPendingIntent(R.id.iv_play_pause, playPendingIntent)
val nextIntent = Intent(StatusBarReceiver.ACTION_STATUS_BAR)
nextIntent.setPackage("com.cxzapp.xinlizixun")
nextIntent.setPackage(YdlCommonOut.getApp().packageName)
nextIntent.putExtra(StatusBarReceiver.EXTRA, StatusBarReceiver.EXTRA_NEXT)
val nextPendingIntent =
PendingIntent.getBroadcast(context, 1, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT)
......
......@@ -17,6 +17,8 @@ class Music : Serializable {
var duration: Long = 0 // 持续时间
var path: String? = null // 播放地址
var canPlay: Boolean = true // 是否能播放
override fun equals(o: Any?): Boolean {
if (o !is Music) {
return false
......
......@@ -14,6 +14,6 @@ import com.ydl.media.audio.AudioPlayer
class NoisyAudioStreamReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
}
......@@ -21,7 +21,7 @@ class RemoteControlReceiver : BroadcastReceiver() {
}
when (event.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_HEADSETHOOK -> AudioPlayer.get().playPause()
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_HEADSETHOOK -> AudioPlayer.get().playOrPause()
KeyEvent.KEYCODE_MEDIA_NEXT -> AudioPlayer.get().next()
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> AudioPlayer.get().prev()
}
......
......@@ -23,7 +23,7 @@ class StatusBarReceiver : BroadcastReceiver() {
if (TextUtils.equals(extra, EXTRA_NEXT)) {
AudioPlayer.get().next()
} else if (TextUtils.equals(extra, EXTRA_PLAY_PAUSE)) {
AudioPlayer.get().playPause()
AudioPlayer.get().playOrPause()
}
}
......
......@@ -56,7 +56,7 @@ class PlayerFloatHelper {
/**
* 显示悬浮控件
*/
fun show(context: Context, playTypeEnum: PlayTypeEnum = PlayTypeEnum.PLAY_TYPE_NONE, playData:HashMap<String,String> = hashMapOf<String,String>()) {
fun show(context: Context, playTypeEnum: PlayTypeEnum = PlayTypeEnum.PLAY_TYPE_NONE, playData:HashMap<String,String> = hashMapOf()) {
playingType = playTypeEnum
if (playData.size>0){
......
......@@ -63,18 +63,16 @@ class PlayerFloatView(private val ctx: Context) : FrameLayout(ctx) {
}
PlayerFloatHelper.removeView(ctx)
PlayerFloatHelper.playTempData.clear()
AudioPlayer.get().stopPlayer()
AudioPlayer.get().resetPlayer()
}
play_state.setOnClickListener {
if (AudioPlayer.get().isPlaying) {
play_state.setImageResource(R.drawable.ico_yyfc_play)
AudioPlayer.get().playPause()
AudioPlayer.get().pausePlayer()
mListeners.forEach {
it.onPauseClick()
}
} else {
play_state.setImageResource(R.drawable.ico_yyfc_pause)
AudioPlayer.get().playPause()
} else if (AudioPlayer.get().isPausing) {
AudioPlayer.get().startPlayer()
mListeners.forEach {
it.onStartClick()
}
......@@ -84,24 +82,40 @@ class PlayerFloatView(private val ctx: Context) : FrameLayout(ctx) {
mStateChangeListener = object : OnPlayerEventListener {
override fun onComplete() {
updatePlayState()
tv_start.text = getStringTime(AudioPlayer.get().getDuration().toInt())
play_state.setImageResource(R.drawable.ico_yyfc_play)
mListeners.forEach {
it.onPlayFinish()
}
}
override fun onPreLoad(playPosition: Int): Boolean {
AudioPlayer.get().getMusicList().elementAtOrNull(playPosition)?.let {
if (it.canPlay) {
tv_title.text = it.title
tv_name.text = it.artist
return true
} else {
AudioPlayer.get().next()
}
}
return true
}
override fun onLoad(music: Music) {
}
override fun onPlayerStart() {
override fun onStartPlay() {
play_state.setImageResource(R.drawable.ico_yyfc_pause)
}
override fun onPlayerPause() {
override fun onPausePlay() {
play_state.setImageResource(R.drawable.ico_yyfc_play)
}
@SuppressLint("SetTextI18n")
override fun onPublish(percent: Int, currentPosition: Long) {
tv_now_playing_time.text = getStringTime(currentPosition.toInt())
tv_start.text = getStringTime(currentPosition.toInt())
}
override fun onBufferingUpdate(percent: Int) {
......@@ -109,6 +123,7 @@ class PlayerFloatView(private val ctx: Context) : FrameLayout(ctx) {
@SuppressLint("SetTextI18n")
override fun onPrepared(duration: Long) {
setDuration()
updatePlayState()
}
}
......@@ -142,9 +157,13 @@ class PlayerFloatView(private val ctx: Context) : FrameLayout(ctx) {
} else {
AudioPlayer.get().playMusic?.artist
}
tv_duration.text = " / ${getStringTime(AudioPlayer.get().getDuration().toInt())}"
setDuration()
}
@SuppressLint("SetTextI18n")
private fun setDuration() {
tv_duration.text = " / ${getStringTime(AudioPlayer.get().getDuration().toInt())}"
}
private fun getStringTime(time: Int): String {
if (time <= 0) return "00:00"
......
......@@ -58,7 +58,7 @@
tools:text="丁sir" />
<TextView
android:id="@+id/tv_now_playing_time"
android:id="@+id/tv_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/tv_title"
......@@ -71,8 +71,8 @@
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBaseline_toBaselineOf="@id/tv_now_playing_time"
app:layout_constraintStart_toEndOf="@id/tv_now_playing_time"
app:layout_constraintBaseline_toBaselineOf="@id/tv_start"
app:layout_constraintStart_toEndOf="@id/tv_start"
android:textColor="#BFBFBF"
android:textSize="10sp"
tools:text=" / 30:28" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment