From 718f31c92e2029d05260810435a2c70cef6e6ce5 Mon Sep 17 00:00:00 2001 From: lmw <125975490@qq.com> Date: 星期四, 24 四月 2025 10:45:55 +0800 Subject: [PATCH] save --- app/src/main/java/com/sinata/xqmuse/MainActivity.kt | 278 ++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 170 insertions(+), 108 deletions(-) diff --git a/app/src/main/java/com/sinata/xqmuse/MainActivity.kt b/app/src/main/java/com/sinata/xqmuse/MainActivity.kt index 2792e10..c341a57 100644 --- a/app/src/main/java/com/sinata/xqmuse/MainActivity.kt +++ b/app/src/main/java/com/sinata/xqmuse/MainActivity.kt @@ -2,11 +2,11 @@ import android.annotation.SuppressLint import android.content.Intent -import android.os.Handler -import android.os.Looper -import android.os.Message +import android.net.Uri +import android.os.* import android.provider.Settings import android.util.Log +import android.view.Gravity import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentPagerAdapter @@ -16,6 +16,10 @@ import com.flyco.tablayout.listener.CustomTabEntity import com.flyco.tablayout.listener.OnTabSelectListener import com.google.gson.Gson +import com.lzf.easyfloat.EasyFloat +import com.lzf.easyfloat.enums.ShowPattern +import com.lzf.easyfloat.enums.SidePattern +import com.lzf.easyfloat.interfaces.OnInvokeView import com.sinata.xqmuse.dialog.TipDialog import com.sinata.xqmuse.network.HttpManager import com.sinata.xqmuse.network.entity.VoiceDetail @@ -34,12 +38,14 @@ import com.sinata.xqmuse.utils.Const import com.sinata.xqmuse.utils.event.EmptyEvent import com.sinata.xqmuse.utils.event.IntEvent +import com.umeng.socialize.utils.DeviceConfigInternal.context import kotlinx.android.synthetic.main.activity_main.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast import xyz.doikki.videoplayer.player.VideoView + class MainActivity : TransparentStatusBarActivity(), OnTabSelectListener,AudioUtils.OnAudioStatusUpdateListener { override fun setContentView() = R.layout.activity_main @@ -48,7 +54,7 @@ var teacherVideoView:VideoView? = null private var bgPlayer:AudioUtils? = null//背景音乐播放器 - private var thinkBgPlayer:AudioUtils? = null//冥想背景音播放器 +// private var thinkBgPlayer:AudioUtils? = null//冥想背景音播放器 // private var thinkPlayer:AudioUtils? = null//冥想背景音播放器 private var guideAudio:String? = null @@ -57,7 +63,7 @@ private var thinkHandler:Handler? = null //冥想时间相关 private var inGuide = false //true 引导中... - private val isFirst by lazy { intent.getBooleanExtra("isFirst",false) } //首次安装,需要到导师引导页 + private val isFirst by lazy { intent.getBooleanExtra("isFirst", false) } //首次安装,需要到导师引导页 private val MSG_PROGRESS = 0//疗愈进度+1 private val MSG_TODAY = 1//今日疗愈更新计时 @@ -70,33 +76,40 @@ var hasTreeFirstShow = false //此字段用来判断 树苗的首次弹窗是否已经触发,和isFirst字段配合使用 var isBGMChanged = false //此字段用来判断 在疗愈播放中,修改了背景音乐,在疗愈结束后 需要更新BGM音源 + private val EasyFloatTag = "BACKGROUND" + private var floater: EasyFloat.Builder? = null //浮窗 + override fun initClick() { player_close.setOnClickListener { - TipDialog.show(supportFragmentManager,"是否关闭当前音频?",object :TipDialog.OnClickCallback{ + TipDialog.show(supportFragmentManager, "是否关闭当前音频?", object : TipDialog.OnClickCallback { override fun onOk() { EventBus.getDefault().post(EmptyEvent(Const.EventCode.FINISH_THINK)) } override fun onCancel() { } - },"确认","取消") + }, "确认", "取消") } cl_player.setOnClickListener { - voice?.goDetail(this) + ThinkAudioService.voice?.goDetail(this) } player_play.setOnClickListener { - playing = !playing - if (playing){ + ThinkAudioService.playing = !ThinkAudioService.playing + if (ThinkAudioService.playing){ player_play.setImageResource(R.mipmap.player_pause) - thinkBgPlayer?.resume() + EventBus.getDefault().post(EmptyEvent(Const.EventCode.USER_INFO_CHANGED)) + EventBus.getDefault().post(EmptyEvent(Const.EventCode.SERVICE_AUDIO_RESUME)) +// thinkBgPlayer?.resume() // thinkPlayer?.resume() thinkHandler?.sendEmptyMessage(MSG_PROGRESS) startTime = System.currentTimeMillis() }else{ player_play.setImageResource(R.mipmap.player_start) - thinkBgPlayer?.pause() + EventBus.getDefault().post(EmptyEvent(Const.EventCode.USER_INFO_CHANGED)) + EventBus.getDefault().post(EmptyEvent(Const.EventCode.SERVICE_AUDIO_PAUSE)) +// thinkBgPlayer?.pause() // thinkPlayer?.pause() thinkHandler?.removeMessages(MSG_PROGRESS) saveThinkRecord() @@ -121,24 +134,26 @@ override fun handleMessage(msg: Message) { super.handleMessage(msg) when(msg.what){ - MSG_PROGRESS->{ - currentPosition = thinkBgPlayer?.currentPosition ?:0 - EventBus.getDefault().post(EmptyEvent(Const.EventCode.GOT_THINK_POSITION)) - sendEmptyMessageDelayed(MSG_PROGRESS,1000) + MSG_PROGRESS -> { + EventBus.getDefault().post(EmptyEvent(Const.EventCode.SERVICE_AUDIO_PROGRESS)) + sendEmptyMessageDelayed(MSG_PROGRESS, 1000) + if (System.currentTimeMillis() - startTime >= 60000){ + saveThinkRecord() + } } - MSG_COUNTDOWN->{ - if (System.currentTimeMillis()>= finishTime) + MSG_COUNTDOWN -> { + if (System.currentTimeMillis() >= ThinkAudioService.finishTime) EventBus.getDefault().post(EmptyEvent(Const.EventCode.FINISH_THINK)) else - sendEmptyMessageDelayed(MSG_COUNTDOWN,1000) + sendEmptyMessageDelayed(MSG_COUNTDOWN, 1000) } - MSG_TODAY->{ + MSG_TODAY -> { //todo 分离hanlder,这个保持原功能,进度和计时相关应放进Service if (System.currentTimeMillis() - lastTodayTime > 60000) { //距离上次刷新过去了1分钟 - Log.e(Const.Tag,"已经过1分钟,需要重新获取今日疗愈数据") + Log.e(Const.Tag, "已经过1分钟,需要重新获取今日疗愈数据") lastTodayTime = System.currentTimeMillis() (fragments[0] as HomeFragment).getToday() } - sendEmptyMessageDelayed(MSG_TODAY,5000) + sendEmptyMessageDelayed(MSG_TODAY, 5000) } } } @@ -151,27 +166,29 @@ if (guidePlayer == null) guidePlayer = AudioUtils() if (guideAudio.isNullOrEmpty()) - HttpManager.getPlan().request(this){_,data-> + HttpManager.getPlan().request(this){ _, data-> guideAudio = data if (inGuide){ guidePlayer?.setVolume(0.6f) - guidePlayer?.loopPlayMusic(this,data) + guidePlayer?.loopPlayMusic(this, data) } } else{ guidePlayer?.setVolume(0.6f) - guidePlayer?.loopPlayMusic(this,guideAudio) + guidePlayer?.loopPlayMusic(this, guideAudio) } } private fun startBgm() { - val bgm = SPUtils.instance().getString(Const.User.BGM) - if (!bgm.isNullOrEmpty()){ - if (bgPlayer == null) - bgPlayer = AudioUtils() - val volume = SPUtils.instance().getInt(Const.User.VOLUME,50) - bgPlayer?.setVolume(volume.toFloat()/100) - bgPlayer?.loopPlayMusic(this,bgm) + HttpManager.getHomeBackgroundMusicByUserId().request(this){ _, data-> + if (!data?.audioFile.isNullOrEmpty()){ + if (bgPlayer == null) + bgPlayer = AudioUtils() + val volume = SPUtils.instance().getInt(Const.User.VOLUME, 50) + bgPlayer?.setVolume(volume.toFloat() / 100) + bgPlayer?.loopPlayMusic(this, data?.audioFile) + } + (fragments[0] as HomeFragment).changeBg(data?.imageUrl ?: "", data?.backUrl ?: "") } } @@ -180,21 +197,22 @@ */ private fun startThink() { bgPlayer?.pause() - index = 0 - if (voice?.meditationMusicList?.isNullOrEmpty() == false){ - if (thinkBgPlayer == null){ - thinkBgPlayer = AudioUtils() - thinkBgPlayer!!.setOnAudioStatusUpdateListener(this) + ThinkAudioService.index = 0 + if (ThinkAudioService.voice?.meditationMusicList?.isNullOrEmpty() == false){ + checkFloat() //检测浮窗 + // 启动音乐服务 + val serviceIntent = Intent(this, ThinkAudioService::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(serviceIntent) + } else { + startService(serviceIntent) } - val volume = SPUtils.instance().getInt(Const.User.VOLUME_THINK,50) - thinkBgPlayer?.setVolume(volume.toFloat()/100) - thinkBgPlayer?.startPlayMusic(this, voice?.meditationMusicList?.get(index)) - currentDuration = voice?.meditationSecondList?.get(index)?:0 + ThinkAudioService.currentDuration = ThinkAudioService.voice?.meditationSecondList?.get(ThinkAudioService.index)?:0 EventBus.getDefault().post(EmptyEvent(Const.EventCode.GOT_THINK_DURATION)) - playing = true + ThinkAudioService.playing = true cl_player.visible() - tv_player.text = voice?.meditationTitle - iv_player.setImageURI(voice?.coverUrl?.split(",")?.firstOrNull()) + tv_player.text = ThinkAudioService.voice?.meditationTitle + iv_player.setImageURI(ThinkAudioService.voice?.coverUrl?.split(",")?.firstOrNull()) player_play.setImageResource(R.mipmap.player_pause) thinkHandler?.sendEmptyMessage(MSG_PROGRESS) startTime = System.currentTimeMillis() //记录开始冥想的时间 @@ -207,15 +225,16 @@ */ private fun finishThink(){ saveThinkRecord() - voice = null - index = 0 - finishTime = 0L - thinkBgPlayer?.stopPlayMusic(true) - playing = false + ThinkAudioService.voice = null + ThinkAudioService.index = 0 + ThinkAudioService.finishTime = 0L + // 停止服务 + stopService(Intent(this, ThinkAudioService::class.java)) + ThinkAudioService.playing = false thinkHandler?.removeMessages(0) cl_player.gone() (fragments[0] as HomeFragment).refreshTodayPlayingState() //对比当前音频是否是每日疗愈 - if (JkApplication.isForeground){ + if (XQApplication.isForeground){ if (isBGMChanged) //BGM已经被切换,重新播放新BGM startBgm() else //BGM未改变,直接续播 @@ -224,17 +243,44 @@ } /** + * 申请浮窗权限 增加稳定性 + */ + private fun checkFloat() { + if (!Settings.canDrawOverlays(this) && SPUtils.instance().getString("isRefusedFloat").isNullOrEmpty()) { //没有浮窗权限并且没有拒绝过 + TipDialog.show( + supportFragmentManager, + "为了增加后台播放的稳定性,我们需要开启悬浮窗口权限", + object : TipDialog.OnClickCallback { + override fun onOk() { + var intent = Intent( + Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + packageName) + ) + startActivityForResult(intent, 1234) + } + + override fun onCancel() { + } + }, + "去开启", + "取消" + ) + } + } + + + /** * 保存冥想记录 */ private fun saveThinkRecord() { - if (voice == null||startTime == 0L||SPUtils.instance().getString(Const.User.TOKEN).isNullOrEmpty()) + if (ThinkAudioService.voice == null||startTime == 0L||SPUtils.instance().getString(Const.User.TOKEN).isNullOrEmpty()) return val time = ((System.currentTimeMillis() - startTime) / 1000).toInt() - startTime = 0L - HttpManager.saveViewingHistory(voice?.id?:"", time).request(this,false,{ _, _-> - Log.e(Const.Tag,"冥想记录成功:$time 秒") - }){_,_-> - Log.e(Const.Tag,"冥想记录失败:$time 秒") + startTime = System.currentTimeMillis() + HttpManager.saveViewingHistory(ThinkAudioService.voice?.id ?: "", time).request(this, false, { _, _ -> + Log.e(Const.Tag, "冥想记录成功:$time 秒") + }){ _, _-> + Log.e(Const.Tag, "冥想记录失败:$time 秒") } } @@ -246,7 +292,7 @@ } private fun initTab() { - val titles = arrayListOf("疗愈","课程","","疗愈馆","我的") + val titles = arrayListOf("疗愈", "课程", "", "疗愈馆", "我的") val iconChecked = arrayListOf( R.mipmap.home_selected, R.mipmap.play_selected, @@ -267,7 +313,7 @@ fragments.add(DiscoveryFragment()) fragments.add(MineFragment()) view_pager.offscreenPageLimit = fragments.size - view_pager.adapter = object : FragmentPagerAdapter(supportFragmentManager,0) { + view_pager.adapter = object : FragmentPagerAdapter(supportFragmentManager, 0) { override fun getItem(p0: Int): Fragment { return fragments[p0] } @@ -291,12 +337,16 @@ } override fun onTabSelect(position: Int) { - if (position == 4 && SPUtils.instance().getString(Const.User.TOKEN).isNullOrEmpty()){ - toast("请先登录") - startActivity<LoginActivity>() - tab_bar.currentTab = 0 - return + if (position == 4 ){ + if (SPUtils.instance().getString(Const.User.TOKEN).isNullOrEmpty()){ + toast("请先登录") + startActivity<LoginActivity>() + tab_bar.currentTab = 0 + return + }else + (fragments[4] as MineFragment).showUserInfo() } + view_pager.currentItem = position if (position == 2){ (fragments[2] as TreeFragment).getTree() @@ -310,13 +360,18 @@ cl_player.alpha = 1f } } + if (position == 1){ + (fragments[1] as CourseFragment).refreshDataByResume() + } if (position == 4){ (fragments[4] as MineFragment).queryUnread() } if (position != 1) EventBus.getDefault().post(EmptyEvent(Const.EventCode.PAUSE_TEACHER_VIDEO)) - if (position == 0) + if (position == 0){ + (fragments[0] as HomeFragment).refreshDataByResume() startTodayCheck() + } else stopTodayCheck() } @@ -325,7 +380,7 @@ } @Subscribe - fun onEvent(e:EmptyEvent){ + fun onEvent(e: EmptyEvent){ if (e.code == Const.EventCode.CHANGE_USER){ tab_bar.currentTab = 0 onTabSelect(0) @@ -341,37 +396,38 @@ tab_bar.currentTab = 3 onTabSelect(3) }else if(e.code == Const.EventCode.APP_FOREGROUND){ - if (voice==null) + EasyFloat.hide(EasyFloatTag) + if (ThinkAudioService.voice==null) bgPlayer?.resume() }else if(e.code == Const.EventCode.APP_BACKGROUND){ bgPlayer?.pause() + if ( ThinkAudioService.playing && Settings.canDrawOverlays(this) ) { + showFloater() + EasyFloat.show(EasyFloatTag) + } }else if(e.code == Const.EventCode.CHANGE_BGM){ - if (voice == null) + if (ThinkAudioService.voice == null) startBgm() else isBGMChanged = true //正在播放疗愈,无法立即切换背景音乐 - (fragments[0] as HomeFragment).changeBg() }else if(e.code == Const.EventCode.START_THINK){ startThink() }else if(e.code == Const.EventCode.FINISH_THINK){ finishThink() }else if(e.code == Const.EventCode.PAUSE_OR_RESUME_THINK){ player_play.callOnClick() - }else if(e.code == Const.EventCode.CHANGE_THINK_VOLUME){ - val v = SPUtils.instance().getInt(Const.User.VOLUME_THINK,50) - thinkBgPlayer?.setVolume(v.toFloat()/100) }else if(e.code == Const.EventCode.START_GUIDE_AUDIO){ inGuide = true startGuide() bgPlayer?.pause() - thinkBgPlayer?.pause() + EventBus.getDefault().post(EmptyEvent(Const.EventCode.SERVICE_AUDIO_PAUSE)) }else if(e.code == Const.EventCode.FINISH_GUIDE_AUDIO){ inGuide = false guidePlayer?.stopPlayMusic(false) - if (voice!=null&& playing){ - thinkBgPlayer?.resume() + if (ThinkAudioService.voice!=null&& ThinkAudioService.playing){ + EventBus.getDefault().post(EmptyEvent(Const.EventCode.SERVICE_AUDIO_RESUME)) } - if (voice == null) + if (ThinkAudioService.voice == null) bgPlayer?.resume() }else if(e.code == Const.EventCode.REFRESH_PRIVATE){ //重新答题后,刷新私人定制 (fragments[0] as HomeFragment).getPrivacy() @@ -381,9 +437,9 @@ } @Subscribe - fun onIntEvent(e:IntEvent){ + fun onIntEvent(e: IntEvent){ if (e.code == Const.EventCode.THINK_SEEK_PROGRESS){ - thinkBgPlayer?.seekTo(e.i) + EventBus.getDefault().post(IntEvent(Const.EventCode.SERVICE_AUDIO_SEEK,e.i)) player_play.callOnClick() } } @@ -393,16 +449,38 @@ val answer = SPUtils.instance().getString(Const.User.ANSWER) if (!answer.isNullOrEmpty()){ //已登录并且有答案 val reqAnswer = Gson().fromJson(answer, ReqAnswer::class.java) - reqAnswer?.device = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) - HttpManager.saveUserAnswers(reqAnswer).request(this,false,success = { _, _-> - SPUtils.instance().put(Const.User.ANSWER,"").apply() - Log.e(Const.Tag,"私人定制已保存") + reqAnswer?.device = Settings.Secure.getString( + contentResolver, + Settings.Secure.ANDROID_ID + ) + HttpManager.saveUserAnswers(reqAnswer).request(this, false, success = { _, _ -> + SPUtils.instance().put(Const.User.ANSWER, "").apply() + Log.e(Const.Tag, "私人定制已保存") (fragments[0] as HomeFragment).getPrivacy() - }){_,_-> + }){ _, _-> } } } + private fun showFloater() { + if (floater == null){ + floater = EasyFloat.with(applicationContext) + .setLayout(R.layout.layout_floter, OnInvokeView { + }) + .setShowPattern(ShowPattern.ALL_TIME) + .setSidePattern(SidePattern.RESULT_LEFT) + .setGravity(Gravity.START or Gravity.BOTTOM, 0, 0) + .setDragEnable(true) + .setTag(EasyFloatTag) + .setMatchParent(widthMatch = false, heightMatch = false) + .registerCallback { + touchEvent { view, motionEvent -> + motionEvent.action + } + } + floater?.show() + } + } private fun startTodayCheck(){ thinkHandler?.sendEmptyMessage(MSG_TODAY) @@ -416,16 +494,25 @@ super.onResume() if (view_pager.currentItem == 4){ (fragments[4] as MineFragment).queryUnread() + (fragments[4] as MineFragment).showUserInfo() } else if (view_pager.currentItem == 0){ startTodayCheck() + (fragments[0] as HomeFragment).refreshDataByResume() } else if (view_pager.currentItem == 2){ (fragments[2] as TreeFragment).getTree() + } else if (view_pager.currentItem == 1){ + (fragments[1] as CourseFragment).refreshDataByResume() } if (isFirst&&!hasTreeFirstShow&&!SPUtils.instance().getString(Const.User.ANSWER).isNullOrEmpty()){ //如果是第一次安装并且还没显示树苗打卡引导并且答完题了 就去树苗引导 tab_bar.currentTab = 2 onTabSelect(2) (fragments[2] as TreeFragment).showFirst() hasTreeFirstShow = true + } + if (XQApplication.finishAnswer){ + XQApplication.finishAnswer = false + tab_bar.currentTab = 2 + onTabSelect(2) } } @@ -450,22 +537,7 @@ } override fun onFinishPlay() { - if (voice == null) //说明是手动关闭的,不需要处理下一步播放逻辑 - return - if (isRecycle){ //单曲 - if (playing) - thinkBgPlayer?.startPlayMusic(this, voice?.meditationMusicList?.get(index)) - }else{//顺序 - index++ - if (index>=voice?.meditationMusicList?.size?:0)//列表已播完 - EventBus.getDefault().post(EmptyEvent(Const.EventCode.FINISH_THINK)) - else{ - currentDuration = voice?.meditationSecondList?.get(index)?:0 - EventBus.getDefault().post(EmptyEvent(Const.EventCode.GOT_THINK_DURATION)) - if (playing) - thinkBgPlayer?.startPlayMusic(this, voice?.meditationMusicList?.get(index)) - } - } + } override fun onGetDuration(duration: Int) { @@ -475,15 +547,5 @@ override fun onBackPressed() { if (teacherVideoView?.onBackPressed() != true) super.onBackPressed() - } - - companion object{ //冥想播放相关参数 - var playing = false //true播放中 - var isRecycle = false //true单曲循环播放 - var voice: VoiceDetail? = null //冥想详情 - var index = 0 //当前播放序号 - var currentDuration = 0 //当前音频长度(秒) - var currentPosition = 0L //当前音频进度(毫秒) - var finishTime = 0L //自动结束的时间戳 } } \ No newline at end of file -- Gitblit v1.7.1