| @@ -63,6 +63,7 @@ | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_total_test.xml" value="0.33" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_first.xml" value="0.4979166666666667" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.20104166666666667" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | |||
| @@ -1,5 +1,6 @@ | |||
| package com.xkl.cdl | |||
| import android.annotation.SuppressLint | |||
| import android.util.TypedValue | |||
| import android.view.View | |||
| import android.widget.LinearLayout | |||
| @@ -20,6 +21,7 @@ import com.xkl.cdl.databinding.IncWordDetailBinding | |||
| * @param example String? 例句 | |||
| * @param refrence String? 参考 | |||
| */ | |||
| @SuppressLint("SetTextI18n") | |||
| fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence : String?){ | |||
| phrase?.let { | |||
| tvPhraseFlag.visibility = View.VISIBLE | |||
| @@ -45,7 +47,7 @@ fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence | |||
| example?.let { | |||
| tvExampleFlag.visibility = View.VISIBLE | |||
| tvExample.visibility = View.VISIBLE | |||
| tvExample.text = example | |||
| tvExample.text = "▪ ${it.replace("\n", "\n▪ ")}" | |||
| }?:let { | |||
| tvExampleFlag.visibility = View.GONE | |||
| tvExample.visibility = View.GONE | |||
| @@ -78,6 +78,15 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C | |||
| } | |||
| } | |||
| } | |||
| private val normalColorNotLearnOver by lazy { | |||
| ContextCompat.getColor(context, R.color.gray_2) //学习未完成未选中时的颜色 | |||
| } | |||
| private val normalColorLearnOver by lazy { ContextCompat.getColor(context, R.color.gray_1) } //学习已完成未选中时的颜色 | |||
| private val mainTextColor by lazy {ContextCompat.getColor(context, R.color.main_text_color) } //选中颜色 | |||
| private val translationColor by lazy {ContextCompat.getColor(context, R.color.translation) } //透明颜色 | |||
| private val themeColor by lazy { ContextCompat.getColor(context,R.color.theme_color) } //主题颜色 | |||
| /** | |||
| * 处理颜色 选中色 未选中色(学习完成/学习未完成) | |||
| @@ -86,10 +95,6 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C | |||
| * @param lesson Lesson | |||
| */ | |||
| private fun ItemCourseLessonBinding.initColor(position: Int, lesson: Lesson) { | |||
| val normalColorNotLearnOver = ContextCompat.getColor(context, R.color.gray_2) //学习未完成未选中时的颜色 | |||
| val normalColorLearnOver = ContextCompat.getColor(context, R.color.gray_1) //学习已完成未选中时的颜色 | |||
| val mainTextColor = ContextCompat.getColor(context, R.color.main_text_color) //选中颜色 | |||
| val translationColor = ContextCompat.getColor(context, R.color.translation) //透明颜色 | |||
| //item的背景和状态设置 | |||
| if (selectPos == position) { //选中,背景设置 | |||
| layoutContent.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_3)) //选中背景 | |||
| @@ -106,7 +111,7 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C | |||
| } | |||
| } else { //未选中:根据学习情况判断 | |||
| layoutContent.setBackgroundColor(translationColor) //未选中背景透明 | |||
| if (lesson.learnIsOver) { | |||
| if (lesson.learnIsOver) { //学习完成 | |||
| tvLessonName.run { | |||
| setTextColor(normalColorLearnOver) //课时名称颜色 | |||
| paint.isFakeBoldText = false //加粗 | |||
| @@ -114,10 +119,10 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C | |||
| tvLessonNumber.setTextColor(normalColorLearnOver) //数量颜色 | |||
| ivArrowRight.run { | |||
| setBackgroundColor(translationColor) | |||
| imageTintList = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.theme_color)) | |||
| strokeColor = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.theme_color)) | |||
| imageTintList = ColorStateList.valueOf(normalColorLearnOver) | |||
| strokeColor = ColorStateList.valueOf(normalColorLearnOver) | |||
| } | |||
| } else { | |||
| } else { //未完成 | |||
| tvLessonName.run { | |||
| setTextColor(normalColorNotLearnOver) //课时名称颜色 | |||
| paint.isFakeBoldText = false //加粗 | |||
| @@ -125,8 +130,8 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C | |||
| tvLessonNumber.setTextColor(normalColorNotLearnOver) //数量颜色 | |||
| ivArrowRight.run { | |||
| setBackgroundColor(translationColor) | |||
| imageTintList = ColorStateList.valueOf(normalColorNotLearnOver) | |||
| strokeColor = ColorStateList.valueOf(normalColorNotLearnOver) | |||
| imageTintList = ColorStateList.valueOf(themeColor) | |||
| strokeColor = ColorStateList.valueOf(themeColor) | |||
| } | |||
| } | |||
| } | |||
| @@ -154,10 +154,19 @@ object AppConstants { | |||
| const val DIALOG_TYPE_EXAM_OVER = 2 | |||
| /** 对话框类型: 学习结束弹窗类型 */ | |||
| const val DIALOG_TYPE_LEARN_OVER = 3 | |||
| /**对话框类型,item学习完成*/ | |||
| const val DIALOG_TYPE_LESSON_ITEM_OVER = 4 | |||
| /**--- 总线动作 --------------------------------- */ | |||
| /**action key 改变界面 到目录页 */ | |||
| const val EVENT_COURSE = "action_change_page" | |||
| const val EVENT_CHANGE_PAGE = "action_change_page" | |||
| /** lesson学习 数据传递 */ | |||
| const val EVENT_LESSON_DATA = "lesson_learn_data" | |||
| /** lesson学习中动作事件 : 课时学习中的动作*/ | |||
| const val EVENT_LESSON_ACTION = "lesson_learn_action" | |||
| /**总测数据与动作*/ | |||
| const val EVENT_TOTAL_TEST = "total_test" | |||
| /** 事件动作:学前总测结束弹窗之 开始学习 */ | |||
| const val ACTION_COURSE_TEST_START_LEARN = 1 | |||
| @@ -177,6 +186,12 @@ object AppConstants { | |||
| const val ACTION_LESSON_AFTER_TEST_NEXT = 8 | |||
| /**数据动作: 课时学习完成*/ | |||
| const val DATA_LESSON_LEARN_OVER = 9 | |||
| /**学后总测试完成: 再测一次*/ | |||
| const val ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN = 10 | |||
| /** 学后总测试完成,切换到目录页显示 */ | |||
| const val ACTION_COURSE_TEST_AFTER_TOTAL_OVER = 11 | |||
| /**学后总测结束,传递数据*/ | |||
| const val DATA_COURSE_AFTER_TEST_OVER = 12 | |||
| /**--- 弹窗动作 --------------------------------- */ | |||
| /** 学前总测结束弹窗: 开始学习 ,课时学前测试开始弹窗*/ | |||
| @@ -189,6 +204,8 @@ object AppConstants { | |||
| const val DIALOG_LESSON_AFTER_TEST_AGAIN = 4 | |||
| /**课时学后测试弹窗动作: 下一步*/ | |||
| const val DIALOG_LESSON_AFTER_TEST_NEXT = 5 | |||
| /**弹窗动作提示: 完成*/ | |||
| const val DIALOG_OVER = 6 | |||
| /**课时学后总测的再测一次*/ | |||
| const val DIALOG_AFTER_TOTAL_TEST_AGAIN = 7 | |||
| } | |||
| @@ -29,7 +29,7 @@ import android.os.Parcelable | |||
| * 词汇量测试 | |||
| * | |||
| */ | |||
| class LearnDialogBean(val dialogType:Int) : Parcelable { | |||
| class LearnDialogBean(val dialogType:Int) :Parcelable { | |||
| /*---------------测试使用------------------------------------*/ | |||
| /** 测试类型 */ | |||
| @@ -46,19 +46,13 @@ class LearnDialogBean(val dialogType:Int) : Parcelable { | |||
| /** 题数与时间 */ | |||
| var showTimeCount = "" | |||
| constructor(parcel : Parcel) : this(parcel.readInt()) { | |||
| examType = parcel.readInt() | |||
| score = parcel.readInt() | |||
| correctNumber = parcel.readInt() | |||
| errorNumber = parcel.readInt() | |||
| chapter_lesson_name = parcel.readString().toString() | |||
| showTimeCount = parcel.readString().toString() | |||
| } | |||
| override fun writeToParcel(parcel : Parcel, flags : Int) { | |||
| @@ -67,6 +61,8 @@ class LearnDialogBean(val dialogType:Int) : Parcelable { | |||
| parcel.writeInt(score) | |||
| parcel.writeInt(correctNumber) | |||
| parcel.writeInt(errorNumber) | |||
| parcel.writeString(chapter_lesson_name) | |||
| parcel.writeString(showTimeCount) | |||
| } | |||
| override fun describeContents() : Int { | |||
| @@ -82,6 +78,4 @@ class LearnDialogBean(val dialogType:Int) : Parcelable { | |||
| return arrayOfNulls(size) | |||
| } | |||
| } | |||
| } | |||
| @@ -1,5 +1,7 @@ | |||
| package com.xkl.cdl.data.bean.course | |||
| import androidx.databinding.BaseObservable | |||
| /** | |||
| * author suliang | |||
| * create 2022/3/22 10:08 | |||
| @@ -1,15 +1,18 @@ | |||
| package com.xkl.cdl.data.bean.course | |||
| import com.xkl.cdl.data.AppConstants | |||
| import java.io.Serializable | |||
| /** | |||
| * author suliang | |||
| * create 2022/3/29 9:52 | |||
| * Describe: 课程学习的详情 | |||
| */ | |||
| class CourseDetail { | |||
| class CourseDetail:Serializable{ | |||
| var courseLearnProgress: Double = 0.0 //课程学习进度 | |||
| var st_before: Double = -1.0 //学前总成绩 : -1代表没有进行学前总测试 | |||
| var st_after: Double = -1.0 //学后总成绩 : -1代表没有进行学后总测试 | |||
| var st_before: Double = AppConstants.NOT_DOING //学前总成绩 : -1代表没有进行学前总测试 | |||
| var st_after: Double = AppConstants.NOT_DOING //学后总成绩 : -1代表没有进行学后总测试 | |||
| var before: HashMap<String, Double> = hashMapOf() //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | |||
| var after: HashMap<String, Double> = hashMapOf() //章节学后测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | |||
| var right = hashMapOf<String, Int>() //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||
| @@ -30,9 +30,9 @@ data class Lesson( | |||
| /** 学习进度位置,为已学下标的位置,在作文课堂练习时,学习取当前条,其他取下一条*/ | |||
| var learnedIndex: Int = -1 | |||
| /**课时学前测试成绩 */ | |||
| var beforeTestScore = -1.0 | |||
| var beforeTestScore = AppConstants.NOT_DOING | |||
| /** 课时学后测试 */ | |||
| var afterTestScore = -1.0 | |||
| var afterTestScore = AppConstants.NOT_DOING | |||
| /**是否学习完成: 为学习内容是否完成,不包含学前,学后测试*/ | |||
| var learnIsOver = false | |||
| /**是否是最后一个课时 */ | |||
| @@ -225,7 +225,7 @@ object CourseManager { | |||
| } | |||
| /** | |||
| * 计算项目总进度 | |||
| * 计算项目总进度 ,并将课程进度值设置进入集合中 | |||
| * @param subjectId Int 项目Id | |||
| * @param packId Long 修改进度的课程包id | |||
| * @param courseId Long 修改进度的课程id | |||
| @@ -289,4 +289,35 @@ object CourseManager { | |||
| if (totalCourseSize == 0) return 0.0 | |||
| return totalProgress / totalCourseSize | |||
| } | |||
| /** | |||
| * 重学课程的课时时,计算项目的进度,不会进行赋值 | |||
| * @param subjectId Int 项目 | |||
| * @param courseId Long 重学的课程 | |||
| * @param courseProgress Double 被重学课时的课程进度 | |||
| * @return Double 项目的总进度 | |||
| */ | |||
| fun calculateSubjectProgressWithCourseLessonRelearn(subjectId : Int,coursePackId:Long, courseId : Long,courseProgress:Double) : Double { | |||
| val totalProgress = mSortInfoList.get(subjectId)?.let { | |||
| var tempProgress = 0.0 | |||
| it.forEach { | |||
| if (it.packId == coursePackId && it.courseId == courseId){ | |||
| tempProgress += courseProgress | |||
| return@forEach | |||
| }else { | |||
| tempProgress += it.s | |||
| } | |||
| } | |||
| tempProgress | |||
| }?: 0.0 | |||
| if (totalProgress == 0.0 ) return totalProgress | |||
| var totalCourseSize = 0 | |||
| subjectWithCoursePackMap.get(subjectId)?.forEach { | |||
| totalCourseSize += it.childrenCourses.size | |||
| } | |||
| if (totalCourseSize == 0) return 0.0 | |||
| return totalProgress / totalCourseSize | |||
| } | |||
| } | |||
| @@ -124,8 +124,8 @@ object DBCourseManager { | |||
| totalNumber = this.wordIds.size //总数 | |||
| correctNumber = detail.right.getOrElse(key, { 0 }) //正确数 | |||
| errorNumber = detail.wrong.getOrElse(key, { 0 }) //错误数 | |||
| beforeTestScore = detail.before.getOrElse(key, { -1.0 }) //课时学前测试成绩 | |||
| afterTestScore = detail.after.getOrElse(key, { -1.0 }) //课时学后测试成绩 | |||
| beforeTestScore = detail.before.getOrElse(key, { AppConstants.NOT_DOING }) //课时学前测试成绩 | |||
| afterTestScore = detail.after.getOrElse(key, { AppConstants.NOT_DOING }) //课时学后测试成绩 | |||
| this.learnedIndex = learnIndex //学习位置,当前位置为已学 | |||
| this.learnIsOver = learnIsOver | |||
| this.lessonType = lessonType | |||
| @@ -3,7 +3,6 @@ package com.xkl.cdl.data.repository | |||
| import android.util.LruCache | |||
| import androidx.lifecycle.MutableLiveData | |||
| import com.suliang.common.AppConfig | |||
| import com.suliang.common.eventbus.NonStickyMutableLiveData | |||
| import com.suliang.common.extension.diskIo2Main | |||
| import com.suliang.common.util.file.FileUtil | |||
| import com.xkl.cdl.data.AppConstants | |||
| @@ -30,12 +29,12 @@ object AudioCache { | |||
| } | |||
| /** 通知查到的录音 */ | |||
| var audioLiveData = NonStickyMutableLiveData<String?>() | |||
| private lateinit var audioLiveData : MutableLiveData<String?> | |||
| // fun initAudioLiveData() : MutableLiveData<String?>{ | |||
| // audioLiveData = NonStickyMutableLiveData<String?>() | |||
| // return audioLiveData | |||
| // } | |||
| fun initAudioLiveData() : MutableLiveData<String?> { | |||
| audioLiveData = MutableLiveData<String?>() | |||
| return audioLiveData | |||
| } | |||
| /** | |||
| * 获取对应音频 | |||
| @@ -78,6 +77,7 @@ object AudioCache { | |||
| return@fromCallable lruCache.get(defaultKey) ?: "" | |||
| }.compose(diskIo2Main()).subscribe { | |||
| if (this::audioLiveData.isInitialized) | |||
| audioLiveData.value = it | |||
| } | |||
| } | |||
| @@ -1,12 +1,14 @@ | |||
| package com.xkl.cdl.data.repository | |||
| import androidx.lifecycle.MutableLiveData | |||
| import com.suliang.common.util.file.FileUtil | |||
| import com.xkl.cdl.data.bean.course.CourseDetail | |||
| import com.xkl.cdl.data.bean.course.Lesson | |||
| import com.xkl.cdl.data.manager.db.DBCourseManager | |||
| import com.xkl.cdl.data.manager.db.DbControlBase | |||
| import io.reactivex.rxjava3.core.Observable | |||
| import mqComsumerV1.Struct | |||
| import java.io.File | |||
| /** | |||
| * author suliang | |||
| @@ -33,9 +35,16 @@ object DataRepository { | |||
| } | |||
| /** 获取课程的详情 */ | |||
| fun getCourseStatistics(): Observable<CourseDetail>{ | |||
| fun getCourseStatistics(subjectId:Int,coursePackId:Long,courseId:Long): Observable<CourseDetail>{ | |||
| return Observable.create{ | |||
| val courseDetail = CourseDetail() | |||
| // TODO: 2022/5/6 这里自己使用的缓存 | |||
| val file = File(FileUtil.getSaveDirPath("appcache"), "${subjectId}_${coursePackId}_${courseId}") | |||
| val courseDetail = if (file.exists()){ | |||
| FileUtil.bytesToObject(FileUtil.readFile(file)) as CourseDetail | |||
| }else{ | |||
| CourseDetail() | |||
| } | |||
| it.onNext(courseDetail) | |||
| it.onComplete() | |||
| } | |||
| @@ -2,15 +2,10 @@ package com.xkl.cdl.data.repository | |||
| import android.util.LruCache | |||
| import androidx.lifecycle.MutableLiveData | |||
| import com.suliang.common.AppConfig | |||
| import com.suliang.common.eventbus.NonStickyMutableLiveData | |||
| import com.suliang.common.extension.diskIo2Main | |||
| import com.suliang.common.util.file.FileUtil | |||
| import com.xkl.cdl.data.AppConstants | |||
| import com.xkl.cdl.data.manager.db.DBCourseManager | |||
| import com.xkl.cdl.data.manager.db.DbControlBase | |||
| import io.reactivex.rxjava3.core.Observable | |||
| import java.io.File | |||
| import java.util.* | |||
| /** | |||
| @@ -29,9 +24,13 @@ object PhotoCache { | |||
| } | |||
| } | |||
| /** 通知查到的录音 */ | |||
| var photoLiveData = NonStickyMutableLiveData<ByteArray?>() | |||
| /** 通知查到的图片字节码 */ | |||
| private lateinit var photoLiveData : MutableLiveData<ByteArray?> | |||
| fun initPhotoLiveData() : MutableLiveData<ByteArray?> { | |||
| photoLiveData = MutableLiveData<ByteArray?>() | |||
| return photoLiveData | |||
| } | |||
| /** | |||
| * 获取对应图片 | |||
| * 1缓存 2文件 3数据库 | |||
| @@ -50,6 +49,7 @@ object PhotoCache { | |||
| return@fromCallable lruCache.get(defaultKey) | |||
| }.compose(diskIo2Main()).subscribe { | |||
| if (this::photoLiveData.isInitialized) | |||
| photoLiveData.value = it | |||
| } | |||
| } | |||
| @@ -1,17 +0,0 @@ | |||
| package com.xkl.cdl.dialog | |||
| /** | |||
| * author suliang | |||
| * create 2022/4/6 9:54 | |||
| * Describe: LearnDialog 按钮点击动作 | |||
| */ | |||
| enum class DialogEventAction { | |||
| /**下一步*/ | |||
| NEXT, | |||
| /** 开始学习 */ | |||
| START_LEARN, | |||
| /** 课时学前测试 */ | |||
| START_LESSON_BEFORE_TEST | |||
| // TODO: 2022/4/6 可以添加相应的动作action,来处理对应的动作 | |||
| } | |||
| @@ -52,6 +52,8 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| AppConstants.DIALOG_TYPE_EXAM_START -> when(learnDialogBean.examType){ | |||
| //课时学前测试开始弹窗 | |||
| AppConstants.TEST_TYPE_BEFORE -> initLessonBeforeTestStart() | |||
| //课时最后一个课时测试结束的下一步弹出此弹窗:学后总测试开始的弹窗 | |||
| AppConstants.TEST_TYPE_AFTER_TOTAL -> initCourseAfterTestStart() | |||
| } | |||
| //测试结束弹窗 | |||
| AppConstants.DIALOG_TYPE_EXAM_OVER -> when (learnDialogBean.examType) { | |||
| @@ -59,9 +61,15 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| AppConstants.TEST_TYPE_BEFORE_TOTAL -> initCourseBeforeTotalTestOver() | |||
| //课时学前测试结束弹窗 | |||
| AppConstants.TEST_TYPE_BEFORE-> initLessonBeforeTestOver() | |||
| //课时后测试结束 | |||
| AppConstants.TEST_TYPE_AFTER -> initLessonAfterTestOver() | |||
| //学后总测试结束弹窗 | |||
| AppConstants.TEST_TYPE_AFTER_TOTAL -> initCourseAfterTestOver() | |||
| } | |||
| //学习结束弹窗 | |||
| AppConstants.DIALOG_TYPE_LEARN_OVER -> initLessonLearningOver() | |||
| /**课时列表点击课时完全完成*/ | |||
| AppConstants.DIALOG_TYPE_LESSON_ITEM_OVER -> initLessonItemClickLessonOver() | |||
| } | |||
| } | |||
| @@ -131,6 +139,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| */ | |||
| private fun initLessonBeforeTestStart() { | |||
| binding.run { | |||
| ivClose.visibility = View.VISIBLE | |||
| tvTitle.visibility = View.VISIBLE | |||
| tvLessonName.visibility = View.VISIBLE | |||
| tvCountTime.visibility = View.VISIBLE | |||
| @@ -138,19 +147,12 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| tvLessonName.text = learnDialogBean.chapter_lesson_name | |||
| tvCountTime.text = learnDialogBean.showTimeCount | |||
| tvRight.text = "开始测试" | |||
| imgIv.setImageResource(R.mipmap.girl_1) | |||
| imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_1 else R.mipmap.girl_1) | |||
| //开始测试,进入课时学前测试界面 | |||
| binding.tvRight.click { | |||
| onDialogListener(AppConstants.DIALOG_START_TEST, this@LearnDialog) | |||
| } | |||
| // tvLeft.visibility = View.VISIBLE | |||
| // vSplit.visibility = View.VISIBLE | |||
| // tvLeft.text = "跳过测试" | |||
| //跳过测试,直接进入学习界面 | |||
| // binding.tvLeft.click { | |||
| // onDialogListener(AppConstants.DIALOG_START_LEARN, this@LearnDialog) | |||
| // } | |||
| binding.ivClose.click { dismissAllowingStateLoss() } | |||
| } | |||
| } | |||
| @@ -159,6 +161,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| */ | |||
| private fun initLessonBeforeTestOver() { | |||
| binding.run { | |||
| imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | |||
| tvScore.visibility = View.VISIBLE | |||
| tvTip.visibility = View.VISIBLE | |||
| tvTitle.visibility = View.VISIBLE | |||
| @@ -185,7 +188,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| binding.run { | |||
| imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | |||
| tvTitle.visibility = View.VISIBLE | |||
| tvTitle.text = "恭喜你,本课时学习完成" | |||
| tvTitle.text = "恭喜你,本课时学习完成!" | |||
| incStatisticsNumber.root.visibility = View.VISIBLE | |||
| tvLearnOverTip.visibility = View.VISIBLE | |||
| tvLearnOverForAfterCountTime.visibility = View.VISIBLE | |||
| @@ -217,7 +220,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| tvLeft.visibility = View.VISIBLE | |||
| vSplit.visibility = View.VISIBLE | |||
| tvTitle.text = "恭喜你,完成了课时学后测试" | |||
| tvTop1.text = "重新学习" | |||
| tvTop.text = "重新学习" | |||
| tvLeft.text = "再测一次" | |||
| tvRight.text = "下一课时" | |||
| @@ -236,5 +239,98 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi | |||
| onDialogListener(AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT,this) | |||
| } | |||
| } | |||
| /** | |||
| * 课程学后总测试开始前提示弹窗 | |||
| */ | |||
| private fun initCourseAfterTestStart() { | |||
| binding.run { | |||
| imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | |||
| tvLessonName.visibility = View.INVISIBLE //占布局,避免布局变形 | |||
| tvTitle.visibility = View.VISIBLE | |||
| tvTitle.text = "恭喜你,本课程全部学习完成!" | |||
| tvTip1.visibility = View.VISIBLE | |||
| tvTip1.text = "我的学习效果是?快去学后总测试吧!" | |||
| tvCountTime.visibility = View.VISIBLE | |||
| tvCountTime.text = learnDialogBean.showTimeCount | |||
| tvRight.text = "开始测试" | |||
| //开始测试,进入课时学前测试界面 | |||
| binding.tvRight.click { | |||
| onDialogListener(AppConstants.DIALOG_START_TEST, this@LearnDialog) | |||
| } | |||
| tvLeft.visibility = View.VISIBLE | |||
| vSplit.visibility = View.VISIBLE | |||
| tvLeft.text = "完成" | |||
| binding.tvLeft.click { | |||
| onDialogListener(AppConstants.DIALOG_OVER, this@LearnDialog) | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 课程学后总测试结束弹窗 | |||
| */ | |||
| private fun initCourseAfterTestOver(){ | |||
| initNumber() | |||
| initScore() | |||
| binding.run { | |||
| tvScore.visibility = View.VISIBLE | |||
| tvTip.visibility = View.VISIBLE | |||
| tvTitle.visibility = View.VISIBLE | |||
| tvTip1.visibility = View.VISIBLE | |||
| incStatisticsNumber.root.visibility = View.VISIBLE | |||
| tvTop.visibility = View.VISIBLE | |||
| tvLeft.visibility = View.VISIBLE | |||
| vSplit.visibility = View.VISIBLE | |||
| tvTitle.text = "恭喜你,完成了学后总测试" | |||
| tvTop.text = "继续学习" | |||
| tvLeft.text = "再测一次" | |||
| tvRight.text = "完成" | |||
| } | |||
| binding.tvTop.click { | |||
| onDialogListener(AppConstants.DIALOG_OVER, this) | |||
| } | |||
| binding.tvLeft.click { | |||
| onDialogListener(AppConstants.DIALOG_AFTER_TOTAL_TEST_AGAIN,this) | |||
| } | |||
| binding.tvRight.click { | |||
| onDialogListener(AppConstants.DIALOG_OVER, this) | |||
| } | |||
| } | |||
| /** | |||
| * 课时列表item点击时课程已完全学习完成(学前测、学后测、学习都已完成)的提示弹窗 | |||
| * tv_title,inc_statistics_number,tv_learn_over_tip,tv_learn_over_for_after_count_time,tv_left,vSplit | |||
| */ | |||
| private fun initLessonItemClickLessonOver(){ | |||
| initNumber() | |||
| binding.run { | |||
| imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | |||
| ivClose.visibility = View.VISIBLE | |||
| tvTitle.visibility = View.VISIBLE | |||
| tvTitle.text = "恭喜你,本课时学习完成!" | |||
| incStatisticsNumber.root.visibility = View.VISIBLE | |||
| tvLearnOverTip.visibility = View.VISIBLE | |||
| tvLearnOverTip.text = "你可重新学习本课时,或重新进行课时学后测试" | |||
| tvLearnOverForAfterCountTime.visibility = View.VISIBLE | |||
| tvLearnOverForAfterCountTime.text = "(上次课时学后测试成绩:${learnDialogBean.score})" | |||
| tvLeft.visibility = View.VISIBLE | |||
| tvLeft.text = "重新学习" | |||
| vSplit.visibility = View.VISIBLE | |||
| tvRight.text = "课时学后测试" | |||
| } | |||
| binding.ivClose.click { dismissAllowingStateLoss() } | |||
| binding.tvLeft.click { onDialogListener(AppConstants.DIALOG_LESSON_RELEARN, this) } | |||
| binding.tvRight.click { onDialogListener(AppConstants.DIALOG_START_TEST, this) } | |||
| } | |||
| } | |||
| @@ -12,8 +12,8 @@ import androidx.lifecycle.ViewModelProvider | |||
| import androidx.recyclerview.widget.GridLayoutManager | |||
| import androidx.recyclerview.widget.SimpleItemAnimator | |||
| import com.airbnb.lottie.LottieAnimationView | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.base.activity.BaseActivityVM | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.suliang.common.extension.click | |||
| import com.suliang.common.util.DateUtil | |||
| import com.suliang.common.util.DrawableUti | |||
| @@ -96,7 +96,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
| } | |||
| /** 查询到播放数据过来 */ | |||
| AudioCache.audioLiveData.observe(this) { | |||
| AudioCache.initAudioLiveData().observe(this) { | |||
| if (it == null) { | |||
| //发音文件为空 | |||
| showToast("未找到发音文件") | |||
| @@ -600,15 +600,14 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
| LearnDialog.newInstance(learnDialogBean).apply { | |||
| onDialogListener = { action, dialog -> | |||
| when (vm.intentData.examType) { | |||
| //学前测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页 | |||
| //学前总测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页 | |||
| AppConstants.TEST_TYPE_BEFORE_TOTAL -> when (action) { | |||
| AppConstants.DIALOG_START_LEARN -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 继续学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_COURSE_TEST_START_LEARN) | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post(LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_COURSE_TEST_START_LEARN)) | |||
| finish() | |||
| } | |||
| } | |||
| @@ -616,13 +615,13 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
| AppConstants.TEST_TYPE_BEFORE -> when (action) { | |||
| AppConstants.DIALOG_START_LEARN -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 继续学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| //发送动作 : 开始学习 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN).apply { | |||
| leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| } | |||
| @@ -640,35 +639,61 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
| if (isRightClick){ | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 重新学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | |||
| leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| } | |||
| }.show(childFragmentManager,"lesson_relearn_tip") | |||
| } | |||
| //再测一次 | |||
| AppConstants.DIALOG_LESSON_AFTER_TEST_AGAIN -> { | |||
| //发送动作 : 继续学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| //发送动作 : 再测一次 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | |||
| leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| //下一步 | |||
| AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT -> { | |||
| //发送动作 : 继续学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| //发送动作 : 下一步 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_NEXT).apply { | |||
| leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| } | |||
| //学后总测试结束 | |||
| AppConstants.TEST_TYPE_AFTER_TOTAL -> when(action){ | |||
| //测试完成,切换到目录页 | |||
| AppConstants.DIALOG_OVER -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 继续学习 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_OVER)) | |||
| finish() | |||
| } | |||
| //再测一次 | |||
| AppConstants.DIALOG_AFTER_TOTAL_TEST_AGAIN -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 再测一次 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post( | |||
| LearnEventData(vm.intentData.subjectId, | |||
| vm.intentData.courseId, | |||
| AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN)) | |||
| finish() | |||
| } | |||
| } | |||
| } | |||
| @@ -4,8 +4,7 @@ import android.graphics.drawable.Drawable | |||
| import androidx.lifecycle.LifecycleOwner | |||
| import androidx.lifecycle.MutableLiveData | |||
| import androidx.lifecycle.viewModelScope | |||
| import com.googlecode.protobuf.format.JsonFormat | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.extension.createRandomNewChar | |||
| import com.suliang.common.extension.diskIo2Main | |||
| import com.suliang.common.util.DateUtil | |||
| @@ -135,6 +134,10 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| //倒计时结束 | |||
| val currentCountingTimeOver = MutableLiveData<Boolean>() | |||
| init { | |||
| isRunValidTime = false | |||
| } | |||
| /** 修改获取下一题的标记为true,则在onResume时,自动获取第一题 */ | |||
| fun loadFirst(){ | |||
| isGetNextIng = true | |||
| @@ -231,9 +234,9 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| //计算分数 | |||
| calculateScore() | |||
| when(intentData.examType){ | |||
| AppConstants.TEST_TYPE_BEFORE -> { //学前总测为lesson添加错误数 与 分数 | |||
| AppConstants.TEST_TYPE_BEFORE -> { //课时学前测试为lesson添加错误数 与 分数 | |||
| intentData.lesson?.let { | |||
| it.errorNumber = it.errorNumber + newErrorMap.size | |||
| it.errorNumber += newErrorMap.size | |||
| it.beforeTestScore = scoreValue.toDouble() | |||
| } | |||
| } | |||
| @@ -461,10 +464,6 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| } else { //相当于新错 | |||
| if (!newErrorMap.containsKey(key)) { | |||
| newErrorMap[key] = true | |||
| //课时前错误 ,则更新课时错误数量 | |||
| if (intentData.examType == AppConstants.TEST_TYPE_BEFORE) { | |||
| intentData.lesson!!.errorNumber = intentData.lesson!!.errorNumber + 1 | |||
| } | |||
| } | |||
| } | |||
| mLearnEntities.add(builder.build()) | |||
| @@ -495,13 +494,12 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| //其他测试 | |||
| else -> { | |||
| val calculateCorrectNumber : Double = correctLiveData.value!! + unAnswerNumber * 0.25 | |||
| val scoreValue = ((calculateCorrectNumber - testData.size * 0.25) / (testData.size * 0.25) * 100).toInt() | |||
| val scoreValue = ((calculateCorrectNumber - testData.size * 0.25) / (testData.size * 0.75) * 100).toInt() | |||
| this.scoreValue = when { | |||
| scoreValue < 0 -> 0 | |||
| scoreValue > 100 -> 100 | |||
| else -> scoreValue | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -651,16 +649,16 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| private fun sendEventBus(){ | |||
| when(intentData.examType){ | |||
| AppConstants.TEST_TYPE_BEFORE_TOTAL -> { //学前总测发送数据、学前总测发送数据 | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData( | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).post( LearnEventData( | |||
| intentData.subjectId, | |||
| intentData.courseId, | |||
| AppConstants.DATA_COURSE_BEFORE_TEST_OVER).apply { | |||
| this.scoreValue = this@LearnExamViewModel.scoreValue | |||
| this.newErrorMap = this@LearnExamViewModel.newErrorMap | |||
| } | |||
| }) | |||
| } | |||
| AppConstants.TEST_TYPE_BEFORE-> { // 课时学前测试结束发送数据 | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData( | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post( LearnEventData( | |||
| intentData.subjectId, | |||
| intentData.courseId, | |||
| AppConstants.DATA_LESSON_BEFORE_TEST_OVER).apply { | |||
| @@ -668,18 +666,25 @@ class LearnExamViewModel : LearnBaseViewModel() { | |||
| intentData.lesson?.let { | |||
| leesonPositionIndex = it.lessonPositionInList | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| AppConstants.TEST_TYPE_AFTER -> { //课时学后测试结束发送数据 | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData( | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post(LearnEventData( | |||
| intentData.subjectId, | |||
| intentData.courseId, | |||
| AppConstants.DATA_LESSON_AFTER_TEST_OVER).apply { | |||
| this.newErrorMap = this@LearnExamViewModel.newErrorMap | |||
| intentData.lesson?.let { | |||
| leesonPositionIndex = it.lessonPositionInList | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| AppConstants.TEST_TYPE_AFTER_TOTAL -> { //学后总测发送数据 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).post(LearnEventData( | |||
| intentData.subjectId, | |||
| intentData.courseId, | |||
| AppConstants.DATA_COURSE_AFTER_TEST_OVER).apply { | |||
| this.scoreValue = this@LearnExamViewModel.scoreValue | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| @@ -13,8 +13,8 @@ import androidx.recyclerview.widget.LinearLayoutManager | |||
| import androidx.recyclerview.widget.RecyclerView | |||
| import androidx.recyclerview.widget.RecyclerView.OnScrollListener | |||
| import androidx.recyclerview.widget.SimpleItemAnimator | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.base.activity.BaseActivityVM | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.suliang.common.extension.click | |||
| import com.suliang.common.util.DateUtil | |||
| import com.suliang.common.util.LogUtil | |||
| @@ -244,7 +244,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView | |||
| vm.loadNext() | |||
| //发音数据 | |||
| AudioCache.audioLiveData.observe(this) { | |||
| AudioCache.initAudioLiveData().observe(this) { | |||
| it?.run { | |||
| if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE) MPManager.play( | |||
| it, listener = impListener) | |||
| @@ -254,7 +254,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView | |||
| //如果需要显示图片,则添加监听 | |||
| if (vm.isNeedLoadPhoto) { | |||
| //图片数据 | |||
| PhotoCache.photoLiveData.observe(this) { | |||
| PhotoCache.initPhotoLiveData().observe(this) { | |||
| it?.run { ImageLoader.loadImage(bindingWord.imgWord, it) } ?: let { bindingWord.imgWord.visibility = View.GONE } | |||
| } | |||
| } | |||
| @@ -619,8 +619,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView | |||
| private fun showLearnOverDialog() { | |||
| vm.loadAfterTest().observe(this) { showTimeCount -> | |||
| LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LEARN_OVER).apply { | |||
| correctNumber = vm.learnData.lesson.correctNumber + vm.learnRuleUtil.currentCorrectMap.size | |||
| errorNumber = vm.learnData.lesson.errorNumber + vm.learnRuleUtil.currentErrorMap.size | |||
| correctNumber = vm.learnData.lesson.correctNumber | |||
| errorNumber = vm.learnData.lesson.errorNumber | |||
| this.showTimeCount = showTimeCount | |||
| }).apply { | |||
| onDialogListener = { action, dialog -> | |||
| @@ -636,12 +636,13 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView | |||
| if (isRightClick){ | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 重新学习 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| LearnEventData(vm.learnData.lesson.subjectId, | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.learnData.lesson.subjectId, | |||
| vm.learnData.lesson.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | |||
| leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| } | |||
| }.show(childFragmentManager,"lesson_relearn_tip") | |||
| @@ -649,12 +650,13 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView | |||
| AppConstants.DIALOG_START_TEST -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 学后测试 | |||
| LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(vm.learnData.lesson.subjectId, | |||
| vm.learnData.lesson.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | |||
| leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | |||
| } | |||
| }) | |||
| finish() | |||
| } | |||
| } | |||
| } | |||
| @@ -3,12 +3,10 @@ package com.xkl.cdl.module.learn | |||
| import androidx.lifecycle.LifecycleOwner | |||
| import androidx.lifecycle.MutableLiveData | |||
| import androidx.lifecycle.viewModelScope | |||
| import com.googlecode.protobuf.format.JsonFormat | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.extension.createRandomNewChar | |||
| import com.suliang.common.extension.diskIo2Main | |||
| import com.suliang.common.util.DateUtil | |||
| import com.suliang.common.util.LogUtil | |||
| import com.xkl.cdl.data.AppConstants | |||
| import com.xkl.cdl.data.DataTransferHolder | |||
| import com.xkl.cdl.data.bean.LearnWord | |||
| @@ -75,6 +73,7 @@ class LearnWordViewModel : LearnBaseViewModel() { | |||
| //数据上传完成监听: true 学习完成的上传 false可能是半途的返回事件,直接退出 | |||
| val saveDataLiveData = MutableLiveData<Boolean>() | |||
| /** 获取数据 */ | |||
| fun loadNext() { | |||
| //修改标记 | |||
| @@ -89,9 +88,10 @@ class LearnWordViewModel : LearnBaseViewModel() { | |||
| currentLearnWord.value = it | |||
| } ?: let { //没有数据 即学习完成 | |||
| isAllOver = true | |||
| // 停止有效计时 | |||
| isRunValidTime = false | |||
| //停止总计时 | |||
| stopTotalCountTing() | |||
| // TODO: 2022/4/26 停止有效计时 | |||
| //封装保存数据 | |||
| saveData() | |||
| } | |||
| @@ -246,7 +246,7 @@ class LearnWordViewModel : LearnBaseViewModel() { | |||
| learnedIndex = currentLessonLearnedPosition | |||
| correctNumber += learnRuleUtil.currentCorrectMap.size | |||
| errorNumber += learnRuleUtil.currentErrorMap.size | |||
| learnIsOver = (correctNumber + errorNumber == totalNumber) | |||
| learnIsOver = learnedIndex == wordIds.size - 1 | |||
| } | |||
| //添加到错误本集合中,主要用于小游戏练习(学前总 课时都没有添加,从这里添加到集合后发送出去,添加到集合) | |||
| learnData.examErrorMap?.putAll(learnRuleUtil.currentErrorMap) | |||
| @@ -282,12 +282,12 @@ class LearnWordViewModel : LearnBaseViewModel() { | |||
| /** 发送数据事件 */ | |||
| private fun sendEventBus() { | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData(learnData.lesson.subjectId, | |||
| learnData.lesson.courseId, | |||
| AppConstants.DATA_LESSON_LEARN_OVER).apply { | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post(LearnEventData(learnData.lesson.subjectId, | |||
| learnData.lesson.courseId, | |||
| AppConstants.DATA_LESSON_LEARN_OVER).apply { | |||
| this.leesonPositionIndex = learnData.lesson.lessonPositionInList | |||
| this.newErrorMap = learnData.examErrorMap | |||
| } | |||
| }) | |||
| } | |||
| @@ -22,11 +22,14 @@ import com.xkl.cdl.R | |||
| import com.xkl.cdl.adapter.AdapterAutoPlaySelectRepeat | |||
| import com.xkl.cdl.adapter.ViewPagerAdapter | |||
| import com.xkl.cdl.data.AppConstants | |||
| import com.xkl.cdl.data.bean.LearnDialogBean | |||
| import com.xkl.cdl.data.binding.BindingAdapter | |||
| import com.xkl.cdl.data.manager.CourseManager | |||
| import com.xkl.cdl.databinding.ActivityCourseMainBinding | |||
| import com.xkl.cdl.databinding.DialogBottomAutoPlaySelectBinding | |||
| import com.xkl.cdl.databinding.DialogBottomCourseMoreBinding | |||
| import com.xkl.cdl.dialog.CommonDialog | |||
| import com.xkl.cdl.dialog.CommonDialogBean | |||
| import com.xkl.cdl.module.m_center_learn.coursechildren.CourseMainFragment | |||
| import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | |||
| @@ -170,7 +173,7 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP | |||
| } | |||
| } | |||
| } | |||
| //改变page后设置进度 | |||
| //改变page后设置进度,获取该课程的进度进行设置 | |||
| vm.currentCourseProgress.value = vm.coursePack.childrenCourses[position].courseLearnProgress | |||
| } | |||
| }) | |||
| @@ -188,20 +191,23 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP | |||
| progressbar.progress = it.toInt() | |||
| tvProgress.text = if (binding.includeCourseTypeTab.root.visibility == View.VISIBLE) { | |||
| val format = when (binding.viewPager2.currentItem) { | |||
| 0 -> "认读进度:%s" | |||
| 1 -> "拼写进度:%s" | |||
| 2 -> "辨音进度:%s" | |||
| else -> "进度:%s" | |||
| 0 -> "认读进度: %s%%" | |||
| 1 -> "拼写进度: %s%%" | |||
| 2 -> "辨音进度: %s%%" | |||
| else -> "进度: %s%%" | |||
| } | |||
| String.format(format, CourseManager.useToShowProgress(it)) | |||
| } else { | |||
| String.format("进度:%s", CourseManager.useToShowProgress(it)) | |||
| String.format("进度: %s%%", CourseManager.useToShowProgress(it)) | |||
| } | |||
| } | |||
| } | |||
| //更多按钮点击 | |||
| binding.includeCourseProgress.ivMore.click { | |||
| if (vm.showMoreEnable) | |||
| showMoreDialog() | |||
| else | |||
| showToast("请先进行学习") | |||
| } | |||
| } | |||
| @@ -232,13 +238,30 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP | |||
| } | |||
| moreBinding.tvClearLearnRecord.click { | |||
| dismiss() | |||
| // TODO: 2022/3/29 弹窗显示清除学习记录 | |||
| showCourseRelearnDialog() | |||
| } | |||
| } | |||
| } | |||
| moreDialog?.show() | |||
| } | |||
| /** 课程重学弹窗提示 */ | |||
| fun showCourseRelearnDialog(){ | |||
| //弹窗显示清除学习记录 | |||
| val bean = CommonDialogBean(titleText = R.string.course_relearn_title, | |||
| contentText = R.string.course_relearn_content, | |||
| leftText = R.string.course_relearn_sure, rightText = R.string.cancel) | |||
| CommonDialog.newInstance(bean).apply { | |||
| onCommonDialogButtonClickListener = { dialog, isRightClick -> | |||
| dialog.dismissAllowingStateLoss() | |||
| if (!isRightClick){ | |||
| ((this@CoursePackMainActivity.binding.viewPager2.adapter as ViewPagerAdapter).getItem(this@CoursePackMainActivity.binding.viewPager2.currentItem) as CourseMainFragment).run { | |||
| this.courseRelearn() | |||
| } | |||
| } | |||
| } | |||
| }.show(supportFragmentManager,"course_relearn_dialog") | |||
| } | |||
| /** 自动播放次数选择: 仅单词会有该选项 */ | |||
| private fun showAutoPlaySelectDialog() { | |||
| if (autoPlaySeletDialog == null) { | |||
| @@ -269,6 +292,14 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP | |||
| private fun startAutoPlay(time: Int) { | |||
| } | |||
| override fun onStop() { | |||
| super.onStop() | |||
| //如果是中文项目,更新课程包的进度 | |||
| if (vm.coursePack.subjectId == AppConstants.SUBJECT_CHINESE){ | |||
| vm.coursePack.learnProgress = vm.coursePack.childrenCourses[0].courseLearnProgress | |||
| } | |||
| } | |||
| /** ViewModel Factory工厂 */ | |||
| @@ -10,12 +10,14 @@ import com.xkl.cdl.data.manager.CourseManager | |||
| * Describe: 课程主页 | |||
| */ | |||
| class CoursePackMainActivityViewModel(subjectId: Int , coursePackInPosition : Int) : BaseViewModel() { | |||
| //操作的课程包 | |||
| val coursePack = CourseManager.subjectWithCoursePackMap[subjectId]!![coursePackInPosition] | |||
| //设置显示当前课程的进度值和显示内容 | |||
| val currentCourseProgress = MutableLiveData<Double>() | |||
| //更多点击是否有效 | |||
| var showMoreEnable = false | |||
| } | |||
| @@ -5,9 +5,8 @@ import androidx.constraintlayout.widget.ConstraintLayout | |||
| import androidx.lifecycle.ViewModelProvider | |||
| import androidx.recyclerview.widget.LinearLayoutManager | |||
| import androidx.recyclerview.widget.RecyclerView | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.base.fragment.BaseFragmentVM | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.suliang.common.util.DateUtil | |||
| import com.xkl.cdl.R | |||
| import com.xkl.cdl.adapter.AdapterLesson | |||
| import com.xkl.cdl.data.AppConstants | |||
| @@ -18,12 +17,11 @@ import com.xkl.cdl.data.bean.course.Lesson | |||
| import com.xkl.cdl.data.bean.intentdata.ExamData | |||
| import com.xkl.cdl.data.event.LearnEventData | |||
| import com.xkl.cdl.data.manager.CourseManager | |||
| import com.xkl.cdl.data.repository.DataRepository | |||
| import com.xkl.cdl.databinding.FragmentCourseLessonBinding | |||
| import com.xkl.cdl.dialog.CommonDialog | |||
| import com.xkl.cdl.dialog.CommonDialogBean | |||
| import com.xkl.cdl.dialog.LearnDialog | |||
| import com.xkl.cdl.module.learn.LearnWordActivity | |||
| import mqComsumerV1.Struct | |||
| import java.text.DateFormat | |||
| /** | |||
| * 课程章节目录 | |||
| @@ -49,6 +47,8 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) | |||
| adapterLesson = AdapterLesson(vm).apply { | |||
| onItemClick = onLessonClick | |||
| //默认选中位置,默认为0 ,如果学习完成则设置为-1 | |||
| selectPos = vm.initSelectPosition() | |||
| } | |||
| adapter = adapterLesson | |||
| } | |||
| @@ -65,9 +65,10 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| private fun listenerLiveBus() { | |||
| //监听数据 | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).observe(this) { learnEventData -> | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).observe(this) { learnEventData -> | |||
| if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe | |||
| when (learnEventData.actionFlag) { | |||
| //课时学前测试结束,传递数据回来更新数据 | |||
| AppConstants.DATA_LESSON_BEFORE_TEST_OVER -> { | |||
| // 更新Lesson 更新detail课时学前成绩,错误条目数,测试前错误列表 | |||
| @@ -82,17 +83,17 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| } | |||
| } | |||
| } | |||
| //课时学前测试结束,开始学习 -> 进入学习界面 | |||
| AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN -> { | |||
| startLearn(vm.allLesson[learnEventData.leesonPositionIndex]) | |||
| } | |||
| //课时学习结束 | |||
| //课时学习完成 | |||
| AppConstants.DATA_LESSON_LEARN_OVER -> { | |||
| // 更新Lesson 更新detail错误条目数 | |||
| if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe | |||
| //更新Lesson 更新detail错误条目数 | |||
| adapterLesson.notifyItemChanged(learnEventData.leesonPositionIndex) | |||
| vm.allLesson[learnEventData.leesonPositionIndex].let { | |||
| val key = "${it.chapterId}_${it.lessonId}" | |||
| //更新错误数 | |||
| vm.courseDetail.wrong.put(key, it.errorNumber) | |||
| //更新正确数 | |||
| vm.courseDetail.right.put(key, it.correctNumber) | |||
| //添加到错误本中,现在主要用于小游戏取值 | |||
| learnEventData.newErrorMap?.forEach { | |||
| vm.courseDetail.temporary_words.put(it.key, "") | |||
| @@ -112,6 +113,7 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| } | |||
| vm.courseDetail.courseLearnProgress = courseProgress | |||
| vm.course.courseLearnProgress = courseProgress | |||
| vm.coursePackMainActivityVM.currentCourseProgress.value = courseProgress | |||
| //项目总进度 | |||
| val subjectProgress = CourseManager.calculateSubjectProgress(vm.course.subjectId, vm.course.coursePackId, | |||
| vm.course.courseId, courseProgress) | |||
| @@ -128,27 +130,50 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| vm.courseDetail.after.put(key, it.beforeTestScore) | |||
| } | |||
| } | |||
| //学后测试结束,弹窗动作 | |||
| } | |||
| } | |||
| //监听课时学习的动作 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).observe(this) { learnEventData -> | |||
| if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe | |||
| when (learnEventData.actionFlag) { | |||
| //课时学前测试结束,开始学习 -> 进入学习界面 | |||
| AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN -> { | |||
| startLearn(vm.allLesson[learnEventData.leesonPositionIndex]) | |||
| } | |||
| //学后测试结束,弹窗动作 课时重新学习 | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN -> { | |||
| //课时学后测试,点击重学 | |||
| // TODO: 2022/4/22 清除当前课时数据,并更新当前课时,后进入学习界面 | |||
| learnEventData.leesonPositionIndex | |||
| vm.allLesson[learnEventData.leesonPositionIndex].learnIsOver = false | |||
| vm.relearnLesson(learnEventData.leesonPositionIndex).observe(this) { | |||
| //item更新 | |||
| adapterLesson.notifyItemChanged(learnEventData.leesonPositionIndex) | |||
| //进行点击,此时当前课时item应该处于显示中,可直接点击 | |||
| (binding.recyclerView.layoutManager as LinearLayoutManager).findViewByPosition( | |||
| learnEventData.leesonPositionIndex) | |||
| ?.findViewById<ConstraintLayout>(R.id.layout_content) | |||
| ?.performClick() | |||
| } | |||
| } | |||
| /**课时学后测试弹窗动作: 再测一次 ,学习结束弹窗: 开始学后测试,共同点:直接进入测试,没有弹窗提示*/ | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN -> { | |||
| //学后测试,再测一次 | |||
| loadLessonAfterTest(vm.allLesson[learnEventData.leesonPositionIndex]) | |||
| } | |||
| //下一步 | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_NEXT -> { | |||
| //下一课时 or 下一步(提示课程学习完成) | |||
| // TODO: 2022/4/22 判断课程是否学习完成,学习完成,显示课程学习完成弹窗,否则进入下一个没有学习完成的课时,进行学习 | |||
| when(vm.course.courseLearnProgress){ | |||
| 100.0 -> showCourseOverDialog() | |||
| when (vm.course.courseLearnProgress) { | |||
| 100.0 -> { | |||
| adapterLesson.selectPos = -1 | |||
| adapterLesson.notifyDataSetChanged() | |||
| showCourseOverDialog() | |||
| } | |||
| else -> { | |||
| var nextLessonPosition = -1 | |||
| //从下一课时开始到最后一个课时 | |||
| for ( i in learnEventData.leesonPositionIndex + 1 until vm.allLesson.size){ | |||
| for (i in learnEventData.leesonPositionIndex + 1 until vm.allLesson.size) { | |||
| if (!vm.allLesson[i].learnIsOver) { | |||
| nextLessonPosition = i | |||
| break | |||
| @@ -167,9 +192,11 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager | |||
| val findFirstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition() //第一个可见位置 | |||
| val findLastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition() //最后一个可见位置 | |||
| if (nextLessonPosition in findFirstVisibleItemPosition .. findLastVisibleItemPosition){ | |||
| linearLayoutManager.findViewByPosition(nextLessonPosition)?.findViewById<ConstraintLayout>(R.id.layout_content)?.performClick() | |||
| }else{ | |||
| if (nextLessonPosition in findFirstVisibleItemPosition .. findLastVisibleItemPosition) { | |||
| linearLayoutManager.findViewByPosition(nextLessonPosition) | |||
| ?.findViewById<ConstraintLayout>(R.id.layout_content) | |||
| ?.performClick() | |||
| } else { | |||
| recycleViewScrollListener.lessonPosition = nextLessonPosition | |||
| binding.recyclerView.addOnScrollListener(recycleViewScrollListener) | |||
| binding.recyclerView.smoothScrollToPosition(nextLessonPosition) | |||
| @@ -187,10 +214,12 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| var lessonPosition = 0 | |||
| override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) { | |||
| super.onScrollStateChanged(recyclerView, newState) | |||
| if (newState == RecyclerView.SCROLL_STATE_IDLE){ | |||
| if (newState == RecyclerView.SCROLL_STATE_IDLE) { | |||
| binding.recyclerView.removeOnScrollListener(this) | |||
| val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager | |||
| linearLayoutManager.findViewByPosition(lessonPosition)?.findViewById<ConstraintLayout>(R.id.layout_content)?.performClick() | |||
| linearLayoutManager.findViewByPosition(lessonPosition) | |||
| ?.findViewById<ConstraintLayout>(R.id.layout_content) | |||
| ?.performClick() | |||
| } | |||
| } | |||
| } | |||
| @@ -200,17 +229,16 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| private val onLessonClick : (v : View, position : Int, lesson : Lesson) -> Unit = { view, position, entity -> | |||
| when (entity.lessonType) { | |||
| AppConstants.LESSON_TYPE_WORD -> { | |||
| startLearn(entity) | |||
| /* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做 | |||
| //弹窗显示学前测试提示 | |||
| showLessonBeforeTestStartDialog(entity) | |||
| }else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习 | |||
| startLearn(entity) | |||
| }else if (entity.afterTestScore != AppConstants.NOT_DOING){ | |||
| loadLessonAfterTest(entity) | |||
| }else{ //当前课时学习完成的弹窗 | |||
| showLessonAllOverDialog(entity) | |||
| }*/ | |||
| if (entity.beforeTestScore == AppConstants.NOT_DOING) { //课时学前测试,没有做 | |||
| //弹窗显示学前测试提示 | |||
| showLessonBeforeTestStartDialog(entity) | |||
| } else if (!entity.learnIsOver) { //当前课时未学完,直接开始学习 | |||
| startLearn(entity) | |||
| } else if (entity.afterTestScore == AppConstants.NOT_DOING) { | |||
| loadLessonAfterTest(entity) | |||
| } else { //当前课时学习完成的弹窗 | |||
| showLessonAllOverDialog(entity) | |||
| } | |||
| } | |||
| AppConstants.LESSON_TYPE_SENTENCE -> { | |||
| @@ -271,9 +299,42 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| * @param lesson Lesson 课时 | |||
| */ | |||
| private fun startLearn(lesson : Lesson) { | |||
| vm.loadLessonLearnData(lesson).observe(this) { | |||
| DataTransferHolder.instance.putData(value = it) | |||
| startActivity(LearnWordActivity::class.java) | |||
| when (lesson.lessonType) { | |||
| AppConstants.LESSON_TYPE_WORD -> { | |||
| startLessonLearnForWord(lesson) | |||
| /* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做 | |||
| //弹窗显示学前测试提示 | |||
| showLessonBeforeTestStartDialog(entity) | |||
| }else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习 | |||
| startLearn(entity) | |||
| }else if (entity.afterTestScore != AppConstants.NOT_DOING){ | |||
| loadLessonAfterTest(entity) | |||
| }else{ //当前课时学习完成的弹窗 | |||
| showLessonAllOverDialog(entity) | |||
| }*/ | |||
| } | |||
| AppConstants.LESSON_TYPE_SENTENCE -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_DIALOGUE -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_COMPOSITION_VIDEO -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_COMPOSITION_EXAM -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_COMPOSITION_READING -> { | |||
| } | |||
| AppConstants.LESSON_TYPE_COMPOSITION_TASK -> { | |||
| } | |||
| } | |||
| } | |||
| @@ -305,22 +366,87 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| /** lesson的学习 lessonType 为 word类型 */ | |||
| private fun startLessonLearnForWord() { | |||
| private fun startLessonLearnForWord(lesson : Lesson) { | |||
| vm.loadLessonLearnData(lesson).observe(this) { | |||
| DataTransferHolder.instance.putData(value = it) | |||
| startActivity(LearnWordActivity::class.java) | |||
| } | |||
| } | |||
| /** | |||
| * 当前课时学前、学习、学后都完成了的弹窗 | |||
| */ | |||
| private fun showLessonAllOverDialog(lesson : Lesson) { | |||
| LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LESSON_ITEM_OVER).apply { | |||
| correctNumber = lesson.correctNumber | |||
| errorNumber = lesson.errorNumber | |||
| score = lesson.afterTestScore.toInt() | |||
| }).apply { | |||
| onDialogListener = { action, dialog -> | |||
| when (action) { | |||
| //重学动作 | |||
| AppConstants.DIALOG_LESSON_RELEARN -> CommonDialog.newInstance( | |||
| CommonDialogBean(titleText = R.string.lesson_relearn_title, | |||
| contentText = R.string.lesson_relearn_content, leftText = R.string.cancel, | |||
| rightText = R.string.sure)).apply { | |||
| onCommonDialogButtonClickListener = { relearnDialog, isRightClick -> | |||
| relearnDialog.dismissAllowingStateLoss() | |||
| if (isRightClick) { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 重新学习 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||
| LearnEventData(lesson.subjectId, lesson.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | |||
| leesonPositionIndex = lesson.lessonPositionInList | |||
| }) | |||
| } | |||
| } | |||
| }.show(childFragmentManager, "lesson_relearn_tip") | |||
| // 开始学后测试 | |||
| AppConstants.DIALOG_START_TEST -> { | |||
| dialog.dismissAllowingStateLoss() | |||
| //发送动作 : 学后测试 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( LearnEventData(lesson.subjectId, lesson.courseId, | |||
| AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | |||
| leesonPositionIndex = lesson.lessonPositionInList | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| }.show(childFragmentManager, "learn_over_dialog") | |||
| } | |||
| /** | |||
| * 显示课程学习完成的弹窗 | |||
| * 显示课程学习完成的弹窗,在最后一个课时测试完成的下一步,相当于在课时目录页显示去学后总测试的弹窗 | |||
| */ | |||
| private fun showCourseOverDialog() { | |||
| // TODO: 2022/4/29 课程学习完成弹窗 | |||
| vm.loadTest(AppConstants.TEST_TYPE_AFTER_TOTAL).observe(this) { | |||
| val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_START).apply { | |||
| examType = AppConstants.TEST_TYPE_AFTER_TOTAL | |||
| showTimeCount = CourseManager.expectedTestTime(vm.course.courseType, examType, it) | |||
| } | |||
| LearnDialog.newInstance(learnDialogBean).apply { | |||
| onDialogListener = { action, dialog -> | |||
| dialog.dismissAllowingStateLoss() | |||
| when (action) { | |||
| //开始是学后总测试 | |||
| AppConstants.DIALOG_START_TEST -> {//生成数据 | |||
| val examData = ExamData(vm.course.subjectId, learnDialogBean.examType, vm.course.courseTitle, | |||
| vm.course.courseTitle).apply { | |||
| coursePackId = vm.course.coursePackId | |||
| coursePackType = vm.course.coursePackType | |||
| courseId = vm.course.courseId | |||
| courseType = vm.course.courseType | |||
| this.testData = it | |||
| } | |||
| (parentFragment as CourseMainFragment).startExam(examData) | |||
| } | |||
| } | |||
| } | |||
| }.show(childFragmentManager, "course_learn_after_test_before") | |||
| } | |||
| } | |||
| @@ -1,13 +1,13 @@ | |||
| package com.xkl.cdl.module.m_center_learn.coursechildren | |||
| import android.os.Bundle | |||
| import androidx.fragment.app.Fragment | |||
| import androidx.lifecycle.ViewModel | |||
| import androidx.lifecycle.ViewModelProvider | |||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||
| import com.suliang.common.AppConfig | |||
| import com.suliang.common.base.fragment.BaseFragmentVM | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.suliang.common.extension.replaceFragment | |||
| import com.suliang.common.util.LogUtil | |||
| import com.xkl.cdl.R | |||
| import com.xkl.cdl.data.AppConstants | |||
| import com.xkl.cdl.data.DataTransferHolder | |||
| @@ -34,28 +34,36 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF | |||
| } | |||
| } | |||
| /**标记当前显示的fragment*/ | |||
| private lateinit var currentFragment : Fragment | |||
| override fun initViewModel() : CourseMainFragmentViewModel { | |||
| return ViewModelProvider(this, | |||
| ViewModelFactory(requireArguments().getInt(AppConfig.INTENT_1)))[CourseMainFragmentViewModel::class.java].apply { | |||
| val vmmodel = ViewModelProvider(this, ViewModelFactory( | |||
| requireArguments().getInt(AppConfig.INTENT_1)))[CourseMainFragmentViewModel::class.java].apply { | |||
| coursePackMainActivityVM = ViewModelProvider(requireActivity())[CoursePackMainActivityViewModel::class.java] | |||
| // LogUtil.e("CourseMainFragment coursePackMainActivityVM hashCode -> ${coursePackMainActivityVM.hashCode()}") | |||
| } | |||
| lifecycle.addObserver(vmmodel) | |||
| return vmmodel | |||
| } | |||
| override fun initFragment() { | |||
| //设置课程 和 需要操作的类型 | |||
| vm.course = vm.coursePackMainActivityVM.coursePack.childrenCourses[vm.courseIndex].apply { | |||
| vm.dbControlBase = DbControlBase(subjectId, coursePackId,coursePackType, courseId, courseType) | |||
| vm.dbControlBase = DbControlBase(subjectId, coursePackId, coursePackType, courseId, courseType) | |||
| } | |||
| //监听动作 总测完成,切换到目录页 | |||
| LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).observe(this) { | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).observe(this) { | |||
| if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe | |||
| when (it.actionFlag) { | |||
| // 学前总测、学后总测 之继续学习 -> 切换到目录页 | |||
| AppConstants.ACTION_COURSE_TEST_START_LEARN -> changeFragment(1) | |||
| AppConstants.ACTION_COURSE_TEST_START_LEARN -> if (currentFragment !is CourseLessonFragment) changeFragment(1) | |||
| } | |||
| } | |||
| //监听动作 总测完成 | |||
| LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).observe(this) { | |||
| if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe | |||
| when (it.actionFlag) { | |||
| //学前总测结束,传递数据回来更新数据 | |||
| AppConstants.DATA_COURSE_BEFORE_TEST_OVER -> { | |||
| vm.courseDetail.st_before = it.scoreValue.toDouble() //学前总分 | |||
| @@ -70,13 +78,28 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF | |||
| } | |||
| } | |||
| } | |||
| //学后总测结束传递数据回来。更新数据 | |||
| AppConstants.DATA_COURSE_AFTER_TEST_OVER -> vm.courseDetail.st_after = it.scoreValue.toDouble() //学后总分 | |||
| //学后总测试结束动作: 再测一次 | |||
| AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN -> { | |||
| vm.loadTest(AppConstants.TEST_TYPE_AFTER_TOTAL).observe(this) { | |||
| val examData = ExamData(vm.course.subjectId, AppConstants.TEST_TYPE_AFTER_TOTAL, vm.course.courseTitle, | |||
| vm.course.courseTitle).apply { | |||
| coursePackId = vm.course.coursePackId | |||
| coursePackType = vm.course.coursePackType | |||
| courseId = vm.course.courseId | |||
| courseType = vm.course.courseType | |||
| this.testData = it | |||
| } | |||
| startExam(examData) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| override fun loadData() { | |||
| LogUtil.e("CourseMainFragment 加载数据 --》 ${vm.courseIndex}") | |||
| vm.loadMain().observe(this) { | |||
| changeChildrenFragment() | |||
| } | |||
| @@ -87,22 +110,17 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF | |||
| * 改变加载的子Fragment | |||
| */ | |||
| private fun changeChildrenFragment() { | |||
| // //加载复习 | |||
| // replaceFragment(R.id.layout_root, CourseReviewFragment.newInstance()) | |||
| // //学前总测 | |||
| // replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL)) | |||
| //学后总测 | |||
| // replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL)) | |||
| //学习目录 | |||
| // TODO: 2022/5/5 复习页面加载 | |||
| vm.courseDetail.run { | |||
| if (st_before == AppConstants.NOT_DOING) { //学前总测未做 | |||
| replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL)) | |||
| currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL) | |||
| replaceFragment(R.id.layout_root, currentFragment) | |||
| } else if (courseLearnProgress != 100.0) { //学习未完成 | |||
| replaceFragment(R.id.layout_root, CourseLessonFragment.newInstance()) | |||
| currentFragment = CourseLessonFragment.newInstance() | |||
| replaceFragment(R.id.layout_root, currentFragment) | |||
| } else { //学习完成,学后总测试界面 | |||
| replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL)) | |||
| currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL) | |||
| replaceFragment(R.id.layout_root,currentFragment) | |||
| } | |||
| } | |||
| } | |||
| @@ -113,8 +131,14 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF | |||
| */ | |||
| fun changeFragment(position : Int) { | |||
| when (position) { | |||
| 1 -> replaceFragment(R.id.layout_root, CourseLessonFragment.newInstance()) | |||
| 2 -> replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL)) | |||
| 1 -> { | |||
| currentFragment = CourseLessonFragment.newInstance() | |||
| replaceFragment(R.id.layout_root,currentFragment ) | |||
| } | |||
| 2 -> { | |||
| currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL) | |||
| replaceFragment(R.id.layout_root, currentFragment) | |||
| } | |||
| } | |||
| } | |||
| @@ -125,10 +149,12 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF | |||
| LearnExamActivity.newInstance(requireContext()) | |||
| } | |||
| override fun onDestroy() { | |||
| super.onDestroy() | |||
| //退出本课程后移除该课程的事件监听 | |||
| // LiveDataBus.remove(AppConstants.EVENT_COURSE) | |||
| /** 课程重学方法 */ | |||
| fun courseRelearn() { | |||
| //调用重学,重学重新加载数据,重新加载界面 | |||
| vm.relearnCourse().observe(this){ | |||
| loadData() | |||
| } | |||
| } | |||
| @@ -1,16 +1,20 @@ | |||
| package com.xkl.cdl.module.m_center_learn.coursechildren | |||
| import androidx.lifecycle.LifecycleOwner | |||
| import androidx.lifecycle.MutableLiveData | |||
| import com.suliang.common.base.viewmodel.BaseViewModel | |||
| import com.suliang.common.extension.diskIo2DiskIo | |||
| import com.suliang.common.extension.diskIo2Main | |||
| import com.suliang.common.util.DateUtil | |||
| import com.suliang.common.util.file.FileUtil | |||
| import com.xkl.cdl.data.AppConstants | |||
| import com.xkl.cdl.data.bean.LearnWord | |||
| import com.xkl.cdl.data.bean.course.Course | |||
| import com.xkl.cdl.data.bean.course.CourseDetail | |||
| import com.xkl.cdl.data.bean.course.ExamBean | |||
| import com.xkl.cdl.data.bean.course.Lesson | |||
| import com.xkl.cdl.data.bean.intentdata.LearnData | |||
| import com.xkl.cdl.data.manager.CourseManager | |||
| import com.xkl.cdl.data.manager.db.DBCourseManager | |||
| import com.xkl.cdl.data.manager.db.DbControlBase | |||
| import com.xkl.cdl.data.repository.DataRepository | |||
| @@ -18,6 +22,7 @@ import com.xkl.cdl.module.m_center_learn.CoursePackMainActivityViewModel | |||
| import io.reactivex.rxjava3.core.Observable | |||
| import io.reactivex.rxjava3.functions.BiFunction | |||
| import mqComsumerV1.Struct | |||
| import java.io.File | |||
| import java.util.* | |||
| import kotlin.collections.HashMap | |||
| @@ -55,10 +60,10 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
| //获取课程的复习数据 | |||
| //获取课程的章节数据 | |||
| fun loadMain() : MutableLiveData<Boolean> { | |||
| // showHideLoading(true) | |||
| val mutableLiveData = MutableLiveData<Boolean>() | |||
| Observable.zip(DataRepository.getCourseStatistics().flatMap { | |||
| Observable.zip(DataRepository.getCourseStatistics(course.subjectId,course.coursePackId,course.courseId).flatMap { | |||
| courseDetail = it | |||
| course.courseLearnProgress = it.courseLearnProgress | |||
| return@flatMap DataRepository.getCourseAllLesson(dbControlBase, it) | |||
| }.flatMap { | |||
| allLesson = it | |||
| @@ -66,14 +71,20 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
| }, | |||
| DataRepository.getReviewData(), | |||
| BiFunction<HashMap<String, Long>, Array<String>, Boolean> { t1 : HashMap<String, Long>?, t2 : Array<String>? -> | |||
| // TODO: 2022/5/5 初始化需要复习的数据 | |||
| showMoreIsEnable() | |||
| true | |||
| }).compose(diskIo2Main()).subscribe { | |||
| // showHideLoading(false) | |||
| mutableLiveData.value = it | |||
| } | |||
| return mutableLiveData | |||
| } | |||
| /** 课程包主页上的更多按钮点击是否有效 */ | |||
| private fun showMoreIsEnable(){ | |||
| coursePackMainActivityVM.showMoreEnable = courseDetail.st_before != AppConstants.NOT_DOING | |||
| } | |||
| /** | |||
| * 获取课程的测试数据 | |||
| * @param testType Int 测试类型 | |||
| @@ -129,6 +140,7 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
| .subscribe { | |||
| result.value = LearnData(lesson).apply { | |||
| learnWordList = it | |||
| examErrorMap = courseDetail.exam_w_r_list | |||
| } | |||
| } | |||
| return result | |||
| @@ -153,5 +165,126 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
| }.compose(diskIo2DiskIo()).subscribe() | |||
| } | |||
| /** 初始化默认选中位置 */ | |||
| fun initSelectPosition() : Int { | |||
| //没有学习点,默认课程学习课时位置为第一个 | |||
| var temposition = 0 | |||
| when{ | |||
| //学后总测试完成,默认无选中 | |||
| courseDetail.st_after != AppConstants.NOT_DOING -> temposition = -1 | |||
| //有学习点 | |||
| courseDetail.course_learn_point.isNotEmpty() -> { | |||
| run m@{ | |||
| allLesson.forEachIndexed { index, lesson -> | |||
| if ("${lesson.chapterId}_${lesson.lessonId}" == courseDetail.course_learn_point) { | |||
| temposition = index | |||
| return@m | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return temposition | |||
| } | |||
| /** | |||
| * 课时重学 | |||
| * @param lessonPositionIndex Int 重学课时所在位置 | |||
| */ | |||
| fun relearnLesson(lessonPositionIndex : Int):MutableLiveData<Boolean> { | |||
| val result = MutableLiveData<Boolean>() | |||
| //重学课时后课程的进度 | |||
| val courseProgress = CourseManager.calculateEnglishCourseProgress(allLesson,true,lessonPositionIndex) | |||
| //重学课时后项目的总进度 | |||
| val subjectProgress = CourseManager.calculateSubjectProgressWithCourseLessonRelearn(course.subjectId,course.coursePackId,course.courseId,courseProgress) | |||
| Observable.fromCallable { | |||
| // TODO: 2022/5/5 进行数据清除和保存 | |||
| }.compose(diskIo2DiskIo()).subscribe{ | |||
| //更新lesson | |||
| val lesson = allLesson[lessonPositionIndex].apply { | |||
| errorNumber = 0 | |||
| correctNumber = 0 | |||
| learnedIndex = -1 | |||
| learnIsOver = false | |||
| afterTestScore = AppConstants.NOT_DOING | |||
| } | |||
| //更新courseDetail | |||
| courseDetail.run { | |||
| val lessonKey = "${lesson.chapterId}_${lesson.lessonId}" | |||
| //正确错误数归0,不会清除备忘本数据 | |||
| right[lessonKey] = 0 | |||
| wrong[lessonKey] = 0 | |||
| //移除学后测试成绩 | |||
| after.remove(lessonKey) | |||
| //移除章节学习点 | |||
| lesson_learn_point.remove(lessonKey) | |||
| val wordStartKey = "${lessonKey}_" | |||
| //移除总测、课时学前测试的学习错误数据 | |||
| exam_w_r_list.filterKeys { | |||
| it.startsWith(wordStartKey) | |||
| }.forEach{ | |||
| exam_w_r_list.remove(it.key) | |||
| } | |||
| //移除错误本中的记录 | |||
| temporary_words.filterKeys { it.startsWith(wordStartKey) }.forEach{ | |||
| temporary_words.remove(it.key) | |||
| } | |||
| //更新课程进度 | |||
| courseLearnProgress = courseProgress | |||
| course.courseLearnProgress = courseProgress | |||
| coursePackMainActivityVM.currentCourseProgress.postValue(courseProgress) | |||
| //更新统计总进度 | |||
| CourseManager.calculateSubjectProgress(course.subjectId, course.coursePackId, | |||
| course.courseId, courseProgress) | |||
| //完成 | |||
| result.postValue(true) | |||
| } | |||
| } | |||
| return result | |||
| } | |||
| /** | |||
| * 课程重学方法 | |||
| */ | |||
| fun relearnCourse(): MutableLiveData<Boolean> { | |||
| val result = MutableLiveData<Boolean>() | |||
| //重学需要重新计算进度 | |||
| val subjectProgress = CourseManager.calculateSubjectProgressWithCourseRelearn(course.subjectId,course.coursePackId,course.courseId) | |||
| Observable.fromCallable { | |||
| // TODO: 2022/5/5 调用课程重学 重新请求详情 | |||
| val file = File(FileUtil.getSaveDirPath("appcache"), "${course.subjectId}_${course.coursePackId}_${course.courseId}") | |||
| if (file.exists()){ file.delete() } | |||
| }.compose(diskIo2DiskIo()) | |||
| .subscribe{ | |||
| courseDetail.run { | |||
| courseLearnProgress = 0.0 | |||
| st_before = AppConstants.NOT_DOING | |||
| st_after = AppConstants.NOT_DOING | |||
| before.clear() | |||
| after.clear() | |||
| right.clear() | |||
| wrong.clear() | |||
| lesson_learn_point.clear() | |||
| exam_w_r_list.clear() | |||
| course_learn_point = "" | |||
| rl += 1 | |||
| temporary_words.clear() | |||
| vp.clear() | |||
| exercise_schedule.clear() | |||
| } | |||
| result.postValue(true) | |||
| } | |||
| return result | |||
| } | |||
| // TODO: 2022/5/6 这里在退出时进行了统计数据缓存保存,在loadMain的时候进行了read缓存 ,后期需要清除 | |||
| override fun onDestroy(owner : LifecycleOwner) { | |||
| val objectToBytes = FileUtil.objectToBytes(courseDetail) | |||
| FileUtil.writeBytesToFile(FileUtil.getSaveDirPath("appcache"),"${course.subjectId}_${course.coursePackId}_${course.courseId}",objectToBytes) | |||
| super.onDestroy(owner) | |||
| } | |||
| } | |||
| @@ -13,23 +13,24 @@ import com.xkl.cdl.data.bean.course.ExamBean | |||
| import com.xkl.cdl.data.bean.intentdata.ExamData | |||
| import com.xkl.cdl.data.manager.CourseManager | |||
| import com.xkl.cdl.databinding.FragmentCourseTotalTestBinding | |||
| import com.xkl.cdl.module.m_center_learn.CoursePackMainActivity | |||
| /** | |||
| * 课程总测试: 学前总,学后总 | |||
| * @property totalTestType 测试类型 | |||
| */ | |||
| class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, CourseMainFragmentViewModel>() { | |||
| companion object { | |||
| @JvmStatic | |||
| fun newInstance(totalTestType: Int) = CourseTotalTestFragment().apply { | |||
| fun newInstance(totalTestType : Int) = CourseTotalTestFragment().apply { | |||
| arguments = Bundle().apply { | |||
| putInt(AppConfig.INTENT_1, totalTestType) | |||
| } | |||
| } | |||
| } | |||
| override fun initViewModel(): CourseMainFragmentViewModel { | |||
| override fun initViewModel() : CourseMainFragmentViewModel { | |||
| return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java] | |||
| } | |||
| @@ -38,25 +39,26 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| //由于使用的是与父类相同的loadingEvent,所以将此evnet移除 | |||
| vm.loadingEvent.removeObservers(this) | |||
| } | |||
| //传递过来的总测类型: 学前,学后 | |||
| private var totalTestType = 0 | |||
| //测试的数据 | |||
| private var testData : List<ExamBean> = emptyList() | |||
| override fun initFragment() { | |||
| totalTestType = requireArguments().getInt(AppConfig.INTENT_1) | |||
| } | |||
| override fun loadData() { | |||
| vm.loadTest(totalTestType).observe(this){ | |||
| vm.loadTest(totalTestType).observe(this) { | |||
| testData = it | |||
| initView() | |||
| } | |||
| } | |||
| private fun initView(){ | |||
| binding.tvCountTip.text = CourseManager.expectedTestTime(vm.course.courseType,totalTestType,testData!!) | |||
| private fun initView() { | |||
| binding.tvCountTip.text = CourseManager.expectedTestTime(vm.course.courseType, totalTestType, testData!!) | |||
| when (totalTestType) { | |||
| AppConstants.TEST_TYPE_BEFORE_TOTAL -> { | |||
| // TODO: 2022/4/21 需要把开始学习给取消了 | |||
| @@ -86,10 +88,9 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| tvTitle.setText(R.string.tips_current_course_learn_over) | |||
| tvMainTip.visibility = View.VISIBLE | |||
| //根据测试成绩处理 | |||
| vm.courseDetail.st_before = 81.0 | |||
| vm.courseDetail.st_before.let { | |||
| when { | |||
| it == -1.0 -> { //未测 | |||
| when (it) { | |||
| AppConstants.NOT_DOING -> { //未测 | |||
| tvMainTip.setText(R.string.test_total_after_tip_1) | |||
| button2.run { | |||
| setText(R.string.test_type_after_total) | |||
| @@ -98,26 +99,12 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| } | |||
| } | |||
| } | |||
| it < AppConstants.TEST_SCORE_LEVEL_1 -> { //测试未通过 | |||
| tvMainTip.setHtml("你还未通过学后总测试,上次得分: <font color=\'#F26255\'>$it</font>") | |||
| button1.run { | |||
| visibility = View.VISIBLE | |||
| setText(R.string.continue_learn) | |||
| click { view -> | |||
| continueLearn(view) | |||
| } | |||
| } | |||
| button2.run { | |||
| setText(R.string.start_test) | |||
| click { view -> | |||
| startTest(view) | |||
| } | |||
| else -> { //有成绩,直接完成 | |||
| if (it >= AppConstants.TEST_SCORE_LEVEL_2) { | |||
| tvMainTip.setHtml("你已完成学后总测试,上次得分: <font color=\'#5082E6\'>$it</font>") | |||
| }else { | |||
| tvMainTip.setHtml("你已完成学后总测试,上次得分: <font color=\'#F26255\'>$it</font>") | |||
| } | |||
| } | |||
| it >= AppConstants.TEST_SCORE_LEVEL_1 -> { //测试通过 | |||
| tvMainTip.setHtml("你已通过学后总测试,上次得分: <font color=\'#5082E6\'>$it</font>") | |||
| tvTips.visibility = View.VISIBLE | |||
| tvCountTip.visibility = View.GONE | |||
| button1.run { | |||
| @@ -134,6 +121,9 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| } | |||
| } | |||
| tvClearLearnRecord.visibility = View.VISIBLE | |||
| tvClearLearnRecord.click { | |||
| (activity as CoursePackMainActivity).showCourseRelearnDialog() | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -142,17 +132,15 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| } | |||
| } | |||
| /**继续学习*/ | |||
| private fun continueLearn(view: View) { | |||
| private fun continueLearn(view : View) { | |||
| (requireParentFragment() as CourseMainFragment).changeFragment(1) | |||
| } | |||
| /** 开始测试 : 生成测试题,跳转到测试 | |||
| * | |||
| */ | |||
| private fun startTest(view: View) { | |||
| private fun startTest(view : View) { | |||
| //生成数据 | |||
| val examData = ExamData(vm.course.subjectId, totalTestType, vm.course.courseTitle, vm.course.courseTitle).apply { | |||
| coursePackId = vm.course.coursePackId | |||
| @@ -164,5 +152,5 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C | |||
| } | |||
| (parentFragment as CourseMainFragment).startExam(examData) | |||
| } | |||
| } | |||
| @@ -3,10 +3,8 @@ package com.xkl.cdl.module.main | |||
| import android.os.Bundle | |||
| import androidx.lifecycle.ViewModelProvider | |||
| import com.suliang.common.base.activity.BaseActivityVM | |||
| import com.suliang.common.eventbus.LiveDataBus | |||
| import com.suliang.common.extension.loadFragment | |||
| import com.suliang.common.extension.showHideFragment | |||
| import com.suliang.common.util.LogUtil | |||
| import com.xkl.cdl.R | |||
| import com.xkl.cdl.databinding.ActivityMainBinding | |||
| import com.xkl.cdl.module.m_center_learn.LearnCenterFragment | |||
| @@ -14,7 +12,6 @@ import com.xkl.cdl.module.m_memo.MemoFragment | |||
| import com.xkl.cdl.module.m_my.MyFragment | |||
| import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | |||
| import com.xkl.cdl.module.m_statics.StaticsFragment | |||
| import com.xkl.cdl.module.splash.SplashActivity | |||
| /** | |||
| * 主界面、控制切换子Fragment | |||
| @@ -1,5 +1,6 @@ | |||
| package com.xkl.cdl.util | |||
| import com.suliang.common.util.LogUtil | |||
| import com.xkl.cdl.data.bean.BaseWord | |||
| import java.io.* | |||
| import java.util.* | |||
| @@ -307,6 +308,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List | |||
| currentCorrectMap[key] = true | |||
| } | |||
| if (isLearnFirst) currentIsError = false | |||
| LogUtil.e("currentCorrectMap--->${currentCorrectMap.size} --> $currentCorrectMap") | |||
| } | |||
| /** | |||
| @@ -324,6 +326,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List | |||
| } else if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key)) { //测试中数据的错误 | |||
| currentErrorMap[key] = true | |||
| } | |||
| LogUtil.e("currentErrorMap --->${currentErrorMap.size} $currentErrorMap") | |||
| //开始进行数据扩容替换 | |||
| replaceErrorToNull(item) //替换已有错误为空 | |||
| insertErrorWord(item, false) //开始插入 | |||
| @@ -334,7 +337,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List | |||
| * @return true在 false不存在 | |||
| */ | |||
| fun isInExamErrorMap(key : String) : Boolean { | |||
| return examErrorsMap?.getOrDefault(key, null) ?: false | |||
| return examErrorsMap?.getOrDefault(key, false) ?: false | |||
| } | |||
| /** 是否是在学习的错误列表中 */ | |||
| @@ -242,17 +242,23 @@ | |||
| android:visibility="gone" | |||
| /> | |||
| <!--所有布局id--> | |||
| <!-- <androidx.constraintlayout.widget.Group--> | |||
| <!-- android:layout_width="wrap_content"--> | |||
| <!-- android:layout_height="wrap_content"--> | |||
| <!-- app:constraint_referenced_ids="iv_close,tv_score,tv_tip,tv_title,--> | |||
| <!-- tv_lesson_name,tv_count_time,,tv_tip_1,--> | |||
| <!-- inc_statistics_number,--> | |||
| <!-- tv_learn_over_tip,--> | |||
| <!-- tv_learn_over_for_after_count_time,--> | |||
| <!-- tv_top,tv_top_1,tv_left,vSplit"--> | |||
| <!-- tools:visibility="gone"--> | |||
| <!-- />--> | |||
| <!-- <androidx.constraintlayout.widget.Group | |||
| android:layout_width="wrap_content" | |||
| android:layout_height="wrap_content" | |||
| app:constraint_referenced_ids="iv_close,tv_score,tv_tip,tv_title, | |||
| tv_lesson_name,tv_count_time,,tv_tip_1, | |||
| inc_statistics_number, | |||
| tv_learn_over_tip, | |||
| tv_learn_over_for_after_count_time, | |||
| tv_top,tv_top_1,tv_left,vSplit" | |||
| tools:visibility="gone" | |||
| /> | |||
| <androidx.constraintlayout.widget.Group | |||
| android:layout_width="wrap_content" | |||
| android:layout_height="wrap_content" | |||
| app:constraint_referenced_ids="tv_title,tv_tip_1,tv_lesson_name,tv_count_time,tv_left,vSplit" | |||
| />--> | |||
| <!-- <!–学前总测试控制显示的布局id–>--> | |||
| <!-- <androidx.constraintlayout.widget.Group--> | |||
| <!-- android:id="@+id/group_total_test"--> | |||
| @@ -278,7 +284,7 @@ | |||
| /> --> | |||
| <!--课时正常学习结束的布局组 --> | |||
| <!-- 课时完全结束的点击显示弹窗的布局组 --> | |||
| <!-- <androidx.constraintlayout.widget.Group--> | |||
| <!-- android:layout_width="wrap_content"--> | |||
| <!-- android:layout_height="wrap_content"--> | |||
| @@ -39,7 +39,7 @@ | |||
| android:layout_marginStart="28dp" | |||
| android:layout_marginTop="8dp" | |||
| android:text="@string/error" | |||
| android:textColor="@color/gray_2" | |||
| android:textColor="@color/main_text_color" | |||
| android:textSize="@dimen/smallerSize" | |||
| app:layout_constraintStart_toEndOf="@+id/guideline_1" | |||
| app:layout_constraintTop_toTopOf="parent" /> | |||
| @@ -75,5 +75,8 @@ | |||
| <string name="auto_playing">自动播放中···</string> | |||
| <string name="quit_learn_title">你确定要退出本课程的学习吗?</string> | |||
| <string name="quit_learn_content">退出后系统将保存你的学习进度</string> | |||
| <string name="course_relearn_title">你确定要清空本课程的学习记录吗?</string> | |||
| <string name="course_relearn_content">清空后你的学习记录将不可恢复,请谨慎操作</string> | |||
| <string name="course_relearn_sure">确认清空</string> | |||
| </resources> | |||
| @@ -99,6 +99,8 @@ ext { | |||
| grpc_android: "io.grpc:grpc-android:1.27.0", | |||
| grpc_protobuf: "io.grpc:grpc-protobuf:1.27.0", | |||
| grpc_stub: "io.grpc:grpc-stub:1.27.0", | |||
| //liveEventBus https://github.com/JeremyLiao/LiveEventBus | |||
| liveEventBus : "io.github.jeremyliao:live-event-bus-x:1.8.0" | |||
| ] | |||
| @@ -67,6 +67,8 @@ dependencies { | |||
| coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' | |||
| //MMKV | |||
| api customDependencies.MMKV | |||
| // liveEventBus | |||
| api customDependencies.liveEventBus | |||
| @@ -10,48 +10,48 @@ import com.suliang.common.util.LogUtil | |||
| * Describe: 打印生命周期的Activity | |||
| */ | |||
| open class LifecycleLogActivity : AppCompatActivity() { | |||
| override fun onCreate(savedInstanceState: Bundle?) { | |||
| super.onCreate(savedInstanceState) | |||
| LogUtil.e("onCreate()") | |||
| } | |||
| override fun onRestart() { | |||
| super.onRestart() | |||
| LogUtil.e("onRestart()") | |||
| } | |||
| override fun onStart() { | |||
| super.onStart() | |||
| LogUtil.e("onStart()") | |||
| } | |||
| override fun onResume() { | |||
| super.onResume() | |||
| LogUtil.e("onResume()") | |||
| } | |||
| override fun onPause() { | |||
| super.onPause() | |||
| LogUtil.e("onPause()") | |||
| } | |||
| override fun onStop() { | |||
| super.onStop() | |||
| LogUtil.e("onStop()") | |||
| } | |||
| override fun onDestroy() { | |||
| super.onDestroy() | |||
| LogUtil.e("onDestroy()") | |||
| } | |||
| override fun onSaveInstanceState(outState: Bundle) { | |||
| super.onSaveInstanceState(outState) | |||
| LogUtil.e("onSaveInstanceState()") | |||
| } | |||
| override fun onRestoreInstanceState(savedInstanceState: Bundle) { | |||
| super.onRestoreInstanceState(savedInstanceState) | |||
| LogUtil.e("onRestoreInstanceState()") | |||
| } | |||
| // override fun onCreate(savedInstanceState: Bundle?) { | |||
| // super.onCreate(savedInstanceState) | |||
| // LogUtil.e("onCreate()") | |||
| // } | |||
| // | |||
| // override fun onRestart() { | |||
| // super.onRestart() | |||
| // LogUtil.e("onRestart()") | |||
| // } | |||
| // | |||
| // override fun onStart() { | |||
| // super.onStart() | |||
| // LogUtil.e("onStart()") | |||
| // } | |||
| // | |||
| // override fun onResume() { | |||
| // super.onResume() | |||
| // LogUtil.e("onResume()") | |||
| // } | |||
| // | |||
| // override fun onPause() { | |||
| // super.onPause() | |||
| // LogUtil.e("onPause()") | |||
| // } | |||
| // | |||
| // override fun onStop() { | |||
| // super.onStop() | |||
| // LogUtil.e("onStop()") | |||
| // } | |||
| // | |||
| // override fun onDestroy() { | |||
| // super.onDestroy() | |||
| // LogUtil.e("onDestroy()") | |||
| // } | |||
| // | |||
| // override fun onSaveInstanceState(outState: Bundle) { | |||
| // super.onSaveInstanceState(outState) | |||
| // LogUtil.e("onSaveInstanceState()") | |||
| // } | |||
| // | |||
| // override fun onRestoreInstanceState(savedInstanceState: Bundle) { | |||
| // super.onRestoreInstanceState(savedInstanceState) | |||
| // LogUtil.e("onRestoreInstanceState()") | |||
| // } | |||
| } | |||
| @@ -17,6 +17,7 @@ abstract class BaseFragmentVM<VB : ViewBinding, VM : BaseViewModel> : BaseFragme | |||
| override fun initFirst() { | |||
| vm = initViewModel() | |||
| lifecycle.addObserver(vm) | |||
| vm.pageEvent.observe(this) { startActivity(it) } | |||
| vm.toastEvent.observe(this){ showToast(it) } | |||
| vm.loadingEvent.observe(this) { | |||
| @@ -16,37 +16,37 @@ import com.suliang.common.util.LogUtil | |||
| open class BaseViewModel : ViewModel(), ViewModelLifecycle, ViewBehavior { | |||
| override fun onCreate(owner: LifecycleOwner) { | |||
| super.onCreate(owner) | |||
| LogUtil.i("${javaClass.name} onCreate() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onCreate() ") | |||
| } | |||
| override fun onStart(owner: LifecycleOwner) { | |||
| super.onStart(owner) | |||
| LogUtil.i("${javaClass.name} onStart() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onStart() ") | |||
| } | |||
| override fun onResume(owner: LifecycleOwner) { | |||
| super.onResume(owner) | |||
| LogUtil.i("${javaClass.name} onResume() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onResume() ") | |||
| } | |||
| override fun onPause(owner: LifecycleOwner) { | |||
| super.onPause(owner) | |||
| LogUtil.i("${javaClass.name} onPause() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onPause() ") | |||
| } | |||
| override fun onStop(owner: LifecycleOwner) { | |||
| super.onStop(owner) | |||
| LogUtil.i("${javaClass.name} onStop() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onStop() ") | |||
| } | |||
| override fun onDestroy(owner: LifecycleOwner) { | |||
| super.onDestroy(owner) | |||
| LogUtil.i("${javaClass.name} onDestroy() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onDestroy() ") | |||
| } | |||
| override fun onCleared() { | |||
| super.onCleared() | |||
| LogUtil.i("${javaClass.name} onCleared() ") | |||
| LogUtil.i("${javaClass.name}_${hashCode()} onCleared() ") | |||
| } | |||
| @@ -1,15 +1,85 @@ | |||
| package com.suliang.common.eventbus | |||
| import android.os.Looper | |||
| import androidx.lifecycle.MutableLiveData | |||
| /** | |||
| * author suliang | |||
| * create 2022/3/15 10:01 | |||
| * Describe: 事件总线,这条总线把任何类中的数据直接传递到activity 或是 fragment 上 | |||
| * https://blog.csdn.net/lp131452064/article/details/82736296 | |||
| * https://juejin.cn/post/6844903768459329544 | |||
| */ | |||
| @Deprecated("this class is deprecated" ,replaceWith = ReplaceWith("LiveEventBus"),level = DeprecationLevel.ERROR) | |||
| object LiveDataBus { | |||
| private val bus = mutableMapOf<String, MutableLiveData<Any>>() | |||
| /** | |||
| * 发送事件 | |||
| * @param key String | |||
| * @param value T | |||
| * @param isSticky 是否是粘性事件,默认为false | |||
| */ | |||
| fun <T : Any> postEvent(key:String, value:T, isSticky : Boolean = false){ | |||
| if (Looper.getMainLooper().thread == Thread.currentThread()){ | |||
| subscribeEvent<T>(key,isSticky).value = value | |||
| }else{ | |||
| subscribeEvent<T>(key,isSticky).postValue(value) | |||
| } | |||
| } | |||
| /** | |||
| * 订阅事件 | |||
| * @param key bus中的key | |||
| * @param isSticky 是否是粘性事件,默认为false | |||
| */ | |||
| fun <T:Any> subscribeEvent(key:String,isSticky:Boolean = false): MutableLiveData<T> { | |||
| if (!bus.containsKey(key)){ | |||
| if (isSticky){ | |||
| bus[key] = MutableLiveData() | |||
| }else{ | |||
| bus[key] = NonStickyMutableLivedata() | |||
| } | |||
| } | |||
| return bus[key] as MutableLiveData<T> | |||
| } | |||
| fun remove(key : String) { | |||
| bus.remove(key) | |||
| } | |||
| fun clearAll() { | |||
| bus.clear() | |||
| } | |||
| // @SuppressWarnings("UNCHECKED_CAST") | |||
| // @Synchronized | |||
| // fun <T> with(key : String) : MutableLiveData<T> { | |||
| // if (!bus.containsKey(key)) { | |||
| // bus[key] = MutableLiveData() | |||
| // } | |||
| // return bus[key] as MutableLiveData<T> | |||
| // } | |||
| // | |||
| // @SuppressWarnings("UNCHECKED_CAST") | |||
| // @Synchronized | |||
| // fun <T> withNonSticky(key : String) : MutableLiveData<T> { | |||
| // if (!bus.containsKey(key)) { | |||
| // bus[key] = NonStickyMutableLivedata() | |||
| // } | |||
| // return bus[key] as MutableLiveData<T> | |||
| // } | |||
| private val bus = mutableMapOf<String,MutableLiveData<Any>>() | |||
| // /** | |||
| // * 注册订阅者 | |||
| @@ -28,52 +98,22 @@ object LiveDataBus { | |||
| //java使用传入泛型class, kotlin使用可直接传入泛型,不需要class类型 | |||
| @SuppressWarnings("UNCHECKED_CAST") | |||
| @Synchronized | |||
| fun <T> with(key:String) : MutableLiveData<T>{ | |||
| if (!bus.containsKey(key)){ | |||
| bus[key] = MutableLiveData() | |||
| } | |||
| return bus[key] as MutableLiveData<T> | |||
| } | |||
| @SuppressWarnings("UNCHECKED_CAST") | |||
| @Synchronized | |||
| fun <T> withNonSticky(key:String) : MutableLiveData<T>{ | |||
| if (!bus.containsKey(key)){ | |||
| bus[key] = NonStickyMutableLiveData() | |||
| } | |||
| return bus[key] as MutableLiveData<T> | |||
| } | |||
| @SuppressWarnings("UNCHECKED_CAST") | |||
| @Synchronized | |||
| fun <T> with(key:String,type: Class<T>) : MutableLiveData<T>{ | |||
| if (!bus.containsKey(key)){ | |||
| bus[key] = MutableLiveData() | |||
| } | |||
| return bus[key] as MutableLiveData<T> | |||
| } | |||
| @SuppressWarnings("UNCHECKED_CAST") | |||
| @Synchronized | |||
| fun <T> withNonSticky(key:String,type: Class<T>) : MutableLiveData<T>{ | |||
| if (!bus.containsKey(key)){ | |||
| bus[key] = NonStickyMutableLiveData() | |||
| } | |||
| return bus[key] as MutableLiveData<T> | |||
| } | |||
| fun remove(key:String){ | |||
| bus.remove(key) | |||
| } | |||
| fun clearAll(){ | |||
| bus.clear() | |||
| } | |||
| // @SuppressWarnings("UNCHECKED_CAST") | |||
| // @Synchronized | |||
| // fun <T> with(key:String,type: Class<T>) : MutableLiveData<T>{ | |||
| // if (!bus.containsKey(key)){ | |||
| // bus[key] = MutableLiveData() | |||
| // } | |||
| // return bus[key] as MutableLiveData<T> | |||
| // } | |||
| // @SuppressWarnings("UNCHECKED_CAST") | |||
| // @Synchronized | |||
| // fun <T> withNonSticky(key:String,type: Class<T>) : MutableLiveData<T>{ | |||
| // if (!bus.containsKey(key)){ | |||
| // bus[key] = NonStickyMutableLiveData() | |||
| // } | |||
| // return bus[key] as MutableLiveData<T> | |||
| // } | |||
| } | |||
| @@ -12,21 +12,37 @@ import java.lang.reflect.Method | |||
| * author suliang | |||
| * create 2022/3/15 10:51 | |||
| * Describe: 非粘性LiveData ,需要先设置监听再发送数据,即后注册的监听收不到以前的监听 | |||
| * 事件总线的LiveData 非粘性事件传false(刚注册时如果有事件则不发送) 粘性事件传true | |||
| * @param isSticky false非粘性事件 true粘性事件 | |||
| */ | |||
| class NonStickyMutableLiveData<T> : MutableLiveData<T>() { | |||
| // private var stickFlag : Boolean = false | |||
| internal class NonStickyMutableLivedata<T> : MutableLiveData<T>() { | |||
| // override fun observe(owner : LifecycleOwner, observer : Observer<in T>) { | |||
| // super.observe(owner, ObserverWrapper<T>(observer)) | |||
| // } | |||
| // | |||
| // class ObserverWrapper<T>(var observer:Observer<in T>) : Observer<T> { | |||
| // var isSticky = false | |||
| // override fun onChanged(t : T) { | |||
| // if (isSticky){ | |||
| // observer.onChanged(t) | |||
| // }else{ | |||
| // isSticky = true | |||
| // } | |||
| // } | |||
| // } | |||
| override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { | |||
| super.observe(owner, observer) | |||
| hook(observer) | |||
| // if (!stickFlag){ | |||
| // hook(observer) | |||
| // stickFlag = true | |||
| // } | |||
| } | |||
| private fun hook(observer: Observer<in T>) = try { | |||
| override fun removeObserver(observer : Observer<in T>) { | |||
| super.removeObserver(observer) | |||
| } | |||
| private fun hook(observer : Observer<in T>) = try { | |||
| //得到 mLastVersion | |||
| //获取到LiveData的类中的mObserver对象 | |||
| // SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers | |||
| @@ -38,7 +54,7 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() { | |||
| //得到map对应的class对象 | |||
| val mObserversClass = mObserVersObject.javaClass | |||
| //获取到mObservers对象的get方法 | |||
| val get:Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||
| val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||
| get.isAccessible = true | |||
| //执行get方法,获取到对象 | |||
| val invokeEntry = get.invoke(mObserVersObject, observer) | |||
| @@ -46,7 +62,7 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() { | |||
| val observerWrapper = if (invokeEntry is Map.Entry<*, *>) { | |||
| invokeEntry.value | |||
| } else throw NullPointerException("observerWrapper is null") | |||
| //得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass | |||
| //getClass 返回对应的当前正在运行是的类所对应的 | |||
| val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion") | |||
| @@ -56,11 +72,10 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() { | |||
| mVersion.isAccessible = true | |||
| //把mVersion数据填入到mLastVersion中 | |||
| val mVersionValue = mVersion.get(this) | |||
| mLastVersion.set(observerWrapper,mVersionValue) | |||
| }catch (e: Exception){ | |||
| mLastVersion.set(observerWrapper, mVersionValue) | |||
| } catch (e : Exception) { | |||
| e.printStackTrace() | |||
| } | |||
| } | |||
| @@ -34,7 +34,7 @@ fun View.click(clickListener : ((view : View) -> Unit)?){ | |||
| } | |||
| this.setOnTouchListener{ view , motionEvent -> | |||
| when(motionEvent.action){ | |||
| MotionEvent.ACTION_DOWN -> view.alpha = 0.7f | |||
| MotionEvent.ACTION_DOWN -> view.alpha = 0.8f | |||
| MotionEvent.ACTION_UP -> view.alpha = 1f | |||
| else -> view.alpha = 1f | |||
| } | |||
| @@ -400,9 +400,15 @@ object FileUtil { | |||
| closeStream(out) | |||
| return result | |||
| } | |||
| /*** | |||
| * 从对象获取字节数组 | |||
| * @param data Any 对象,需要实现序列化 | |||
| * @return ByteArray 字节数组 | |||
| * @throws Exception | |||
| */ | |||
| @Throws(Exception::class) | |||
| fun objectToBytes(data: Any): ByteArray { | |||
| fun objectToBytes(data: Serializable): ByteArray { | |||
| var oos: ObjectOutputStream? = null | |||
| return try { | |||
| val bos = ByteArrayOutputStream() | |||
| @@ -413,6 +419,15 @@ object FileUtil { | |||
| oos?.close() | |||
| } | |||
| } | |||
| /** | |||
| * 从字节数组获取对象 | |||
| * @param data ByteArray | |||
| * @return Any | |||
| */ | |||
| fun bytesToObject(data:ByteArray): Any{ | |||
| return ObjectInputStream(ByteArrayInputStream(data)).readObject() | |||
| } | |||
| /** | |||
| * 获取文件大小 | |||
| @@ -1,4 +1,3 @@ | |||
| <resources> | |||
| <!-- TODO: Remove or change this placeholder text --> | |||
| <string name="hello_blank_fragment">Hello blank fragment</string> | |||
| </resources> | |||