Browse Source

复习功能

master
suliang 2 years ago
parent
commit
181d0cbb2f

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

@@ -78,7 +78,7 @@
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_word_choose_content.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_spell.xml" value="0.4859375" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_test_statistic.xml" value="0.5" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_title.xml" value="0.5784919653893696" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_title.xml" value="0.25" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_word.xml" value="0.390625" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_over_number.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_spell_learn_tip.xml" value="0.67" />

BIN
app/libs/mobile_cache.aar View File


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

@@ -163,6 +163,8 @@ object AppConstants {
const val DIALOG_TYPE_LESSON_ITEM_CLICK_COMPOSITION_KNOWLEDGE_OVER = 6
/** 作文知识点课时学习界面学习完成 */
const val DIALOG_TYPE_LESSON_COMPOSITION_KNOWLEDGE_LEARNING_OVER = 7
/** 复习完成 */
const val DIALOG_TYPE_REVIEW_OVER = 8
/**--- 总线动作 --------------------------------- */
/**action key 改变界面 到目录页 */
@@ -173,6 +175,8 @@ object AppConstants {
const val EVENT_LESSON_ACTION = "lesson_learn_action"
/**总测数据与动作*/
const val EVENT_TOTAL_TEST = "total_test"
/**复习结果*/
const val EVENT_REVIEW_DATA = "review"
/** 事件动作:学前总测结束弹窗之 开始学习 */
@@ -201,6 +205,8 @@ object AppConstants {
const val DATA_COURSE_AFTER_TEST_OVER = 12
/** 作文测试完成动作,再测一次*/
const val ACTION_LESSON_COMPOSITION_TEST_AGAIN = 13
/**复习结束*/
const val DATA_REVIEW = 14
/**--- 弹窗动作 --------------------------------- */
/** 学前总测结束弹窗: 开始学习 ,课时学前测试开始弹窗*/

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

@@ -33,7 +33,9 @@ class DataTransferHolder private constructor(){
*/
@Suppress("UNCHECKED_CAST")
fun <T> getData(key : String = AppConfig.INTENT_1) : T{
return dataMap[key] as T
return (dataMap[key] as T).also {
clear()
}
}

/**

+ 5
- 1
app/src/main/java/com/xkl/cdl/data/bean/intentdata/LearnData.kt View File

@@ -8,7 +8,8 @@ import com.xkl.cdl.data.bean.course.Lesson
* author suliang
* create 2022/4/2 14:55
* Describe: 课时学习时的传参
* @param lesson 课时学习是为课时数据,其他特殊时候,如自动播放,只是用以包装课程的基本信息如果项目id、课程包类型、课程类型等
* @param lesson 课时学习是为课时数据,其他特殊时候,
* 如自动播放、复习,只是用以包装课程的基本信息如项目id、课程包类型、课程类型等
*/
class LearnData(val lesson: Lesson) {
@@ -25,4 +26,7 @@ class LearnData(val lesson: Lesson) {
//作文课堂练习数据
var readingList : List<CompositionReadingBean> = mutableListOf()
//是否是复习
var isReview = false
}

+ 1
- 1
app/src/main/java/com/xkl/cdl/data/event/LearnEventData.kt View File

@@ -14,7 +14,7 @@ class LearnEventData(val subjectId : Int, var courseId : Long, val actionFlag :
var scoreValue = 0 //分数
var newErrorMap : HashMap<String, Boolean>? = null //新错误单词列表
//课时学前测试 除了学前总测传递数据,还需要课时位置数据,
//课时学前测试 除了学前总测传递数据,还需要课时位置数据 在复习时用以标记为最后复习的value位置
var leesonPositionIndex = 0 // lesson所在位置

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

@@ -22,6 +22,7 @@ import com.xkl.videoplayer.bean.VideoAnchor
import io.reactivex.rxjava3.annotations.NonNull
import net.sqlcipher.database.SQLiteDatabase
import java.io.File
import java.util.*

/**
* author suliang
@@ -723,4 +724,58 @@ object DBCourseManager {
return result
}
/**
* 查询复习数据
* @param dbControlBase DbControlBase
* @param reviewDataList MutableList<LearnWord> 复习数据
* @return Boolean 查询到有数据返回true,如果都没有查询到数据,则返回false
*/
@SuppressLint("Range")
fun queryReviewData(dbControlBase : DbControlBase, reviewDataList : MutableList<LearnWord>) : Boolean {
//没有查询到复习数据的位置集合
val notHaveData = arrayListOf<Int>()
open(dbControlBase)
reviewDataList.forEachIndexed{ index , learnWord ->
val sql = "SELECT * FROM chapter WHERE chapter_id = ${learnWord.chapterId} and lesson_id = ${learnWord.lessonId} AND word_id = ${learnWord.wordId} "
val rawQuery = mDataBase?.rawQuery(sql, null)
rawQuery?.run {
if (this.count == 0 ){
notHaveData.add(index)
return@run
}
while (moveToNext()){
learnWord.word = getString(getColumnIndex("word"))
learnWord.basic_explanation = getString(getColumnIndex("basic_explaination"))
learnWord.extend_explanation = getString(getColumnIndex("all_explaination"))
learnWord.phrase = getString(getColumnIndex("phrase"))
learnWord.example = getString(getColumnIndex("example"))
learnWord.reference = getString(getColumnIndex("reference"))
when (dbControlBase.courseType) {
AppConstants.COURSE_TYPE_CHINESE_LITERACY -> {
learnWord.literacyIspolyphone = getInt(getColumnIndex("polyphone")) > 0
learnWord.phonetic_cn = getString(getColumnIndex("phonetic"))
}
AppConstants.COURSE_TYPE_CHINESE_PINYIN -> {
learnWord.phonetic_cn = getString(getColumnIndex("phonetic"))
}
else -> {
learnWord.phonetic_uk = getString(getColumnIndex("phonetic_uk"))
learnWord.phonetic_us = getString(getColumnIndex("phonetic_us"))
}
}
}
}?: notHaveData.add(index)
}
if (notHaveData.size > 0 ){
//反序
Collections.reverse(notHaveData)
notHaveData.forEach{
reviewDataList.removeAt(it)
}
}
return reviewDataList.size > 0
}
}

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

@@ -78,6 +78,8 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
AppConstants.DIALOG_TYPE_LESSON_ITEM_CLICK_COMPOSITION_KNOWLEDGE_OVER -> initCompositionKnowledgeLearning(true)
/** 作文课时学习中完成弹窗 */
AppConstants.DIALOG_TYPE_LESSON_COMPOSITION_KNOWLEDGE_LEARNING_OVER -> initCompositionKnowledgeLearning(false)
/** 复习完成 */
AppConstants.DIALOG_TYPE_REVIEW_OVER -> initReviewOver()
}
}
@@ -395,4 +397,23 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
binding.tvLeft.click { onDialogListener(AppConstants.DIALOG_START_TEST,this) }
binding.tvRight.click { onDialogListener(AppConstants.DIALOG_OVER,this) }
}
/**
* 复习完成 tv_title,tv_tip_1
*/
private fun initReviewOver(){
binding.run {
imgIv.setImageResource(if (Random.nextBoolean()) R.mipmap.boy_2 else R.mipmap.girl_2)
tvTitle.visibility = View.VISIBLE
tvTitle.text = "智能复习已完成,太棒了!"
tvTip1.visibility = View.VISIBLE
tvTip1.text = when{
learnDialogBean.errorNumber == 0 -> "我复习了${learnDialogBean.correctNumber}个词条"
else -> "我复习了${learnDialogBean.correctNumber}个词条,词汇量增加了${learnDialogBean.errorNumber}"
}
tvRight.text = "完成"
}
binding.tvRight.click { onDialogListener(AppConstants.DIALOG_OVER,this) }
}
}

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

@@ -62,10 +62,11 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
private lateinit var bindingWord : IncLearnWordBinding
//详情布局
private lateinit var incWorcDetailBinding: IncWordDetailBinding
private lateinit var incWorcDetailBinding : IncWordDetailBinding
//拼写内容布局
private lateinit var bindingSpell : IncLearnSpellBinding
//拼写前的提示
private lateinit var incSpellTipBinding : IncSpellLearnTipBinding
@@ -105,13 +106,21 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
setBackgroundColor(Color.parseColor("#1A5082E6"))
setTextColor(ContextCompat.getColor(this@LearnWordActivity, R.color.theme_color))
}
} else if (vm.learnData.isReview) {
binding.tvBanner.apply {
visibility = View.VISIBLE
setText(R.string.smart_reviewing)
setBackgroundColor(Color.parseColor("#1A5082E6"))
setTextColor(ContextCompat.getColor(this@LearnWordActivity, R.color.theme_color))
}
}
}
/** 标题初始 */
private fun initTitle() {
binding.incLearnTitle.run {
showProgress = false
//复习时显示复习正确的进度,学习、自动播放不显示进度
showProgress = vm.learnData.isReview
imgBack.click { onBackPressed() }
tvTitle.text = vm.learnData.lesson.lessonName
when (vm.learnData.lesson.coursePackType) {
@@ -135,9 +144,9 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
/** 历史轨迹初始 */
private fun initHistoricalRoute() {
val initCourseType = when{
val initCourseType = when {
//自动播放时,将历史轨迹的课时类型修改为单词类型,避免辨音课程自动播放时显示横线
vm.learnData.isAutoPlay -> AppConstants.COURSE_TYPE_ENGLISH_DISCERN
vm.learnData.isAutoPlay -> AppConstants.COURSE_TYPE_ENGLISH_DISCERN
else -> vm.learnData.lesson.courseType
}
adapterHistorical = AdapterHistoricalRoute(initCourseType).apply {
@@ -178,7 +187,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//拼写纠错按钮 点击事件
bindingSpell.tvControlError.click {
when (it.tag as Int) {
SPELL_TAG_ALL_RIGHT -> vm.currentSpellIsCorrect = false
SPELL_TAG_ALL_RIGHT -> vm.currentSpellIsCorrect = false
SPELL_TAG_IN_ERROR -> {
vm.currentSpellIsCorrect = true
//下一条显示
@@ -191,8 +200,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
bindingSpell.incWord.tvWord.click {
//拼写完成点击才有效,拼写中点击无效
if (!spellAdapter.isSpelling)
readWord()
if (!spellAdapter.isSpelling) readWord()
}
}
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> {
@@ -222,9 +230,9 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
incWorcDetailBinding.root.visibility = it
}
}
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_COMPOSITION){
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_COMPOSITION) {
bindingWord.imgWord.visibility = View.GONE
val layoutParams = bindingWord.incWord.root.layoutParams as ConstraintLayout.LayoutParams
val layoutParams = bindingWord.incWord.root.layoutParams as ConstraintLayout.LayoutParams
layoutParams.goneTopMargin = ScreenUtil.dp2px(12f).toInt()
bindingWord.incWord.root.requestLayout()
}
@@ -233,8 +241,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//初始化按钮
private fun initControlButton() {
//自动播放隐藏操作按钮
if (vm.learnData.isAutoPlay){
binding.incControlButton.root.visibility= View.GONE
if (vm.learnData.isAutoPlay) {
binding.incControlButton.root.visibility = View.GONE
return
}
//其他课程默认按钮全部隐藏
@@ -268,12 +276,12 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
//最底部
private fun initBottom(){
private fun initBottom() {
//有效时间
vm.validTime.observe(this){
binding.tvValidTime.text = "本次学习 ${DateUtil.formatGMT(it,DateUtil.FORMAT_2)}"
vm.validTime.observe(this) {
binding.tvValidTime.text = "本次学习 ${DateUtil.formatGMT(it, DateUtil.FORMAT_2)}"
}
if (vm.learnData.isAutoPlay){
if (vm.learnData.isAutoPlay) {
binding.tvPlay.run {
visibility = View.VISIBLE
tag = 1
@@ -285,7 +293,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
binding.tvPlay.click {
when(binding.tvPlay.tag as Int){
when (binding.tvPlay.tag as Int) {
1 -> { //暂停播放
vm.isAutoPlaying = false
binding.tvPlay.apply {
@@ -297,7 +305,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
binding.tvBanner.apply {
setText(R.string.auto_play_banner_paused)
setBackgroundColor(Color.parseColor("#1AF26255"))
setTextColor(ContextCompat.getColor(this@LearnWordActivity,R.color.red_1))
setTextColor(ContextCompat.getColor(this@LearnWordActivity, R.color.red_1))
}
}
2 -> { //继续播放
@@ -318,19 +326,20 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
}
//停止播放
binding.tvPlayStop.click {onBackPressed()}
binding.tvPlayStop.click { onBackPressed() }
}
}
/** 发音监听 */
private val impListener = object : IMPListener {
override fun onMpState(state : EMediaState) {
when{
vm.learnData.isAutoPlay -> when (state) {
when {
vm.learnData.isAutoPlay -> when (state) {
EMediaState.COMPLETE, EMediaState.ERROR -> {
//播放次数+1
vm.currentPlayTime ++
vm.currentPlayTime++
//继续播放,或获取下一条
LiveEventBus.get<Int>("auto_play").postDelay(0,700)
LiveEventBus.get<Int>("auto_play").postDelay(0, 700)
}
}
else -> when (state) {
@@ -345,10 +354,10 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
override fun loadData() {
vm.loadNext()
//如果自动播放,监听信息
if (vm.learnData.isAutoPlay){
LiveEventBus.get<Int>("auto_play").observe(this){
if (vm.learnData.isAutoPlay) {
LiveEventBus.get<Int>("auto_play").observe(this) {
if (!vm.isAutoPlaying) return@observe
when(vm.currentPlayTime){
when (vm.currentPlayTime) {
vm.learnData.autoPlayTime -> vm.loadNext()
else -> readWord()
}
@@ -358,19 +367,20 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//发音数据
AudioCache.initAudioLiveData().observe(this) {
//自动播放的单词音频数据
if (vm.learnData.isAutoPlay){
if (vm.learnData.isAutoPlay) {
it?.run {
MPManager.play(it,listener = impListener)
}?:let {
MPManager.play(it, listener = impListener)
} ?: let {
showToast("未找到发音文件")
//获取下一条
vm.loadNext()
}
return@observe
}
//学习、复习时的发音数据
it?.run {
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE)
MPManager.play(it, listener = impListener)
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_VOICE && bindingWord.ivVoice.visibility == View.VISIBLE) MPManager.play(
it, listener = impListener)
else MPManager.play(it)
} ?: showToast("未找到发音文件")
}
@@ -379,7 +389,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//图片数据
PhotoCache.initPhotoLiveData().observe(this) {
it?.run {
if(vm.learnData.isAutoPlay)bindingWord.imgWord.visibility = View.VISIBLE
if (vm.learnData.isAutoPlay) bindingWord.imgWord.visibility = View.VISIBLE
ImageLoader.loadImage(bindingWord.imgWord, it)
} ?: let { bindingWord.imgWord.visibility = View.GONE }
}
@@ -392,7 +402,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
adapterHistorical.addData(it)
binding.rvHistoricalRoute.scrollToPosition(adapterHistorical.itemCount - 1)
}
if (vm.learnData.isAutoPlay){
//自动播放界面初始
if (vm.learnData.isAutoPlay) {
initAutoPlayWord(it)
return@observe
}
@@ -413,9 +424,9 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//上传数据后的处理
vm.saveDataLiveData.observe(this) {
when {
//学习完成的保存数据
//学习完成的保存数据后显示学习完成弹窗
it -> showLearnOverDialog()
//学习未完成的保存数据
//学习未完成的保存数据,直接关闭
else -> finish()
}
}
@@ -434,10 +445,10 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
//单词内容
bindingWord.incWord.tvWord.apply {
//识字需单独处理
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_LITERACY){
setHtml(ViewUtil.literacyToHtmlWord(learnWord.word, learnWord.showColor))
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_LITERACY) {
setHtml(ViewUtil.literacyToHtmlWord(learnWord.word, learnWord.showColor))
} else {
text = learnWord.word
text = learnWord.word
}
setTextColor(ContextCompat.getColor(this@LearnWordActivity, learnWord.showColor)) //单词显示颜色
}
@@ -506,7 +517,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
binding.incControlButton.tvCenter.visibility = View.INVISIBLE
binding.incControlButton.tvRight.visibility = when (vm.learnData.lesson.coursePackType) {
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION,AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK -> View.INVISIBLE
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION, AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK -> View.INVISIBLE
else -> View.VISIBLE
}
@@ -569,8 +580,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
binding.incControlButton.tvCenter.visibility = View.VISIBLE
//音标,显示重读
when(vm.learnData.lesson.coursePackType){
AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK ->binding.incControlButton.tvRight.visibility = View.VISIBLE
when (vm.learnData.lesson.coursePackType) {
AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK -> binding.incControlButton.tvRight.visibility = View.VISIBLE
}
}
@@ -602,17 +613,16 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
/**点击下一条*/
private fun clickNext() {
//拼写,需要处理历史轨迹 和在下一条的时候保存当前学习数据
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_SPELL){
if (vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_ENGLISH_SPELL) {
adapterHistorical.currentLearnOver()
when{
when {
//正确
vm.currentSpellIsCorrect -> {
//传递正确
vm.clickCorrect(adapterHistorical.currentIsLastSelect)
val value = vm.currentLearnWord.value!!
// 正常第一次不需要移除,第一个表达式则判断为第一次出现但是为学前测试错误 ,第二个表达式为小循环但不为小循环最后一次且后面还有数据则需要移除
if ((value.first && value.repeatNum == 1) || (!value.first && value.repeatNum <vm.learnRuleUtil.insertInterval.size && vm.learnRuleUtil.isHaveNext))
adapterHistorical.spellNeedRemoveCurrent()
if ((value.first && value.repeatNum == 1) || (!value.first && value.repeatNum < vm.learnRuleUtil.insertInterval.size && vm.learnRuleUtil.isHaveNext)) adapterHistorical.spellNeedRemoveCurrent()
}
else -> {
vm.clickError(adapterHistorical.currentIsLastSelect)
@@ -622,7 +632,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
//当前数据为历史轨迹点击 且 最后一条学习未完成 且不为最后一条
if (!adapterHistorical.currentIsLastSelect && vm.currentIsHistoricalItemClick && !adapterHistorical.lastIsLearnOver) {
if (!adapterHistorical.currentIsLastSelect && vm.currentIsHistoricalItemClick && !adapterHistorical.lastIsLearnOver) {
skipToHistoricalLastItem()
} else {
vm.loadNext()
@@ -631,17 +641,18 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
/** 滑动到最后一项进行点击 */
private fun skipToHistoricalLastItem() {
binding.rvHistoricalRoute.post{
binding.rvHistoricalRoute.post {
val position = adapterHistorical.itemCount - 1 //最后item的位置
val last = historicalLayoutManager.findLastCompletelyVisibleItemPosition() //最后完全可见
if (position > last ){ //需要操作的位置大于当前最后显示的位置,则进行滚动
if (position > last) { //需要操作的位置大于当前最后显示的位置,则进行滚动
binding.rvHistoricalRoute.addOnScrollListener(historicalScrollListener)
binding.rvHistoricalRoute.smoothScrollToPosition(position)
}else { //position view 可见
} else { //position view 可见
historicalLayoutManager.findViewByPosition(position)?.performClick()
}
}
}
private val historicalScrollListener = object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) {
super.onScrollStateChanged(recyclerView, newState)
@@ -733,7 +744,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
private val itemSpellRecoveryClick = { showValue : SpannableStringBuilder, isOver : Boolean, nextPosition : Int ->
bindingSpell.incWord.tvWord.text = showValue
//纠错完成
if (isOver){
if (isOver) {
binding.incControlButton.tvLeft.visibility = View.VISIBLE
}
bindingSpell.spellRecyclerView.scrollToPosition(nextPosition)
@@ -763,9 +774,9 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
override fun dispatchTouchEvent(ev : MotionEvent?) : Boolean {
//执行有效计时
when{
when {
//自动播放只有在非播放时触摸有效
vm.learnData.isAutoPlay -> when{
vm.learnData.isAutoPlay -> when {
!vm.isAutoPlaying -> vm.executeLearnValidTime()
}
else -> vm.executeLearnValidTime()
@@ -775,16 +786,41 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
/** 返回 */
override fun onBackPressed() {
when {
vm.isAllOver -> finish()
else -> when {
vm.learnData.isAutoPlay -> autoPlayBackDialog()
vm.isHasLearned -> learnBackDialog()
else -> finish()
}
backDialog()
}
private fun backDialog() {
vm.showOrDismissBackDialogForTime(true)
val commonDialogBean = when {
vm.learnData.isAutoPlay -> CommonDialogBean(titleText = R.string.quit_auto_play_title, leftText = R.string.cancel,
rightText = R.string.quit)
else -> CommonDialogBean(titleText = R.string.quit_learn_title, contentText = R.string.quit_learn_content,
leftText = R.string.quit, rightText = R.string.cancel)
}
CommonDialog.newInstance(commonDialogBean).apply {
onCommonDialogButtonClickListener = { dialog, isRightClick ->
dialog.dismissAllowingStateLoss()
when {
//自动播放
vm.learnData.isAutoPlay -> when {
isRightClick -> vm.saveData()
else -> {
vm.showOrDismissBackDialogForTime(false)
LiveEventBus.get<Int>("auto_play").post(0)
}
}
//学习、复习
else -> when {
isRightClick -> vm.showOrDismissBackDialogForTime(false)
else -> vm.saveData()
}
}
}
}.show(supportFragmentManager, "learn_word_activity")
}
/** 学习时的返回弹窗 */

/* */
/** 学习时的返回弹窗 *//*
private fun learnBackDialog() {
vm.showOrDismissBackDialogForTime(true)
CommonDialog.newInstance(
@@ -798,7 +834,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
}.show(supportFragmentManager, "learn_back_dialog")
}
/** 自动播放时的返回弹窗 */
*/
/** 自动播放时的返回弹窗 *//*
private fun autoPlayBackDialog() {
vm.showOrDismissBackDialogForTime(true)
CommonDialog.newInstance(
@@ -814,17 +851,19 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
}
}.show(supportFragmentManager, "auto_play_back_dialog")
}
}*/
/** 学习完成 */
private fun showLearnOverDialog() {
when{
when {
//自动播放完成弹窗
vm.learnData.isAutoPlay -> showAutoPlayOverDialog()
//复习完成
vm.learnData.isReview -> showReviewOverDialog()
//作文知识点完成
vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> showCompositionKnowLeageLearningOver()
vm.learnData.lesson.courseType == AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> showCompositionKnowLeageLearningOver()
//其他单词类,带学后测试的课时完成
else -> showLessonWordLearningOver()
else -> showLessonWordLearningOver()
}
}
@@ -847,7 +886,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
dialog.dismissAllowingStateLoss()
//发送动作 : 学后测试
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION)
.post(LearnEventData(vm.learnData.lesson.subjectId, vm.learnData.lesson.courseId, AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply {
.post(LearnEventData(vm.learnData.lesson.subjectId, vm.learnData.lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_AGAIN).apply {
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList
})
finish()
@@ -862,9 +902,9 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
* 自动播放完成弹窗
*/
private fun showAutoPlayOverDialog() {
val drawable = DrawableUti.changeSvgSizeAndColor(resources, R.drawable.ic_right, R.color.theme_color,3)
CommonDialog.newInstance(CommonDialogBean(titleText = R.string.quit_auto_play_title_over,
rightText = R.string.sure),drawable).apply {
val drawable = DrawableUti.changeSvgSizeAndColor(resources, R.drawable.ic_right, R.color.theme_color, 3)
CommonDialog.newInstance(CommonDialogBean(titleText = R.string.quit_auto_play_title_over, rightText = R.string.sure),
drawable).apply {
onCommonDialogButtonClickListener = { dialog, _ ->
dialog.dismissAllowingStateLoss()
finish()
@@ -872,18 +912,34 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}.show(supportFragmentManager, "auto_play_back_dialog")
}
/**
* 复习完成弹窗
*/
private fun showReviewOverDialog() {
LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_REVIEW_OVER).apply {
correctNumber = vm.currentLessonLearnedPosition + 1 //本次已复习完成数量
errorNumber = vm.newVocabularyList.size //大循环复习完成数量
}).apply {
onDialogListener = { action, dialog ->
//完成 关闭,不处理
dialog.dismissAllowingStateLoss()
finish()
}
}.show(supportFragmentManager, "review_over")
}
/**
* 作文知识点学习完成弹窗
*/
private fun showCompositionKnowLeageLearningOver(){
private fun showCompositionKnowLeageLearningOver() {
LearnDialog.newInstance(LearnDialogBean(AppConstants.DIALOG_TYPE_LESSON_COMPOSITION_KNOWLEDGE_LEARNING_OVER).apply {
correctNumber = vm.learnData.lesson.correctNumber
errorNumber = vm.learnData.lesson.errorNumber
}).apply {
onDialogListener = { action, dialog ->
when(action){
when (action) {
//重学,重学弹窗提示
AppConstants.DIALOG_LESSON_RELEARN -> lessonRelearnDialog(dialog)
AppConstants.DIALOG_LESSON_RELEARN -> lessonRelearnDialog(dialog)
//完成 关闭,不处理
AppConstants.DIALOG_OVER -> {
dialog.dismissAllowingStateLoss()
@@ -891,7 +947,7 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}
}
}
}.show(supportFragmentManager,"composition_knowledge_learn_over")
}.show(supportFragmentManager, "composition_knowledge_learn_over")
}
/***
@@ -908,7 +964,8 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
dialog.dismissAllowingStateLoss()
//发送动作 : 重新学习
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_ACTION)
.post(LearnEventData(vm.learnData.lesson.subjectId, vm.learnData.lesson.courseId, AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply {
.post(LearnEventData(vm.learnData.lesson.subjectId, vm.learnData.lesson.courseId,
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN).apply {
leesonPositionIndex = vm.learnData.lesson.lessonPositionInList
})
finish()
@@ -917,7 +974,5 @@ class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordView
}.show(dialog.childFragmentManager, "lesson_relearn_tip")
}

}

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

@@ -47,10 +47,7 @@ class LearnWordViewModel : LearnBaseViewModel() {
//是否需要显示单词图片
var isNeedLoadPhoto = when (learnData.lesson.coursePackType) {
AppConstants.COURSEPACK_TYPE_ENGLISH_WORD,
AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK,
AppConstants.COURSEPACK_TYPE_CHINESE_LITERACY,
AppConstants.COURSEPACK_TYPE_CHINESE_PINYIN -> true
AppConstants.COURSEPACK_TYPE_ENGLISH_WORD, AppConstants.COURSEPACK_TYPE_ENGLISH_SOUNDMARK, AppConstants.COURSEPACK_TYPE_CHINESE_LITERACY, AppConstants.COURSEPACK_TYPE_CHINESE_PINYIN -> true
else -> false
}
@@ -87,6 +84,17 @@ class LearnWordViewModel : LearnBaseViewModel() {
//当前单词的自动播放次数
var currentPlayTime = 0
//当前复习时,大七次复习完成的集合,即新增词汇量集合
val newVocabularyList : MutableList<String> by lazy {
mutableListOf()
}
//复习只保留一条数据,正确只添加第一次出现的最后一条,错误时直接覆盖
val reviewMap : MutableMap<String, LearnEntity.Builder> by lazy {
mutableMapOf()
}
/**
* 定义有效时间
* 学习和自动播放有一点不一样哟
@@ -209,9 +217,9 @@ class LearnWordViewModel : LearnBaseViewModel() {
/**
* 保存当前学习数据
* @param item LearnWord
* @param isLastItem Boolean
* @param isCorrect Boolean
* @param item LearnWord 当前item
* @param isLastItem Boolean 是否是最后一个即非其他历史记录
* @param isCorrect Boolean 学习结果是否正确
*/
private fun saveCurrentLearnData(item : LearnWord, isLastItem : Boolean, isCorrect : Boolean) {
val key = "${item.chapterId}_${item.lessonId}_${item.wordId}"
@@ -219,22 +227,51 @@ class LearnWordViewModel : LearnBaseViewModel() {
//正确
isCorrect -> when {
//第一次正确
isLastItem && item.first -> record.addEntity(createBaseLearnEntity(item.wordId).apply {
if (learnRuleUtil.isInExamErrorMap(key)) {
isOnlySavePoint = true //设置仅保存学习点
isLastItem && item.first -> when {
//复习正确
learnData.isReview -> {
reviewMap[key] = createBaseLearnEntity(item).apply {
reviewNum = item.reviewNum + 1L
}
if (item.reviewNum == 7) {
newVocabularyList.add(key)
}
}
})
//学习正确
else -> record.addEntity(createBaseLearnEntity(item).apply {
if (learnRuleUtil.isInExamErrorMap(key)) {
isOnlySavePoint = true //设置仅保存学习点
}
})
}
}
//错误
else -> {
val newEntityBuilder = createBaseLearnEntity(item.wordId)
val newEntityBuilder = createBaseLearnEntity(item)
when {
//复习错误,直接放入集合,如果前面有数据将直接覆盖数据,只保存一条数据
learnData.isReview -> {
reviewMap[key] = createBaseLearnEntity(item).apply {
reviewNum = 1 //必须大于0,否则会被当作为第一次学习
isError = true
lastReviewDate = this.created
}
//如果在复习完成的集合中,进行移除
if (newVocabularyList.contains(key)) {
newVocabularyList.remove(key)
}
//return避免record添加newEntityBuilder
return
}
//第一次错误
isLastItem && item.first -> when {
//在错误列表中
learnRuleUtil.isInExamErrorMap(key) -> newEntityBuilder.setIsOnlySavePoint(true)
.setIsError(true)
.setReviewNum(1).lastReviewDate = getCurrentDateWithString()
learnRuleUtil.isInExamErrorMap(key) -> newEntityBuilder.apply {
isOnlySavePoint = true
isError = true
reviewNum = 1
lastReviewDate = getCurrentDateWithString()
}
else -> newEntityBuilder.isError = true
}
//历史轨迹错误
@@ -253,16 +290,14 @@ class LearnWordViewModel : LearnBaseViewModel() {
}
/** 生成一个基本的LearnEntity */
private fun createBaseLearnEntity(wordId : Long) : LearnEntity.Builder {
private fun createBaseLearnEntity(item : LearnWord) : LearnEntity.Builder {
return Struct.LearnEntity.newBuilder().apply {
learnData.lesson.let {
projectId = it.subjectId.toLong()
packId = it.coursePackId
courseId = it.courseId
chapterId = it.chapterId
lessonId = it.lessonId
entityId = wordId
}
projectId = item.subjectId.toLong()
packId = item.coursePackId
courseId = item.courseId
chapterId = item.chapterId
lessonId = item.lessonId
entityId = item.wordId
tag = "android"
created = getCurrentDateWithString()
}
@@ -295,8 +330,8 @@ class LearnWordViewModel : LearnBaseViewModel() {
Observable.create<Boolean> {
// record 已经实例化并已经将数据保存
if (!saveInit) {
//自动播放不修改课时信息
if (!learnData.isAutoPlay) {
//自动播放与复习不修改课时信息
if (!learnData.isAutoPlay || !learnData.isReview) {
learnData.lesson.apply {
learnedIndex = currentLessonLearnedPosition
correctNumber += learnRuleUtil.currentCorrectMap.size
@@ -306,6 +341,12 @@ class LearnWordViewModel : LearnBaseViewModel() {
//添加到错误本集合中,主要用于小游戏练习(学前总 课时都没有添加,从这里添加到集合后发送出去,添加到集合)
learnData.examErrorMap?.putAll(learnRuleUtil.currentErrorMap)
}
//如果是复习,数据是走reviewMap获取
if (learnData.isReview) {
reviewMap.forEach { entry ->
record.addEntity(entry.value)
}
}
record.addDuration(saveCurrentLearnDuration())
saveInit = true
}
@@ -314,7 +355,7 @@ class LearnWordViewModel : LearnBaseViewModel() {
}.compose(diskIo2Main()).subscribe({
showHideLoading(false)
sendEventBus() //返回发送数据
//数据保存完成后,通过数据为空进行通知,测试完成
//数据保存完成后,通过数据为空进行通知,完成
saveDataLiveData.value = isAllOver
}, {
showHideLoading(false)
@@ -338,6 +379,15 @@ class LearnWordViewModel : LearnBaseViewModel() {
private fun sendEventBus() {
//自动播放不发送信息通知
if (learnData.isAutoPlay) return
//复习发送事件,接收复习结果
if (learnData.isReview) {
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_REVIEW_DATA)
.post(LearnEventData(learnData.lesson.subjectId, learnData.lesson.courseId, AppConstants.DATA_REVIEW).apply {
this.leesonPositionIndex = currentLessonLearnedPosition
})
return
}
//学习发送结果
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_LESSON_DATA)
.post(LearnEventData(learnData.lesson.subjectId, learnData.lesson.courseId,
AppConstants.DATA_LESSON_LEARN_OVER).apply {

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

@@ -26,6 +26,8 @@ import com.xkl.cdl.adapter.AdapterAutoPlaySelectRepeat
import com.xkl.cdl.adapter.ViewPagerAdapter
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.bean.LearnWord
import com.xkl.cdl.data.bean.course.Course
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.bean.intentdata.LearnData
import com.xkl.cdl.data.binding.BindingAdapter
@@ -292,6 +294,21 @@ class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CourseP
}
}
/**
* 启动复习
* @param course Course
* @param reviewData MutableList<LearnWord>
*/
fun startReview(course: Course, reviewData: MutableList<LearnWord>){
val lesson = Lesson(course.subjectId, course.coursePackId, course.coursePackType,
course.courseId, course.courseType, 0, "", 0, course.courseTitle)
DataTransferHolder.instance.putData(value = LearnData(lesson).apply {
learnWordList = reviewData
isReview = true
})
startActivity(LearnWordActivity::class.java)
}
/** ViewModel Factory工厂 */
inner class ViewModelFactory(private val subjectId : Int, private val coursePackInPosition : Int) :

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

@@ -102,14 +102,17 @@ class CourseMainFragment : BaseFragmentVM<FragmentCourseMainBinding, CourseMainF
override fun loadData() {
vm.loadMain().observe(this) {
when (vm.course.courseType) {
//作文只有一个目录结构
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> changeChildrenFragmentForComposition()
else -> changeChildrenFragmentForWord()
}
changeChildren()
}
}
fun changeChildren() {
when (vm.course.courseType) {
//作文只有一个目录结构
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> changeChildrenFragmentForComposition()
else -> changeChildrenFragmentForWord()
}
}
/**
* 改变加载的子Fragment 单词类

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

@@ -25,6 +25,7 @@ import com.xkl.cdl.data.manager.db.DbControlBase
import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.module.XKLApplication
import com.xkl.cdl.module.m_center_learn.CoursePackMainActivityViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.functions.BiFunction
import io.reactivex.rxjava3.schedulers.Schedulers
@@ -71,6 +72,7 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
//获取课程的复习数据
//获取课程的章节数据
fun loadMain() : MutableLiveData<Boolean> {
isAssignmentReviewData = false
val mutableLiveData = MutableLiveData<Boolean>()
Observable.zip(DataRepository.getCourseDetails(course.subjectId, course.coursePackId, course.courseId).flatMap {
courseDetail = it
@@ -401,4 +403,16 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() {
return result
}
/** 查询复习课程的详细数据 */
fun queryReviewForDb():MutableLiveData<Boolean> {
val result = MutableLiveData<Boolean>()
Observable.fromCallable<Boolean> {
return@fromCallable DBCourseManager.queryReviewData(dbControlBase,reviewDataList)
}.subscribeOn(Schedulers.from(AppExecutors.diskIO))
.subscribe{
result.postValue(it)
}
return result
}
}

+ 44
- 4
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseReviewFragment.kt View File

@@ -3,11 +3,19 @@ package com.xkl.cdl.module.m_center_learn.coursechildren
import android.os.Bundle
import android.view.View
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.extension.click
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.bean.intentdata.LearnData
import com.xkl.cdl.data.event.LearnEventData
import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.databinding.FragmentCourseReviewBinding
import com.xkl.cdl.module.learn.LearnWordActivity
import com.xkl.cdl.module.m_center_learn.CoursePackMainActivity

/**
* 复习界面
@@ -68,11 +76,21 @@ class CourseReviewFragment : BaseFragmentVM<FragmentCourseReviewBinding, CourseM
}
//开始复习
binding.tvStartReview.click {
showToast("开始复习")
if (vm.isAssignmentReviewData){ //已经赋值,直接赋值跳转
(requireActivity() as CoursePackMainActivity).startReview(vm.course,vm.reviewDataList)
}else{ //没有赋值,需要进行
vm.queryReviewForDb().observe(this){
vm.isAssignmentReviewData = true
if (it){
(requireActivity() as CoursePackMainActivity).startReview(vm.course,vm.reviewDataList)
}else{
showToast("复习数据查询失败")
//如果是学习中心跳转过来,直接进行状态页
if (pageSource == 0 ){
(requireParentFragment() as CourseMainFragment).changeChildren()
}
}
}
}
}
//查看备忘本
@@ -103,7 +121,29 @@ class CourseReviewFragment : BaseFragmentVM<FragmentCourseReviewBinding, CourseM
}
override fun loadData() {
LiveEventBus.get<LearnEventData>(AppConstants.EVENT_REVIEW_DATA).observe(this){
if (it.subjectId != vm.course.subjectId || it.courseId != vm.course.courseId) return@observe
when(it.actionFlag){
AppConstants.DATA_REVIEW -> {
//复习完成
if (it.leesonPositionIndex == vm.reviewDataList.size - 1){
//清空
vm.reviewDataList.clear()
//切换界面
val pageSource = arguments?.getInt(AppConfig.INTENT_1) ?: 0
if ( pageSource == 0 ){
(requireParentFragment() as CourseMainFragment).changeChildren()
}else{ // TODO: 2022/6/6 备忘本需隐藏复习按钮,修改文字
initMemoData()
binding.tvStartReview.visibility = View.GONE
}
}else { // 复习未完成 todo 需要验证一下 sublist().clear()
vm.reviewDataList.subList(0, it.leesonPositionIndex + 1).clear()
initReviewData()
}
}
}
}
}
override fun initViewModel() : CourseMainFragmentViewModel {

+ 0
- 1
app/src/main/java/com/xkl/cdl/module/m_memo/MemoFragmentViewModel.kt View File

@@ -41,7 +41,6 @@ class MemoFragmentViewModel : BaseViewModel() {
it.onNext(wordList)
it.onComplete()
}.compose(diskIo2DiskIo()).subscribe({
AppApi.GetWordListResponse.parseFrom(it).wrongList?.forEach { wrong ->

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

@@ -15,8 +15,7 @@
<!--标题头部导航-->
<include
android:id="@+id/inc_learn_title"
layout="@layout/inc_learn_title"
app:showProgress="@{false}" />
layout="@layout/inc_learn_title" />

<View
android:layout_width="match_parent"

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

@@ -303,7 +303,11 @@
<!-- android:layout_height="wrap_content"-->
<!-- app:constraint_referenced_ids="tv_score,tv_tip,tv_title,inc_statistics_number,tv_left,vSplit"-->
<!-- />-->

<!--复习结束-->
<!-- <androidx.constraintlayout.widget.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="tv_title,tv_tip_1"/>-->


</androidx.constraintlayout.widget.ConstraintLayout>

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

@@ -66,7 +66,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_title"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone"/>
tools:visibility="visible"/>


<com.xkl.cdl.widget.VoiceSwitch

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

@@ -86,5 +86,6 @@
<string name="quit_auto_play_title_over">本课程自动播放完毕</string>
<string name="course_introduction">课程简介</string>
<string name="start_see_memo">查看备忘本</string>
<string name="smart_reviewing">智能复习中</string>

</resources>

Loading…
Cancel
Save