package com.sinata.xqmuse.ui.tree
|
|
import android.animation.ValueAnimator
|
import android.content.res.Resources
|
import android.graphics.drawable.Drawable
|
import android.util.Log
|
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
import cn.sinata.xldutils.fragment.BaseFragment
|
import cn.sinata.xldutils.gone
|
import cn.sinata.xldutils.visible
|
import com.danikula.videocache.CacheListener
|
import com.github.penfeizhou.animation.apng.APNGDrawable
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.sinata.xqmuse.MainActivity
|
import com.sinata.xqmuse.R
|
import com.sinata.xqmuse.dialog.TreeTipDialog
|
import com.sinata.xqmuse.network.HttpManager
|
import com.sinata.xqmuse.network.entity.TreeInfo
|
import com.sinata.xqmuse.network.requestByF
|
import com.sinata.xqmuse.ui.H5Activity
|
import com.sinata.xqmuse.utils.AudioUtils
|
import com.sinata.xqmuse.utils.Const
|
import com.sinata.xqmuse.utils.ScreenUtil
|
import com.sinata.xqmuse.utils.cache.ProxyVideoCacheManager
|
import com.sinata.xqmuse.utils.event.EmptyEvent
|
import com.sinata.xqmuse.utils.extention.checkLogin
|
import com.sinata.xqmuse.utils.extention.clickDelay
|
import com.sinata.xqmuse.utils.interfaces.StringCallback
|
import kotlinx.android.synthetic.main.fragment_tree.*
|
import okhttp3.*
|
import org.greenrobot.eventbus.EventBus
|
import org.jetbrains.anko.support.v4.dip
|
import org.jetbrains.anko.support.v4.runOnUiThread
|
import org.jetbrains.anko.support.v4.startActivity
|
import org.jetbrains.anko.support.v4.toast
|
import retrofit2.Retrofit
|
import java.io.File
|
import java.io.FileOutputStream
|
import java.io.IOException
|
import java.io.InputStream
|
import java.net.HttpURLConnection
|
import java.net.URL
|
import kotlin.math.max
|
|
|
class TreeFragment : BaseFragment() {
|
override fun contentViewId() = R.layout.fragment_tree
|
|
private val behavior by lazy {
|
BottomSheetBehavior.from(bottom)
|
}
|
|
private val audioPlayer by lazy { AudioUtils() } //音频播放
|
private var tree:TreeInfo? = null
|
private val cacheDir by lazy { requireActivity().cacheDir }
|
//常量
|
val GROWTH_ANIM_DURATION = 500L
|
|
override fun onFirstVisibleToUser() {
|
//用于处理当虚拟导航栏存在时,BottomSheetBehavior窥视高度不对的问题
|
val virtualBarHeigh = ScreenUtil().getVirtualBarHeigh(activity)
|
Log.e("虚拟导航栏高度", "$virtualBarHeigh")
|
val navigationBarHeight = getNavigationBarHeight()
|
Log.e("导航栏高度", "$navigationBarHeight")
|
// if (virtualBarHeigh >= getNavigationBarHeight()) //如果虚拟导航栏高度大于或等于导航栏高度,说明虚拟导航栏在显示,需要减去导航栏的高度
|
// behavior.setPeekHeight(dip(63) + getNavigationBarHeight(), true)
|
// else
|
behavior.setPeekHeight(dip(63), true)
|
tv_rule.setOnClickListener {
|
HttpManager.getH5(6).requestByF(this){ _, data->
|
data?.let {
|
startActivity<H5Activity>(
|
"title" to "规则说明",
|
"url" to it.content,
|
"showClose" to false
|
)
|
}
|
}
|
}
|
|
tv_sign.clickDelay {
|
HttpManager.sign().requestByF(this){ _, data->
|
tv_sign.isEnabled = false
|
tv_sign.text = "已签到"
|
tree?.energyValue = (tree?.energyValue?:0)+10
|
tree?.totalEnergyValue = (tree?.totalEnergyValue?:0)+10
|
tv_power.text = "当前能量值:${(tree?.energyValue?:0)}"
|
signed.visible()
|
signed.postDelayed({ signed.gone() }, 1500)
|
}
|
}
|
tv_to_think.setOnClickListener {
|
EventBus.getDefault().post(EmptyEvent(Const.EventCode.SWITCH_HOME))
|
}
|
tv_to_think_2.setOnClickListener {
|
EventBus.getDefault().post(EmptyEvent(Const.EventCode.SWITCH_HOME))
|
}
|
iv_water.clickDelay {
|
// showWater()
|
// return@clickDelay
|
// tree?.energyValue = 0
|
// tree!!.treeLevelType++
|
// showTreeAnim(tree!!.getTreeApng(),true)
|
// audioPlayer.startPlayMusic(requireContext(),tree!!.getLevelUpAudio())
|
// TreeTipDialog.show(childFragmentManager,"升级","恭喜!你的树苗已升级为${tree!!.getLevelName()}阶段!")
|
if (tree?.energyValue == 0)
|
toast("能量值不足")
|
// else if (tree?.status == 1)
|
// toast("树苗已枯萎,请重新播种")
|
else if (tree?.sowAgain == 1)
|
toast("树苗已成熟,请重新播种")
|
else
|
HttpManager.watering().requestByF(this){ _, data->
|
data?.apply {
|
EventBus.getDefault().post(EmptyEvent(Const.EventCode.USER_INFO_CHANGED)) //刷新成长值
|
tv_max.text = "/$nextLevel"
|
tv_growth.text = growthValue.toString()
|
val targetHeight = growthValue.toDouble()/nextLevel*dip(155)
|
val layoutParams = progress.layoutParams
|
showGrowthAnim(layoutParams.height, max(1, targetHeight.toInt()))
|
showWater()
|
tree?.energyValue = energyValue
|
tv_power.text = "当前能量值:${(tree?.energyValue?:0)}"
|
if (tree!!.treeLevelType != data.treeLevelType){
|
showGrowUpDialog(data.treeLevelType)
|
}else if (tree!!.status != 2){
|
tree!!.status = 2
|
showTreeAnim(tree!!.getTreeApng(), tree!!.treeLevelType != 1)
|
}
|
}
|
}
|
}
|
|
tv_power.setOnClickListener {
|
startActivity<PowerActivity>("power" to tree?.totalEnergyValue)
|
}
|
|
tv_gif.setOnClickListener {
|
startActivity<GiftActivity>()
|
}
|
|
tv_again.setOnClickListener {
|
HttpManager.restart().requestByF(this){ _, _->
|
getTree()
|
}
|
}
|
|
//MediaPlayer,IjkPlayer
|
// val am = resources.assets
|
// var afd: AssetFileDescriptor? = null
|
// try {
|
// afd = am.openFd("bg_tree.mp4")
|
// } catch (e: IOException) {
|
// e.printStackTrace()
|
// }
|
// player.setAssetFileDescriptor(afd)
|
|
val url = "android.resource://" + requireContext().packageName.toString() + "/" + R.raw.bg
|
player.setUrl(url)
|
player.setLooping(true)
|
player.start()
|
showSunshine()
|
checkFirst()
|
// getTree()
|
}
|
|
private fun checkFirst() {
|
if (checkLogin())
|
HttpManager.isFirst().requestByF(this){ _, data->
|
if (data == true)
|
showFirst()
|
}
|
}
|
|
/**
|
* 依次弹窗升级和播放语音
|
*/
|
private fun showGrowUpDialog(targetLevel: Int){
|
tree!!.treeLevelType++
|
showTreeAnim(tree!!.getTreeApng(), true)
|
audioPlayer.startPlayMusic(requireContext(), tree!!.getLevelUpAudio())
|
val dialog = TreeTipDialog.show(childFragmentManager, "生命之树", tree!!.getLevelName())
|
audioPlayer.setOnAudioStatusUpdateListener(object : AudioUtils.OnAudioStatusUpdateListener {
|
override fun onUpdate(db: Double, time: Long) {
|
}
|
|
override fun onStop(filePath: String?) {
|
}
|
|
override fun onStartPlay() {
|
}
|
|
override fun onFinishPlay() {
|
dialog.canDismiss()
|
}
|
|
override fun onGetDuration(duration: Int) {
|
}
|
})
|
dialog.onDismissCallback = object :TreeTipDialog.OnDismissCallback{
|
override fun onDismiss() {
|
if (tree!!.treeLevelType != targetLevel) //继续展示下一级
|
showGrowUpDialog(targetLevel)
|
else{
|
audioPlayer.setOnAudioStatusUpdateListener(null)
|
}
|
}
|
}
|
}
|
|
fun getTree(){
|
HttpManager.getUserTree().requestByF(this){ _, data->
|
val changed = data?.treeLevelType != tree?.treeLevelType //等级发生变化
|
tree = data
|
data?.apply {
|
tv_power.text = "当前能量值:${energyValue}"
|
tv_max.text = "/$nextLevel"
|
tv_growth.text = growthValue.toString()
|
val targetHeight = growthValue.toDouble()/nextLevel*dip(155)
|
val layoutParams = progress.layoutParams
|
showGrowthAnim(layoutParams.height, max(1, targetHeight.toInt()))
|
tv_sign.isEnabled = isSign == 2
|
tv_sign.text = if (tv_sign.isEnabled) "打卡签到" else "已签到"
|
tv_to_think.isEnabled = taskOne == 2
|
tv_to_think_2.isEnabled = taskTwo == 2
|
if (status == 2){
|
if (changed)
|
showTreeAnim(getTreeApng(), treeLevelType != 1)
|
} else
|
showTreeDead()
|
}
|
}
|
}
|
|
/**
|
* 首次进入树苗打卡,播放音频和弹窗说明
|
*/
|
fun showFirst(){
|
if (!(activity as MainActivity).hasTreeFirstShow){
|
TreeTipDialog.show(childFragmentManager)
|
audioPlayer.startPlayMusic(requireContext(), Const.VOICE_TREE.first)
|
}
|
}
|
|
private fun showTreeDead() {
|
iv_tree.setImageResource(tree!!.getTreeDead())
|
// tv_again.visible()
|
}
|
|
/**
|
* 成长值动画
|
*/
|
private fun showGrowthAnim(start: Int, end: Int){
|
val ofInt = ValueAnimator.ofInt(start, end)
|
ofInt.duration = GROWTH_ANIM_DURATION
|
ofInt.addUpdateListener {
|
val layoutParams = progress.layoutParams
|
layoutParams.height = it.animatedValue as Int
|
progress.layoutParams = layoutParams
|
}
|
ofInt.start()
|
}
|
|
private fun showWater(){
|
// val apngDrawable = APNGDrawable.fromAsset(requireContext(),"apngb_water.png")
|
// iv_water_anim.setImageDrawable(apngDrawable)
|
// apngDrawable.setLoopLimit(2)
|
// apngDrawable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback(){
|
// override fun onAnimationEnd(drawable: Drawable?) {
|
// super.onAnimationEnd(drawable)
|
// iv_water_anim.setImageResource(0)
|
// }
|
// })
|
showOrDownApng(Const.APNG_TREE.WATER,object :StringCallback{
|
override fun onResult(rst: String) {
|
waterAnim()
|
}
|
})
|
}
|
|
private fun showOrDownApng(url:String,callback: StringCallback){
|
if (isFileCached(url)){
|
callback.onResult("")
|
}else
|
downloadFileToCache(url,callback)
|
}
|
|
private fun waterAnim(){
|
val apngDrawable = APNGDrawable.fromFile(getCachedFile(Const.APNG_TREE.WATER)?.absolutePath)
|
runOnUiThread {
|
iv_water_anim.setImageDrawable(apngDrawable)
|
apngDrawable.setLoopLimit(2)
|
apngDrawable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback(){
|
override fun onAnimationEnd(drawable: Drawable?) {
|
super.onAnimationEnd(drawable)
|
iv_water_anim.setImageResource(0)
|
}
|
})
|
}
|
}
|
|
// 获取缓存文件路径
|
fun getCachedFile(url: String): File? {
|
val cacheDir = requireActivity().cacheDir
|
val file = File(cacheDir, url.substring(url.lastIndexOf("/")))
|
return if (file.exists()) file else null
|
}
|
|
// 检查文件是否已缓存
|
fun isFileCached(url: String): Boolean {
|
return getCachedFile(url) != null
|
}
|
|
fun downloadFileToCache(url: String,callback: StringCallback) {
|
val client = OkHttpClient()
|
val request = Request.Builder().url(url).build()
|
|
client.newCall(request).enqueue(object : okhttp3.Callback {
|
override fun onFailure(call: okhttp3.Call, e: IOException) {
|
// 下载失败处理
|
e.printStackTrace()
|
}
|
|
override fun onResponse(call: Call, response: Response) {
|
if (!response.isSuccessful) {
|
throw IOException("下载失败: ${response.code()}")
|
}
|
|
// 获取内部缓存目录
|
val cacheDir = requireActivity().cacheDir
|
val outputFile = File(cacheDir, url.substring(url.lastIndexOf("/") + 1))
|
if (outputFile.exists() && outputFile.isDirectory) {
|
// 删除目录或调整文件名
|
outputFile.delete()
|
}
|
try {
|
// 将文件写入缓存
|
val inputStream = response.body()?.byteStream()
|
val outputStream = FileOutputStream(outputFile)
|
inputStream?.use { input ->
|
outputStream.use { output ->
|
input.copyTo(output)
|
}
|
}
|
// 下载成功,文件路径为 outputFile.absolutePath
|
callback.onResult("")
|
} catch (e: Exception) {
|
e.printStackTrace()
|
}
|
}
|
})
|
}
|
|
private fun showSunshine(){
|
showOrDownApng(Const.APNG_TREE.SUNSHINE,object :StringCallback{
|
override fun onResult(rst: String) {
|
runOnUiThread {
|
val apngDrawable = APNGDrawable.fromFile(getCachedFile(Const.APNG_TREE.SUNSHINE)?.absolutePath)
|
iv_sunshine.setImageDrawable(apngDrawable)
|
}
|
}
|
})
|
// val apngDrawable = APNGDrawable.fromAsset(requireContext(), "sunshine.png")
|
// iv_sunshine.setImageDrawable(apngDrawable)
|
// apngDrawable.setLoopLimit(5)
|
}
|
|
private fun showTreeAnim(resStr: String, isLoop: Boolean){
|
showOrDownApng(resStr,object :StringCallback{
|
override fun onResult(rst: String) {
|
runOnUiThread {
|
val apngDrawable = APNGDrawable.fromFile(getCachedFile(resStr)?.absolutePath)
|
iv_tree.setImageDrawable(apngDrawable)
|
apngDrawable.setLoopLimit(if (isLoop) -1 else 1)
|
if (tree?.treeLevelType?:0 >= 10)
|
tv_again.visible()
|
else
|
tv_again.gone()
|
}
|
}
|
})
|
}
|
|
override fun onPause() {
|
super.onPause()
|
player?.pause()
|
}
|
|
override fun onResume() {
|
super.onResume()
|
player?.resume()
|
}
|
|
override fun onDestroy() {
|
super.onDestroy()
|
player?.release()
|
}
|
|
private fun getNavigationBarHeight(): Int {
|
val resources: Resources = activity!!.getResources()
|
val resourceId: Int = resources.getIdentifier("navigation_bar_height", "dimen", "android")
|
val height: Int = resources.getDimensionPixelSize(resourceId)
|
return height
|
}
|
}
|