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.pngBinary files differ
app/src/main/assets/apngb_level_10.pngBinary files differ
app/src/main/assets/apngb_level_2.pngBinary files differ
app/src/main/assets/apngb_level_3.pngBinary files differ
app/src/main/assets/apngb_level_4.pngBinary files differ
app/src/main/assets/apngb_level_5.pngBinary files differ
app/src/main/assets/apngb_level_6.pngBinary files differ
app/src/main/assets/apngb_level_7.pngBinary files differ
app/src/main/assets/apngb_level_8.pngBinary files differ
app/src/main/assets/apngb_level_9.pngBinary files differ
app/src/main/assets/apngb_water.pngBinary files differ
app/src/main/assets/sunshine.pngBinary 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,7 +69,11 @@ 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 ) } } } @@ -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) @@ -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) } } @@ -244,7 +262,32 @@ } private fun showWater(){ val apngDrawable = APNGDrawable.fromAsset(requireContext(),"apngb_water.png") // 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(){ @@ -254,15 +297,79 @@ } }) } } // 获取缓存文件路径 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") 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) 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) @@ -270,6 +377,9 @@ else tv_again.gone() } } }) } override fun onPause() { super.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"