<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_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_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_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/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_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" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> |
package com.xkl.cdl | package com.xkl.cdl | ||||
import android.annotation.SuppressLint | |||||
import android.util.TypedValue | import android.util.TypedValue | ||||
import android.view.View | import android.view.View | ||||
import android.widget.LinearLayout | import android.widget.LinearLayout | ||||
* @param example String? 例句 | * @param example String? 例句 | ||||
* @param refrence String? 参考 | * @param refrence String? 参考 | ||||
*/ | */ | ||||
@SuppressLint("SetTextI18n") | |||||
fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence : String?){ | fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence : String?){ | ||||
phrase?.let { | phrase?.let { | ||||
tvPhraseFlag.visibility = View.VISIBLE | tvPhraseFlag.visibility = View.VISIBLE | ||||
example?.let { | example?.let { | ||||
tvExampleFlag.visibility = View.VISIBLE | tvExampleFlag.visibility = View.VISIBLE | ||||
tvExample.visibility = View.VISIBLE | tvExample.visibility = View.VISIBLE | ||||
tvExample.text = example | |||||
tvExample.text = "▪ ${it.replace("\n", "\n▪ ")}" | |||||
}?:let { | }?:let { | ||||
tvExampleFlag.visibility = View.GONE | tvExampleFlag.visibility = View.GONE | ||||
tvExample.visibility = View.GONE | tvExample.visibility = View.GONE |
} | } | ||||
} | } | ||||
} | } | ||||
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) } //主题颜色 | |||||
/** | /** | ||||
* 处理颜色 选中色 未选中色(学习完成/学习未完成) | * 处理颜色 选中色 未选中色(学习完成/学习未完成) | ||||
* @param lesson Lesson | * @param lesson Lesson | ||||
*/ | */ | ||||
private fun ItemCourseLessonBinding.initColor(position: Int, 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的背景和状态设置 | //item的背景和状态设置 | ||||
if (selectPos == position) { //选中,背景设置 | if (selectPos == position) { //选中,背景设置 | ||||
layoutContent.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_3)) //选中背景 | layoutContent.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_3)) //选中背景 | ||||
} | } | ||||
} else { //未选中:根据学习情况判断 | } else { //未选中:根据学习情况判断 | ||||
layoutContent.setBackgroundColor(translationColor) //未选中背景透明 | layoutContent.setBackgroundColor(translationColor) //未选中背景透明 | ||||
if (lesson.learnIsOver) { | |||||
if (lesson.learnIsOver) { //学习完成 | |||||
tvLessonName.run { | tvLessonName.run { | ||||
setTextColor(normalColorLearnOver) //课时名称颜色 | setTextColor(normalColorLearnOver) //课时名称颜色 | ||||
paint.isFakeBoldText = false //加粗 | paint.isFakeBoldText = false //加粗 | ||||
tvLessonNumber.setTextColor(normalColorLearnOver) //数量颜色 | tvLessonNumber.setTextColor(normalColorLearnOver) //数量颜色 | ||||
ivArrowRight.run { | ivArrowRight.run { | ||||
setBackgroundColor(translationColor) | 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 { | tvLessonName.run { | ||||
setTextColor(normalColorNotLearnOver) //课时名称颜色 | setTextColor(normalColorNotLearnOver) //课时名称颜色 | ||||
paint.isFakeBoldText = false //加粗 | paint.isFakeBoldText = false //加粗 | ||||
tvLessonNumber.setTextColor(normalColorNotLearnOver) //数量颜色 | tvLessonNumber.setTextColor(normalColorNotLearnOver) //数量颜色 | ||||
ivArrowRight.run { | ivArrowRight.run { | ||||
setBackgroundColor(translationColor) | setBackgroundColor(translationColor) | ||||
imageTintList = ColorStateList.valueOf(normalColorNotLearnOver) | |||||
strokeColor = ColorStateList.valueOf(normalColorNotLearnOver) | |||||
imageTintList = ColorStateList.valueOf(themeColor) | |||||
strokeColor = ColorStateList.valueOf(themeColor) | |||||
} | } | ||||
} | } | ||||
} | } |
const val DIALOG_TYPE_EXAM_OVER = 2 | const val DIALOG_TYPE_EXAM_OVER = 2 | ||||
/** 对话框类型: 学习结束弹窗类型 */ | /** 对话框类型: 学习结束弹窗类型 */ | ||||
const val DIALOG_TYPE_LEARN_OVER = 3 | const val DIALOG_TYPE_LEARN_OVER = 3 | ||||
/**对话框类型,item学习完成*/ | |||||
const val DIALOG_TYPE_LESSON_ITEM_OVER = 4 | |||||
/**--- 总线动作 --------------------------------- */ | /**--- 总线动作 --------------------------------- */ | ||||
/**action key 改变界面 到目录页 */ | /**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 | const val ACTION_COURSE_TEST_START_LEARN = 1 | ||||
const val ACTION_LESSON_AFTER_TEST_NEXT = 8 | const val ACTION_LESSON_AFTER_TEST_NEXT = 8 | ||||
/**数据动作: 课时学习完成*/ | /**数据动作: 课时学习完成*/ | ||||
const val DATA_LESSON_LEARN_OVER = 9 | 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 | |||||
/**--- 弹窗动作 --------------------------------- */ | /**--- 弹窗动作 --------------------------------- */ | ||||
/** 学前总测结束弹窗: 开始学习 ,课时学前测试开始弹窗*/ | /** 学前总测结束弹窗: 开始学习 ,课时学前测试开始弹窗*/ | ||||
const val DIALOG_LESSON_AFTER_TEST_AGAIN = 4 | const val DIALOG_LESSON_AFTER_TEST_AGAIN = 4 | ||||
/**课时学后测试弹窗动作: 下一步*/ | /**课时学后测试弹窗动作: 下一步*/ | ||||
const val DIALOG_LESSON_AFTER_TEST_NEXT = 5 | const val DIALOG_LESSON_AFTER_TEST_NEXT = 5 | ||||
/**弹窗动作提示: 完成*/ | |||||
const val DIALOG_OVER = 6 | |||||
/**课时学后总测的再测一次*/ | |||||
const val DIALOG_AFTER_TOTAL_TEST_AGAIN = 7 | |||||
} | } |
* 词汇量测试 | * 词汇量测试 | ||||
* | * | ||||
*/ | */ | ||||
class LearnDialogBean(val dialogType:Int) : Parcelable { | |||||
class LearnDialogBean(val dialogType:Int) :Parcelable { | |||||
/*---------------测试使用------------------------------------*/ | /*---------------测试使用------------------------------------*/ | ||||
/** 测试类型 */ | /** 测试类型 */ | ||||
/** 题数与时间 */ | /** 题数与时间 */ | ||||
var showTimeCount = "" | var showTimeCount = "" | ||||
constructor(parcel : Parcel) : this(parcel.readInt()) { | constructor(parcel : Parcel) : this(parcel.readInt()) { | ||||
examType = parcel.readInt() | examType = parcel.readInt() | ||||
score = parcel.readInt() | score = parcel.readInt() | ||||
correctNumber = parcel.readInt() | correctNumber = parcel.readInt() | ||||
errorNumber = parcel.readInt() | errorNumber = parcel.readInt() | ||||
chapter_lesson_name = parcel.readString().toString() | |||||
showTimeCount = parcel.readString().toString() | |||||
} | } | ||||
override fun writeToParcel(parcel : Parcel, flags : Int) { | override fun writeToParcel(parcel : Parcel, flags : Int) { | ||||
parcel.writeInt(score) | parcel.writeInt(score) | ||||
parcel.writeInt(correctNumber) | parcel.writeInt(correctNumber) | ||||
parcel.writeInt(errorNumber) | parcel.writeInt(errorNumber) | ||||
parcel.writeString(chapter_lesson_name) | |||||
parcel.writeString(showTimeCount) | |||||
} | } | ||||
override fun describeContents() : Int { | override fun describeContents() : Int { | ||||
return arrayOfNulls(size) | return arrayOfNulls(size) | ||||
} | } | ||||
} | } | ||||
} | } |
package com.xkl.cdl.data.bean.course | package com.xkl.cdl.data.bean.course | ||||
import androidx.databinding.BaseObservable | |||||
/** | /** | ||||
* author suliang | * author suliang | ||||
* create 2022/3/22 10:08 | * create 2022/3/22 10:08 |
package com.xkl.cdl.data.bean.course | package com.xkl.cdl.data.bean.course | ||||
import com.xkl.cdl.data.AppConstants | |||||
import java.io.Serializable | |||||
/** | /** | ||||
* author suliang | * author suliang | ||||
* create 2022/3/29 9:52 | * create 2022/3/29 9:52 | ||||
* Describe: 课程学习的详情 | * Describe: 课程学习的详情 | ||||
*/ | */ | ||||
class CourseDetail { | |||||
class CourseDetail:Serializable{ | |||||
var courseLearnProgress: Double = 0.0 //课程学习进度 | 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 before: HashMap<String, Double> = hashMapOf() //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | ||||
var after: 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=>条目数量 | var right = hashMapOf<String, Int>() //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 |
/** 学习进度位置,为已学下标的位置,在作文课堂练习时,学习取当前条,其他取下一条*/ | /** 学习进度位置,为已学下标的位置,在作文课堂练习时,学习取当前条,其他取下一条*/ | ||||
var learnedIndex: Int = -1 | 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 | var learnIsOver = false | ||||
/**是否是最后一个课时 */ | /**是否是最后一个课时 */ |
} | } | ||||
/** | /** | ||||
* 计算项目总进度 | |||||
* 计算项目总进度 ,并将课程进度值设置进入集合中 | |||||
* @param subjectId Int 项目Id | * @param subjectId Int 项目Id | ||||
* @param packId Long 修改进度的课程包id | * @param packId Long 修改进度的课程包id | ||||
* @param courseId Long 修改进度的课程id | * @param courseId Long 修改进度的课程id | ||||
if (totalCourseSize == 0) return 0.0 | if (totalCourseSize == 0) return 0.0 | ||||
return totalProgress / totalCourseSize | 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 | |||||
} | |||||
} | } |
totalNumber = this.wordIds.size //总数 | totalNumber = this.wordIds.size //总数 | ||||
correctNumber = detail.right.getOrElse(key, { 0 }) //正确数 | correctNumber = detail.right.getOrElse(key, { 0 }) //正确数 | ||||
errorNumber = detail.wrong.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.learnedIndex = learnIndex //学习位置,当前位置为已学 | ||||
this.learnIsOver = learnIsOver | this.learnIsOver = learnIsOver | ||||
this.lessonType = lessonType | this.lessonType = lessonType |
import android.util.LruCache | import android.util.LruCache | ||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import com.suliang.common.AppConfig | import com.suliang.common.AppConfig | ||||
import com.suliang.common.eventbus.NonStickyMutableLiveData | |||||
import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
import com.suliang.common.util.file.FileUtil | import com.suliang.common.util.file.FileUtil | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
} | } | ||||
/** 通知查到的录音 */ | /** 通知查到的录音 */ | ||||
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 | |||||
} | |||||
/** | /** | ||||
* 获取对应音频 | * 获取对应音频 | ||||
return@fromCallable lruCache.get(defaultKey) ?: "" | return@fromCallable lruCache.get(defaultKey) ?: "" | ||||
}.compose(diskIo2Main()).subscribe { | }.compose(diskIo2Main()).subscribe { | ||||
if (this::audioLiveData.isInitialized) | |||||
audioLiveData.value = it | audioLiveData.value = it | ||||
} | } | ||||
} | } |
package com.xkl.cdl.data.repository | package com.xkl.cdl.data.repository | ||||
import androidx.lifecycle.MutableLiveData | 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.CourseDetail | ||||
import com.xkl.cdl.data.bean.course.Lesson | import com.xkl.cdl.data.bean.course.Lesson | ||||
import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
import mqComsumerV1.Struct | import mqComsumerV1.Struct | ||||
import java.io.File | |||||
/** | /** | ||||
* author suliang | * author suliang | ||||
} | } | ||||
/** 获取课程的详情 */ | /** 获取课程的详情 */ | ||||
fun getCourseStatistics(): Observable<CourseDetail>{ | |||||
fun getCourseStatistics(subjectId:Int,coursePackId:Long,courseId:Long): Observable<CourseDetail>{ | |||||
return Observable.create{ | 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.onNext(courseDetail) | ||||
it.onComplete() | it.onComplete() | ||||
} | } |
import android.util.LruCache | import android.util.LruCache | ||||
import androidx.lifecycle.MutableLiveData | 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.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.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
import java.io.File | |||||
import java.util.* | import java.util.* | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
/** 通知查到的录音 */ | |||||
var photoLiveData = NonStickyMutableLiveData<ByteArray?>() | |||||
/** 通知查到的图片字节码 */ | |||||
private lateinit var photoLiveData : MutableLiveData<ByteArray?> | |||||
fun initPhotoLiveData() : MutableLiveData<ByteArray?> { | |||||
photoLiveData = MutableLiveData<ByteArray?>() | |||||
return photoLiveData | |||||
} | |||||
/** | /** | ||||
* 获取对应图片 | * 获取对应图片 | ||||
* 1缓存 2文件 3数据库 | * 1缓存 2文件 3数据库 | ||||
return@fromCallable lruCache.get(defaultKey) | return@fromCallable lruCache.get(defaultKey) | ||||
}.compose(diskIo2Main()).subscribe { | }.compose(diskIo2Main()).subscribe { | ||||
if (this::photoLiveData.isInitialized) | |||||
photoLiveData.value = it | photoLiveData.value = it | ||||
} | } | ||||
} | } |
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,来处理对应的动作 | |||||
} |
AppConstants.DIALOG_TYPE_EXAM_START -> when(learnDialogBean.examType){ | AppConstants.DIALOG_TYPE_EXAM_START -> when(learnDialogBean.examType){ | ||||
//课时学前测试开始弹窗 | //课时学前测试开始弹窗 | ||||
AppConstants.TEST_TYPE_BEFORE -> initLessonBeforeTestStart() | AppConstants.TEST_TYPE_BEFORE -> initLessonBeforeTestStart() | ||||
//课时最后一个课时测试结束的下一步弹出此弹窗:学后总测试开始的弹窗 | |||||
AppConstants.TEST_TYPE_AFTER_TOTAL -> initCourseAfterTestStart() | |||||
} | } | ||||
//测试结束弹窗 | //测试结束弹窗 | ||||
AppConstants.DIALOG_TYPE_EXAM_OVER -> when (learnDialogBean.examType) { | AppConstants.DIALOG_TYPE_EXAM_OVER -> when (learnDialogBean.examType) { | ||||
AppConstants.TEST_TYPE_BEFORE_TOTAL -> initCourseBeforeTotalTestOver() | AppConstants.TEST_TYPE_BEFORE_TOTAL -> initCourseBeforeTotalTestOver() | ||||
//课时学前测试结束弹窗 | //课时学前测试结束弹窗 | ||||
AppConstants.TEST_TYPE_BEFORE-> initLessonBeforeTestOver() | 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_LEARN_OVER -> initLessonLearningOver() | ||||
/**课时列表点击课时完全完成*/ | |||||
AppConstants.DIALOG_TYPE_LESSON_ITEM_OVER -> initLessonItemClickLessonOver() | |||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
private fun initLessonBeforeTestStart() { | private fun initLessonBeforeTestStart() { | ||||
binding.run { | binding.run { | ||||
ivClose.visibility = View.VISIBLE | |||||
tvTitle.visibility = View.VISIBLE | tvTitle.visibility = View.VISIBLE | ||||
tvLessonName.visibility = View.VISIBLE | tvLessonName.visibility = View.VISIBLE | ||||
tvCountTime.visibility = View.VISIBLE | tvCountTime.visibility = View.VISIBLE | ||||
tvLessonName.text = learnDialogBean.chapter_lesson_name | tvLessonName.text = learnDialogBean.chapter_lesson_name | ||||
tvCountTime.text = learnDialogBean.showTimeCount | tvCountTime.text = learnDialogBean.showTimeCount | ||||
tvRight.text = "开始测试" | 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 { | binding.tvRight.click { | ||||
onDialogListener(AppConstants.DIALOG_START_TEST, this@LearnDialog) | 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() } | |||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
private fun initLessonBeforeTestOver() { | private fun initLessonBeforeTestOver() { | ||||
binding.run { | binding.run { | ||||
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | |||||
tvScore.visibility = View.VISIBLE | tvScore.visibility = View.VISIBLE | ||||
tvTip.visibility = View.VISIBLE | tvTip.visibility = View.VISIBLE | ||||
tvTitle.visibility = View.VISIBLE | tvTitle.visibility = View.VISIBLE | ||||
binding.run { | binding.run { | ||||
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2) | ||||
tvTitle.visibility = View.VISIBLE | tvTitle.visibility = View.VISIBLE | ||||
tvTitle.text = "恭喜你,本课时学习完成" | |||||
tvTitle.text = "恭喜你,本课时学习完成!" | |||||
incStatisticsNumber.root.visibility = View.VISIBLE | incStatisticsNumber.root.visibility = View.VISIBLE | ||||
tvLearnOverTip.visibility = View.VISIBLE | tvLearnOverTip.visibility = View.VISIBLE | ||||
tvLearnOverForAfterCountTime.visibility = View.VISIBLE | tvLearnOverForAfterCountTime.visibility = View.VISIBLE | ||||
tvLeft.visibility = View.VISIBLE | tvLeft.visibility = View.VISIBLE | ||||
vSplit.visibility = View.VISIBLE | vSplit.visibility = View.VISIBLE | ||||
tvTitle.text = "恭喜你,完成了课时学后测试" | tvTitle.text = "恭喜你,完成了课时学后测试" | ||||
tvTop1.text = "重新学习" | |||||
tvTop.text = "重新学习" | |||||
tvLeft.text = "再测一次" | tvLeft.text = "再测一次" | ||||
tvRight.text = "下一课时" | tvRight.text = "下一课时" | ||||
onDialogListener(AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT,this) | 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) } | |||||
} | |||||
} | } |
import androidx.recyclerview.widget.GridLayoutManager | import androidx.recyclerview.widget.GridLayoutManager | ||||
import androidx.recyclerview.widget.SimpleItemAnimator | import androidx.recyclerview.widget.SimpleItemAnimator | ||||
import com.airbnb.lottie.LottieAnimationView | import com.airbnb.lottie.LottieAnimationView | ||||
import com.jeremyliao.liveeventbus.LiveEventBus | |||||
import com.suliang.common.base.activity.BaseActivityVM | import com.suliang.common.base.activity.BaseActivityVM | ||||
import com.suliang.common.eventbus.LiveDataBus | |||||
import com.suliang.common.extension.click | import com.suliang.common.extension.click | ||||
import com.suliang.common.util.DateUtil | import com.suliang.common.util.DateUtil | ||||
import com.suliang.common.util.DrawableUti | import com.suliang.common.util.DrawableUti | ||||
} | } | ||||
/** 查询到播放数据过来 */ | /** 查询到播放数据过来 */ | ||||
AudioCache.audioLiveData.observe(this) { | |||||
AudioCache.initAudioLiveData().observe(this) { | |||||
if (it == null) { | if (it == null) { | ||||
//发音文件为空 | //发音文件为空 | ||||
showToast("未找到发音文件") | showToast("未找到发音文件") | ||||
LearnDialog.newInstance(learnDialogBean).apply { | LearnDialog.newInstance(learnDialogBean).apply { | ||||
onDialogListener = { action, dialog -> | onDialogListener = { action, dialog -> | ||||
when (vm.intentData.examType) { | when (vm.intentData.examType) { | ||||
//学前测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页 | |||||
//学前总测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页 | |||||
AppConstants.TEST_TYPE_BEFORE_TOTAL -> when (action) { | AppConstants.TEST_TYPE_BEFORE_TOTAL -> when (action) { | ||||
AppConstants.DIALOG_START_LEARN -> { | AppConstants.DIALOG_START_LEARN -> { | ||||
dialog.dismissAllowingStateLoss() | 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() | finish() | ||||
} | } | ||||
} | } | ||||
AppConstants.TEST_TYPE_BEFORE -> when (action) { | AppConstants.TEST_TYPE_BEFORE -> when (action) { | ||||
AppConstants.DIALOG_START_LEARN -> { | AppConstants.DIALOG_START_LEARN -> { | ||||
dialog.dismissAllowingStateLoss() | dialog.dismissAllowingStateLoss() | ||||
//发送动作 : 继续学习 | |||||
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||||
//发送动作 : 开始学习 | |||||
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||||
LearnEventData(vm.intentData.subjectId, | LearnEventData(vm.intentData.subjectId, | ||||
vm.intentData.courseId, | vm.intentData.courseId, | ||||
AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN).apply { | AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN).apply { | ||||
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | ||||
} | |||||
}) | |||||
finish() | finish() | ||||
} | } | ||||
} | } | ||||
if (isRightClick){ | if (isRightClick){ | ||||
dialog.dismissAllowingStateLoss() | dialog.dismissAllowingStateLoss() | ||||
//发送动作 : 重新学习 | //发送动作 : 重新学习 | ||||
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||||
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||||
LearnEventData(vm.intentData.subjectId, | LearnEventData(vm.intentData.subjectId, | ||||
vm.intentData.courseId, | vm.intentData.courseId, | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | ||||
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | ||||
} | |||||
}) | |||||
finish() | |||||
} | } | ||||
} | } | ||||
}.show(childFragmentManager,"lesson_relearn_tip") | }.show(childFragmentManager,"lesson_relearn_tip") | ||||
} | } | ||||
//再测一次 | //再测一次 | ||||
AppConstants.DIALOG_LESSON_AFTER_TEST_AGAIN -> { | 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, | LearnEventData(vm.intentData.subjectId, | ||||
vm.intentData.courseId, | vm.intentData.courseId, | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | ||||
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | ||||
} | |||||
}) | |||||
finish() | |||||
} | } | ||||
//下一步 | //下一步 | ||||
AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT -> { | 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, | LearnEventData(vm.intentData.subjectId, | ||||
vm.intentData.courseId, | vm.intentData.courseId, | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_NEXT).apply { | AppConstants.ACTION_LESSON_AFTER_TEST_NEXT).apply { | ||||
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!! | 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() | |||||
} | } | ||||
} | } | ||||
} | } |
import androidx.lifecycle.LifecycleOwner | import androidx.lifecycle.LifecycleOwner | ||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import androidx.lifecycle.viewModelScope | 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.createRandomNewChar | ||||
import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
import com.suliang.common.util.DateUtil | import com.suliang.common.util.DateUtil | ||||
//倒计时结束 | //倒计时结束 | ||||
val currentCountingTimeOver = MutableLiveData<Boolean>() | val currentCountingTimeOver = MutableLiveData<Boolean>() | ||||
init { | |||||
isRunValidTime = false | |||||
} | |||||
/** 修改获取下一题的标记为true,则在onResume时,自动获取第一题 */ | /** 修改获取下一题的标记为true,则在onResume时,自动获取第一题 */ | ||||
fun loadFirst(){ | fun loadFirst(){ | ||||
isGetNextIng = true | isGetNextIng = true | ||||
//计算分数 | //计算分数 | ||||
calculateScore() | calculateScore() | ||||
when(intentData.examType){ | when(intentData.examType){ | ||||
AppConstants.TEST_TYPE_BEFORE -> { //学前总测为lesson添加错误数 与 分数 | |||||
AppConstants.TEST_TYPE_BEFORE -> { //课时学前测试为lesson添加错误数 与 分数 | |||||
intentData.lesson?.let { | intentData.lesson?.let { | ||||
it.errorNumber = it.errorNumber + newErrorMap.size | |||||
it.errorNumber += newErrorMap.size | |||||
it.beforeTestScore = scoreValue.toDouble() | it.beforeTestScore = scoreValue.toDouble() | ||||
} | } | ||||
} | } | ||||
} else { //相当于新错 | } else { //相当于新错 | ||||
if (!newErrorMap.containsKey(key)) { | if (!newErrorMap.containsKey(key)) { | ||||
newErrorMap[key] = true | newErrorMap[key] = true | ||||
//课时前错误 ,则更新课时错误数量 | |||||
if (intentData.examType == AppConstants.TEST_TYPE_BEFORE) { | |||||
intentData.lesson!!.errorNumber = intentData.lesson!!.errorNumber + 1 | |||||
} | |||||
} | } | ||||
} | } | ||||
mLearnEntities.add(builder.build()) | mLearnEntities.add(builder.build()) | ||||
//其他测试 | //其他测试 | ||||
else -> { | else -> { | ||||
val calculateCorrectNumber : Double = correctLiveData.value!! + unAnswerNumber * 0.25 | 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 { | this.scoreValue = when { | ||||
scoreValue < 0 -> 0 | scoreValue < 0 -> 0 | ||||
scoreValue > 100 -> 100 | scoreValue > 100 -> 100 | ||||
else -> scoreValue | else -> scoreValue | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private fun sendEventBus(){ | private fun sendEventBus(){ | ||||
when(intentData.examType){ | when(intentData.examType){ | ||||
AppConstants.TEST_TYPE_BEFORE_TOTAL -> { //学前总测发送数据、学前总测发送数据 | 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.subjectId, | ||||
intentData.courseId, | intentData.courseId, | ||||
AppConstants.DATA_COURSE_BEFORE_TEST_OVER).apply { | AppConstants.DATA_COURSE_BEFORE_TEST_OVER).apply { | ||||
this.scoreValue = this@LearnExamViewModel.scoreValue | this.scoreValue = this@LearnExamViewModel.scoreValue | ||||
this.newErrorMap = this@LearnExamViewModel.newErrorMap | this.newErrorMap = this@LearnExamViewModel.newErrorMap | ||||
} | |||||
}) | |||||
} | } | ||||
AppConstants.TEST_TYPE_BEFORE-> { // 课时学前测试结束发送数据 | AppConstants.TEST_TYPE_BEFORE-> { // 课时学前测试结束发送数据 | ||||
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData( | |||||
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post( LearnEventData( | |||||
intentData.subjectId, | intentData.subjectId, | ||||
intentData.courseId, | intentData.courseId, | ||||
AppConstants.DATA_LESSON_BEFORE_TEST_OVER).apply { | AppConstants.DATA_LESSON_BEFORE_TEST_OVER).apply { | ||||
intentData.lesson?.let { | intentData.lesson?.let { | ||||
leesonPositionIndex = it.lessonPositionInList | leesonPositionIndex = it.lessonPositionInList | ||||
} | } | ||||
} | |||||
}) | |||||
} | } | ||||
AppConstants.TEST_TYPE_AFTER -> { //课时学后测试结束发送数据 | AppConstants.TEST_TYPE_AFTER -> { //课时学后测试结束发送数据 | ||||
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData( | |||||
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post(LearnEventData( | |||||
intentData.subjectId, | intentData.subjectId, | ||||
intentData.courseId, | intentData.courseId, | ||||
AppConstants.DATA_LESSON_AFTER_TEST_OVER).apply { | AppConstants.DATA_LESSON_AFTER_TEST_OVER).apply { | ||||
this.newErrorMap = this@LearnExamViewModel.newErrorMap | |||||
intentData.lesson?.let { | intentData.lesson?.let { | ||||
leesonPositionIndex = it.lessonPositionInList | 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 | |||||
}) | |||||
} | } | ||||
} | } | ||||
} | } |
import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener | import androidx.recyclerview.widget.RecyclerView.OnScrollListener | ||||
import androidx.recyclerview.widget.SimpleItemAnimator | import androidx.recyclerview.widget.SimpleItemAnimator | ||||
import com.jeremyliao.liveeventbus.LiveEventBus | |||||
import com.suliang.common.base.activity.BaseActivityVM | import com.suliang.common.base.activity.BaseActivityVM | ||||
import com.suliang.common.eventbus.LiveDataBus | |||||
import com.suliang.common.extension.click | import com.suliang.common.extension.click | ||||
import com.suliang.common.util.DateUtil | import com.suliang.common.util.DateUtil | ||||
import com.suliang.common.util.LogUtil | import com.suliang.common.util.LogUtil | ||||
vm.loadNext() | vm.loadNext() | ||||
//发音数据 | //发音数据 | ||||
AudioCache.audioLiveData.observe(this) { | |||||
AudioCache.initAudioLiveData().observe(this) { | |||||
it?.run { | it?.run { | ||||
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE) MPManager.play( | if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE) MPManager.play( | ||||
it, listener = impListener) | it, listener = impListener) | ||||
//如果需要显示图片,则添加监听 | //如果需要显示图片,则添加监听 | ||||
if (vm.isNeedLoadPhoto) { | if (vm.isNeedLoadPhoto) { | ||||
//图片数据 | //图片数据 | ||||
PhotoCache.photoLiveData.observe(this) { | |||||
PhotoCache.initPhotoLiveData().observe(this) { | |||||
it?.run { ImageLoader.loadImage(bindingWord.imgWord, it) } ?: let { bindingWord.imgWord.visibility = View.GONE } | it?.run { ImageLoader.loadImage(bindingWord.imgWord, it) } ?: let { bindingWord.imgWord.visibility = View.GONE } | ||||
} | } | ||||
} | } | ||||
private fun showLearnOverDialog() { | private fun showLearnOverDialog() { | ||||
vm.loadAfterTest().observe(this) { showTimeCount -> | vm.loadAfterTest().observe(this) { showTimeCount -> | ||||
LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LEARN_OVER).apply { | 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 | this.showTimeCount = showTimeCount | ||||
}).apply { | }).apply { | ||||
onDialogListener = { action, dialog -> | onDialogListener = { action, dialog -> | ||||
if (isRightClick){ | if (isRightClick){ | ||||
dialog.dismissAllowingStateLoss() | 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, | vm.learnData.lesson.courseId, | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply { | ||||
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | ||||
} | |||||
}) | |||||
finish() | |||||
} | } | ||||
} | } | ||||
}.show(childFragmentManager,"lesson_relearn_tip") | }.show(childFragmentManager,"lesson_relearn_tip") | ||||
AppConstants.DIALOG_START_TEST -> { | AppConstants.DIALOG_START_TEST -> { | ||||
dialog.dismissAllowingStateLoss() | dialog.dismissAllowingStateLoss() | ||||
//发送动作 : 学后测试 | //发送动作 : 学后测试 | ||||
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value = | |||||
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( | |||||
LearnEventData(vm.learnData.lesson.subjectId, | LearnEventData(vm.learnData.lesson.subjectId, | ||||
vm.learnData.lesson.courseId, | vm.learnData.lesson.courseId, | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply { | ||||
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | leesonPositionIndex = vm.learnData.lesson.lessonPositionInList | ||||
} | |||||
}) | |||||
finish() | |||||
} | } | ||||
} | } | ||||
} | } |
import androidx.lifecycle.LifecycleOwner | import androidx.lifecycle.LifecycleOwner | ||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import androidx.lifecycle.viewModelScope | 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.createRandomNewChar | ||||
import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
import com.suliang.common.util.DateUtil | import com.suliang.common.util.DateUtil | ||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.data.DataTransferHolder | import com.xkl.cdl.data.DataTransferHolder | ||||
import com.xkl.cdl.data.bean.LearnWord | import com.xkl.cdl.data.bean.LearnWord | ||||
//数据上传完成监听: true 学习完成的上传 false可能是半途的返回事件,直接退出 | //数据上传完成监听: true 学习完成的上传 false可能是半途的返回事件,直接退出 | ||||
val saveDataLiveData = MutableLiveData<Boolean>() | val saveDataLiveData = MutableLiveData<Boolean>() | ||||
/** 获取数据 */ | /** 获取数据 */ | ||||
fun loadNext() { | fun loadNext() { | ||||
//修改标记 | //修改标记 | ||||
currentLearnWord.value = it | currentLearnWord.value = it | ||||
} ?: let { //没有数据 即学习完成 | } ?: let { //没有数据 即学习完成 | ||||
isAllOver = true | isAllOver = true | ||||
// 停止有效计时 | |||||
isRunValidTime = false | |||||
//停止总计时 | //停止总计时 | ||||
stopTotalCountTing() | stopTotalCountTing() | ||||
// TODO: 2022/4/26 停止有效计时 | |||||
//封装保存数据 | //封装保存数据 | ||||
saveData() | saveData() | ||||
} | } | ||||
learnedIndex = currentLessonLearnedPosition | learnedIndex = currentLessonLearnedPosition | ||||
correctNumber += learnRuleUtil.currentCorrectMap.size | correctNumber += learnRuleUtil.currentCorrectMap.size | ||||
errorNumber += learnRuleUtil.currentErrorMap.size | errorNumber += learnRuleUtil.currentErrorMap.size | ||||
learnIsOver = (correctNumber + errorNumber == totalNumber) | |||||
learnIsOver = learnedIndex == wordIds.size - 1 | |||||
} | } | ||||
//添加到错误本集合中,主要用于小游戏练习(学前总 课时都没有添加,从这里添加到集合后发送出去,添加到集合) | //添加到错误本集合中,主要用于小游戏练习(学前总 课时都没有添加,从这里添加到集合后发送出去,添加到集合) | ||||
learnData.examErrorMap?.putAll(learnRuleUtil.currentErrorMap) | learnData.examErrorMap?.putAll(learnRuleUtil.currentErrorMap) | ||||
/** 发送数据事件 */ | /** 发送数据事件 */ | ||||
private fun sendEventBus() { | 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.leesonPositionIndex = learnData.lesson.lessonPositionInList | ||||
this.newErrorMap = learnData.examErrorMap | this.newErrorMap = learnData.examErrorMap | ||||
} | |||||
}) | |||||
} | } | ||||
import com.xkl.cdl.adapter.AdapterAutoPlaySelectRepeat | import com.xkl.cdl.adapter.AdapterAutoPlaySelectRepeat | ||||
import com.xkl.cdl.adapter.ViewPagerAdapter | import com.xkl.cdl.adapter.ViewPagerAdapter | ||||
import com.xkl.cdl.data.AppConstants | 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.binding.BindingAdapter | ||||
import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
import com.xkl.cdl.databinding.ActivityCourseMainBinding | import com.xkl.cdl.databinding.ActivityCourseMainBinding | ||||
import com.xkl.cdl.databinding.DialogBottomAutoPlaySelectBinding | import com.xkl.cdl.databinding.DialogBottomAutoPlaySelectBinding | ||||
import com.xkl.cdl.databinding.DialogBottomCourseMoreBinding | 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.xkl.cdl.module.m_center_learn.coursechildren.CourseMainFragment | ||||
import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | ||||
} | } | ||||
} | } | ||||
} | } | ||||
//改变page后设置进度 | |||||
//改变page后设置进度,获取该课程的进度进行设置 | |||||
vm.currentCourseProgress.value = vm.coursePack.childrenCourses[position].courseLearnProgress | vm.currentCourseProgress.value = vm.coursePack.childrenCourses[position].courseLearnProgress | ||||
} | } | ||||
}) | }) | ||||
progressbar.progress = it.toInt() | progressbar.progress = it.toInt() | ||||
tvProgress.text = if (binding.includeCourseTypeTab.root.visibility == View.VISIBLE) { | tvProgress.text = if (binding.includeCourseTypeTab.root.visibility == View.VISIBLE) { | ||||
val format = when (binding.viewPager2.currentItem) { | 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)) | String.format(format, CourseManager.useToShowProgress(it)) | ||||
} else { | } else { | ||||
String.format("进度:%s", CourseManager.useToShowProgress(it)) | |||||
String.format("进度: %s%%", CourseManager.useToShowProgress(it)) | |||||
} | } | ||||
} | } | ||||
} | } | ||||
//更多按钮点击 | //更多按钮点击 | ||||
binding.includeCourseProgress.ivMore.click { | binding.includeCourseProgress.ivMore.click { | ||||
if (vm.showMoreEnable) | |||||
showMoreDialog() | showMoreDialog() | ||||
else | |||||
showToast("请先进行学习") | |||||
} | } | ||||
} | } | ||||
} | } | ||||
moreBinding.tvClearLearnRecord.click { | moreBinding.tvClearLearnRecord.click { | ||||
dismiss() | dismiss() | ||||
// TODO: 2022/3/29 弹窗显示清除学习记录 | |||||
showCourseRelearnDialog() | |||||
} | } | ||||
} | } | ||||
} | } | ||||
moreDialog?.show() | 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() { | private fun showAutoPlaySelectDialog() { | ||||
if (autoPlaySeletDialog == null) { | if (autoPlaySeletDialog == null) { | ||||
private fun startAutoPlay(time: Int) { | 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工厂 */ | /** ViewModel Factory工厂 */ |
* Describe: 课程主页 | * Describe: 课程主页 | ||||
*/ | */ | ||||
class CoursePackMainActivityViewModel(subjectId: Int , coursePackInPosition : Int) : BaseViewModel() { | class CoursePackMainActivityViewModel(subjectId: Int , coursePackInPosition : Int) : BaseViewModel() { | ||||
//操作的课程包 | //操作的课程包 | ||||
val coursePack = CourseManager.subjectWithCoursePackMap[subjectId]!![coursePackInPosition] | val coursePack = CourseManager.subjectWithCoursePackMap[subjectId]!![coursePackInPosition] | ||||
//设置显示当前课程的进度值和显示内容 | //设置显示当前课程的进度值和显示内容 | ||||
val currentCourseProgress = MutableLiveData<Double>() | val currentCourseProgress = MutableLiveData<Double>() | ||||
//更多点击是否有效 | |||||
var showMoreEnable = false | |||||
} | } |
import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
import androidx.recyclerview.widget.LinearLayoutManager | import androidx.recyclerview.widget.LinearLayoutManager | ||||
import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||
import com.jeremyliao.liveeventbus.LiveEventBus | |||||
import com.suliang.common.base.fragment.BaseFragmentVM | 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.R | ||||
import com.xkl.cdl.adapter.AdapterLesson | import com.xkl.cdl.adapter.AdapterLesson | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.data.bean.intentdata.ExamData | import com.xkl.cdl.data.bean.intentdata.ExamData | ||||
import com.xkl.cdl.data.event.LearnEventData | import com.xkl.cdl.data.event.LearnEventData | ||||
import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
import com.xkl.cdl.data.repository.DataRepository | |||||
import com.xkl.cdl.databinding.FragmentCourseLessonBinding | 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.dialog.LearnDialog | ||||
import com.xkl.cdl.module.learn.LearnWordActivity | import com.xkl.cdl.module.learn.LearnWordActivity | ||||
import mqComsumerV1.Struct | |||||
import java.text.DateFormat | |||||
/** | /** | ||||
* 课程章节目录 | * 课程章节目录 | ||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) | layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) | ||||
adapterLesson = AdapterLesson(vm).apply { | adapterLesson = AdapterLesson(vm).apply { | ||||
onItemClick = onLessonClick | onItemClick = onLessonClick | ||||
//默认选中位置,默认为0 ,如果学习完成则设置为-1 | |||||
selectPos = vm.initSelectPosition() | |||||
} | } | ||||
adapter = adapterLesson | adapter = adapterLesson | ||||
} | } | ||||
private fun listenerLiveBus() { | 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 | if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe | ||||
when (learnEventData.actionFlag) { | when (learnEventData.actionFlag) { | ||||
//课时学前测试结束,传递数据回来更新数据 | //课时学前测试结束,传递数据回来更新数据 | ||||
AppConstants.DATA_LESSON_BEFORE_TEST_OVER -> { | AppConstants.DATA_LESSON_BEFORE_TEST_OVER -> { | ||||
// 更新Lesson 更新detail课时学前成绩,错误条目数,测试前错误列表 | // 更新Lesson 更新detail课时学前成绩,错误条目数,测试前错误列表 | ||||
} | } | ||||
} | } | ||||
} | } | ||||
//课时学前测试结束,开始学习 -> 进入学习界面 | |||||
AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN -> { | |||||
startLearn(vm.allLesson[learnEventData.leesonPositionIndex]) | |||||
} | |||||
//课时学习结束 | |||||
//课时学习完成 | |||||
AppConstants.DATA_LESSON_LEARN_OVER -> { | 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) | adapterLesson.notifyItemChanged(learnEventData.leesonPositionIndex) | ||||
vm.allLesson[learnEventData.leesonPositionIndex].let { | vm.allLesson[learnEventData.leesonPositionIndex].let { | ||||
val key = "${it.chapterId}_${it.lessonId}" | val key = "${it.chapterId}_${it.lessonId}" | ||||
//更新错误数 | |||||
vm.courseDetail.wrong.put(key, it.errorNumber) | vm.courseDetail.wrong.put(key, it.errorNumber) | ||||
//更新正确数 | |||||
vm.courseDetail.right.put(key, it.correctNumber) | |||||
//添加到错误本中,现在主要用于小游戏取值 | //添加到错误本中,现在主要用于小游戏取值 | ||||
learnEventData.newErrorMap?.forEach { | learnEventData.newErrorMap?.forEach { | ||||
vm.courseDetail.temporary_words.put(it.key, "") | vm.courseDetail.temporary_words.put(it.key, "") | ||||
} | } | ||||
vm.courseDetail.courseLearnProgress = courseProgress | vm.courseDetail.courseLearnProgress = courseProgress | ||||
vm.course.courseLearnProgress = courseProgress | vm.course.courseLearnProgress = courseProgress | ||||
vm.coursePackMainActivityVM.currentCourseProgress.value = courseProgress | |||||
//项目总进度 | //项目总进度 | ||||
val subjectProgress = CourseManager.calculateSubjectProgress(vm.course.subjectId, vm.course.coursePackId, | val subjectProgress = CourseManager.calculateSubjectProgress(vm.course.subjectId, vm.course.coursePackId, | ||||
vm.course.courseId, courseProgress) | vm.course.courseId, courseProgress) | ||||
vm.courseDetail.after.put(key, it.beforeTestScore) | 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 -> { | AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN -> { | ||||
//课时学后测试,点击重学 | //课时学后测试,点击重学 | ||||
// TODO: 2022/4/22 清除当前课时数据,并更新当前课时,后进入学习界面 | // 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 -> { | AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN -> { | ||||
//学后测试,再测一次 | //学后测试,再测一次 | ||||
loadLessonAfterTest(vm.allLesson[learnEventData.leesonPositionIndex]) | loadLessonAfterTest(vm.allLesson[learnEventData.leesonPositionIndex]) | ||||
} | } | ||||
//下一步 | |||||
AppConstants.ACTION_LESSON_AFTER_TEST_NEXT -> { | AppConstants.ACTION_LESSON_AFTER_TEST_NEXT -> { | ||||
//下一课时 or 下一步(提示课程学习完成) | //下一课时 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 -> { | else -> { | ||||
var nextLessonPosition = -1 | 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) { | if (!vm.allLesson[i].learnIsOver) { | ||||
nextLessonPosition = i | nextLessonPosition = i | ||||
break | break | ||||
val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager | val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager | ||||
val findFirstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition() //第一个可见位置 | val findFirstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition() //第一个可见位置 | ||||
val findLastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition() //最后一个可见位置 | 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 | recycleViewScrollListener.lessonPosition = nextLessonPosition | ||||
binding.recyclerView.addOnScrollListener(recycleViewScrollListener) | binding.recyclerView.addOnScrollListener(recycleViewScrollListener) | ||||
binding.recyclerView.smoothScrollToPosition(nextLessonPosition) | binding.recyclerView.smoothScrollToPosition(nextLessonPosition) | ||||
var lessonPosition = 0 | var lessonPosition = 0 | ||||
override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) { | override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) { | ||||
super.onScrollStateChanged(recyclerView, newState) | super.onScrollStateChanged(recyclerView, newState) | ||||
if (newState == RecyclerView.SCROLL_STATE_IDLE){ | |||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) { | |||||
binding.recyclerView.removeOnScrollListener(this) | binding.recyclerView.removeOnScrollListener(this) | ||||
val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager | 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() | |||||
} | } | ||||
} | } | ||||
} | } | ||||
private val onLessonClick : (v : View, position : Int, lesson : Lesson) -> Unit = { view, position, entity -> | private val onLessonClick : (v : View, position : Int, lesson : Lesson) -> Unit = { view, position, entity -> | ||||
when (entity.lessonType) { | when (entity.lessonType) { | ||||
AppConstants.LESSON_TYPE_WORD -> { | 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 -> { | AppConstants.LESSON_TYPE_SENTENCE -> { | ||||
* @param lesson Lesson 课时 | * @param lesson Lesson 课时 | ||||
*/ | */ | ||||
private fun startLearn(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 -> { | |||||
} | |||||
} | } | ||||
} | } | ||||
/** lesson的学习 lessonType 为 word类型 */ | /** 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) { | 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() { | 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") | |||||
} | |||||
} | } | ||||
package com.xkl.cdl.module.m_center_learn.coursechildren | package com.xkl.cdl.module.m_center_learn.coursechildren | ||||
import android.os.Bundle | import android.os.Bundle | ||||
import androidx.fragment.app.Fragment | |||||
import androidx.lifecycle.ViewModel | import androidx.lifecycle.ViewModel | ||||
import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
import com.jeremyliao.liveeventbus.LiveEventBus | |||||
import com.suliang.common.AppConfig | import com.suliang.common.AppConfig | ||||
import com.suliang.common.base.fragment.BaseFragmentVM | import com.suliang.common.base.fragment.BaseFragmentVM | ||||
import com.suliang.common.eventbus.LiveDataBus | |||||
import com.suliang.common.extension.replaceFragment | import com.suliang.common.extension.replaceFragment | ||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.R | import com.xkl.cdl.R | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.data.DataTransferHolder | import com.xkl.cdl.data.DataTransferHolder | ||||
} | } | ||||
} | } | ||||
/**标记当前显示的fragment*/ | |||||
private lateinit var currentFragment : Fragment | |||||
override fun initViewModel() : CourseMainFragmentViewModel { | 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] | coursePackMainActivityVM = ViewModelProvider(requireActivity())[CoursePackMainActivityViewModel::class.java] | ||||
// LogUtil.e("CourseMainFragment coursePackMainActivityVM hashCode -> ${coursePackMainActivityVM.hashCode()}") | |||||
} | } | ||||
lifecycle.addObserver(vmmodel) | |||||
return vmmodel | |||||
} | } | ||||
override fun initFragment() { | override fun initFragment() { | ||||
//设置课程 和 需要操作的类型 | //设置课程 和 需要操作的类型 | ||||
vm.course = vm.coursePackMainActivityVM.coursePack.childrenCourses[vm.courseIndex].apply { | 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 | if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe | ||||
when (it.actionFlag) { | 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 -> { | AppConstants.DATA_COURSE_BEFORE_TEST_OVER -> { | ||||
vm.courseDetail.st_before = it.scoreValue.toDouble() //学前总分 | vm.courseDetail.st_before = it.scoreValue.toDouble() //学前总分 | ||||
} | } | ||||
} | } | ||||
} | } | ||||
//学后总测结束传递数据回来。更新数据 | |||||
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() { | override fun loadData() { | ||||
LogUtil.e("CourseMainFragment 加载数据 --》 ${vm.courseIndex}") | |||||
vm.loadMain().observe(this) { | vm.loadMain().observe(this) { | ||||
changeChildrenFragment() | changeChildrenFragment() | ||||
} | } | ||||
* 改变加载的子Fragment | * 改变加载的子Fragment | ||||
*/ | */ | ||||
private fun changeChildrenFragment() { | 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 { | vm.courseDetail.run { | ||||
if (st_before == AppConstants.NOT_DOING) { //学前总测未做 | 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) { //学习未完成 | } else if (courseLearnProgress != 100.0) { //学习未完成 | ||||
replaceFragment(R.id.layout_root, CourseLessonFragment.newInstance()) | |||||
currentFragment = CourseLessonFragment.newInstance() | |||||
replaceFragment(R.id.layout_root, currentFragment) | |||||
} else { //学习完成,学后总测试界面 | } 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) | |||||
} | } | ||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
fun changeFragment(position : Int) { | fun changeFragment(position : Int) { | ||||
when (position) { | 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) | |||||
} | |||||
} | } | ||||
} | } | ||||
LearnExamActivity.newInstance(requireContext()) | LearnExamActivity.newInstance(requireContext()) | ||||
} | } | ||||
override fun onDestroy() { | |||||
super.onDestroy() | |||||
//退出本课程后移除该课程的事件监听 | |||||
// LiveDataBus.remove(AppConstants.EVENT_COURSE) | |||||
/** 课程重学方法 */ | |||||
fun courseRelearn() { | |||||
//调用重学,重学重新加载数据,重新加载界面 | |||||
vm.relearnCourse().observe(this){ | |||||
loadData() | |||||
} | |||||
} | } | ||||
package com.xkl.cdl.module.m_center_learn.coursechildren | package com.xkl.cdl.module.m_center_learn.coursechildren | ||||
import androidx.lifecycle.LifecycleOwner | |||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import com.suliang.common.base.viewmodel.BaseViewModel | import com.suliang.common.base.viewmodel.BaseViewModel | ||||
import com.suliang.common.extension.diskIo2DiskIo | import com.suliang.common.extension.diskIo2DiskIo | ||||
import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
import com.suliang.common.util.DateUtil | 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.LearnWord | ||||
import com.xkl.cdl.data.bean.course.Course | import com.xkl.cdl.data.bean.course.Course | ||||
import com.xkl.cdl.data.bean.course.CourseDetail | import com.xkl.cdl.data.bean.course.CourseDetail | ||||
import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
import com.xkl.cdl.data.bean.course.Lesson | import com.xkl.cdl.data.bean.course.Lesson | ||||
import com.xkl.cdl.data.bean.intentdata.LearnData | 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.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import com.xkl.cdl.data.repository.DataRepository | import com.xkl.cdl.data.repository.DataRepository | ||||
import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
import io.reactivex.rxjava3.functions.BiFunction | import io.reactivex.rxjava3.functions.BiFunction | ||||
import mqComsumerV1.Struct | import mqComsumerV1.Struct | ||||
import java.io.File | |||||
import java.util.* | import java.util.* | ||||
import kotlin.collections.HashMap | import kotlin.collections.HashMap | ||||
//获取课程的复习数据 | //获取课程的复习数据 | ||||
//获取课程的章节数据 | //获取课程的章节数据 | ||||
fun loadMain() : MutableLiveData<Boolean> { | fun loadMain() : MutableLiveData<Boolean> { | ||||
// showHideLoading(true) | |||||
val mutableLiveData = MutableLiveData<Boolean>() | val mutableLiveData = MutableLiveData<Boolean>() | ||||
Observable.zip(DataRepository.getCourseStatistics().flatMap { | |||||
Observable.zip(DataRepository.getCourseStatistics(course.subjectId,course.coursePackId,course.courseId).flatMap { | |||||
courseDetail = it | courseDetail = it | ||||
course.courseLearnProgress = it.courseLearnProgress | |||||
return@flatMap DataRepository.getCourseAllLesson(dbControlBase, it) | return@flatMap DataRepository.getCourseAllLesson(dbControlBase, it) | ||||
}.flatMap { | }.flatMap { | ||||
allLesson = it | allLesson = it | ||||
}, | }, | ||||
DataRepository.getReviewData(), | DataRepository.getReviewData(), | ||||
BiFunction<HashMap<String, Long>, Array<String>, Boolean> { t1 : HashMap<String, Long>?, t2 : Array<String>? -> | BiFunction<HashMap<String, Long>, Array<String>, Boolean> { t1 : HashMap<String, Long>?, t2 : Array<String>? -> | ||||
// TODO: 2022/5/5 初始化需要复习的数据 | |||||
showMoreIsEnable() | |||||
true | true | ||||
}).compose(diskIo2Main()).subscribe { | }).compose(diskIo2Main()).subscribe { | ||||
// showHideLoading(false) | |||||
mutableLiveData.value = it | mutableLiveData.value = it | ||||
} | } | ||||
return mutableLiveData | return mutableLiveData | ||||
} | } | ||||
/** 课程包主页上的更多按钮点击是否有效 */ | |||||
private fun showMoreIsEnable(){ | |||||
coursePackMainActivityVM.showMoreEnable = courseDetail.st_before != AppConstants.NOT_DOING | |||||
} | |||||
/** | /** | ||||
* 获取课程的测试数据 | * 获取课程的测试数据 | ||||
* @param testType Int 测试类型 | * @param testType Int 测试类型 | ||||
.subscribe { | .subscribe { | ||||
result.value = LearnData(lesson).apply { | result.value = LearnData(lesson).apply { | ||||
learnWordList = it | learnWordList = it | ||||
examErrorMap = courseDetail.exam_w_r_list | |||||
} | } | ||||
} | } | ||||
return result | return result | ||||
}.compose(diskIo2DiskIo()).subscribe() | }.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) | |||||
} | |||||
} | } |
import com.xkl.cdl.data.bean.intentdata.ExamData | import com.xkl.cdl.data.bean.intentdata.ExamData | ||||
import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
import com.xkl.cdl.databinding.FragmentCourseTotalTestBinding | import com.xkl.cdl.databinding.FragmentCourseTotalTestBinding | ||||
import com.xkl.cdl.module.m_center_learn.CoursePackMainActivity | |||||
/** | /** | ||||
* 课程总测试: 学前总,学后总 | * 课程总测试: 学前总,学后总 | ||||
* @property totalTestType 测试类型 | * @property totalTestType 测试类型 | ||||
*/ | */ | ||||
class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, CourseMainFragmentViewModel>() { | class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, CourseMainFragmentViewModel>() { | ||||
companion object { | companion object { | ||||
@JvmStatic | @JvmStatic | ||||
fun newInstance(totalTestType: Int) = CourseTotalTestFragment().apply { | |||||
fun newInstance(totalTestType : Int) = CourseTotalTestFragment().apply { | |||||
arguments = Bundle().apply { | arguments = Bundle().apply { | ||||
putInt(AppConfig.INTENT_1, totalTestType) | putInt(AppConfig.INTENT_1, totalTestType) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
override fun initViewModel(): CourseMainFragmentViewModel { | |||||
override fun initViewModel() : CourseMainFragmentViewModel { | |||||
return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java] | return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java] | ||||
} | } | ||||
//由于使用的是与父类相同的loadingEvent,所以将此evnet移除 | //由于使用的是与父类相同的loadingEvent,所以将此evnet移除 | ||||
vm.loadingEvent.removeObservers(this) | vm.loadingEvent.removeObservers(this) | ||||
} | } | ||||
//传递过来的总测类型: 学前,学后 | //传递过来的总测类型: 学前,学后 | ||||
private var totalTestType = 0 | private var totalTestType = 0 | ||||
//测试的数据 | //测试的数据 | ||||
private var testData : List<ExamBean> = emptyList() | private var testData : List<ExamBean> = emptyList() | ||||
override fun initFragment() { | override fun initFragment() { | ||||
totalTestType = requireArguments().getInt(AppConfig.INTENT_1) | totalTestType = requireArguments().getInt(AppConfig.INTENT_1) | ||||
} | } | ||||
override fun loadData() { | override fun loadData() { | ||||
vm.loadTest(totalTestType).observe(this){ | |||||
vm.loadTest(totalTestType).observe(this) { | |||||
testData = it | testData = it | ||||
initView() | 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) { | when (totalTestType) { | ||||
AppConstants.TEST_TYPE_BEFORE_TOTAL -> { | AppConstants.TEST_TYPE_BEFORE_TOTAL -> { | ||||
// TODO: 2022/4/21 需要把开始学习给取消了 | // TODO: 2022/4/21 需要把开始学习给取消了 | ||||
tvTitle.setText(R.string.tips_current_course_learn_over) | tvTitle.setText(R.string.tips_current_course_learn_over) | ||||
tvMainTip.visibility = View.VISIBLE | tvMainTip.visibility = View.VISIBLE | ||||
//根据测试成绩处理 | //根据测试成绩处理 | ||||
vm.courseDetail.st_before = 81.0 | |||||
vm.courseDetail.st_before.let { | vm.courseDetail.st_before.let { | ||||
when { | |||||
it == -1.0 -> { //未测 | |||||
when (it) { | |||||
AppConstants.NOT_DOING -> { //未测 | |||||
tvMainTip.setText(R.string.test_total_after_tip_1) | tvMainTip.setText(R.string.test_total_after_tip_1) | ||||
button2.run { | button2.run { | ||||
setText(R.string.test_type_after_total) | setText(R.string.test_type_after_total) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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 | tvTips.visibility = View.VISIBLE | ||||
tvCountTip.visibility = View.GONE | tvCountTip.visibility = View.GONE | ||||
button1.run { | button1.run { | ||||
} | } | ||||
} | } | ||||
tvClearLearnRecord.visibility = View.VISIBLE | tvClearLearnRecord.visibility = View.VISIBLE | ||||
tvClearLearnRecord.click { | |||||
(activity as CoursePackMainActivity).showCourseRelearnDialog() | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/**继续学习*/ | /**继续学习*/ | ||||
private fun continueLearn(view: View) { | |||||
private fun continueLearn(view : View) { | |||||
(requireParentFragment() as CourseMainFragment).changeFragment(1) | (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 { | val examData = ExamData(vm.course.subjectId, totalTestType, vm.course.courseTitle, vm.course.courseTitle).apply { | ||||
coursePackId = vm.course.coursePackId | coursePackId = vm.course.coursePackId | ||||
} | } | ||||
(parentFragment as CourseMainFragment).startExam(examData) | (parentFragment as CourseMainFragment).startExam(examData) | ||||
} | } | ||||
} | } |
import android.os.Bundle | import android.os.Bundle | ||||
import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
import com.suliang.common.base.activity.BaseActivityVM | import com.suliang.common.base.activity.BaseActivityVM | ||||
import com.suliang.common.eventbus.LiveDataBus | |||||
import com.suliang.common.extension.loadFragment | import com.suliang.common.extension.loadFragment | ||||
import com.suliang.common.extension.showHideFragment | import com.suliang.common.extension.showHideFragment | ||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.R | import com.xkl.cdl.R | ||||
import com.xkl.cdl.databinding.ActivityMainBinding | import com.xkl.cdl.databinding.ActivityMainBinding | ||||
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment | import com.xkl.cdl.module.m_center_learn.LearnCenterFragment | ||||
import com.xkl.cdl.module.m_my.MyFragment | import com.xkl.cdl.module.m_my.MyFragment | ||||
import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | ||||
import com.xkl.cdl.module.m_statics.StaticsFragment | import com.xkl.cdl.module.m_statics.StaticsFragment | ||||
import com.xkl.cdl.module.splash.SplashActivity | |||||
/** | /** | ||||
* 主界面、控制切换子Fragment | * 主界面、控制切换子Fragment |
package com.xkl.cdl.util | package com.xkl.cdl.util | ||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.data.bean.BaseWord | import com.xkl.cdl.data.bean.BaseWord | ||||
import java.io.* | import java.io.* | ||||
import java.util.* | import java.util.* | ||||
currentCorrectMap[key] = true | currentCorrectMap[key] = true | ||||
} | } | ||||
if (isLearnFirst) currentIsError = false | if (isLearnFirst) currentIsError = false | ||||
LogUtil.e("currentCorrectMap--->${currentCorrectMap.size} --> $currentCorrectMap") | |||||
} | } | ||||
/** | /** | ||||
} else if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key)) { //测试中数据的错误 | } else if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key)) { //测试中数据的错误 | ||||
currentErrorMap[key] = true | currentErrorMap[key] = true | ||||
} | } | ||||
LogUtil.e("currentErrorMap --->${currentErrorMap.size} $currentErrorMap") | |||||
//开始进行数据扩容替换 | //开始进行数据扩容替换 | ||||
replaceErrorToNull(item) //替换已有错误为空 | replaceErrorToNull(item) //替换已有错误为空 | ||||
insertErrorWord(item, false) //开始插入 | insertErrorWord(item, false) //开始插入 | ||||
* @return true在 false不存在 | * @return true在 false不存在 | ||||
*/ | */ | ||||
fun isInExamErrorMap(key : String) : Boolean { | fun isInExamErrorMap(key : String) : Boolean { | ||||
return examErrorsMap?.getOrDefault(key, null) ?: false | |||||
return examErrorsMap?.getOrDefault(key, false) ?: false | |||||
} | } | ||||
/** 是否是在学习的错误列表中 */ | /** 是否是在学习的错误列表中 */ |
android:visibility="gone" | android:visibility="gone" | ||||
/> | /> | ||||
<!--所有布局id--> | <!--所有布局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–>--> | <!-- <!–学前总测试控制显示的布局id–>--> | ||||
<!-- <androidx.constraintlayout.widget.Group--> | <!-- <androidx.constraintlayout.widget.Group--> | ||||
<!-- android:id="@+id/group_total_test"--> | <!-- android:id="@+id/group_total_test"--> | ||||
/> --> | /> --> | ||||
<!--课时正常学习结束的布局组 --> | |||||
<!-- 课时完全结束的点击显示弹窗的布局组 --> | |||||
<!-- <androidx.constraintlayout.widget.Group--> | <!-- <androidx.constraintlayout.widget.Group--> | ||||
<!-- android:layout_width="wrap_content"--> | <!-- android:layout_width="wrap_content"--> | ||||
<!-- android:layout_height="wrap_content"--> | <!-- android:layout_height="wrap_content"--> |
android:layout_marginStart="28dp" | android:layout_marginStart="28dp" | ||||
android:layout_marginTop="8dp" | android:layout_marginTop="8dp" | ||||
android:text="@string/error" | android:text="@string/error" | ||||
android:textColor="@color/gray_2" | |||||
android:textColor="@color/main_text_color" | |||||
android:textSize="@dimen/smallerSize" | android:textSize="@dimen/smallerSize" | ||||
app:layout_constraintStart_toEndOf="@+id/guideline_1" | app:layout_constraintStart_toEndOf="@+id/guideline_1" | ||||
app:layout_constraintTop_toTopOf="parent" /> | app:layout_constraintTop_toTopOf="parent" /> |
<string name="auto_playing">自动播放中···</string> | <string name="auto_playing">自动播放中···</string> | ||||
<string name="quit_learn_title">你确定要退出本课程的学习吗?</string> | <string name="quit_learn_title">你确定要退出本课程的学习吗?</string> | ||||
<string name="quit_learn_content">退出后系统将保存你的学习进度</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> | </resources> |
grpc_android: "io.grpc:grpc-android:1.27.0", | grpc_android: "io.grpc:grpc-android:1.27.0", | ||||
grpc_protobuf: "io.grpc:grpc-protobuf:1.27.0", | grpc_protobuf: "io.grpc:grpc-protobuf:1.27.0", | ||||
grpc_stub: "io.grpc:grpc-stub: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" | |||||
] | ] | ||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' | ||||
//MMKV | //MMKV | ||||
api customDependencies.MMKV | api customDependencies.MMKV | ||||
// liveEventBus | |||||
api customDependencies.liveEventBus | |||||
* Describe: 打印生命周期的Activity | * Describe: 打印生命周期的Activity | ||||
*/ | */ | ||||
open class LifecycleLogActivity : AppCompatActivity() { | 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()") | |||||
// } | |||||
} | } |
override fun initFirst() { | override fun initFirst() { | ||||
vm = initViewModel() | vm = initViewModel() | ||||
lifecycle.addObserver(vm) | |||||
vm.pageEvent.observe(this) { startActivity(it) } | vm.pageEvent.observe(this) { startActivity(it) } | ||||
vm.toastEvent.observe(this){ showToast(it) } | vm.toastEvent.observe(this){ showToast(it) } | ||||
vm.loadingEvent.observe(this) { | vm.loadingEvent.observe(this) { |
open class BaseViewModel : ViewModel(), ViewModelLifecycle, ViewBehavior { | open class BaseViewModel : ViewModel(), ViewModelLifecycle, ViewBehavior { | ||||
override fun onCreate(owner: LifecycleOwner) { | override fun onCreate(owner: LifecycleOwner) { | ||||
super.onCreate(owner) | super.onCreate(owner) | ||||
LogUtil.i("${javaClass.name} onCreate() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onCreate() ") | |||||
} | } | ||||
override fun onStart(owner: LifecycleOwner) { | override fun onStart(owner: LifecycleOwner) { | ||||
super.onStart(owner) | super.onStart(owner) | ||||
LogUtil.i("${javaClass.name} onStart() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onStart() ") | |||||
} | } | ||||
override fun onResume(owner: LifecycleOwner) { | override fun onResume(owner: LifecycleOwner) { | ||||
super.onResume(owner) | super.onResume(owner) | ||||
LogUtil.i("${javaClass.name} onResume() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onResume() ") | |||||
} | } | ||||
override fun onPause(owner: LifecycleOwner) { | override fun onPause(owner: LifecycleOwner) { | ||||
super.onPause(owner) | super.onPause(owner) | ||||
LogUtil.i("${javaClass.name} onPause() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onPause() ") | |||||
} | } | ||||
override fun onStop(owner: LifecycleOwner) { | override fun onStop(owner: LifecycleOwner) { | ||||
super.onStop(owner) | super.onStop(owner) | ||||
LogUtil.i("${javaClass.name} onStop() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onStop() ") | |||||
} | } | ||||
override fun onDestroy(owner: LifecycleOwner) { | override fun onDestroy(owner: LifecycleOwner) { | ||||
super.onDestroy(owner) | super.onDestroy(owner) | ||||
LogUtil.i("${javaClass.name} onDestroy() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onDestroy() ") | |||||
} | } | ||||
override fun onCleared() { | override fun onCleared() { | ||||
super.onCleared() | super.onCleared() | ||||
LogUtil.i("${javaClass.name} onCleared() ") | |||||
LogUtil.i("${javaClass.name}_${hashCode()} onCleared() ") | |||||
} | } | ||||
package com.suliang.common.eventbus | package com.suliang.common.eventbus | ||||
import android.os.Looper | |||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
/** | /** | ||||
* author suliang | * author suliang | ||||
* create 2022/3/15 10:01 | * create 2022/3/15 10:01 | ||||
* Describe: 事件总线,这条总线把任何类中的数据直接传递到activity 或是 fragment 上 | * 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 { | 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>>() | |||||
// /** | // /** | ||||
// * 注册订阅者 | // * 注册订阅者 | ||||
//java使用传入泛型class, kotlin使用可直接传入泛型,不需要class类型 | //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> | |||||
// } | |||||
} | } |
* author suliang | * author suliang | ||||
* create 2022/3/15 10:51 | * create 2022/3/15 10:51 | ||||
* Describe: 非粘性LiveData ,需要先设置监听再发送数据,即后注册的监听收不到以前的监听 | * 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>) { | override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { | ||||
super.observe(owner, observer) | super.observe(owner, observer) | ||||
hook(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 | //得到 mLastVersion | ||||
//获取到LiveData的类中的mObserver对象 | //获取到LiveData的类中的mObserver对象 | ||||
// SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers | // SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers | ||||
//得到map对应的class对象 | //得到map对应的class对象 | ||||
val mObserversClass = mObserVersObject.javaClass | val mObserversClass = mObserVersObject.javaClass | ||||
//获取到mObservers对象的get方法 | //获取到mObservers对象的get方法 | ||||
val get:Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||||
val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||||
get.isAccessible = true | get.isAccessible = true | ||||
//执行get方法,获取到对象 | //执行get方法,获取到对象 | ||||
val invokeEntry = get.invoke(mObserVersObject, observer) | val invokeEntry = get.invoke(mObserVersObject, observer) | ||||
val observerWrapper = if (invokeEntry is Map.Entry<*, *>) { | val observerWrapper = if (invokeEntry is Map.Entry<*, *>) { | ||||
invokeEntry.value | invokeEntry.value | ||||
} else throw NullPointerException("observerWrapper is null") | } else throw NullPointerException("observerWrapper is null") | ||||
//得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass | //得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass | ||||
//getClass 返回对应的当前正在运行是的类所对应的 | //getClass 返回对应的当前正在运行是的类所对应的 | ||||
val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion") | val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion") | ||||
mVersion.isAccessible = true | mVersion.isAccessible = true | ||||
//把mVersion数据填入到mLastVersion中 | //把mVersion数据填入到mLastVersion中 | ||||
val mVersionValue = mVersion.get(this) | val mVersionValue = mVersion.get(this) | ||||
mLastVersion.set(observerWrapper,mVersionValue) | |||||
}catch (e: Exception){ | |||||
mLastVersion.set(observerWrapper, mVersionValue) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | e.printStackTrace() | ||||
} | } | ||||
} | } |
} | } | ||||
this.setOnTouchListener{ view , motionEvent -> | this.setOnTouchListener{ view , motionEvent -> | ||||
when(motionEvent.action){ | when(motionEvent.action){ | ||||
MotionEvent.ACTION_DOWN -> view.alpha = 0.7f | |||||
MotionEvent.ACTION_DOWN -> view.alpha = 0.8f | |||||
MotionEvent.ACTION_UP -> view.alpha = 1f | MotionEvent.ACTION_UP -> view.alpha = 1f | ||||
else -> view.alpha = 1f | else -> view.alpha = 1f | ||||
} | } |
closeStream(out) | closeStream(out) | ||||
return result | return result | ||||
} | } | ||||
/*** | |||||
* 从对象获取字节数组 | |||||
* @param data Any 对象,需要实现序列化 | |||||
* @return ByteArray 字节数组 | |||||
* @throws Exception | |||||
*/ | |||||
@Throws(Exception::class) | @Throws(Exception::class) | ||||
fun objectToBytes(data: Any): ByteArray { | |||||
fun objectToBytes(data: Serializable): ByteArray { | |||||
var oos: ObjectOutputStream? = null | var oos: ObjectOutputStream? = null | ||||
return try { | return try { | ||||
val bos = ByteArrayOutputStream() | val bos = ByteArrayOutputStream() | ||||
oos?.close() | oos?.close() | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 从字节数组获取对象 | |||||
* @param data ByteArray | |||||
* @return Any | |||||
*/ | |||||
fun bytesToObject(data:ByteArray): Any{ | |||||
return ObjectInputStream(ByteArrayInputStream(data)).readObject() | |||||
} | |||||
/** | /** | ||||
* 获取文件大小 | * 获取文件大小 |
<resources> | <resources> | ||||
<!-- TODO: Remove or change this placeholder text --> | |||||
<string name="hello_blank_fragment">Hello blank fragment</string> | |||||
</resources> | </resources> |