Browse Source

learn

master
suliang 2 years ago
parent
commit
46d0154889
40 changed files with 956 additions and 392 deletions
  1. 1
    0
      .idea/misc.xml
  2. 3
    1
      app/src/main/java/com/xkl/cdl/Extension.kt
  3. 15
    10
      app/src/main/java/com/xkl/cdl/adapter/AdapterLesson.kt
  4. 20
    3
      app/src/main/java/com/xkl/cdl/data/AppConstants.kt
  5. 5
    11
      app/src/main/java/com/xkl/cdl/data/bean/LearnDialogBean.kt
  6. 2
    0
      app/src/main/java/com/xkl/cdl/data/bean/course/Course.kt
  7. 6
    3
      app/src/main/java/com/xkl/cdl/data/bean/course/CourseDetail.kt
  8. 2
    2
      app/src/main/java/com/xkl/cdl/data/bean/course/Lesson.kt
  9. 32
    1
      app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt
  10. 2
    2
      app/src/main/java/com/xkl/cdl/data/manager/db/DBCourseManager.kt
  11. 6
    6
      app/src/main/java/com/xkl/cdl/data/repository/AudioCache.kt
  12. 11
    2
      app/src/main/java/com/xkl/cdl/data/repository/DataRepository.kt
  13. 7
    7
      app/src/main/java/com/xkl/cdl/data/repository/PhotoCache.kt
  14. 0
    17
      app/src/main/java/com/xkl/cdl/dialog/DialogEventAction.kt
  15. 107
    11
      app/src/main/java/com/xkl/cdl/dialog/LearnDialog.kt
  16. 43
    18
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt
  17. 22
    17
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamViewModel.kt
  18. 12
    10
      app/src/main/java/com/xkl/cdl/module/learn/LearnWordActivity.kt
  19. 9
    9
      app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt
  20. 39
    8
      app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackMainActivity.kt
  21. 5
    3
      app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackMainActivityViewModel.kt
  22. 169
    43
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseLessonFragment.kt
  23. 57
    31
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragment.kt
  24. 136
    3
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragmentViewModel.kt
  25. 25
    37
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseTotalTestFragment.kt
  26. 0
    3
      app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt
  27. 4
    1
      app/src/main/java/com/xkl/cdl/util/LearnRuleUtil.kt
  28. 18
    12
      app/src/main/res/layout/dialog_lesson_learn.xml
  29. 1
    1
      app/src/main/res/layout/inc_over_number.xml
  30. 3
    0
      app/src/main/res/values/strings.xml
  31. 2
    0
      build.gradle
  32. 2
    0
      lib/common/build.gradle
  33. 44
    44
      lib/common/src/main/java/com/suliang/common/base/activity/LifecycleLogActivity.kt
  34. 1
    0
      lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragmentVM.kt
  35. 7
    7
      lib/common/src/main/java/com/suliang/common/base/viewmodel/BaseViewModel.kt
  36. 87
    47
      lib/common/src/main/java/com/suliang/common/eventbus/LiveDataBus.kt
  37. 32
    17
      lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLivedata.kt
  38. 1
    1
      lib/common/src/main/java/com/suliang/common/extension/ViewClickExtension.kt
  39. 17
    2
      lib/common/src/main/java/com/suliang/common/util/file/FileUtil.kt
  40. 1
    2
      lib/common/src/main/res/values/strings.xml

+ 1
- 0
.idea/misc.xml View File

@@ -63,6 +63,7 @@
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_total_test.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_first.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.20104166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" />

+ 3
- 1
app/src/main/java/com/xkl/cdl/Extension.kt View File

@@ -1,5 +1,6 @@
package com.xkl.cdl

import android.annotation.SuppressLint
import android.util.TypedValue
import android.view.View
import android.widget.LinearLayout
@@ -20,6 +21,7 @@ import com.xkl.cdl.databinding.IncWordDetailBinding
* @param example String? 例句
* @param refrence String? 参考
*/
@SuppressLint("SetTextI18n")
fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence : String?){
phrase?.let {
tvPhraseFlag.visibility = View.VISIBLE
@@ -45,7 +47,7 @@ fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence
example?.let {
tvExampleFlag.visibility = View.VISIBLE
tvExample.visibility = View.VISIBLE
tvExample.text = example
tvExample.text = "▪ ${it.replace("\n", "\n▪ ")}"
}?:let {
tvExampleFlag.visibility = View.GONE
tvExample.visibility = View.GONE

+ 15
- 10
app/src/main/java/com/xkl/cdl/adapter/AdapterLesson.kt View File

@@ -78,6 +78,15 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C
}
}
}
private val normalColorNotLearnOver by lazy {
ContextCompat.getColor(context, R.color.gray_2) //学习未完成未选中时的颜色
}
private val normalColorLearnOver by lazy { ContextCompat.getColor(context, R.color.gray_1) } //学习已完成未选中时的颜色
private val mainTextColor by lazy {ContextCompat.getColor(context, R.color.main_text_color) } //选中颜色
private val translationColor by lazy {ContextCompat.getColor(context, R.color.translation) } //透明颜色
private val themeColor by lazy { ContextCompat.getColor(context,R.color.theme_color) } //主题颜色

/**
* 处理颜色 选中色 未选中色(学习完成/学习未完成)
@@ -86,10 +95,6 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C
* @param lesson Lesson
*/
private fun ItemCourseLessonBinding.initColor(position: Int, lesson: Lesson) {
val normalColorNotLearnOver = ContextCompat.getColor(context, R.color.gray_2) //学习未完成未选中时的颜色
val normalColorLearnOver = ContextCompat.getColor(context, R.color.gray_1) //学习已完成未选中时的颜色
val mainTextColor = ContextCompat.getColor(context, R.color.main_text_color) //选中颜色
val translationColor = ContextCompat.getColor(context, R.color.translation) //透明颜色
//item的背景和状态设置
if (selectPos == position) { //选中,背景设置
layoutContent.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_3)) //选中背景
@@ -106,7 +111,7 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C
}
} else { //未选中:根据学习情况判断
layoutContent.setBackgroundColor(translationColor) //未选中背景透明
if (lesson.learnIsOver) {
if (lesson.learnIsOver) { //学习完成
tvLessonName.run {
setTextColor(normalColorLearnOver) //课时名称颜色
paint.isFakeBoldText = false //加粗
@@ -114,10 +119,10 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C
tvLessonNumber.setTextColor(normalColorLearnOver) //数量颜色
ivArrowRight.run {
setBackgroundColor(translationColor)
imageTintList = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.theme_color))
strokeColor = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.theme_color))
imageTintList = ColorStateList.valueOf(normalColorLearnOver)
strokeColor = ColorStateList.valueOf(normalColorLearnOver)
}
} else {
} else { //未完成
tvLessonName.run {
setTextColor(normalColorNotLearnOver) //课时名称颜色
paint.isFakeBoldText = false //加粗
@@ -125,8 +130,8 @@ class AdapterLesson(vm: CourseMainFragmentViewModel) : BaseRVAdapterVM<Lesson, C
tvLessonNumber.setTextColor(normalColorNotLearnOver) //数量颜色
ivArrowRight.run {
setBackgroundColor(translationColor)
imageTintList = ColorStateList.valueOf(normalColorNotLearnOver)
strokeColor = ColorStateList.valueOf(normalColorNotLearnOver)
imageTintList = ColorStateList.valueOf(themeColor)
strokeColor = ColorStateList.valueOf(themeColor)
}
}
}

+ 20
- 3
app/src/main/java/com/xkl/cdl/data/AppConstants.kt View File

@@ -154,10 +154,19 @@ object AppConstants {
const val DIALOG_TYPE_EXAM_OVER = 2
/** 对话框类型: 学习结束弹窗类型 */
const val DIALOG_TYPE_LEARN_OVER = 3
/**对话框类型,item学习完成*/
const val DIALOG_TYPE_LESSON_ITEM_OVER = 4
/**--- 总线动作 --------------------------------- */
/**action key 改变界面 到目录页 */
const val EVENT_COURSE = "action_change_page"
const val EVENT_CHANGE_PAGE = "action_change_page"
/** lesson学习 数据传递 */
const val EVENT_LESSON_DATA = "lesson_learn_data"
/** lesson学习中动作事件 : 课时学习中的动作*/
const val EVENT_LESSON_ACTION = "lesson_learn_action"
/**总测数据与动作*/
const val EVENT_TOTAL_TEST = "total_test"
/** 事件动作:学前总测结束弹窗之 开始学习 */
const val ACTION_COURSE_TEST_START_LEARN = 1
@@ -177,6 +186,12 @@ object AppConstants {
const val ACTION_LESSON_AFTER_TEST_NEXT = 8
/**数据动作: 课时学习完成*/
const val DATA_LESSON_LEARN_OVER = 9
/**学后总测试完成: 再测一次*/
const val ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN = 10
/** 学后总测试完成,切换到目录页显示 */
const val ACTION_COURSE_TEST_AFTER_TOTAL_OVER = 11
/**学后总测结束,传递数据*/
const val DATA_COURSE_AFTER_TEST_OVER = 12
/**--- 弹窗动作 --------------------------------- */
/** 学前总测结束弹窗: 开始学习 ,课时学前测试开始弹窗*/
@@ -189,6 +204,8 @@ object AppConstants {
const val DIALOG_LESSON_AFTER_TEST_AGAIN = 4
/**课时学后测试弹窗动作: 下一步*/
const val DIALOG_LESSON_AFTER_TEST_NEXT = 5
/**弹窗动作提示: 完成*/
const val DIALOG_OVER = 6
/**课时学后总测的再测一次*/
const val DIALOG_AFTER_TOTAL_TEST_AGAIN = 7
}

+ 5
- 11
app/src/main/java/com/xkl/cdl/data/bean/LearnDialogBean.kt View File

@@ -29,7 +29,7 @@ import android.os.Parcelable
* 词汇量测试
*
*/
class LearnDialogBean(val dialogType:Int) : Parcelable {
class LearnDialogBean(val dialogType:Int) :Parcelable {
/*---------------测试使用------------------------------------*/
/** 测试类型 */
@@ -46,19 +46,13 @@ class LearnDialogBean(val dialogType:Int) : Parcelable {
/** 题数与时间 */
var showTimeCount = ""
constructor(parcel : Parcel) : this(parcel.readInt()) {
examType = parcel.readInt()
score = parcel.readInt()
correctNumber = parcel.readInt()
errorNumber = parcel.readInt()
chapter_lesson_name = parcel.readString().toString()
showTimeCount = parcel.readString().toString()
}
override fun writeToParcel(parcel : Parcel, flags : Int) {
@@ -67,6 +61,8 @@ class LearnDialogBean(val dialogType:Int) : Parcelable {
parcel.writeInt(score)
parcel.writeInt(correctNumber)
parcel.writeInt(errorNumber)
parcel.writeString(chapter_lesson_name)
parcel.writeString(showTimeCount)
}
override fun describeContents() : Int {
@@ -82,6 +78,4 @@ class LearnDialogBean(val dialogType:Int) : Parcelable {
return arrayOfNulls(size)
}
}
}

+ 2
- 0
app/src/main/java/com/xkl/cdl/data/bean/course/Course.kt View File

@@ -1,5 +1,7 @@
package com.xkl.cdl.data.bean.course

import androidx.databinding.BaseObservable

/**
* author suliang
* create 2022/3/22 10:08

+ 6
- 3
app/src/main/java/com/xkl/cdl/data/bean/course/CourseDetail.kt View File

@@ -1,15 +1,18 @@
package com.xkl.cdl.data.bean.course

import com.xkl.cdl.data.AppConstants
import java.io.Serializable


/**
* author suliang
* create 2022/3/29 9:52
* Describe: 课程学习的详情
*/
class CourseDetail {
class CourseDetail:Serializable{
var courseLearnProgress: Double = 0.0 //课程学习进度
var st_before: Double = -1.0 //学前总成绩 : -1代表没有进行学前总测试
var st_after: Double = -1.0 //学后总成绩 : -1代表没有进行学后总测试
var st_before: Double = AppConstants.NOT_DOING //学前总成绩 : -1代表没有进行学前总测试
var st_after: Double = AppConstants.NOT_DOING //学后总成绩 : -1代表没有进行学后总测试
var before: HashMap<String, Double> = hashMapOf() //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩
var after: HashMap<String, Double> = hashMapOf() //章节学后测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩
var right = hashMapOf<String, Int>() //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量

+ 2
- 2
app/src/main/java/com/xkl/cdl/data/bean/course/Lesson.kt View File

@@ -30,9 +30,9 @@ data class Lesson(
/** 学习进度位置,为已学下标的位置,在作文课堂练习时,学习取当前条,其他取下一条*/
var learnedIndex: Int = -1
/**课时学前测试成绩 */
var beforeTestScore = -1.0
var beforeTestScore = AppConstants.NOT_DOING
/** 课时学后测试 */
var afterTestScore = -1.0
var afterTestScore = AppConstants.NOT_DOING
/**是否学习完成: 为学习内容是否完成,不包含学前,学后测试*/
var learnIsOver = false
/**是否是最后一个课时 */

+ 32
- 1
app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt View File

@@ -225,7 +225,7 @@ object CourseManager {
}
/**
* 计算项目总进度
* 计算项目总进度 ,并将课程进度值设置进入集合中
* @param subjectId Int 项目Id
* @param packId Long 修改进度的课程包id
* @param courseId Long 修改进度的课程id
@@ -289,4 +289,35 @@ object CourseManager {
if (totalCourseSize == 0) return 0.0
return totalProgress / totalCourseSize
}
/**
* 重学课程的课时时,计算项目的进度,不会进行赋值
* @param subjectId Int 项目
* @param courseId Long 重学的课程
* @param courseProgress Double 被重学课时的课程进度
* @return Double 项目的总进度
*/
fun calculateSubjectProgressWithCourseLessonRelearn(subjectId : Int,coursePackId:Long, courseId : Long,courseProgress:Double) : Double {
val totalProgress = mSortInfoList.get(subjectId)?.let {
var tempProgress = 0.0
it.forEach {
if (it.packId == coursePackId && it.courseId == courseId){
tempProgress += courseProgress
return@forEach
}else {
tempProgress += it.s
}
}
tempProgress
}?: 0.0
if (totalProgress == 0.0 ) return totalProgress
var totalCourseSize = 0
subjectWithCoursePackMap.get(subjectId)?.forEach {
totalCourseSize += it.childrenCourses.size
}
if (totalCourseSize == 0) return 0.0
return totalProgress / totalCourseSize
}
}

+ 2
- 2
app/src/main/java/com/xkl/cdl/data/manager/db/DBCourseManager.kt View File

@@ -124,8 +124,8 @@ object DBCourseManager {
totalNumber = this.wordIds.size //总数
correctNumber = detail.right.getOrElse(key, { 0 }) //正确数
errorNumber = detail.wrong.getOrElse(key, { 0 }) //错误数
beforeTestScore = detail.before.getOrElse(key, { -1.0 }) //课时学前测试成绩
afterTestScore = detail.after.getOrElse(key, { -1.0 }) //课时学后测试成绩
beforeTestScore = detail.before.getOrElse(key, { AppConstants.NOT_DOING }) //课时学前测试成绩
afterTestScore = detail.after.getOrElse(key, { AppConstants.NOT_DOING }) //课时学后测试成绩
this.learnedIndex = learnIndex //学习位置,当前位置为已学
this.learnIsOver = learnIsOver
this.lessonType = lessonType

+ 6
- 6
app/src/main/java/com/xkl/cdl/data/repository/AudioCache.kt View File

@@ -3,7 +3,6 @@ package com.xkl.cdl.data.repository
import android.util.LruCache
import androidx.lifecycle.MutableLiveData
import com.suliang.common.AppConfig
import com.suliang.common.eventbus.NonStickyMutableLiveData
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.file.FileUtil
import com.xkl.cdl.data.AppConstants
@@ -30,12 +29,12 @@ object AudioCache {
}
/** 通知查到的录音 */
var audioLiveData = NonStickyMutableLiveData<String?>()
private lateinit var audioLiveData : MutableLiveData<String?>
// fun initAudioLiveData() : MutableLiveData<String?>{
// audioLiveData = NonStickyMutableLiveData<String?>()
// return audioLiveData
// }
fun initAudioLiveData() : MutableLiveData<String?> {
audioLiveData = MutableLiveData<String?>()
return audioLiveData
}
/**
* 获取对应音频
@@ -78,6 +77,7 @@ object AudioCache {
return@fromCallable lruCache.get(defaultKey) ?: ""
}.compose(diskIo2Main()).subscribe {
if (this::audioLiveData.isInitialized)
audioLiveData.value = it
}
}

+ 11
- 2
app/src/main/java/com/xkl/cdl/data/repository/DataRepository.kt View File

@@ -1,12 +1,14 @@
package com.xkl.cdl.data.repository

import androidx.lifecycle.MutableLiveData
import com.suliang.common.util.file.FileUtil
import com.xkl.cdl.data.bean.course.CourseDetail
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.DbControlBase
import io.reactivex.rxjava3.core.Observable
import mqComsumerV1.Struct
import java.io.File

/**
* author suliang
@@ -33,9 +35,16 @@ object DataRepository {
}

/** 获取课程的详情 */
fun getCourseStatistics(): Observable<CourseDetail>{
fun getCourseStatistics(subjectId:Int,coursePackId:Long,courseId:Long): Observable<CourseDetail>{
return Observable.create{
val courseDetail = CourseDetail()
// TODO: 2022/5/6 这里自己使用的缓存
val file = File(FileUtil.getSaveDirPath("appcache"), "${subjectId}_${coursePackId}_${courseId}")
val courseDetail = if (file.exists()){
FileUtil.bytesToObject(FileUtil.readFile(file)) as CourseDetail
}else{
CourseDetail()
}
it.onNext(courseDetail)
it.onComplete()
}

+ 7
- 7
app/src/main/java/com/xkl/cdl/data/repository/PhotoCache.kt View File

@@ -2,15 +2,10 @@ package com.xkl.cdl.data.repository

import android.util.LruCache
import androidx.lifecycle.MutableLiveData
import com.suliang.common.AppConfig
import com.suliang.common.eventbus.NonStickyMutableLiveData
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.file.FileUtil
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.DbControlBase
import io.reactivex.rxjava3.core.Observable
import java.io.File
import java.util.*

/**
@@ -29,9 +24,13 @@ object PhotoCache {
}
}
/** 通知查到的录音 */
var photoLiveData = NonStickyMutableLiveData<ByteArray?>()
/** 通知查到的图片字节码 */
private lateinit var photoLiveData : MutableLiveData<ByteArray?>
fun initPhotoLiveData() : MutableLiveData<ByteArray?> {
photoLiveData = MutableLiveData<ByteArray?>()
return photoLiveData
}
/**
* 获取对应图片
* 1缓存 2文件 3数据库
@@ -50,6 +49,7 @@ object PhotoCache {
return@fromCallable lruCache.get(defaultKey)
}.compose(diskIo2Main()).subscribe {
if (this::photoLiveData.isInitialized)
photoLiveData.value = it
}
}

+ 0
- 17
app/src/main/java/com/xkl/cdl/dialog/DialogEventAction.kt View File

@@ -1,17 +0,0 @@
package com.xkl.cdl.dialog

/**
* author suliang
* create 2022/4/6 9:54
* Describe: LearnDialog 按钮点击动作
*/
enum class DialogEventAction {
/**下一步*/
NEXT,
/** 开始学习 */
START_LEARN,
/** 课时学前测试 */
START_LESSON_BEFORE_TEST

// TODO: 2022/4/6 可以添加相应的动作action,来处理对应的动作
}

+ 107
- 11
app/src/main/java/com/xkl/cdl/dialog/LearnDialog.kt View File

@@ -52,6 +52,8 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
AppConstants.DIALOG_TYPE_EXAM_START -> when(learnDialogBean.examType){
//课时学前测试开始弹窗
AppConstants.TEST_TYPE_BEFORE -> initLessonBeforeTestStart()
//课时最后一个课时测试结束的下一步弹出此弹窗:学后总测试开始的弹窗
AppConstants.TEST_TYPE_AFTER_TOTAL -> initCourseAfterTestStart()
}
//测试结束弹窗
AppConstants.DIALOG_TYPE_EXAM_OVER -> when (learnDialogBean.examType) {
@@ -59,9 +61,15 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
AppConstants.TEST_TYPE_BEFORE_TOTAL -> initCourseBeforeTotalTestOver()
//课时学前测试结束弹窗
AppConstants.TEST_TYPE_BEFORE-> initLessonBeforeTestOver()
//课时后测试结束
AppConstants.TEST_TYPE_AFTER -> initLessonAfterTestOver()
//学后总测试结束弹窗
AppConstants.TEST_TYPE_AFTER_TOTAL -> initCourseAfterTestOver()
}
//学习结束弹窗
AppConstants.DIALOG_TYPE_LEARN_OVER -> initLessonLearningOver()
/**课时列表点击课时完全完成*/
AppConstants.DIALOG_TYPE_LESSON_ITEM_OVER -> initLessonItemClickLessonOver()
}
}
@@ -131,6 +139,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
*/
private fun initLessonBeforeTestStart() {
binding.run {
ivClose.visibility = View.VISIBLE
tvTitle.visibility = View.VISIBLE
tvLessonName.visibility = View.VISIBLE
tvCountTime.visibility = View.VISIBLE
@@ -138,19 +147,12 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
tvLessonName.text = learnDialogBean.chapter_lesson_name
tvCountTime.text = learnDialogBean.showTimeCount
tvRight.text = "开始测试"
imgIv.setImageResource(R.mipmap.girl_1)
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_1 else R.mipmap.girl_1)
//开始测试,进入课时学前测试界面
binding.tvRight.click {
onDialogListener(AppConstants.DIALOG_START_TEST, this@LearnDialog)
}
// tvLeft.visibility = View.VISIBLE
// vSplit.visibility = View.VISIBLE
// tvLeft.text = "跳过测试"
//跳过测试,直接进入学习界面
// binding.tvLeft.click {
// onDialogListener(AppConstants.DIALOG_START_LEARN, this@LearnDialog)
// }
binding.ivClose.click { dismissAllowingStateLoss() }
}
}
@@ -159,6 +161,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
*/
private fun initLessonBeforeTestOver() {
binding.run {
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2)
tvScore.visibility = View.VISIBLE
tvTip.visibility = View.VISIBLE
tvTitle.visibility = View.VISIBLE
@@ -185,7 +188,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
binding.run {
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2)
tvTitle.visibility = View.VISIBLE
tvTitle.text = "恭喜你,本课时学习完成"
tvTitle.text = "恭喜你,本课时学习完成!"
incStatisticsNumber.root.visibility = View.VISIBLE
tvLearnOverTip.visibility = View.VISIBLE
tvLearnOverForAfterCountTime.visibility = View.VISIBLE
@@ -217,7 +220,7 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
tvLeft.visibility = View.VISIBLE
vSplit.visibility = View.VISIBLE
tvTitle.text = "恭喜你,完成了课时学后测试"
tvTop1.text = "重新学习"
tvTop.text = "重新学习"
tvLeft.text = "再测一次"
tvRight.text = "下一课时"
@@ -236,5 +239,98 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
onDialogListener(AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT,this)
}
}
/**
* 课程学后总测试开始前提示弹窗
*/
private fun initCourseAfterTestStart() {
binding.run {
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2)
tvLessonName.visibility = View.INVISIBLE //占布局,避免布局变形
tvTitle.visibility = View.VISIBLE
tvTitle.text = "恭喜你,本课程全部学习完成!"
tvTip1.visibility = View.VISIBLE
tvTip1.text = "我的学习效果是?快去学后总测试吧!"
tvCountTime.visibility = View.VISIBLE
tvCountTime.text = learnDialogBean.showTimeCount
tvRight.text = "开始测试"
//开始测试,进入课时学前测试界面
binding.tvRight.click {
onDialogListener(AppConstants.DIALOG_START_TEST, this@LearnDialog)
}
tvLeft.visibility = View.VISIBLE
vSplit.visibility = View.VISIBLE
tvLeft.text = "完成"
binding.tvLeft.click {
onDialogListener(AppConstants.DIALOG_OVER, this@LearnDialog)
}
}
}
/**
* 课程学后总测试结束弹窗
*/
private fun initCourseAfterTestOver(){
initNumber()
initScore()
binding.run {
tvScore.visibility = View.VISIBLE
tvTip.visibility = View.VISIBLE
tvTitle.visibility = View.VISIBLE
tvTip1.visibility = View.VISIBLE
incStatisticsNumber.root.visibility = View.VISIBLE
tvTop.visibility = View.VISIBLE
tvLeft.visibility = View.VISIBLE
vSplit.visibility = View.VISIBLE
tvTitle.text = "恭喜你,完成了学后总测试"
tvTop.text = "继续学习"
tvLeft.text = "再测一次"
tvRight.text = "完成"
}
binding.tvTop.click {
onDialogListener(AppConstants.DIALOG_OVER, this)
}
binding.tvLeft.click {
onDialogListener(AppConstants.DIALOG_AFTER_TOTAL_TEST_AGAIN,this)
}
binding.tvRight.click {
onDialogListener(AppConstants.DIALOG_OVER, this)
}
}
/**
* 课时列表item点击时课程已完全学习完成(学前测、学后测、学习都已完成)的提示弹窗
* tv_title,inc_statistics_number,tv_learn_over_tip,tv_learn_over_for_after_count_time,tv_left,vSplit
*/
private fun initLessonItemClickLessonOver(){
initNumber()
binding.run {
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2)
ivClose.visibility = View.VISIBLE
tvTitle.visibility = View.VISIBLE
tvTitle.text = "恭喜你,本课时学习完成!"
incStatisticsNumber.root.visibility = View.VISIBLE
tvLearnOverTip.visibility = View.VISIBLE
tvLearnOverTip.text = "你可重新学习本课时,或重新进行课时学后测试"
tvLearnOverForAfterCountTime.visibility = View.VISIBLE
tvLearnOverForAfterCountTime.text = "(上次课时学后测试成绩:${learnDialogBean.score})"
tvLeft.visibility = View.VISIBLE
tvLeft.text = "重新学习"
vSplit.visibility = View.VISIBLE
tvRight.text = "课时学后测试"
}
binding.ivClose.click { dismissAllowingStateLoss() }
binding.tvLeft.click { onDialogListener(AppConstants.DIALOG_LESSON_RELEARN, this) }
binding.tvRight.click { onDialogListener(AppConstants.DIALOG_START_TEST, this) }
}
}

+ 43
- 18
app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt View File

@@ -12,8 +12,8 @@ import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.airbnb.lottie.LottieAnimationView
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.extension.click
import com.suliang.common.util.DateUtil
import com.suliang.common.util.DrawableUti
@@ -96,7 +96,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
}
/** 查询到播放数据过来 */
AudioCache.audioLiveData.observe(this) {
AudioCache.initAudioLiveData().observe(this) {
if (it == null) {
//发音文件为空
showToast("未找到发音文件")
@@ -600,15 +600,14 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
LearnDialog.newInstance(learnDialogBean).apply {
onDialogListener = { action, dialog ->
when (vm.intentData.examType) {
//学前测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页
//学前测试结束,只有一个按钮,开始学习 -> 发送消息切换到课时列表页
AppConstants.TEST_TYPE_BEFORE_TOTAL -> when (action) {
AppConstants.DIALOG_START_LEARN -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 继续学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_COURSE_TEST_START_LEARN)
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post(LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_COURSE_TEST_START_LEARN))
finish()
}
}
@@ -616,13 +615,13 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
AppConstants.TEST_TYPE_BEFORE -> when (action) {
AppConstants.DIALOG_START_LEARN -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 继续学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
//发送动作 : 开始学习
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN).apply {
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!!
}
})
finish()
}
}
@@ -640,35 +639,61 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
if (isRightClick){
dialog.dismissAllowingStateLoss()
//发送动作 : 重新学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply {
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!!
}
})
finish()
}
}
}.show(childFragmentManager,"lesson_relearn_tip")
}
//再测一次
AppConstants.DIALOG_LESSON_AFTER_TEST_AGAIN -> {
//发送动作 : 继续学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
//发送动作 : 再测一次
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply {
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!!
}
})
finish()
}
//下一步
AppConstants.DIALOG_LESSON_AFTER_TEST_NEXT -> {
//发送动作 : 继续学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
//发送动作 : 下一步
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_NEXT).apply {
leesonPositionIndex = vm.intentData.lesson?.lessonPositionInList!!
}
})
finish()
}
}
//学后总测试结束
AppConstants.TEST_TYPE_AFTER_TOTAL -> when(action){
//测试完成,切换到目录页
AppConstants.DIALOG_OVER -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 继续学习
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_OVER))
finish()
}
//再测一次
AppConstants.DIALOG_AFTER_TOTAL_TEST_AGAIN -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 再测一次
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).post(
LearnEventData(vm.intentData.subjectId,
vm.intentData.courseId,
AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN))
finish()
}
}
}

+ 22
- 17
app/src/main/java/com/xkl/cdl/module/learn/LearnExamViewModel.kt View File

@@ -4,8 +4,7 @@ import android.graphics.drawable.Drawable
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.googlecode.protobuf.format.JsonFormat
import com.suliang.common.eventbus.LiveDataBus
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.extension.createRandomNewChar
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.DateUtil
@@ -135,6 +134,10 @@ class LearnExamViewModel : LearnBaseViewModel() {
//倒计时结束
val currentCountingTimeOver = MutableLiveData<Boolean>()
init {
isRunValidTime = false
}
/** 修改获取下一题的标记为true,则在onResume时,自动获取第一题 */
fun loadFirst(){
isGetNextIng = true
@@ -231,9 +234,9 @@ class LearnExamViewModel : LearnBaseViewModel() {
//计算分数
calculateScore()
when(intentData.examType){
AppConstants.TEST_TYPE_BEFORE -> { //学前测为lesson添加错误数 与 分数
AppConstants.TEST_TYPE_BEFORE -> { //课时学前测为lesson添加错误数 与 分数
intentData.lesson?.let {
it.errorNumber = it.errorNumber + newErrorMap.size
it.errorNumber += newErrorMap.size
it.beforeTestScore = scoreValue.toDouble()
}
}
@@ -461,10 +464,6 @@ class LearnExamViewModel : LearnBaseViewModel() {
} else { //相当于新错
if (!newErrorMap.containsKey(key)) {
newErrorMap[key] = true
//课时前错误 ,则更新课时错误数量
if (intentData.examType == AppConstants.TEST_TYPE_BEFORE) {
intentData.lesson!!.errorNumber = intentData.lesson!!.errorNumber + 1
}
}
}
mLearnEntities.add(builder.build())
@@ -495,13 +494,12 @@ class LearnExamViewModel : LearnBaseViewModel() {
//其他测试
else -> {
val calculateCorrectNumber : Double = correctLiveData.value!! + unAnswerNumber * 0.25
val scoreValue = ((calculateCorrectNumber - testData.size * 0.25) / (testData.size * 0.25) * 100).toInt()
val scoreValue = ((calculateCorrectNumber - testData.size * 0.25) / (testData.size * 0.75) * 100).toInt()
this.scoreValue = when {
scoreValue < 0 -> 0
scoreValue > 100 -> 100
else -> scoreValue
}
}
}
}
@@ -651,16 +649,16 @@ class LearnExamViewModel : LearnBaseViewModel() {
private fun sendEventBus(){
when(intentData.examType){
AppConstants.TEST_TYPE_BEFORE_TOTAL -> { //学前总测发送数据、学前总测发送数据
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData(
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).post( LearnEventData(
intentData.subjectId,
intentData.courseId,
AppConstants.DATA_COURSE_BEFORE_TEST_OVER).apply {
this.scoreValue = this@LearnExamViewModel.scoreValue
this.newErrorMap = this@LearnExamViewModel.newErrorMap
}
})
}
AppConstants.TEST_TYPE_BEFORE-> { // 课时学前测试结束发送数据
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData(
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post( LearnEventData(
intentData.subjectId,
intentData.courseId,
AppConstants.DATA_LESSON_BEFORE_TEST_OVER).apply {
@@ -668,18 +666,25 @@ class LearnExamViewModel : LearnBaseViewModel() {
intentData.lesson?.let {
leesonPositionIndex = it.lessonPositionInList
}
}
})
}
AppConstants.TEST_TYPE_AFTER -> { //课时学后测试结束发送数据
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData(
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post(LearnEventData(
intentData.subjectId,
intentData.courseId,
AppConstants.DATA_LESSON_AFTER_TEST_OVER).apply {
this.newErrorMap = this@LearnExamViewModel.newErrorMap
intentData.lesson?.let {
leesonPositionIndex = it.lessonPositionInList
}
}
})
}
AppConstants.TEST_TYPE_AFTER_TOTAL -> { //学后总测发送数据
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).post(LearnEventData(
intentData.subjectId,
intentData.courseId,
AppConstants.DATA_COURSE_AFTER_TEST_OVER).apply {
this.scoreValue = this@LearnExamViewModel.scoreValue
})
}
}
}

+ 12
- 10
app/src/main/java/com/xkl/cdl/module/learn/LearnWordActivity.kt View File

@@ -13,8 +13,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import androidx.recyclerview.widget.SimpleItemAnimator
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.extension.click
import com.suliang.common.util.DateUtil
import com.suliang.common.util.LogUtil
@@ -244,7 +244,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
vm.loadNext()
//发音数据
AudioCache.audioLiveData.observe(this) {
AudioCache.initAudioLiveData().observe(this) {
it?.run {
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE) MPManager.play(
it, listener = impListener)
@@ -254,7 +254,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//如果需要显示图片,则添加监听
if (vm.isNeedLoadPhoto) {
//图片数据
PhotoCache.photoLiveData.observe(this) {
PhotoCache.initPhotoLiveData().observe(this) {
it?.run { ImageLoader.loadImage(bindingWord.imgWord, it) } ?: let { bindingWord.imgWord.visibility = View.GONE }
}
}
@@ -619,8 +619,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
private fun showLearnOverDialog() {
vm.loadAfterTest().observe(this) { showTimeCount ->
LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LEARN_OVER).apply {
correctNumber = vm.learnData.lesson.correctNumber + vm.learnRuleUtil.currentCorrectMap.size
errorNumber = vm.learnData.lesson.errorNumber + vm.learnRuleUtil.currentErrorMap.size
correctNumber = vm.learnData.lesson.correctNumber
errorNumber = vm.learnData.lesson.errorNumber
this.showTimeCount = showTimeCount
}).apply {
onDialogListener = { action, dialog ->
@@ -636,12 +636,13 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
if (isRightClick){
dialog.dismissAllowingStateLoss()
//发送动作 : 重新学习
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
LearnEventData(vm.learnData.lesson.subjectId,
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.learnData.lesson.subjectId,
vm.learnData.lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply {
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList
}
})
finish()
}
}
}.show(childFragmentManager,"lesson_relearn_tip")
@@ -649,12 +650,13 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
AppConstants.DIALOG_START_TEST -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 学后测试
LiveDataBus.with<LearnEventData>(AppConstants.EVENT_COURSE).value =
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(vm.learnData.lesson.subjectId,
vm.learnData.lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply {
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList
}
})
finish()
}
}
}

+ 9
- 9
app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt View File

@@ -3,12 +3,10 @@ package com.xkl.cdl.module.learn
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.googlecode.protobuf.format.JsonFormat
import com.suliang.common.eventbus.LiveDataBus
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.extension.createRandomNewChar
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.DateUtil
import com.suliang.common.util.LogUtil
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.bean.LearnWord
@@ -75,6 +73,7 @@ class LearnWordViewModel : LearnBaseViewModel() {
//数据上传完成监听: true 学习完成的上传 false可能是半途的返回事件,直接退出
val saveDataLiveData = MutableLiveData<Boolean>()
/** 获取数据 */
fun loadNext() {
//修改标记
@@ -89,9 +88,10 @@ class LearnWordViewModel : LearnBaseViewModel() {
currentLearnWord.value = it
} ?: let { //没有数据 即学习完成
isAllOver = true
// 停止有效计时
isRunValidTime = false
//停止总计时
stopTotalCountTing()
// TODO: 2022/4/26 停止有效计时
//封装保存数据
saveData()
}
@@ -246,7 +246,7 @@ class LearnWordViewModel : LearnBaseViewModel() {
learnedIndex = currentLessonLearnedPosition
correctNumber += learnRuleUtil.currentCorrectMap.size
errorNumber += learnRuleUtil.currentErrorMap.size
learnIsOver = (correctNumber + errorNumber == totalNumber)
learnIsOver = learnedIndex == wordIds.size - 1
}
//添加到错误本集合中,主要用于小游戏练习(学前总 课时都没有添加,从这里添加到集合后发送出去,添加到集合)
learnData.examErrorMap?.putAll(learnRuleUtil.currentErrorMap)
@@ -282,12 +282,12 @@ class LearnWordViewModel : LearnBaseViewModel() {
/** 发送数据事件 */
private fun sendEventBus() {
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).value = LearnEventData(learnData.lesson.subjectId,
learnData.lesson.courseId,
AppConstants.DATA_LESSON_LEARN_OVER).apply {
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).post(LearnEventData(learnData.lesson.subjectId,
learnData.lesson.courseId,
AppConstants.DATA_LESSON_LEARN_OVER).apply {
this.leesonPositionIndex = learnData.lesson.lessonPositionInList
this.newErrorMap = learnData.examErrorMap
}
})
}

+ 39
- 8
app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackMainActivity.kt View File

@@ -22,11 +22,14 @@ import com.xkl.cdl.R
import com.xkl.cdl.adapter.AdapterAutoPlaySelectRepeat
import com.xkl.cdl.adapter.ViewPagerAdapter
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.bean.LearnDialogBean
import com.xkl.cdl.data.binding.BindingAdapter
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.databinding.ActivityCourseMainBinding
import com.xkl.cdl.databinding.DialogBottomAutoPlaySelectBinding
import com.xkl.cdl.databinding.DialogBottomCourseMoreBinding
import com.xkl.cdl.dialog.CommonDialog
import com.xkl.cdl.dialog.CommonDialogBean
import com.xkl.cdl.module.m_center_learn.coursechildren.CourseMainFragment
import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly

@@ -170,7 +173,7 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP
}
}
}
//改变page后设置进度
//改变page后设置进度,获取该课程的进度进行设置
vm.currentCourseProgress.value = vm.coursePack.childrenCourses[position].courseLearnProgress
}
})
@@ -188,20 +191,23 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP
progressbar.progress = it.toInt()
tvProgress.text = if (binding.includeCourseTypeTab.root.visibility == View.VISIBLE) {
val format = when (binding.viewPager2.currentItem) {
0 -> "认读进度:%s"
1 -> "拼写进度:%s"
2 -> "辨音进度:%s"
else -> "进度:%s"
0 -> "认读进度: %s%%"
1 -> "拼写进度: %s%%"
2 -> "辨音进度: %s%%"
else -> "进度: %s%%"
}
String.format(format, CourseManager.useToShowProgress(it))
} else {
String.format("进度:%s", CourseManager.useToShowProgress(it))
String.format("进度: %s%%", CourseManager.useToShowProgress(it))
}
}
}
//更多按钮点击
binding.includeCourseProgress.ivMore.click {
if (vm.showMoreEnable)
showMoreDialog()
else
showToast("请先进行学习")
}
}

@@ -232,13 +238,30 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP
}
moreBinding.tvClearLearnRecord.click {
dismiss()
// TODO: 2022/3/29 弹窗显示清除学习记录
showCourseRelearnDialog()
}
}
}
moreDialog?.show()
}

/** 课程重学弹窗提示 */
fun showCourseRelearnDialog(){
//弹窗显示清除学习记录
val bean = CommonDialogBean(titleText = R.string.course_relearn_title,
contentText = R.string.course_relearn_content,
leftText = R.string.course_relearn_sure, rightText = R.string.cancel)
CommonDialog.newInstance(bean).apply {
onCommonDialogButtonClickListener = { dialog, isRightClick ->
dialog.dismissAllowingStateLoss()
if (!isRightClick){
((this@CoursePackMainActivity.binding.viewPager2.adapter as ViewPagerAdapter).getItem(this@CoursePackMainActivity.binding.viewPager2.currentItem) as CourseMainFragment).run {
this.courseRelearn()
}
}
}
}.show(supportFragmentManager,"course_relearn_dialog")
}
/** 自动播放次数选择: 仅单词会有该选项 */
private fun showAutoPlaySelectDialog() {
if (autoPlaySeletDialog == null) {
@@ -269,6 +292,14 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP
private fun startAutoPlay(time: Int) {

}
override fun onStop() {
super.onStop()
//如果是中文项目,更新课程包的进度
if (vm.coursePack.subjectId == AppConstants.SUBJECT_CHINESE){
vm.coursePack.learnProgress = vm.coursePack.childrenCourses[0].courseLearnProgress
}
}


/** ViewModel Factory工厂 */

+ 5
- 3
app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackMainActivityViewModel.kt View File

@@ -10,12 +10,14 @@ import com.xkl.cdl.data.manager.CourseManager
* Describe: 课程主页
*/
class CoursePackMainActivityViewModel(subjectId: Int , coursePackInPosition : Int) : BaseViewModel() {
//操作的课程包
val coursePack = CourseManager.subjectWithCoursePackMap[subjectId]!![coursePackInPosition]

//设置显示当前课程的进度值和显示内容
val currentCourseProgress = MutableLiveData<Double>()


//更多点击是否有效
var showMoreEnable = false
}

+ 169
- 43
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseLessonFragment.kt View File

@@ -5,9 +5,8 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.util.DateUtil
import com.xkl.cdl.R
import com.xkl.cdl.adapter.AdapterLesson
import com.xkl.cdl.data.AppConstants
@@ -18,12 +17,11 @@ import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.bean.intentdata.ExamData
import com.xkl.cdl.data.event.LearnEventData
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.databinding.FragmentCourseLessonBinding
import com.xkl.cdl.dialog.CommonDialog
import com.xkl.cdl.dialog.CommonDialogBean
import com.xkl.cdl.dialog.LearnDialog
import com.xkl.cdl.module.learn.LearnWordActivity
import mqComsumerV1.Struct
import java.text.DateFormat

/**
* 课程章节目录
@@ -49,6 +47,8 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
adapterLesson = AdapterLesson(vm).apply {
onItemClick = onLessonClick
//默认选中位置,默认为0 ,如果学习完成则设置为-1
selectPos = vm.initSelectPosition()
}
adapter = adapterLesson
}
@@ -65,9 +65,10 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
private fun listenerLiveBus() {
//监听数据
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).observe(this) { learnEventData ->
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA).observe(this) { learnEventData ->
if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe
when (learnEventData.actionFlag) {
//课时学前测试结束,传递数据回来更新数据
AppConstants.DATA_LESSON_BEFORE_TEST_OVER -> {
// 更新Lesson 更新detail课时学前成绩,错误条目数,测试前错误列表
@@ -82,17 +83,17 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
}
}
}
//课时学前测试结束,开始学习 -> 进入学习界面
AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN -> {
startLearn(vm.allLesson[learnEventData.leesonPositionIndex])
}
//课时学习结束
//课时学习完成
AppConstants.DATA_LESSON_LEARN_OVER -> {
// 更新Lesson 更新detail错误条目数
if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe
//更新Lesson 更新detail错误条目数
adapterLesson.notifyItemChanged(learnEventData.leesonPositionIndex)
vm.allLesson[learnEventData.leesonPositionIndex].let {
val key = "${it.chapterId}_${it.lessonId}"
//更新错误数
vm.courseDetail.wrong.put(key, it.errorNumber)
//更新正确数
vm.courseDetail.right.put(key, it.correctNumber)
//添加到错误本中,现在主要用于小游戏取值
learnEventData.newErrorMap?.forEach {
vm.courseDetail.temporary_words.put(it.key, "")
@@ -112,6 +113,7 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
}
vm.courseDetail.courseLearnProgress = courseProgress
vm.course.courseLearnProgress = courseProgress
vm.coursePackMainActivityVM.currentCourseProgress.value = courseProgress
//项目总进度
val subjectProgress = CourseManager.calculateSubjectProgress(vm.course.subjectId, vm.course.coursePackId,
vm.course.courseId, courseProgress)
@@ -128,27 +130,50 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
vm.courseDetail.after.put(key, it.beforeTestScore)
}
}
//学后测试结束,弹窗动作
}
}
//监听课时学习的动作
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).observe(this) { learnEventData ->
if (learnEventData.subjectId != vm.course.subjectId || learnEventData.courseId != vm.course.courseId) return@observe
when (learnEventData.actionFlag) {
//课时学前测试结束,开始学习 -> 进入学习界面
AppConstants.ACTION_LESSON_BEFORE_TEST_OVER_START_LEARN -> {
startLearn(vm.allLesson[learnEventData.leesonPositionIndex])
}
//学后测试结束,弹窗动作 课时重新学习
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN -> {
//课时学后测试,点击重学
// TODO: 2022/4/22 清除当前课时数据,并更新当前课时,后进入学习界面
learnEventData.leesonPositionIndex
vm.allLesson[learnEventData.leesonPositionIndex].learnIsOver = false
vm.relearnLesson(learnEventData.leesonPositionIndex).observe(this) {
//item更新
adapterLesson.notifyItemChanged(learnEventData.leesonPositionIndex)
//进行点击,此时当前课时item应该处于显示中,可直接点击
(binding.recyclerView.layoutManager as LinearLayoutManager).findViewByPosition(
learnEventData.leesonPositionIndex)
?.findViewById<ConstraintLayout>(R.id.layout_content)
?.performClick()
}
}
/**课时学后测试弹窗动作: 再测一次 ,学习结束弹窗: 开始学后测试,共同点:直接进入测试,没有弹窗提示*/
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN -> {
//学后测试,再测一次
loadLessonAfterTest(vm.allLesson[learnEventData.leesonPositionIndex])
}
//下一步
AppConstants.ACTION_LESSON_AFTER_TEST_NEXT -> {
//下一课时 or 下一步(提示课程学习完成)
// TODO: 2022/4/22 判断课程是否学习完成,学习完成,显示课程学习完成弹窗,否则进入下一个没有学习完成的课时,进行学习
when(vm.course.courseLearnProgress){
100.0 -> showCourseOverDialog()
when (vm.course.courseLearnProgress) {
100.0 -> {
adapterLesson.selectPos = -1
adapterLesson.notifyDataSetChanged()
showCourseOverDialog()
}
else -> {
var nextLessonPosition = -1
//从下一课时开始到最后一个课时
for ( i in learnEventData.leesonPositionIndex + 1 until vm.allLesson.size){
for (i in learnEventData.leesonPositionIndex + 1 until vm.allLesson.size) {
if (!vm.allLesson[i].learnIsOver) {
nextLessonPosition = i
break
@@ -167,9 +192,11 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager
val findFirstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition() //第一个可见位置
val findLastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition() //最后一个可见位置
if (nextLessonPosition in findFirstVisibleItemPosition .. findLastVisibleItemPosition){
linearLayoutManager.findViewByPosition(nextLessonPosition)?.findViewById<ConstraintLayout>(R.id.layout_content)?.performClick()
}else{
if (nextLessonPosition in findFirstVisibleItemPosition .. findLastVisibleItemPosition) {
linearLayoutManager.findViewByPosition(nextLessonPosition)
?.findViewById<ConstraintLayout>(R.id.layout_content)
?.performClick()
} else {
recycleViewScrollListener.lessonPosition = nextLessonPosition
binding.recyclerView.addOnScrollListener(recycleViewScrollListener)
binding.recyclerView.smoothScrollToPosition(nextLessonPosition)
@@ -187,10 +214,12 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
var lessonPosition = 0
override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE){
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
binding.recyclerView.removeOnScrollListener(this)
val linearLayoutManager = binding.recyclerView.layoutManager as LinearLayoutManager
linearLayoutManager.findViewByPosition(lessonPosition)?.findViewById<ConstraintLayout>(R.id.layout_content)?.performClick()
linearLayoutManager.findViewByPosition(lessonPosition)
?.findViewById<ConstraintLayout>(R.id.layout_content)
?.performClick()
}
}
}
@@ -200,17 +229,16 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
private val onLessonClick : (v : View, position : Int, lesson : Lesson) -> Unit = { view, position, entity ->
when (entity.lessonType) {
AppConstants.LESSON_TYPE_WORD -> {
startLearn(entity)
/* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做
//弹窗显示学前测试提示
showLessonBeforeTestStartDialog(entity)
}else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习
startLearn(entity)
}else if (entity.afterTestScore != AppConstants.NOT_DOING){
loadLessonAfterTest(entity)
}else{ //当前课时学习完成的弹窗
showLessonAllOverDialog(entity)
}*/
if (entity.beforeTestScore == AppConstants.NOT_DOING) { //课时学前测试,没有做
//弹窗显示学前测试提示
showLessonBeforeTestStartDialog(entity)
} else if (!entity.learnIsOver) { //当前课时未学完,直接开始学习
startLearn(entity)
} else if (entity.afterTestScore == AppConstants.NOT_DOING) {
loadLessonAfterTest(entity)
} else { //当前课时学习完成的弹窗
showLessonAllOverDialog(entity)
}
}
AppConstants.LESSON_TYPE_SENTENCE -> {
@@ -271,9 +299,42 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
* @param lesson Lesson 课时
*/
private fun startLearn(lesson : Lesson) {
vm.loadLessonLearnData(lesson).observe(this) {
DataTransferHolder.instance.putData(value = it)
startActivity(LearnWordActivity::class.java)
when (lesson.lessonType) {
AppConstants.LESSON_TYPE_WORD -> {
startLessonLearnForWord(lesson)
/* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做
//弹窗显示学前测试提示
showLessonBeforeTestStartDialog(entity)
}else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习
startLearn(entity)
}else if (entity.afterTestScore != AppConstants.NOT_DOING){
loadLessonAfterTest(entity)
}else{ //当前课时学习完成的弹窗
showLessonAllOverDialog(entity)
}*/
}
AppConstants.LESSON_TYPE_SENTENCE -> {
}
AppConstants.LESSON_TYPE_DIALOGUE -> {
}
AppConstants.LESSON_TYPE_COMPOSITION_VIDEO -> {
}
AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE -> {
}
AppConstants.LESSON_TYPE_COMPOSITION_EXAM -> {
}
AppConstants.LESSON_TYPE_COMPOSITION_READING -> {
}
AppConstants.LESSON_TYPE_COMPOSITION_TASK -> {
}
}
}
@@ -305,22 +366,87 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM
/** lesson的学习 lessonType 为 word类型 */
private fun startLessonLearnForWord() {
private fun startLessonLearnForWord(lesson : Lesson) {
vm.loadLessonLearnData(lesson).observe(this) {
DataTransferHolder.instance.putData(value = it)
startActivity(LearnWordActivity::class.java)
}
}
/**
* 当前课时学前、学习、学后都完成了的弹窗
*/
private fun showLessonAllOverDialog(lesson : Lesson) {
LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LESSON_ITEM_OVER).apply {
correctNumber = lesson.correctNumber
errorNumber = lesson.errorNumber
score = lesson.afterTestScore.toInt()
}).apply {
onDialogListener = { action, dialog ->
when (action) {
//重学动作
AppConstants.DIALOG_LESSON_RELEARN -> CommonDialog.newInstance(
CommonDialogBean(titleText = R.string.lesson_relearn_title,
contentText = R.string.lesson_relearn_content, leftText = R.string.cancel,
rightText = R.string.sure)).apply {
onCommonDialogButtonClickListener = { relearnDialog, isRightClick ->
relearnDialog.dismissAllowingStateLoss()
if (isRightClick) {
dialog.dismissAllowingStateLoss()
//发送动作 : 重新学习
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post(
LearnEventData(lesson.subjectId, lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply {
leesonPositionIndex = lesson.lessonPositionInList
})
}
}
}.show(childFragmentManager, "lesson_relearn_tip")
// 开始学后测试
AppConstants.DIALOG_START_TEST -> {
dialog.dismissAllowingStateLoss()
//发送动作 : 学后测试
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION).post( LearnEventData(lesson.subjectId, lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply {
leesonPositionIndex = lesson.lessonPositionInList
})
}
}
}
}.show(childFragmentManager, "learn_over_dialog")
}
/**
* 显示课程学习完成的弹窗
* 显示课程学习完成的弹窗,在最后一个课时测试完成的下一步,相当于在课时目录页显示去学后总测试的弹窗
*/
private fun showCourseOverDialog() {
// TODO: 2022/4/29 课程学习完成弹窗
vm.loadTest(AppConstants.TEST_TYPE_AFTER_TOTAL).observe(this) {
val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_START).apply {
examType = AppConstants.TEST_TYPE_AFTER_TOTAL
showTimeCount = CourseManager.expectedTestTime(vm.course.courseType, examType, it)
}
LearnDialog.newInstance(learnDialogBean).apply {
onDialogListener = { action, dialog ->
dialog.dismissAllowingStateLoss()
when (action) {
//开始是学后总测试
AppConstants.DIALOG_START_TEST -> {//生成数据
val examData = ExamData(vm.course.subjectId, learnDialogBean.examType, vm.course.courseTitle,
vm.course.courseTitle).apply {
coursePackId = vm.course.coursePackId
coursePackType = vm.course.coursePackType
courseId = vm.course.courseId
courseType = vm.course.courseType
this.testData = it
}
(parentFragment as CourseMainFragment).startExam(examData)
}
}
}
}.show(childFragmentManager, "course_learn_after_test_before")
}
}

+ 57
- 31
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragment.kt View File

@@ -1,13 +1,13 @@
package com.xkl.cdl.module.m_center_learn.coursechildren

import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.jeremyliao.liveeventbus.LiveEventBus
import com.suliang.common.AppConfig
import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.extension.replaceFragment
import com.suliang.common.util.LogUtil
import com.xkl.cdl.R
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
@@ -34,28 +34,36 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
}
}
/**标记当前显示的fragment*/
private lateinit var currentFragment : Fragment
override fun initViewModel() : CourseMainFragmentViewModel {
return ViewModelProvider(this,
ViewModelFactory(requireArguments().getInt(AppConfig.INTENT_1)))[CourseMainFragmentViewModel::class.java].apply {
val vmmodel = ViewModelProvider(this, ViewModelFactory(
requireArguments().getInt(AppConfig.INTENT_1)))[CourseMainFragmentViewModel::class.java].apply {
coursePackMainActivityVM = ViewModelProvider(requireActivity())[CoursePackMainActivityViewModel::class.java]
// LogUtil.e("CourseMainFragment coursePackMainActivityVM hashCode -> ${coursePackMainActivityVM.hashCode()}")
}
lifecycle.addObserver(vmmodel)
return vmmodel
}
override fun initFragment() {
//设置课程 和 需要操作的类型
vm.course = vm.coursePackMainActivityVM.coursePack.childrenCourses[vm.courseIndex].apply {
vm.dbControlBase = DbControlBase(subjectId, coursePackId,coursePackType, courseId, courseType)
vm.dbControlBase = DbControlBase(subjectId, coursePackId, coursePackType, courseId, courseType)
}
//监听动作 总测完成,切换到目录页
LiveDataBus.withNonSticky<LearnEventData>(AppConstants.EVENT_COURSE).observe(this) {
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_CHANGE_PAGE).observe(this) {
if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe
when (it.actionFlag) {
// 学前总测、学后总测 之继续学习 -> 切换到目录页
AppConstants.ACTION_COURSE_TEST_START_LEARN -> changeFragment(1)
AppConstants.ACTION_COURSE_TEST_START_LEARN -> if (currentFragment !is CourseLessonFragment) changeFragment(1)
}
}
//监听动作 总测完成
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_TOTAL_TEST).observe(this) {
if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe
when (it.actionFlag) {
//学前总测结束,传递数据回来更新数据
AppConstants.DATA_COURSE_BEFORE_TEST_OVER -> {
vm.courseDetail.st_before = it.scoreValue.toDouble() //学前总分
@@ -70,13 +78,28 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
}
}
}
//学后总测结束传递数据回来。更新数据
AppConstants.DATA_COURSE_AFTER_TEST_OVER -> vm.courseDetail.st_after = it.scoreValue.toDouble() //学后总分
//学后总测试结束动作: 再测一次
AppConstants.ACTION_COURSE_TEST_AFTER_TOTAL_AGAIN -> {
vm.loadTest(AppConstants.TEST_TYPE_AFTER_TOTAL).observe(this) {
val examData = ExamData(vm.course.subjectId, AppConstants.TEST_TYPE_AFTER_TOTAL, vm.course.courseTitle,
vm.course.courseTitle).apply {
coursePackId = vm.course.coursePackId
coursePackType = vm.course.coursePackType
courseId = vm.course.courseId
courseType = vm.course.courseType
this.testData = it
}
startExam(examData)
}
}
}
}
}
override fun loadData() {
LogUtil.e("CourseMainFragment 加载数据 --》 ${vm.courseIndex}")
vm.loadMain().observe(this) {
changeChildrenFragment()
}
@@ -87,22 +110,17 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
* 改变加载的子Fragment
*/
private fun changeChildrenFragment() {

// //加载复习
// replaceFragment(R.id.layout_root, CourseReviewFragment.newInstance())
// //学前总测
// replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL))
//学后总测
// replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL))
//学习目录
// TODO: 2022/5/5 复习页面加载
vm.courseDetail.run {
if (st_before == AppConstants.NOT_DOING) { //学前总测未做
replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL))
currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL)
replaceFragment(R.id.layout_root, currentFragment)
} else if (courseLearnProgress != 100.0) { //学习未完成
replaceFragment(R.id.layout_root, CourseLessonFragment.newInstance())
currentFragment = CourseLessonFragment.newInstance()
replaceFragment(R.id.layout_root, currentFragment)
} else { //学习完成,学后总测试界面
replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL))
currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL)
replaceFragment(R.id.layout_root,currentFragment)
}
}
}
@@ -113,8 +131,14 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
*/
fun changeFragment(position : Int) {
when (position) {
1 -> replaceFragment(R.id.layout_root, CourseLessonFragment.newInstance())
2 -> replaceFragment(R.id.layout_root, CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL))
1 -> {
currentFragment = CourseLessonFragment.newInstance()
replaceFragment(R.id.layout_root,currentFragment )
}
2 -> {
currentFragment = CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL)
replaceFragment(R.id.layout_root, currentFragment)
}
}
}
@@ -125,10 +149,12 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
LearnExamActivity.newInstance(requireContext())
}
override fun onDestroy() {
super.onDestroy()
//退出本课程后移除该课程的事件监听
// LiveDataBus.remove(AppConstants.EVENT_COURSE)
/** 课程重学方法 */
fun courseRelearn() {
//调用重学,重学重新加载数据,重新加载界面
vm.relearnCourse().observe(this){
loadData()
}
}

+ 136
- 3
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragmentViewModel.kt View File

@@ -1,16 +1,20 @@
package com.xkl.cdl.module.m_center_learn.coursechildren

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.extension.diskIo2DiskIo
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.DateUtil
import com.suliang.common.util.file.FileUtil
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.bean.LearnWord
import com.xkl.cdl.data.bean.course.Course
import com.xkl.cdl.data.bean.course.CourseDetail
import com.xkl.cdl.data.bean.course.ExamBean
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.bean.intentdata.LearnData
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.DbControlBase
import com.xkl.cdl.data.repository.DataRepository
@@ -18,6 +22,7 @@ import com.xkl.cdl.module.m_center_learn.CoursePackMainActivityViewModel
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.functions.BiFunction
import mqComsumerV1.Struct
import java.io.File
import java.util.*
import kotlin.collections.HashMap

@@ -55,10 +60,10 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
//获取课程的复习数据
//获取课程的章节数据
fun loadMain() : MutableLiveData<Boolean> {
// showHideLoading(true)
val mutableLiveData = MutableLiveData<Boolean>()
Observable.zip(DataRepository.getCourseStatistics().flatMap {
Observable.zip(DataRepository.getCourseStatistics(course.subjectId,course.coursePackId,course.courseId).flatMap {
courseDetail = it
course.courseLearnProgress = it.courseLearnProgress
return@flatMap DataRepository.getCourseAllLesson(dbControlBase, it)
}.flatMap {
allLesson = it
@@ -66,14 +71,20 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
},
DataRepository.getReviewData(),
BiFunction<HashMap<String, Long>, Array<String>, Boolean> { t1 : HashMap<String, Long>?, t2 : Array<String>? ->
// TODO: 2022/5/5 初始化需要复习的数据
showMoreIsEnable()
true
}).compose(diskIo2Main()).subscribe {
// showHideLoading(false)
mutableLiveData.value = it
}
return mutableLiveData
}
/** 课程包主页上的更多按钮点击是否有效 */
private fun showMoreIsEnable(){
coursePackMainActivityVM.showMoreEnable = courseDetail.st_before != AppConstants.NOT_DOING
}
/**
* 获取课程的测试数据
* @param testType Int 测试类型
@@ -129,6 +140,7 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
.subscribe {
result.value = LearnData(lesson).apply {
learnWordList = it
examErrorMap = courseDetail.exam_w_r_list
}
}
return result
@@ -153,5 +165,126 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
}.compose(diskIo2DiskIo()).subscribe()
}
/** 初始化默认选中位置 */
fun initSelectPosition() : Int {
//没有学习点,默认课程学习课时位置为第一个
var temposition = 0
when{
//学后总测试完成,默认无选中
courseDetail.st_after != AppConstants.NOT_DOING -> temposition = -1
//有学习点
courseDetail.course_learn_point.isNotEmpty() -> {
run m@{
allLesson.forEachIndexed { index, lesson ->
if ("${lesson.chapterId}_${lesson.lessonId}" == courseDetail.course_learn_point) {
temposition = index
return@m
}
}
}
}
}
return temposition
}
/**
* 课时重学
* @param lessonPositionIndex Int 重学课时所在位置
*/
fun relearnLesson(lessonPositionIndex : Int):MutableLiveData<Boolean> {
val result = MutableLiveData<Boolean>()
//重学课时后课程的进度
val courseProgress = CourseManager.calculateEnglishCourseProgress(allLesson,true,lessonPositionIndex)
//重学课时后项目的总进度
val subjectProgress = CourseManager.calculateSubjectProgressWithCourseLessonRelearn(course.subjectId,course.coursePackId,course.courseId,courseProgress)
Observable.fromCallable {
// TODO: 2022/5/5 进行数据清除和保存
}.compose(diskIo2DiskIo()).subscribe{
//更新lesson
val lesson = allLesson[lessonPositionIndex].apply {
errorNumber = 0
correctNumber = 0
learnedIndex = -1
learnIsOver = false
afterTestScore = AppConstants.NOT_DOING
}
//更新courseDetail
courseDetail.run {
val lessonKey = "${lesson.chapterId}_${lesson.lessonId}"
//正确错误数归0,不会清除备忘本数据
right[lessonKey] = 0
wrong[lessonKey] = 0
//移除学后测试成绩
after.remove(lessonKey)
//移除章节学习点
lesson_learn_point.remove(lessonKey)
val wordStartKey = "${lessonKey}_"
//移除总测、课时学前测试的学习错误数据
exam_w_r_list.filterKeys {
it.startsWith(wordStartKey)
}.forEach{
exam_w_r_list.remove(it.key)
}
//移除错误本中的记录
temporary_words.filterKeys { it.startsWith(wordStartKey) }.forEach{
temporary_words.remove(it.key)
}
//更新课程进度
courseLearnProgress = courseProgress
course.courseLearnProgress = courseProgress
coursePackMainActivityVM.currentCourseProgress.postValue(courseProgress)
//更新统计总进度
CourseManager.calculateSubjectProgress(course.subjectId, course.coursePackId,
course.courseId, courseProgress)
//完成
result.postValue(true)
}
}
return result
}
/**
* 课程重学方法
*/
fun relearnCourse(): MutableLiveData<Boolean> {
val result = MutableLiveData<Boolean>()
//重学需要重新计算进度
val subjectProgress = CourseManager.calculateSubjectProgressWithCourseRelearn(course.subjectId,course.coursePackId,course.courseId)
Observable.fromCallable {
// TODO: 2022/5/5 调用课程重学 重新请求详情
val file = File(FileUtil.getSaveDirPath("appcache"), "${course.subjectId}_${course.coursePackId}_${course.courseId}")
if (file.exists()){ file.delete() }
}.compose(diskIo2DiskIo())
.subscribe{
courseDetail.run {
courseLearnProgress = 0.0
st_before = AppConstants.NOT_DOING
st_after = AppConstants.NOT_DOING
before.clear()
after.clear()
right.clear()
wrong.clear()
lesson_learn_point.clear()
exam_w_r_list.clear()
course_learn_point = ""
rl += 1
temporary_words.clear()
vp.clear()
exercise_schedule.clear()
}
result.postValue(true)
}
return result
}
// TODO: 2022/5/6 这里在退出时进行了统计数据缓存保存,在loadMain的时候进行了read缓存 ,后期需要清除
override fun onDestroy(owner : LifecycleOwner) {
val objectToBytes = FileUtil.objectToBytes(courseDetail)
FileUtil.writeBytesToFile(FileUtil.getSaveDirPath("appcache"),"${course.subjectId}_${course.coursePackId}_${course.courseId}",objectToBytes)
super.onDestroy(owner)
}
}

+ 25
- 37
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseTotalTestFragment.kt View File

@@ -13,23 +13,24 @@ import com.xkl.cdl.data.bean.course.ExamBean
import com.xkl.cdl.data.bean.intentdata.ExamData
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.databinding.FragmentCourseTotalTestBinding
import com.xkl.cdl.module.m_center_learn.CoursePackMainActivity

/**
* 课程总测试: 学前总,学后总
* @property totalTestType 测试类型
*/
class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, CourseMainFragmentViewModel>() {
companion object {
@JvmStatic
fun newInstance(totalTestType: Int) = CourseTotalTestFragment().apply {
fun newInstance(totalTestType : Int) = CourseTotalTestFragment().apply {
arguments = Bundle().apply {
putInt(AppConfig.INTENT_1, totalTestType)
}
}
}
override fun initViewModel(): CourseMainFragmentViewModel {
override fun initViewModel() : CourseMainFragmentViewModel {
return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java]
}
@@ -38,25 +39,26 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
//由于使用的是与父类相同的loadingEvent,所以将此evnet移除
vm.loadingEvent.removeObservers(this)
}
//传递过来的总测类型: 学前,学后
private var totalTestType = 0
//测试的数据
private var testData : List<ExamBean> = emptyList()
override fun initFragment() {
totalTestType = requireArguments().getInt(AppConfig.INTENT_1)
}
override fun loadData() {
vm.loadTest(totalTestType).observe(this){
vm.loadTest(totalTestType).observe(this) {
testData = it
initView()
}
}
private fun initView(){
binding.tvCountTip.text = CourseManager.expectedTestTime(vm.course.courseType,totalTestType,testData!!)
private fun initView() {
binding.tvCountTip.text = CourseManager.expectedTestTime(vm.course.courseType, totalTestType, testData!!)
when (totalTestType) {
AppConstants.TEST_TYPE_BEFORE_TOTAL -> {
// TODO: 2022/4/21 需要把开始学习给取消了
@@ -86,10 +88,9 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
tvTitle.setText(R.string.tips_current_course_learn_over)
tvMainTip.visibility = View.VISIBLE
//根据测试成绩处理
vm.courseDetail.st_before = 81.0
vm.courseDetail.st_before.let {
when {
it == -1.0 -> { //未测
when (it) {
AppConstants.NOT_DOING -> { //未测
tvMainTip.setText(R.string.test_total_after_tip_1)
button2.run {
setText(R.string.test_type_after_total)
@@ -98,26 +99,12 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
}
}
}
it < AppConstants.TEST_SCORE_LEVEL_1 -> { //测试未通过
tvMainTip.setHtml("你还未通过学后总测试,上次得分: <font color=\'#F26255\'>$it</font>")

button1.run {
visibility = View.VISIBLE
setText(R.string.continue_learn)
click { view ->
continueLearn(view)
}
}
button2.run {
setText(R.string.start_test)
click { view ->
startTest(view)
}
else -> { //有成绩,直接完成
if (it >= AppConstants.TEST_SCORE_LEVEL_2) {
tvMainTip.setHtml("你已完成学后总测试,上次得分: <font color=\'#5082E6\'>$it</font>")
}else {
tvMainTip.setHtml("你已完成学后总测试,上次得分: <font color=\'#F26255\'>$it</font>")
}
}

it >= AppConstants.TEST_SCORE_LEVEL_1 -> { //测试通过
tvMainTip.setHtml("你已通过学后总测试,上次得分: <font color=\'#5082E6\'>$it</font>")
tvTips.visibility = View.VISIBLE
tvCountTip.visibility = View.GONE
button1.run {
@@ -134,6 +121,9 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
}
}
tvClearLearnRecord.visibility = View.VISIBLE
tvClearLearnRecord.click {
(activity as CoursePackMainActivity).showCourseRelearnDialog()
}
}
}
}
@@ -142,17 +132,15 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
}
}

/**继续学习*/
private fun continueLearn(view: View) {
private fun continueLearn(view : View) {
(requireParentFragment() as CourseMainFragment).changeFragment(1)
}
/** 开始测试 : 生成测试题,跳转到测试
*
*/
private fun startTest(view: View) {
private fun startTest(view : View) {
//生成数据
val examData = ExamData(vm.course.subjectId, totalTestType, vm.course.courseTitle, vm.course.courseTitle).apply {
coursePackId = vm.course.coursePackId
@@ -164,5 +152,5 @@ class CourseTotalTestFragment : BaseFragmentVM<FragmentCourseTotalTestBinding, C
}
(parentFragment as CourseMainFragment).startExam(examData)
}
}

+ 0
- 3
app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt View File

@@ -3,10 +3,8 @@ package com.xkl.cdl.module.main
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.extension.loadFragment
import com.suliang.common.extension.showHideFragment
import com.suliang.common.util.LogUtil
import com.xkl.cdl.R
import com.xkl.cdl.databinding.ActivityMainBinding
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment
@@ -14,7 +12,6 @@ import com.xkl.cdl.module.m_memo.MemoFragment
import com.xkl.cdl.module.m_my.MyFragment
import com.xkl.cdl.module.m_service_center.ServiceCenterFragment
import com.xkl.cdl.module.m_statics.StaticsFragment
import com.xkl.cdl.module.splash.SplashActivity

/**
* 主界面、控制切换子Fragment

+ 4
- 1
app/src/main/java/com/xkl/cdl/util/LearnRuleUtil.kt View File

@@ -1,5 +1,6 @@
package com.xkl.cdl.util

import com.suliang.common.util.LogUtil
import com.xkl.cdl.data.bean.BaseWord
import java.io.*
import java.util.*
@@ -307,6 +308,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List
currentCorrectMap[key] = true
}
if (isLearnFirst) currentIsError = false
LogUtil.e("currentCorrectMap--->${currentCorrectMap.size} --> $currentCorrectMap")
}
/**
@@ -324,6 +326,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List
} else if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key)) { //测试中数据的错误
currentErrorMap[key] = true
}
LogUtil.e("currentErrorMap --->${currentErrorMap.size} $currentErrorMap")
//开始进行数据扩容替换
replaceErrorToNull(item) //替换已有错误为空
insertErrorWord(item, false) //开始插入
@@ -334,7 +337,7 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List
* @return true在 false不存在
*/
fun isInExamErrorMap(key : String) : Boolean {
return examErrorsMap?.getOrDefault(key, null) ?: false
return examErrorsMap?.getOrDefault(key, false) ?: false
}
/** 是否是在学习的错误列表中 */

+ 18
- 12
app/src/main/res/layout/dialog_lesson_learn.xml View File

@@ -242,17 +242,23 @@
android:visibility="gone"
/>
<!--所有布局id-->
<!-- <androidx.constraintlayout.widget.Group-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:constraint_referenced_ids="iv_close,tv_score,tv_tip,tv_title,-->
<!-- tv_lesson_name,tv_count_time,,tv_tip_1,-->
<!-- inc_statistics_number,-->
<!-- tv_learn_over_tip,-->
<!-- tv_learn_over_for_after_count_time,-->
<!-- tv_top,tv_top_1,tv_left,vSplit"-->
<!-- tools:visibility="gone"-->
<!-- />-->
<!-- <androidx.constraintlayout.widget.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="iv_close,tv_score,tv_tip,tv_title,
tv_lesson_name,tv_count_time,,tv_tip_1,
inc_statistics_number,
tv_learn_over_tip,
tv_learn_over_for_after_count_time,
tv_top,tv_top_1,tv_left,vSplit"
tools:visibility="gone"
/>
<androidx.constraintlayout.widget.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="tv_title,tv_tip_1,tv_lesson_name,tv_count_time,tv_left,vSplit"
/>-->

<!-- &lt;!&ndash;学前总测试控制显示的布局id&ndash;&gt;-->
<!-- <androidx.constraintlayout.widget.Group-->
<!-- android:id="@+id/group_total_test"-->
@@ -278,7 +284,7 @@
/> -->


<!--课时正常学习结束的布局组 -->
<!-- 课时完全结束的点击显示弹窗的布局组 -->
<!-- <androidx.constraintlayout.widget.Group-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->

+ 1
- 1
app/src/main/res/layout/inc_over_number.xml View File

@@ -39,7 +39,7 @@
android:layout_marginStart="28dp"
android:layout_marginTop="8dp"
android:text="@string/error"
android:textColor="@color/gray_2"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toEndOf="@+id/guideline_1"
app:layout_constraintTop_toTopOf="parent" />

+ 3
- 0
app/src/main/res/values/strings.xml View File

@@ -75,5 +75,8 @@
<string name="auto_playing">自动播放中···</string>
<string name="quit_learn_title">你确定要退出本课程的学习吗?</string>
<string name="quit_learn_content">退出后系统将保存你的学习进度</string>
<string name="course_relearn_title">你确定要清空本课程的学习记录吗?</string>
<string name="course_relearn_content">清空后你的学习记录将不可恢复,请谨慎操作</string>
<string name="course_relearn_sure">确认清空</string>

</resources>

+ 2
- 0
build.gradle View File

@@ -99,6 +99,8 @@ ext {
grpc_android: "io.grpc:grpc-android:1.27.0",
grpc_protobuf: "io.grpc:grpc-protobuf:1.27.0",
grpc_stub: "io.grpc:grpc-stub:1.27.0",
//liveEventBus https://github.com/JeremyLiao/LiveEventBus
liveEventBus : "io.github.jeremyliao:live-event-bus-x:1.8.0"
]



+ 2
- 0
lib/common/build.gradle View File

@@ -67,6 +67,8 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
//MMKV
api customDependencies.MMKV
// liveEventBus
api customDependencies.liveEventBus




+ 44
- 44
lib/common/src/main/java/com/suliang/common/base/activity/LifecycleLogActivity.kt View File

@@ -10,48 +10,48 @@ import com.suliang.common.util.LogUtil
* Describe: 打印生命周期的Activity
*/
open class LifecycleLogActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LogUtil.e("onCreate()")
}
override fun onRestart() {
super.onRestart()
LogUtil.e("onRestart()")
}
override fun onStart() {
super.onStart()
LogUtil.e("onStart()")
}
override fun onResume() {
super.onResume()
LogUtil.e("onResume()")
}
override fun onPause() {
super.onPause()
LogUtil.e("onPause()")
}
override fun onStop() {
super.onStop()
LogUtil.e("onStop()")
}
override fun onDestroy() {
super.onDestroy()
LogUtil.e("onDestroy()")
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
LogUtil.e("onSaveInstanceState()")
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
LogUtil.e("onRestoreInstanceState()")
}
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// LogUtil.e("onCreate()")
// }
//
// override fun onRestart() {
// super.onRestart()
// LogUtil.e("onRestart()")
// }
//
// override fun onStart() {
// super.onStart()
// LogUtil.e("onStart()")
// }
//
// override fun onResume() {
// super.onResume()
// LogUtil.e("onResume()")
// }
//
// override fun onPause() {
// super.onPause()
// LogUtil.e("onPause()")
// }
//
// override fun onStop() {
// super.onStop()
// LogUtil.e("onStop()")
// }
//
// override fun onDestroy() {
// super.onDestroy()
// LogUtil.e("onDestroy()")
// }
//
// override fun onSaveInstanceState(outState: Bundle) {
// super.onSaveInstanceState(outState)
// LogUtil.e("onSaveInstanceState()")
// }
//
// override fun onRestoreInstanceState(savedInstanceState: Bundle) {
// super.onRestoreInstanceState(savedInstanceState)
// LogUtil.e("onRestoreInstanceState()")
// }
}

+ 1
- 0
lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragmentVM.kt View File

@@ -17,6 +17,7 @@ abstract class BaseFragmentVM<VB : ViewBinding, VM : BaseViewModel> : BaseFragme

override fun initFirst() {
vm = initViewModel()
lifecycle.addObserver(vm)
vm.pageEvent.observe(this) { startActivity(it) }
vm.toastEvent.observe(this){ showToast(it) }
vm.loadingEvent.observe(this) {

+ 7
- 7
lib/common/src/main/java/com/suliang/common/base/viewmodel/BaseViewModel.kt View File

@@ -16,37 +16,37 @@ import com.suliang.common.util.LogUtil
open class BaseViewModel : ViewModel(), ViewModelLifecycle, ViewBehavior {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
LogUtil.i("${javaClass.name} onCreate() ")
LogUtil.i("${javaClass.name}_${hashCode()} onCreate() ")
}

override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
LogUtil.i("${javaClass.name} onStart() ")
LogUtil.i("${javaClass.name}_${hashCode()} onStart() ")
}

override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
LogUtil.i("${javaClass.name} onResume() ")
LogUtil.i("${javaClass.name}_${hashCode()} onResume() ")
}

override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
LogUtil.i("${javaClass.name} onPause() ")
LogUtil.i("${javaClass.name}_${hashCode()} onPause() ")
}

override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
LogUtil.i("${javaClass.name} onStop() ")
LogUtil.i("${javaClass.name}_${hashCode()} onStop() ")
}

override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
LogUtil.i("${javaClass.name} onDestroy() ")
LogUtil.i("${javaClass.name}_${hashCode()} onDestroy() ")
}

override fun onCleared() {
super.onCleared()
LogUtil.i("${javaClass.name} onCleared() ")
LogUtil.i("${javaClass.name}_${hashCode()} onCleared() ")
}

+ 87
- 47
lib/common/src/main/java/com/suliang/common/eventbus/LiveDataBus.kt View File

@@ -1,15 +1,85 @@
package com.suliang.common.eventbus

import android.os.Looper
import androidx.lifecycle.MutableLiveData

/**
* author suliang
* create 2022/3/15 10:01
* Describe: 事件总线,这条总线把任何类中的数据直接传递到activity 或是 fragment 上
* https://blog.csdn.net/lp131452064/article/details/82736296
* https://juejin.cn/post/6844903768459329544
*/
@Deprecated("this class is deprecated" ,replaceWith = ReplaceWith("LiveEventBus"),level = DeprecationLevel.ERROR)
object LiveDataBus {
private val bus = mutableMapOf<String, MutableLiveData<Any>>()
/**
* 发送事件
* @param key String
* @param value T
* @param isSticky 是否是粘性事件,默认为false
*/
fun <T : Any> postEvent(key:String, value:T, isSticky : Boolean = false){
if (Looper.getMainLooper().thread == Thread.currentThread()){
subscribeEvent<T>(key,isSticky).value = value
}else{
subscribeEvent<T>(key,isSticky).postValue(value)
}
}
/**
* 订阅事件
* @param key bus中的key
* @param isSticky 是否是粘性事件,默认为false
*/
fun <T:Any> subscribeEvent(key:String,isSticky:Boolean = false): MutableLiveData<T> {
if (!bus.containsKey(key)){
if (isSticky){
bus[key] = MutableLiveData()
}else{
bus[key] = NonStickyMutableLivedata()
}
}
return bus[key] as MutableLiveData<T>
}
fun remove(key : String) {
bus.remove(key)
}
fun clearAll() {
bus.clear()
}




// @SuppressWarnings("UNCHECKED_CAST")
// @Synchronized
// fun <T> with(key : String) : MutableLiveData<T> {
// if (!bus.containsKey(key)) {
// bus[key] = MutableLiveData()
// }
// return bus[key] as MutableLiveData<T>
// }
//
// @SuppressWarnings("UNCHECKED_CAST")
// @Synchronized
// fun <T> withNonSticky(key : String) : MutableLiveData<T> {
// if (!bus.containsKey(key)) {
// bus[key] = NonStickyMutableLivedata()
// }
// return bus[key] as MutableLiveData<T>
// }



private val bus = mutableMapOf<String,MutableLiveData<Any>>()

// /**
// * 注册订阅者
@@ -28,52 +98,22 @@ object LiveDataBus {

//java使用传入泛型class, kotlin使用可直接传入泛型,不需要class类型

@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> with(key:String) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = MutableLiveData()
}
return bus[key] as MutableLiveData<T>
}
@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> withNonSticky(key:String) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = NonStickyMutableLiveData()
}
return bus[key] as MutableLiveData<T>
}



@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> with(key:String,type: Class<T>) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = MutableLiveData()
}
return bus[key] as MutableLiveData<T>
}
@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> withNonSticky(key:String,type: Class<T>) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = NonStickyMutableLiveData()
}
return bus[key] as MutableLiveData<T>
}

fun remove(key:String){
bus.remove(key)
}


fun clearAll(){
bus.clear()
}



// @SuppressWarnings("UNCHECKED_CAST")
// @Synchronized
// fun <T> with(key:String,type: Class<T>) : MutableLiveData<T>{
// if (!bus.containsKey(key)){
// bus[key] = MutableLiveData()
// }
// return bus[key] as MutableLiveData<T>
// }
// @SuppressWarnings("UNCHECKED_CAST")
// @Synchronized
// fun <T> withNonSticky(key:String,type: Class<T>) : MutableLiveData<T>{
// if (!bus.containsKey(key)){
// bus[key] = NonStickyMutableLiveData()
// }
// return bus[key] as MutableLiveData<T>
// }

}

lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLiveData.kt → lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLivedata.kt View File

@@ -12,21 +12,37 @@ import java.lang.reflect.Method
* author suliang
* create 2022/3/15 10:51
* Describe: 非粘性LiveData ,需要先设置监听再发送数据,即后注册的监听收不到以前的监听
* 事件总线的LiveData 非粘性事件传false(刚注册时如果有事件则不发送) 粘性事件传true
* @param isSticky false非粘性事件 true粘性事件
*/
class NonStickyMutableLiveData<T> : MutableLiveData<T>() {

// private var stickFlag : Boolean = false

internal class NonStickyMutableLivedata<T> : MutableLiveData<T>() {
// override fun observe(owner : LifecycleOwner, observer : Observer<in T>) {
// super.observe(owner, ObserverWrapper<T>(observer))
// }
//
// class ObserverWrapper<T>(var observer:Observer<in T>) : Observer<T> {
// var isSticky = false
// override fun onChanged(t : T) {
// if (isSticky){
// observer.onChanged(t)
// }else{
// isSticky = true
// }
// }
// }
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
hook(observer)
// if (!stickFlag){
// hook(observer)
// stickFlag = true
// }
}

private fun hook(observer: Observer<in T>) = try {
override fun removeObserver(observer : Observer<in T>) {
super.removeObserver(observer)
}
private fun hook(observer : Observer<in T>) = try {
//得到 mLastVersion
//获取到LiveData的类中的mObserver对象
// SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers
@@ -38,7 +54,7 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() {
//得到map对应的class对象
val mObserversClass = mObserVersObject.javaClass
//获取到mObservers对象的get方法
val get:Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
get.isAccessible = true
//执行get方法,获取到对象
val invokeEntry = get.invoke(mObserVersObject, observer)
@@ -46,7 +62,7 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() {
val observerWrapper = if (invokeEntry is Map.Entry<*, *>) {
invokeEntry.value
} else throw NullPointerException("observerWrapper is null")
//得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass
//getClass 返回对应的当前正在运行是的类所对应的
val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion")
@@ -56,11 +72,10 @@ class NonStickyMutableLiveData<T> : MutableLiveData<T>() {
mVersion.isAccessible = true
//把mVersion数据填入到mLastVersion中
val mVersionValue = mVersion.get(this)
mLastVersion.set(observerWrapper,mVersionValue)
}catch (e: Exception){
mLastVersion.set(observerWrapper, mVersionValue)
} catch (e : Exception) {
e.printStackTrace()
}


}

+ 1
- 1
lib/common/src/main/java/com/suliang/common/extension/ViewClickExtension.kt View File

@@ -34,7 +34,7 @@ fun View.click(clickListener : ((view : View) -> Unit)?){
}
this.setOnTouchListener{ view , motionEvent ->
when(motionEvent.action){
MotionEvent.ACTION_DOWN -> view.alpha = 0.7f
MotionEvent.ACTION_DOWN -> view.alpha = 0.8f
MotionEvent.ACTION_UP -> view.alpha = 1f
else -> view.alpha = 1f
}

+ 17
- 2
lib/common/src/main/java/com/suliang/common/util/file/FileUtil.kt View File

@@ -400,9 +400,15 @@ object FileUtil {
closeStream(out)
return result
}

/***
* 从对象获取字节数组
* @param data Any 对象,需要实现序列化
* @return ByteArray 字节数组
* @throws Exception
*/
@Throws(Exception::class)
fun objectToBytes(data: Any): ByteArray {
fun objectToBytes(data: Serializable): ByteArray {
var oos: ObjectOutputStream? = null
return try {
val bos = ByteArrayOutputStream()
@@ -413,6 +419,15 @@ object FileUtil {
oos?.close()
}
}
/**
* 从字节数组获取对象
* @param data ByteArray
* @return Any
*/
fun bytesToObject(data:ByteArray): Any{
return ObjectInputStream(ByteArrayInputStream(data)).readObject()
}

/**
* 获取文件大小

+ 1
- 2
lib/common/src/main/res/values/strings.xml View File

@@ -1,4 +1,3 @@
<resources>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>

</resources>

Loading…
Cancel
Save