lmw
2025-04-24 718f31c92e2029d05260810435a2c70cef6e6ce5
save
8个文件已修改
12个文件已删除
2个文件已添加
334 ■■■■ 已修改文件
app/src/main/AndroidManifest.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_1.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_10.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_2.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_3.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_4.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_5.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_6.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_7.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_8.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_level_9.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/apngb_water.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/sunshine.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/network/RRetrofit.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/network/entity/TreeInfo.kt 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/ui/OnlyWebActivity.kt 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/ui/course/PushCourseFragment.kt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/ui/mine/MineFragment.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/ui/tree/TreeFragment.kt 184 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/sinata/xqmuse/utils/Const.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_only_web.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_tree.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml
@@ -150,6 +150,7 @@
        <activity android:name=".ui.course.StudyActivity" android:configChanges="orientation|screenSize|keyboardHidden"/>
        <activity android:name=".ui.home.BuyVoiceActivity" android:label="确认订单"/>
        <activity android:name=".ui.home.MicroVideoActivity" android:launchMode="singleTask"  android:configChanges="orientation|screenSize|keyboardHidden" />
        <activity android:name=".ui.OnlyWebActivity" />
        <service android:name="com.amap.api.location.APSService"/>
        <service android:name=".ThinkAudioService"
app/src/main/assets/apngb_level_1.png
Binary files differ
app/src/main/assets/apngb_level_10.png
Binary files differ
app/src/main/assets/apngb_level_2.png
Binary files differ
app/src/main/assets/apngb_level_3.png
Binary files differ
app/src/main/assets/apngb_level_4.png
Binary files differ
app/src/main/assets/apngb_level_5.png
Binary files differ
app/src/main/assets/apngb_level_6.png
Binary files differ
app/src/main/assets/apngb_level_7.png
Binary files differ
app/src/main/assets/apngb_level_8.png
Binary files differ
app/src/main/assets/apngb_level_9.png
Binary files differ
app/src/main/assets/apngb_water.png
Binary files differ
app/src/main/assets/sunshine.png
Binary files differ
app/src/main/java/com/sinata/xqmuse/network/RRetrofit.kt
@@ -8,6 +8,7 @@
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.util.concurrent.TimeUnit
/**
 * 网络请求retrofit初始化。
@@ -19,6 +20,9 @@
        .addConverterFactory(JsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(OkHttpClient.Builder()
            .connectTimeout(1,TimeUnit.MINUTES)
            .writeTimeout(1,TimeUnit.MINUTES)
            .readTimeout(1,TimeUnit.MINUTES)
            .addInterceptor { chain ->
                val token = SPUtils.instance().getString(Const.User.TOKEN)
                val request =
app/src/main/java/com/sinata/xqmuse/network/entity/TreeInfo.kt
@@ -17,17 +17,28 @@
    var treeLevelType: Int
){
    fun getTreeApng() = when(treeLevelType){ //1=种子 2=发芽 3=幼苗 4=小树苗 5=中等树苗 6=小树 7=中树 8=大树 9=成熟的大树 10=参天大树
        1-> "apngb_level_1.png"
        2-> "apngb_level_2.png"
        3-> "apngb_level_3.png"
        4-> "apngb_level_4.png"
        5-> "apngb_level_5.png"
        6-> "apngb_level_6.png"
        7-> "apngb_level_7.png"
        8-> "apngb_level_8.png"
        9-> "apngb_level_9.png"
        10-> "apngb_level_10.png"
        else->"apngb_level_1.png"
//        1-> "apngb_level_1.png"
//        2-> "apngb_level_2.png"
//        3-> "apngb_level_3.png"
//        4-> "apngb_level_4.png"
//        5-> "apngb_level_5.png"
//        6-> "apngb_level_6.png"
//        7-> "apngb_level_7.png"
//        8-> "apngb_level_8.png"
//        9-> "apngb_level_9.png"
//        10-> "apngb_level_10.png"
//        else->"apngb_level_1.png"
        1-> Const.APNG_TREE.LEVEL_1
        2-> Const.APNG_TREE.LEVEL_2
        3-> Const.APNG_TREE.LEVEL_3
        4-> Const.APNG_TREE.LEVEL_4
        5-> Const.APNG_TREE.LEVEL_5
        6-> Const.APNG_TREE.LEVEL_6
        7-> Const.APNG_TREE.LEVEL_7
        8-> Const.APNG_TREE.LEVEL_8
        9-> Const.APNG_TREE.LEVEL_9
        10-> Const.APNG_TREE.LEVEL_10
        else->Const.APNG_TREE.LEVEL_1
    }
    fun getTreeDead() = when(treeLevelType){ //1=种子 2=发芽 3=幼苗 4=小树苗 5=中等树苗 6=小树 7=中树 8=大树 9=成熟的大树 10=参天大树
@@ -44,15 +55,15 @@
    }
    fun getLevelUpAudio() = when(treeLevelType){ //1=种子 2=发芽 3=幼苗 4=小树苗 5=中等树苗 6=小树 7=中树 8=大树 9=成熟的大树 10=参天大树
        2-> Const.TREE.LEVEL_2
        3-> Const.TREE.LEVEL_3
        4-> Const.TREE.LEVEL_4
        5-> Const.TREE.LEVEL_5
        6-> Const.TREE.LEVEL_6
        7-> Const.TREE.LEVEL_7
        8-> Const.TREE.LEVEL_8
        9-> Const.TREE.LEVEL_9
        10-> Const.TREE.LEVEL_10
        2-> Const.VOICE_TREE.LEVEL_2
        3-> Const.VOICE_TREE.LEVEL_3
        4-> Const.VOICE_TREE.LEVEL_4
        5-> Const.VOICE_TREE.LEVEL_5
        6-> Const.VOICE_TREE.LEVEL_6
        7-> Const.VOICE_TREE.LEVEL_7
        8-> Const.VOICE_TREE.LEVEL_8
        9-> Const.VOICE_TREE.LEVEL_9
        10-> Const.VOICE_TREE.LEVEL_10
        else->""
    }
app/src/main/java/com/sinata/xqmuse/ui/OnlyWebActivity.kt
New file
@@ -0,0 +1,62 @@
package com.sinata.xqmuse.ui
import android.graphics.Bitmap
import android.text.TextUtils
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import com.github.zackratos.ultimatebar.UltimateBar
import com.sinata.xqmuse.R
import kotlinx.android.synthetic.main.activity_only_web.*
import org.jetbrains.anko.startActivity
class OnlyWebActivity:TransparentStatusBarActivity() {
    override fun setContentView() = R.layout.activity_only_web
    override fun initClick() {
    }
    override fun initView() {
        UltimateBar.with(this)
            .statusDark(true)
            .create().immersionBar() //沉浸状态栏
        val titleParam = intent.getStringExtra("title")
        val url = intent.getStringExtra("url")?:""
        title = titleParam
        val settings = webView.settings
        settings.javaScriptEnabled = true
        settings.javaScriptCanOpenWindowsAutomatically = true
        settings.defaultTextEncodingName = "utf-8"
        settings.domStorageEnabled = true
        webView.webChromeClient = object : WebChromeClient() {
            override fun onReceivedTitle(view: WebView, title: String?) {
                super.onReceivedTitle(view, title)
            }
        }
        webView.webViewClient = object : WebViewClient() {
            override fun onPageFinished(view: WebView, url: String?) {
                super.onPageFinished(view, url)
                dismissDialog()
            }
            override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
                showDialog()
            }
            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
                if (!TextUtils.isEmpty(url)) {
                    webView.loadUrl(url)
                }
                return true
            }
        }
        webView.loadUrl(url)
        if (titleParam == "爱心助力榜单"){
            titleBar.addRightButton("我的助力",onClickListener = View.OnClickListener {
                startActivity<OnlyWebActivity>("title" to "推荐名单","url" to intent.getStringExtra("pushList"))
            })}
    }
}
app/src/main/java/com/sinata/xqmuse/ui/course/PushCourseFragment.kt
@@ -62,7 +62,6 @@
    }
    fun refresh(){
        getBanner()
        getType()
        page = 1
        getData()
app/src/main/java/com/sinata/xqmuse/ui/mine/MineFragment.kt
@@ -15,6 +15,7 @@
import com.sinata.xqmuse.network.entity.MineInfo
import com.sinata.xqmuse.network.requestByF
import com.sinata.xqmuse.ui.H5Activity
import com.sinata.xqmuse.ui.OnlyWebActivity
import com.sinata.xqmuse.ui.course.MyCourseActivity
import com.sinata.xqmuse.ui.login.LoginActivity
import com.sinata.xqmuse.utils.Const
@@ -73,7 +74,7 @@
        }
        tv_rank.setOnClickListener {
            userInfo?.apply {
                startActivity<H5Activity>("title" to "爱心助力榜单","url" to Apis.RANK.format(id),"type" to 0,"pushList" to Apis.PUSH_LIST.format(id))
                startActivity<OnlyWebActivity>("title" to "爱心助力榜单","url" to Apis.RANK.format(id),"type" to 0,"pushList" to Apis.PUSH_LIST.format(id))
            }
        }
        tv_account.setOnClickListener {
app/src/main/java/com/sinata/xqmuse/ui/tree/TreeFragment.kt
@@ -8,9 +8,9 @@
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.luck.picture.lib.tools.SPUtils
import com.sinata.xqmuse.MainActivity
import com.sinata.xqmuse.R
import com.sinata.xqmuse.dialog.TreeTipDialog
@@ -21,15 +21,27 @@
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
@@ -40,6 +52,7 @@
    private val audioPlayer by lazy { AudioUtils() } //音频播放
    private var tree:TreeInfo? = null
    private val cacheDir by lazy { requireActivity().cacheDir }
    //常量
    val GROWTH_ANIM_DURATION = 500L
@@ -56,20 +69,24 @@
        tv_rule.setOnClickListener {
            HttpManager.getH5(6).requestByF(this){ _, data->
                data?.let {
                    startActivity<H5Activity>("title" to "规则说明","url" to it.content,"showClose" to false)
                    startActivity<H5Activity>(
                        "title" to "规则说明",
                        "url" to it.content,
                        "showClose" to false
                    )
                }
            }
        }
        tv_sign.clickDelay {
            HttpManager.sign().requestByF(this){_,data->
            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)
                signed.postDelayed({ signed.gone() }, 1500)
            }
        }
        tv_to_think.setOnClickListener {
@@ -79,7 +96,8 @@
            EventBus.getDefault().post(EmptyEvent(Const.EventCode.SWITCH_HOME))
        }
        iv_water.clickDelay {
            showWater()
//            showWater()
//            return@clickDelay
//            tree?.energyValue = 0
//            tree!!.treeLevelType++
//            showTreeAnim(tree!!.getTreeApng(),true)
@@ -92,14 +110,14 @@
            else if (tree?.sowAgain == 1)
                toast("树苗已成熟,请重新播种")
            else
                HttpManager.watering().requestByF(this){_,data->
                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()))
                        showGrowthAnim(layoutParams.height, max(1, targetHeight.toInt()))
                        showWater()
                        tree?.energyValue = energyValue
                        tv_power.text = "当前能量值:${(tree?.energyValue?:0)}"
@@ -107,7 +125,7 @@
                            showGrowUpDialog(data.treeLevelType)
                        }else if (tree!!.status != 2){
                            tree!!.status = 2
                            showTreeAnim(tree!!.getTreeApng(),tree!!.treeLevelType != 1)
                            showTreeAnim(tree!!.getTreeApng(), tree!!.treeLevelType != 1)
                        }
                    }
                }
@@ -122,7 +140,7 @@
        }
        tv_again.setOnClickListener {
            HttpManager.restart().requestByF(this){_,_->
            HttpManager.restart().requestByF(this){ _, _->
                getTree()
            }
        }
@@ -148,7 +166,7 @@
    private fun checkFirst() {
        if (checkLogin())
            HttpManager.isFirst().requestByF(this){_,data->
            HttpManager.isFirst().requestByF(this){ _, data->
                if (data == true)
                    showFirst()
            }
@@ -157,12 +175,12 @@
    /**
     * 依次弹窗升级和播放语音
     */
    private fun showGrowUpDialog(targetLevel:Int){
    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{
        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) {
            }
@@ -191,7 +209,7 @@
    }
    fun getTree(){
        HttpManager.getUserTree().requestByF(this){_,data->
        HttpManager.getUserTree().requestByF(this){ _, data->
            val changed = data?.treeLevelType != tree?.treeLevelType //等级发生变化
            tree = data
            data?.apply {
@@ -200,14 +218,14 @@
                tv_growth.text = growthValue.toString()
                val targetHeight = growthValue.toDouble()/nextLevel*dip(155)
                val layoutParams = progress.layoutParams
                showGrowthAnim(layoutParams.height, max(1,targetHeight.toInt()))
                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)
                        showTreeAnim(getTreeApng(), treeLevelType != 1)
                } else
                    showTreeDead()
            }
@@ -220,7 +238,7 @@
    fun showFirst(){
        if (!(activity as MainActivity).hasTreeFirstShow){
            TreeTipDialog.show(childFragmentManager)
            audioPlayer.startPlayMusic(requireContext(),Const.TREE.first)
            audioPlayer.startPlayMusic(requireContext(), Const.VOICE_TREE.first)
        }
    }
@@ -232,7 +250,7 @@
    /**
     * 成长值动画
     */
    private fun showGrowthAnim(start:Int,end:Int){
    private fun showGrowthAnim(start: Int, end: Int){
        val ofInt = ValueAnimator.ofInt(start, end)
        ofInt.duration = GROWTH_ANIM_DURATION
        ofInt.addUpdateListener {
@@ -244,31 +262,123 @@
    }
    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)
//        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(){
        val apngDrawable = APNGDrawable.fromAsset(requireContext(),"sunshine.png")
        iv_sunshine.setImageDrawable(apngDrawable)
        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){
        val apngDrawable = APNGDrawable.fromAsset(requireContext(),resStr)
        iv_tree.setImageDrawable(apngDrawable)
        apngDrawable.setLoopLimit(if (isLoop) -1 else 1)
        if (tree?.treeLevelType?:0 >= 10)
            tv_again.visible()
        else
            tv_again.gone()
    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() {
app/src/main/java/com/sinata/xqmuse/utils/Const.kt
@@ -24,7 +24,7 @@
        const val SHARE_COURSE_TITLE = "传递心灵温暖,一起感受疗愈力量"
    }
    object TREE {
    object VOICE_TREE {
        val first = OSS_DOMAIN+"xinquan/1d3254a9966b476789491032d8bb908a.wav"
        val LEVEL_2 = OSS_DOMAIN+"xinquan/d8daa4d5490f40f9a68a8469ad697660.wav"
        val LEVEL_3 = OSS_DOMAIN+"xinquan/0da0e117c4374c398347c480d2cfc6b4.wav"
@@ -37,6 +37,21 @@
        val LEVEL_10 = OSS_DOMAIN+"xinquan/8b0303829a6547f5a16c5232883b94cc.wav"
    }
    object APNG_TREE {
        val LEVEL_1 = OSS_DOMAIN+"1744625964828apngb_level_1.png"
        val LEVEL_2 = OSS_DOMAIN+"1744626102004apngb_level_2.png"
        val LEVEL_3 = OSS_DOMAIN+"1744626112494apngb_level_3.png"
        val LEVEL_4 = OSS_DOMAIN+"1744626121574apngb_level_4.png"
        val LEVEL_5 = OSS_DOMAIN+"1744626132663apngb_level_5.png"
        val LEVEL_6 = OSS_DOMAIN+"1744626142519apngb_level_6.png"
        val LEVEL_7 = OSS_DOMAIN+"1744626152068apngb_level_7.png"
        val LEVEL_8 = OSS_DOMAIN+"1744626162562apngb_level_8.png"
        val LEVEL_9 = OSS_DOMAIN+"1744626170896apngb_level_9.png"
        val LEVEL_10 = OSS_DOMAIN+"1744626182350apngb_level_10.png"
        val WATER = OSS_DOMAIN+"1744626198262apngb_water.png"
        val SUNSHINE = OSS_DOMAIN+"1744626206206sunshine.png"
    }
    object User {
        const val TOKEN = "token"
        const val USER_ID = "userId"
app/src/main/res/layout/activity_only_web.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/webView">
</WebView>
app/src/main/res/layout/fragment_tree.xml
@@ -158,14 +158,13 @@
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:id="@+id/iv_water_anim"
                android:layout_marginEnd="30dp"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginBottom="200dp"
                app:layout_constraintBottom_toBottomOf="@id/iv_tree"/>
            <TextView
                android:layout_width="164dp"
                android:layout_height="wrap_content"