| @@ -1,5 +1,9 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <project version="4"> | |||
| <component name="ASMIdeaPluginConfiguration"> | |||
| <asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" /> | |||
| <groovy codeStyle="LEGACY" /> | |||
| </component> | |||
| <component name="DesignSurface"> | |||
| <option name="filePathToZoomLevelMap"> | |||
| <map> | |||
| @@ -56,18 +56,18 @@ android { | |||
| buildTypes { | |||
| release { | |||
| buildConfigField "int", "PORT", "10006" | |||
| buildConfigField "String", "ENVIRONMENT", "\"production\"" | |||
| // buildConfigField "int", "PORT", "10006" | |||
| // buildConfigField "String", "ENVIRONMENT", "\"production\"" | |||
| minifyEnabled false | |||
| shrinkResources false | |||
| debuggable = true | |||
| debuggable = false | |||
| proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |||
| signingConfig signingConfigs.relese | |||
| } | |||
| debug { | |||
| buildConfigField "int", "PORT", "10003" | |||
| buildConfigField "String", "ENVIRONMENT", "\"development\"" | |||
| // buildConfigField "int", "PORT", "10003" | |||
| // buildConfigField "String", "ENVIRONMENT", "\"development\"" | |||
| minifyEnabled false | |||
| zipAlignEnabled false | |||
| debuggable = true | |||
| @@ -9,7 +9,7 @@ | |||
| <application | |||
| android:name=".module.XKLApplication" | |||
| android:allowBackup="true" | |||
| android:icon="@mipmap/ic_launcher" | |||
| android:icon="@mipmap/app_icon" | |||
| android:label="@string/app_name" | |||
| android:roundIcon="@mipmap/ic_launcher_round" | |||
| android:supportsRtl="true" | |||
| @@ -446,7 +446,7 @@ object CourseManager { | |||
| // TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 | |||
| //间隔时间单位 | |||
| private val reviewIntervalUnit = "hour" | |||
| private val reviewIntervalUnit = "day" | |||
| //间隔单位时间 | |||
| private val reviewTime = IntArray(7) { | |||
| @@ -54,7 +54,7 @@ object DBCourseManager { | |||
| SQLiteDatabase.OPEN_READONLY) | |||
| } | |||
| if (mDataBase == null) { | |||
| AppExecutors.mainThread.run { | |||
| AppExecutors.mainThread.execute { | |||
| Toast.makeText(AppGlobals.application, "课程数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | |||
| } | |||
| } | |||
| @@ -156,15 +156,15 @@ object DBCourseManager { | |||
| mutableList.add(lesson) | |||
| 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() | |||
| } | |||
| @@ -33,7 +33,7 @@ object DictionaryManager { | |||
| mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getDictionaryDbPath().path, pwd, null, SQLiteDatabase.OPEN_READONLY) | |||
| } | |||
| if (mDataBase == null) { | |||
| AppExecutors.mainThread.run { | |||
| AppExecutors.mainThread.execute { | |||
| Toast.makeText(AppGlobals.application, "词典数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | |||
| } | |||
| } | |||
| @@ -32,7 +32,7 @@ object VocabularyManager { | |||
| SQLiteDatabase.OPEN_READONLY) | |||
| } | |||
| if (mDataBase == null) { | |||
| AppExecutors.mainThread.run { | |||
| AppExecutors.mainThread.execute { | |||
| Toast.makeText(AppGlobals.application, "词汇量测试数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | |||
| } | |||
| } | |||
| @@ -113,9 +113,9 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| } | |||
| // 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 -> { | |||
| @@ -97,11 +97,11 @@ class MyFragment : BaseFragmentVM<FragmentMyBinding, MyViewModel>() { | |||
| } | |||
| binding.tvNickname.click { | |||
| 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个字符") { | |||
| //修改确认 | |||
| if (it.isNotEmpty() && it.length <= 12) { | |||
| @@ -20,6 +20,8 @@ import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | |||
| import com.xkl.cdl.module.m_statics.StaticsFragment | |||
| import com.xkl.cdl.module.splash.SplashActivity | |||
| 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 | |||
| /** | |||
| @@ -70,10 +72,17 @@ class MainActivity : BaseActivityVM<ActivityMainBinding, MainActivityViewModel>( | |||
| fun setStatusBar(isMyFragment : Boolean){ | |||
| 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() | |||
| } | |||
| @@ -233,9 +233,10 @@ class SplashViewModel : BaseViewModel() { | |||
| downLoadSuccess = false | |||
| } | |||
| } | |||
| println("${coursePackBaseInfo.coursePackName} : 下载成功") | |||
| println("${coursePackBaseInfo.coursePackName} : 下载功能结束") | |||
| //下载成功,解压到对应的文件 | |||
| saveFile?.let { file -> | |||
| downLoadNameAndProgress.postValue("课程数据包解析中,请稍等...") | |||
| coursePackBaseInfo.let { | |||
| try { | |||
| unZipFile_1(file, it) | |||
| @@ -402,7 +403,7 @@ class SplashViewModel : BaseViewModel() { | |||
| nextEntry = entries.nextElement() | |||
| zipInputStream = zipFile.getInputStream(nextEntry) | |||
| outPut = when { | |||
| nextEntry.name.endsWith(("cover.png")) -> { | |||
| nextEntry.name.startsWith("cover.") -> { | |||
| Array<BufferedOutputStream>(1) { | |||
| val fileName = File(FilePathManager.getIconRootPath(), | |||
| "${coursePack.subjectId}/${coursePack.coursePackId}/icon") | |||
| @@ -475,8 +476,10 @@ class SplashViewModel : BaseViewModel() { | |||
| while ((zipInputStream.read(buffer).also { count = it }) != -1) { | |||
| outPut.forEach { | |||
| it.write(buffer, 0, count) | |||
| it.flush() | |||
| } | |||
| } | |||
| zipInputStream?.close() | |||
| outPut.forEach { | |||
| it.close() | |||
| } | |||
| @@ -17,7 +17,7 @@ class RequestUtil { | |||
| companion object{ | |||
| val apiService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { | |||
| HttpUtil.instance.getRetrofitService(ApiService::class.java) | |||
| // HttpUtil.instance.getRetrofitService(ApiService::class.java) | |||
| } | |||
| } | |||
| @@ -1,6 +1,8 @@ | |||
| package com.suliang.common.util.net | |||
| import android.webkit.WebSettings | |||
| import android.widget.Toast | |||
| import com.suliang.common.base.LibApplication | |||
| import com.suliang.common.util.AppGlobals | |||
| import com.suliang.common.util.thread.AppExecutors | |||
| import com.suliang.common.util.thread.MainThreadExecutor | |||
| @@ -26,19 +28,20 @@ class HttpUtil private constructor() { | |||
| .connectTimeout(time_out, TimeUnit.SECONDS) | |||
| .readTimeout(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() | |||
| } | |||
| // 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 { | |||
| @@ -51,10 +54,10 @@ class HttpUtil private constructor() { | |||
| * @param service | |||
| * @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) | |||
| // } | |||
| // | |||
| /** | |||
| @@ -183,53 +186,64 @@ class HttpUtil private constructor() { | |||
| 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) | |||
| }finally { | |||
| return | |||
| } | |||
| //下载成功 | |||
| var inputStream : InputStream? = null | |||
| var outputStream : OutputStream? = null | |||
| var result = false //是否成功标志 | |||
| response.body?.let { | |||
| 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() | |||
| inputStream?.close() | |||
| }catch (e: Exception){ | |||
| // downLoadFileListener.downFileResult(savePathFile) | |||
| result = true | |||
| } catch (e : Exception) { | |||
| 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) | |||
| } | |||
| } | |||