<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<project version="4"> | <project version="4"> | ||||
<component name="ASMIdeaPluginConfiguration"> | |||||
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" /> | |||||
<groovy codeStyle="LEGACY" /> | |||||
</component> | |||||
<component name="DesignSurface"> | <component name="DesignSurface"> | ||||
<option name="filePathToZoomLevelMap"> | <option name="filePathToZoomLevelMap"> | ||||
<map> | <map> |
buildTypes { | buildTypes { | ||||
release { | release { | ||||
buildConfigField "int", "PORT", "10006" | |||||
buildConfigField "String", "ENVIRONMENT", "\"production\"" | |||||
// buildConfigField "int", "PORT", "10006" | |||||
// buildConfigField "String", "ENVIRONMENT", "\"production\"" | |||||
minifyEnabled false | minifyEnabled false | ||||
shrinkResources false | shrinkResources false | ||||
debuggable = true | |||||
debuggable = false | |||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||||
signingConfig signingConfigs.relese | signingConfig signingConfigs.relese | ||||
} | } | ||||
debug { | debug { | ||||
buildConfigField "int", "PORT", "10003" | |||||
buildConfigField "String", "ENVIRONMENT", "\"development\"" | |||||
// buildConfigField "int", "PORT", "10003" | |||||
// buildConfigField "String", "ENVIRONMENT", "\"development\"" | |||||
minifyEnabled false | minifyEnabled false | ||||
zipAlignEnabled false | zipAlignEnabled false | ||||
debuggable = true | debuggable = true |
<application | <application | ||||
android:name=".module.XKLApplication" | android:name=".module.XKLApplication" | ||||
android:allowBackup="true" | android:allowBackup="true" | ||||
android:icon="@mipmap/ic_launcher" | |||||
android:icon="@mipmap/app_icon" | |||||
android:label="@string/app_name" | android:label="@string/app_name" | ||||
android:roundIcon="@mipmap/ic_launcher_round" | android:roundIcon="@mipmap/ic_launcher_round" | ||||
android:supportsRtl="true" | android:supportsRtl="true" |
// TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 | // TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 | ||||
//间隔时间单位 | //间隔时间单位 | ||||
private val reviewIntervalUnit = "hour" | |||||
private val reviewIntervalUnit = "day" | |||||
//间隔单位时间 | //间隔单位时间 | ||||
private val reviewTime = IntArray(7) { | private val reviewTime = IntArray(7) { |
SQLiteDatabase.OPEN_READONLY) | SQLiteDatabase.OPEN_READONLY) | ||||
} | } | ||||
if (mDataBase == null) { | if (mDataBase == null) { | ||||
AppExecutors.mainThread.run { | |||||
AppExecutors.mainThread.execute { | |||||
Toast.makeText(AppGlobals.application, "课程数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | Toast.makeText(AppGlobals.application, "课程数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | ||||
} | } | ||||
} | } | ||||
mutableList.add(lesson) | mutableList.add(lesson) | ||||
positionIndex += 1 | positionIndex += 1 | ||||
// TODO: 2022/5/9 对课时数量进行限制,课时太多,开发人员不好进行测试 | |||||
val needBreak = when (base.coursePackType) { | |||||
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION -> positionIndex == 10 //保留十个课时 | |||||
AppConstants.COURSEPACK_TYPE_ENGLISH_SPOKEN -> positionIndex == 6 //保留六个课时 | |||||
else -> positionIndex == 6 //保留六个课时 | |||||
} | |||||
if (needBreak) { | |||||
break | |||||
} | |||||
// 对课时数量进行限制,课时太多,开发人员不好进行测试 | |||||
// val needBreak = when (base.coursePackType) { | |||||
// AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION -> positionIndex == 10 //保留十个课时 | |||||
// AppConstants.COURSEPACK_TYPE_ENGLISH_SPOKEN -> positionIndex == 6 //保留六个课时 | |||||
// else -> positionIndex == 6 //保留六个课时 | |||||
// } | |||||
// if (needBreak) { | |||||
// break | |||||
// } | |||||
} | } | ||||
it.close() | it.close() | ||||
} | } |
mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getDictionaryDbPath().path, pwd, null, SQLiteDatabase.OPEN_READONLY) | mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getDictionaryDbPath().path, pwd, null, SQLiteDatabase.OPEN_READONLY) | ||||
} | } | ||||
if (mDataBase == null) { | if (mDataBase == null) { | ||||
AppExecutors.mainThread.run { | |||||
AppExecutors.mainThread.execute { | |||||
Toast.makeText(AppGlobals.application, "词典数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | Toast.makeText(AppGlobals.application, "词典数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | ||||
} | } | ||||
} | } |
SQLiteDatabase.OPEN_READONLY) | SQLiteDatabase.OPEN_READONLY) | ||||
} | } | ||||
if (mDataBase == null) { | if (mDataBase == null) { | ||||
AppExecutors.mainThread.run { | |||||
AppExecutors.mainThread.execute { | |||||
Toast.makeText(AppGlobals.application, "词汇量测试数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | Toast.makeText(AppGlobals.application, "词汇量测试数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | ||||
} | } | ||||
} | } |
} | } | ||||
// TODO: 2022/5/17 如果不需要小游戏,则这个可以取消,存放的value为time,暂时感觉没必要,所以直接用空内容数据 | // TODO: 2022/5/17 如果不需要小游戏,则这个可以取消,存放的value为time,暂时感觉没必要,所以直接用空内容数据 | ||||
//添加到错误本中,现在主要用于小游戏取值 | //添加到错误本中,现在主要用于小游戏取值 | ||||
learnEventData.newErrorMap?.forEach { | |||||
vm.courseDetail.temporary_words[it.key] = "" | |||||
} | |||||
// learnEventData.newErrorMap?.forEach { | |||||
// vm.courseDetail.temporary_words[it.key] = "" | |||||
// } | |||||
} | } | ||||
AppConstants.LESSON_TYPE_SENTENCE -> { | AppConstants.LESSON_TYPE_SENTENCE -> { | ||||
} | } | ||||
binding.tvNickname.click { | binding.tvNickname.click { | ||||
XPopup.Builder(context) | XPopup.Builder(context) | ||||
.hasStatusBarShadow(false) | |||||
.isDestroyOnDismiss(true) | |||||
.autoOpenSoftInput(true) | |||||
.isDarkTheme(false) | |||||
.isViewMode(true) | |||||
// .hasStatusBarShadow(false) | |||||
// .isDestroyOnDismiss(true) | |||||
// .autoOpenSoftInput(true) | |||||
// .isDarkTheme(false) | |||||
// .isViewMode(true) | |||||
.asInputConfirm("修改昵称", null, binding.tvNickname.text.toString(), "限制为1-12个字符") { | .asInputConfirm("修改昵称", null, binding.tvNickname.text.toString(), "限制为1-12个字符") { | ||||
//修改确认 | //修改确认 | ||||
if (it.isNotEmpty() && it.length <= 12) { | if (it.isNotEmpty() && it.length <= 12) { |
import com.xkl.cdl.module.m_statics.StaticsFragment | import com.xkl.cdl.module.m_statics.StaticsFragment | ||||
import com.xkl.cdl.module.splash.SplashActivity | import com.xkl.cdl.module.splash.SplashActivity | ||||
import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX | import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX | ||||
import com.zackratos.ultimatebarx.ultimatebarx.navigationBar | |||||
import com.zackratos.ultimatebarx.ultimatebarx.statusBar | |||||
import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | ||||
/** | /** | ||||
fun setStatusBar(isMyFragment : Boolean){ | fun setStatusBar(isMyFragment : Boolean){ | ||||
when{ | when{ | ||||
isMyFragment -> statusBarOnly { | |||||
fitWindow = false //布局是否侵入状态栏 | |||||
color = Color.TRANSPARENT //透明 | |||||
light = true | |||||
isMyFragment -> { | |||||
statusBar { | |||||
fitWindow = false //布局是否侵入状态栏 | |||||
color = Color.TRANSPARENT //透明 | |||||
light = true | |||||
} | |||||
navigationBar { | |||||
fitWindow = false //布局是否侵入状态栏 | |||||
color = Color.TRANSPARENT //透明 | |||||
light = true | |||||
} | |||||
} | } | ||||
else -> initStatusBar() | else -> initStatusBar() | ||||
} | } |
downLoadSuccess = false | downLoadSuccess = false | ||||
} | } | ||||
} | } | ||||
println("${coursePackBaseInfo.coursePackName} : 下载成功") | |||||
println("${coursePackBaseInfo.coursePackName} : 下载功能结束") | |||||
//下载成功,解压到对应的文件 | //下载成功,解压到对应的文件 | ||||
saveFile?.let { file -> | saveFile?.let { file -> | ||||
downLoadNameAndProgress.postValue("课程数据包解析中,请稍等...") | |||||
coursePackBaseInfo.let { | coursePackBaseInfo.let { | ||||
try { | try { | ||||
unZipFile_1(file, it) | unZipFile_1(file, it) | ||||
nextEntry = entries.nextElement() | nextEntry = entries.nextElement() | ||||
zipInputStream = zipFile.getInputStream(nextEntry) | zipInputStream = zipFile.getInputStream(nextEntry) | ||||
outPut = when { | outPut = when { | ||||
nextEntry.name.endsWith(("cover.png")) -> { | |||||
nextEntry.name.startsWith("cover.") -> { | |||||
Array<BufferedOutputStream>(1) { | Array<BufferedOutputStream>(1) { | ||||
val fileName = File(FilePathManager.getIconRootPath(), | val fileName = File(FilePathManager.getIconRootPath(), | ||||
"${coursePack.subjectId}/${coursePack.coursePackId}/icon") | "${coursePack.subjectId}/${coursePack.coursePackId}/icon") | ||||
while ((zipInputStream.read(buffer).also { count = it }) != -1) { | while ((zipInputStream.read(buffer).also { count = it }) != -1) { | ||||
outPut.forEach { | outPut.forEach { | ||||
it.write(buffer, 0, count) | it.write(buffer, 0, count) | ||||
it.flush() | |||||
} | } | ||||
} | } | ||||
zipInputStream?.close() | |||||
outPut.forEach { | outPut.forEach { | ||||
it.close() | it.close() | ||||
} | } |
companion object{ | companion object{ | ||||
val apiService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { | val apiService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { | ||||
HttpUtil.instance.getRetrofitService(ApiService::class.java) | |||||
// HttpUtil.instance.getRetrofitService(ApiService::class.java) | |||||
} | } | ||||
} | } | ||||
package com.suliang.common.util.net | package com.suliang.common.util.net | ||||
import android.webkit.WebSettings | |||||
import android.widget.Toast | import android.widget.Toast | ||||
import com.suliang.common.base.LibApplication | |||||
import com.suliang.common.util.AppGlobals | import com.suliang.common.util.AppGlobals | ||||
import com.suliang.common.util.thread.AppExecutors | import com.suliang.common.util.thread.AppExecutors | ||||
import com.suliang.common.util.thread.MainThreadExecutor | import com.suliang.common.util.thread.MainThreadExecutor | ||||
.connectTimeout(time_out, TimeUnit.SECONDS) | .connectTimeout(time_out, TimeUnit.SECONDS) | ||||
.readTimeout(time_out, TimeUnit.SECONDS) | .readTimeout(time_out, TimeUnit.SECONDS) | ||||
.writeTimeout(time_out, TimeUnit.SECONDS) | .writeTimeout(time_out, TimeUnit.SECONDS) | ||||
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) | |||||
.addInterceptor(RetryInterceptor(2)) //重试拦截器 | |||||
.build() | |||||
} | |||||
private val retrofit : Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { | |||||
Retrofit.Builder().baseUrl("http://api.offline.xuekaole.com") | |||||
.client(okHttpClient) | |||||
// .addConverterFactory(GsonConverterFactory.create()) | |||||
// .addConverterFactory(ScalarsConverterFactory.create()) | |||||
// .addConverterFactory(ProtoConverterFactory.create()) | |||||
.addCallAdapterFactory(RxJava3CallAdapterFactory.create()) | |||||
//下载大文件时不能添加日志拦截器,否则会将所有数据加入内存,造成OOM | |||||
// .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) | |||||
// .addInterceptor(RetryInterceptor(2)) //重试拦截器 | |||||
.build() | .build() | ||||
} | } | ||||
// private val retrofit : Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { | |||||
// Retrofit.Builder().baseUrl("http://api.offline.xuekaole.com") | |||||
// .client(okHttpClient) | |||||
//// .addConverterFactory(GsonConverterFactory.create()) | |||||
//// .addConverterFactory(ScalarsConverterFactory.create()) | |||||
//// .addConverterFactory(ProtoConverterFactory.create()) | |||||
// .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) | |||||
// .build() | |||||
// } | |||||
} | } | ||||
fun getOkhttpClient() : OkHttpClient { | fun getOkhttpClient() : OkHttpClient { | ||||
* @param service | * @param service | ||||
* @return | * @return | ||||
*/ | */ | ||||
fun <T : IApiService> getRetrofitService (service : Class<T> ) : T { | |||||
return retrofit.create(service) | |||||
} | |||||
// fun <T : IApiService> getRetrofitService (service : Class<T> ) : T { | |||||
// return retrofit.create(service) | |||||
// } | |||||
// | |||||
/** | /** | ||||
return | return | ||||
} | } | ||||
//下载 | //下载 | ||||
val newCall = okHttpClient.newCall(Request.Builder().url(urlPath).build()) | |||||
newCall.execute().use { response -> | |||||
//下载失败 | |||||
if (!response.isSuccessful) { | |||||
downLoadFileListener.downFileResult(null) | |||||
return | |||||
} | |||||
//下载成功 | |||||
var inputStream : InputStream? = null | |||||
var outputStream : OutputStream? = null | |||||
response.body?.let { | |||||
try { | |||||
val contentLength:Double = it.contentLength().toDouble() //总长度 | |||||
downLoadFileListener.downFileSize(contentLength.toLong()) //回调总长度 | |||||
inputStream = it.byteStream() | |||||
outputStream = FileOutputStream(savePathFile) | |||||
var readLength : Int = 0 | |||||
var writeLength = 0f | |||||
val bytes = ByteArray(1025 * 1025 * 5) | |||||
var progress = 0 | |||||
while ((inputStream!!.read(bytes)).also { | |||||
readLength = it | |||||
} != -1) { | |||||
outputStream!!.write(bytes, 0, readLength) | |||||
writeLength += readLength | |||||
progress = (writeLength / contentLength * 100).toInt() | |||||
// AppExecutors.mainThread.execute { | |||||
// 进度回调给放到主线程中 | |||||
downLoadFileListener.downFileProgress(progress) //下载百分比 | |||||
// } | |||||
} | |||||
outputStream?.flush() | |||||
outputStream?.close() | |||||
downLoadFileListener.downFileResult(savePathFile) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
val newCall = okHttpClient.newCall(Request.Builder().url(urlPath).removeHeader("User-Agent") | |||||
.addHeader("User-Agent", WebSettings.getDefaultUserAgent(LibApplication.instance())).build()) | |||||
try { | |||||
newCall.execute().let { response -> | |||||
//下载失败 | |||||
if (!response.isSuccessful) { | |||||
downLoadFileListener.downFileResult(null) | downLoadFileListener.downFileResult(null) | ||||
}finally { | |||||
return | |||||
} | |||||
//下载成功 | |||||
var inputStream : InputStream? = null | |||||
var outputStream : OutputStream? = null | |||||
var result = false //是否成功标志 | |||||
response.body?.let { | |||||
try { | try { | ||||
val contentLength:Double = it.contentLength().toDouble() //总长度 | |||||
downLoadFileListener.downFileSize(contentLength.toLong()) //回调总长度 | |||||
inputStream = it.byteStream() | |||||
outputStream = BufferedOutputStream(FileOutputStream(savePathFile)) | |||||
var readLength : Int = 0 | |||||
var writeLength = 0f | |||||
val bytes = ByteArray(1025 * 1025 * 5) | |||||
var progress = 0 | |||||
while ((inputStream!!.read(bytes)).also { | |||||
readLength = it | |||||
} != -1) { | |||||
outputStream!!.write(bytes, 0, readLength) | |||||
writeLength += readLength | |||||
progress = (writeLength / contentLength * 100).toInt() | |||||
// AppExecutors.mainThread.execute { | |||||
// 进度回调给放到主线程中 | |||||
downLoadFileListener.downFileProgress(progress) //下载百分比 | |||||
// } | |||||
} | |||||
outputStream?.flush() | |||||
outputStream?.close() | outputStream?.close() | ||||
inputStream?.close() | |||||
}catch (e: Exception){ | |||||
// downLoadFileListener.downFileResult(savePathFile) | |||||
result = true | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | e.printStackTrace() | ||||
// downLoadFileListener.downFileResult(null) | |||||
result = false | |||||
}finally { | |||||
try { | |||||
outputStream?.close() | |||||
inputStream?.close() | |||||
}catch (e: Exception){ | |||||
e.printStackTrace() | |||||
} | |||||
} | } | ||||
//回调中太多需要处理的数据,这里需要先释放,避免OOM | |||||
if (result) downLoadFileListener.downFileResult(savePathFile) else downLoadFileListener.downFileResult(null) | |||||
} | } | ||||
} | } | ||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
downLoadFileListener.downFileResult(null) | |||||
} | } | ||||
} | } | ||||