<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_lesson.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_lesson.xml" value="0.33" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_main.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_main.xml" value="0.4979166666666667" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.34427083333333336" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.34427083333333336" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_review.xml" value="0.12802768166089964" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_review.xml" value="0.67" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_total_test.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_total_test.xml" value="0.33" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_first.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_first.xml" value="0.4979166666666667" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.20104166666666667" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.25" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_course_lesson.xml" value="0.4785615491009682" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_course_lesson.xml" value="0.4785615491009682" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_empty.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_empty.xml" value="0.4979166666666667" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_historical_route.xml" value="0.4859375" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_historical_route.xml" value="0.4859375" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo.xml" value="0.478125" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_task_image.xml" value="0.23353596757852077" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_task_image.xml" value="0.23353596757852077" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_video_adapter.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_video_adapter.xml" value="0.67" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview_only.xml" value="0.49773550724637683" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview_only.xml" value="0.49773550724637683" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_arrow_right.xml" value="0.29814814814814816" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_arrow_right.xml" value="0.29814814814814816" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_composition.xml" value="0.30092592592592593" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_discern.xml" value="0.30092592592592593" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_literacy.xml" value="0.2972222222222222" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_pinying.xml" value="0.30092592592592593" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_soundmark.xml" value="0.35555555555555557" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_spell.xml" value="0.30092592592592593" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_spoken.xml" value="0.30092592592592593" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_voice.xml" value="0.35555555555555557" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_discern.xml" value="0.5061538461538462" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_discern.xml" value="0.5061538461538462" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_icon___.xml" value="0.287962962962963" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_icon___.xml" value="0.287962962962963" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_menu.xml" value="0.4036458333333333" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_menu.xml" value="0.4036458333333333" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_more.xml" value="0.35555555555555557" /> | |||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_memo.xml" value="0.21574074074074073" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_memo.xml" value="0.21574074074074073" /> | ||||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_my.xml" value="0.44166666666666665" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_my.xml" value="0.44166666666666665" /> |
// jniLibs.srcDirs = ['libs'] | // jniLibs.srcDirs = ['libs'] | ||||
// } | // } | ||||
// } | // } | ||||
自建数据库 | |||||
实现口语收藏、作文笔记收藏 | |||||
CourseMainFragmentViewModel.loadmain() | |||||
计算当前词汇量,课程完成/重学的时候调用一下;重学直接程序帮忙调用 | |||||
public native long calcCurrentVocabulary(long projectID) throws Exception; | |||||
计算学习效率(综合学习效率和课程效率) | |||||
public native void calcEfficiency(projectID, packID, courseID) throws Exception; | |||||
课程学习、时长信息 | |||||
public native String courseDetail(projectID, packID, courseID ) throws Exception; | |||||
速记课程排序列表 进度 | |||||
public native String courseSorted(long projectID ) throws Exception; | |||||
词条数统计 近90天词条数统计 | |||||
public native String entityCountList(long projectID, long gradeID ) throws Exception; | |||||
获取已学课程ID列表 | |||||
public native String getLearnedCourseIDList() throws Exception; | |||||
获取正确/错误词汇列表 | |||||
public native String getWordList(long projectID, long packID, long courseID, long categroy ) throws Exception; | |||||
保存数据struct.Record | |||||
public native void parseData(String var1) throws Exception; | |||||
重学 | |||||
public native void relearn(long var1, long var3, long var5, long var7, long var9, double var11, double var13, double var15) throws Exception; | |||||
保存已学课程ID | |||||
public native void setLearnedCourseID(long var1, long var3, long var5) throws Exception; | |||||
设置视频播放点 | |||||
public native void setVideoPoint(long var1, long var3, long var5, long var7, String var9) throws Exception; | |||||
统计信息 | |||||
public native String statisticsCenter(long var1, long var3) throws Exception; | |||||
设置课程学习点,同时会更新对应lesson的进度点 | |||||
public native void setLearnPoint(long var1, long var3, long var5, long var7, long var9, long var11) throws Exception; | |||||
GetVideoPoint 获取视频播放点 | |||||
public native String getVideoPoint(long var1, long var3, long var5, long var7) throws Exception; | |||||
public native void gameFinished(long var1, long var3, long var5, long var7, long var9) throws Exception; | |||||
public native void changeLocker(long var, long var3, long var5, long var7, long var9, boolean var11) throws Exception; | |||||
public native void delLearnedCourseID(long var1, long var3, long var5) throws Exception; | |||||
public native void destroy(); |
package com.xkl.cdl; | |||||
import com.suliang.common.util.LogUtil; | |||||
import com.xkl.cdl.module.XKLApplication; | |||||
import java.lang.reflect.InvocationHandler; | |||||
import java.lang.reflect.Method; | |||||
import java.lang.reflect.Proxy; | |||||
import mobile_cache.MobileCache; | |||||
/** | |||||
* author suliang | |||||
* create 2022/6/1 10:58 | |||||
* Describe: | |||||
*/ | |||||
public class HookMobileCache { | |||||
public void hook(){ | |||||
try{ | |||||
MobileCache mobileCache = XKLApplication.Companion.getMobileCache(); | |||||
Han han = new Han(mobileCache); | |||||
Object o = Proxy.newProxyInstance(han.getClass().getClassLoader(), mobileCache.getClass().getInterfaces(), han); | |||||
o.hashCode(); | |||||
}catch (Exception e){ | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
class Han implements InvocationHandler{ | |||||
private Object mobileObject ; | |||||
public Han(Object mobileObject) { | |||||
this.mobileObject = mobileObject; | |||||
} | |||||
@Override | |||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||||
//代理前添加操作 | |||||
LogUtil.INSTANCE.e(method.getName()); | |||||
Object value = method.invoke(mobileObject,args); | |||||
LogUtil.INSTANCE.e(value.toString()); | |||||
return value; | |||||
} | |||||
} | |||||
} |
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> { | AppConstants.COURSE_TYPE_ENGLISH_VOICE -> { | ||||
imageViewTypeVoice.run { | imageViewTypeVoice.run { | ||||
visibility = View.VISIBLE | visibility = View.VISIBLE | ||||
setImageResource(R.drawable.ic_voice) | |||||
setImageResource(R.drawable.ic_course_voice) | |||||
} | } | ||||
} | } | ||||
AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> { | AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> { | ||||
imageViewTypeVoice.run{ | imageViewTypeVoice.run{ | ||||
visibility = View.VISIBLE | visibility = View.VISIBLE | ||||
setImageResource(R.drawable.ic_spoken) | |||||
setImageResource(R.drawable.ic_course_spoken) | |||||
} | } | ||||
} | } | ||||
} | } |
package com.xkl.cdl.adapter | |||||
import android.annotation.SuppressLint | |||||
import android.content.res.ColorStateList | |||||
import android.graphics.Color | |||||
import android.view.View | |||||
import android.view.ViewGroup | |||||
import android.view.ViewTreeObserver | |||||
import androidx.core.content.ContextCompat | |||||
import com.google.android.material.badge.BadgeDrawable | |||||
import com.google.android.material.badge.BadgeUtils | |||||
import com.google.android.material.imageview.ShapeableImageView | |||||
import com.suliang.common.base.adapter.BaseAdapterViewHolder | |||||
import com.suliang.common.base.adapter.BaseRVAdapterVM | |||||
import com.suliang.common.databinding.ItemEmptyBinding | |||||
import com.xkl.cdl.R | |||||
import com.xkl.cdl.data.AppConstants | |||||
import com.xkl.cdl.data.bean.MemoCoursePack | |||||
import com.xkl.cdl.data.bean.course.Course | |||||
import com.xkl.cdl.data.binding.BindingAdapter | |||||
import com.xkl.cdl.databinding.ItemMemoBinding | |||||
import com.xkl.cdl.module.m_memo.MemoFragmentViewModel | |||||
/** | |||||
* author suliang | |||||
* create 2022/5/30 16:56 | |||||
* Describe: 备忘本适配器 | |||||
*/ | |||||
class AdapterCoursePackWithMemo(viewModel : MemoFragmentViewModel) : | |||||
BaseRVAdapterVM<MemoCoursePack, MemoFragmentViewModel>(viewModel) { | |||||
private val badgeDrawable : BadgeDrawable by lazy { | |||||
BadgeDrawable.create(context).apply { | |||||
badgeGravity = BadgeDrawable.TOP_END | |||||
maxCharacterCount = 3 | |||||
backgroundColor = ContextCompat.getColor(context, R.color.red_1) | |||||
badgeTextColor = ContextCompat.getColor(context, R.color.white) | |||||
} | |||||
} | |||||
override fun onBindEmptyViewHolder(holder : BaseAdapterViewHolder) { | |||||
(holder.binding as ItemEmptyBinding).run { | |||||
//根据监听,显示具体的内容 | |||||
vm.etSearchLiveData.value?.let { | |||||
if (it.isNotEmpty()) { | |||||
imgEmpty.setImageResource(R.mipmap.empty_nothing_search) | |||||
tvContent.text = "没有搜索到任何内容" | |||||
} else { | |||||
imgEmpty.setImageResource(R.mipmap.empty_nothing) | |||||
tvContent.text = "没有数据" | |||||
} | |||||
} | |||||
} | |||||
} | |||||
override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | |||||
return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_memo)) | |||||
} | |||||
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | |||||
getItem(position).let { item -> | |||||
(holder.binding as ItemMemoBinding).run { | |||||
//图片 | |||||
BindingAdapter.imageByteArray(imgCoursePackCover, item.coursePack.cover) | |||||
//文字 | |||||
tvCoursePackName.text = item.coursePack.coursePackName | |||||
//图标与角标文字 | |||||
item.coursePack.childrenCourses.forEachIndexed { index : Int, course : Course -> | |||||
when (course.courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> setImageIcon(imgCourseIcon1,course.courseType,item.coursePackChildrenReviewNumber[index].size) | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> setImageIcon(imgCourseIcon2,course.courseType,item.coursePackChildrenReviewNumber[index].size) | |||||
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> setImageIcon(imgCourseIcon3,course.courseType,item.coursePackChildrenReviewNumber[index].size) | |||||
//其他只有一个课程类型 | |||||
else -> { | |||||
setImageIcon(imgCourseIcon1,course.courseType,item.coursePackChildrenReviewNumber[index].size) | |||||
imgCourseIcon2.visibility = View.INVISIBLE | |||||
imgCourseIcon3.visibility = View.INVISIBLE | |||||
imgCourseIcon1.visibility = View.VISIBLE | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* 设置图片 角标 与 背景,有复习number数据需要设置角标与背景,否则不需要 | |||||
* @param imageView ShapeableImageView 图片 | |||||
* @param courseType Int 课程类型 | |||||
* @param reviewNumber Int 复习数量 | |||||
*/ | |||||
@SuppressLint("UnsafeOptInUsageError") | |||||
private fun setImageIcon(imageView : ShapeableImageView, courseType : Int, reviewNumber : Int) { | |||||
var color : Int = Color.parseColor("#00000000") | |||||
//取消角标 | |||||
BadgeUtils.detachBadgeDrawable(badgeDrawable,imageView) | |||||
when (reviewNumber) { | |||||
//没有数据 | |||||
0 -> { | |||||
imageView.strokeColor = ColorStateList.valueOf(color) | |||||
//设置图标: 灰色,没有背景 | |||||
imageView.setImageResource(getCourseIcon(courseType)) | |||||
imageView.imageTintList = ColorStateList.valueOf(Color.parseColor("#9A9EB3")) | |||||
} | |||||
//有复习数据 | |||||
else -> { | |||||
when (courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> color = Color.parseColor("#1A5082E6") | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> color = Color.parseColor("#1AF26255") | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPOKEN, AppConstants.COURSE_TYPE_ENGLISH_VOICE -> color = Color.parseColor( | |||||
"#1A52CC52") | |||||
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION, AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK -> color = Color.parseColor( | |||||
"#1A8757E6") | |||||
AppConstants.COURSE_TYPE_CHINESE_PINYIN -> color = Color.parseColor("#1AEB54D8") | |||||
AppConstants.COURSE_TYPE_CHINESE_LITERACY -> color = Color.parseColor("#1AFF8B52") | |||||
} | |||||
imageView.strokeColor = ColorStateList.valueOf(color) | |||||
//设置图标:原图颜色 | |||||
imageView.setImageResource(getCourseIcon(courseType)) | |||||
//添加角标 | |||||
imageView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { | |||||
@SuppressLint("UnsafeOptInUsageError") | |||||
override fun onGlobalLayout() { | |||||
BadgeDrawable.create(context).apply { | |||||
badgeGravity = BadgeDrawable.TOP_END | |||||
number = reviewNumber | |||||
maxCharacterCount = 3 | |||||
backgroundColor = ContextCompat.getColor(context, R.color.red_1) | |||||
badgeTextColor = ContextCompat.getColor(context, R.color.white) | |||||
BadgeUtils.attachBadgeDrawable(this, imageView) | |||||
} | |||||
imageView.viewTreeObserver.removeOnGlobalLayoutListener(this) | |||||
} | |||||
}) | |||||
} | |||||
} | |||||
} | |||||
private fun getCourseIcon(courseType : Int) : Int { | |||||
return when (courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> R.drawable.ic_course_discern | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> R.drawable.ic_course_spell | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> R.drawable.ic_course_spoken | |||||
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> R.drawable.ic_course_voice | |||||
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> R.drawable.ic_course_composition | |||||
AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK -> R.drawable.ic_course_soundmark | |||||
AppConstants.COURSE_TYPE_CHINESE_PINYIN -> R.drawable.ic_course_pinying | |||||
AppConstants.COURSE_TYPE_CHINESE_LITERACY -> R.drawable.ic_course_literacy | |||||
else -> 0 | |||||
} | |||||
} | |||||
private fun getCourseIconOriginColor(courseType : Int) : Int { | |||||
return when (courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> Color.parseColor("#5082E6") | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> Color.parseColor("#F26255") | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPOKEN, AppConstants.COURSE_TYPE_ENGLISH_VOICE -> Color.parseColor("#52CC52") | |||||
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION, AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK -> Color.parseColor( | |||||
"#8757E6") | |||||
AppConstants.COURSE_TYPE_CHINESE_PINYIN -> Color.parseColor("#EB54D8") | |||||
AppConstants.COURSE_TYPE_CHINESE_LITERACY -> Color.parseColor("#FF8B52") | |||||
else -> 0 | |||||
} | |||||
} | |||||
} |
package com.xkl.cdl.data.bean | |||||
import com.xkl.cdl.data.bean.course.CoursePack | |||||
/** | |||||
* author suliang | |||||
* create 2022/5/31 9:53 | |||||
* Describe: 课程包备忘本实体 | |||||
*/ | |||||
class MemoCoursePack(val coursePack: CoursePack){ | |||||
//对应课程的备忘本数据 | |||||
var coursePackChildrenMemoNumber = mutableListOf<MutableList<String>>() | |||||
//对应需要复习的数据 | |||||
var coursePackChildrenReviewNumber = mutableListOf<MutableList<String>>() | |||||
} |
var st_after: Double = AppConstants.NOT_DOING //学后总成绩 : -1代表没有进行学后总测试 | var st_after: Double = AppConstants.NOT_DOING //学后总成绩 : -1代表没有进行学后总测试 | ||||
var before: HashMap<String, Double> = hashMapOf() //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | var before: HashMap<String, Double> = hashMapOf() //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | ||||
var after: HashMap<String, Double> = hashMapOf() //章节学后测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | var after: HashMap<String, Double> = hashMapOf() //章节学后测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | ||||
var right = hashMapOf<String, Int>() //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
var wrong: HashMap<String, Int> = hashMapOf() //错误条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
var right = hashMapOf<String,Long>() //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
var wrong: HashMap<String, Long> = hashMapOf() //错误条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
var lesson_learn_point: HashMap<String, Long> = hashMapOf() //课时学习点 key=>{chapter_id}_{lesson_id} value=>{entity_id) | var lesson_learn_point: HashMap<String, Long> = hashMapOf() //课时学习点 key=>{chapter_id}_{lesson_id} value=>{entity_id) | ||||
var exam_w_r_list: HashMap<String, Boolean> = hashMapOf() //课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false | var exam_w_r_list: HashMap<String, Boolean> = hashMapOf() //课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false | ||||
var course_learn_point: String = "" //课程学习进度点 {chapter_id}_{lesson_id}_{entity_id} | var course_learn_point: String = "" //课程学习进度点 {chapter_id}_{lesson_id}_{entity_id} | ||||
var vp: HashMap<Long, String> = hashMapOf() //视频播放点,记录最新的就行 时间点 key=>video_id value=>{时间点} | var vp: HashMap<Long, String> = hashMapOf() //视频播放点,记录最新的就行 时间点 key=>video_id value=>{时间点} | ||||
var exercise_schedule: HashMap<Long, Double> = hashMapOf() //课程练习进度(仅作文有效) | |||||
var rl: Int = 0 //课程重学次数;有值表示是重新学,默认不是重新学习,对应数值表示第几次重学 用于辨音,拼写判断是否解锁, | |||||
var chapter_rl: HashMap<String, Long> = hashMapOf() //章节重学次数,key =>{chapter_id}_{lesson_id} value=> relearn times | |||||
var ct: Long = 0 //课程已学词汇量 | var ct: Long = 0 //课程已学词汇量 | ||||
var e = 0.0 //学习效率 | var e = 0.0 //学习效率 | ||||
var valid: HashMap<Long, Long> = hashMapOf() //有效学习时长,单位毫秒 key=>分时标记,value=>时长 | var valid: HashMap<Long, Long> = hashMapOf() //有效学习时长,单位毫秒 key=>分时标记,value=>时长 | ||||
var current_week_total_durations: Long = 0 | var current_week_total_durations: Long = 0 | ||||
var last_e: Double = 0.0 //上周期学习效率 | var last_e: Double = 0.0 //上周期学习效率 | ||||
var temporary_words: HashMap<String, String> = hashMapOf() //课程错误本,重学会删除 key=>{chapter_id}_{lesson_id}_{entity_id} value=> first learn time | var temporary_words: HashMap<String, String> = hashMapOf() //课程错误本,重学会删除 key=>{chapter_id}_{lesson_id}_{entity_id} value=> first learn time | ||||
// var exercise_schedule: HashMap<Long, Double> = hashMapOf() //课程练习进度(仅作文有效) | |||||
// var rl: Int = 0 //课程重学次数;有值表示是重新学,默认不是重新学习,对应数值表示第几次重学 用于辨音,拼写判断是否解锁, | |||||
// var chapter_rl: HashMap<String, Long> = hashMapOf() //章节重学次数,key =>{chapter_id}_{lesson_id} value=> relearn times | |||||
} | } |
field = value | field = value | ||||
notifyPropertyChanged(BR.learnProgress) | notifyPropertyChanged(BR.learnProgress) | ||||
} | } | ||||
override fun equals(other: Any?): Boolean { | |||||
override fun equals(other : Any?) : Boolean { | |||||
if (this === other) return true | if (this === other) return true | ||||
if (javaClass != other?.javaClass) return false | if (javaClass != other?.javaClass) return false | ||||
other as CoursePack | other as CoursePack | ||||
if (coursePackId != other.coursePackId) return false | if (coursePackId != other.coursePackId) return false | ||||
if (coursePackName != other.coursePackName) return false | if (coursePackName != other.coursePackName) return false | ||||
if (!cover.contentEquals(other.cover)) return false | if (!cover.contentEquals(other.cover)) return false | ||||
if (summary != other.summary) return false | if (summary != other.summary) return false | ||||
if (subjectId != other.subjectId) return false | if (subjectId != other.subjectId) return false | ||||
if (coursePackType != other.coursePackType) return false | if (coursePackType != other.coursePackType) return false | ||||
if (inCoursePackPosition != other.inCoursePackPosition) return false | |||||
if (childrenCourses != other.childrenCourses) return false | if (childrenCourses != other.childrenCourses) return false | ||||
if (learnProgress != other.learnProgress) return false | |||||
return true | return true | ||||
} | } | ||||
override fun hashCode(): Int { | |||||
override fun hashCode() : Int { | |||||
var result = coursePackId.hashCode() | var result = coursePackId.hashCode() | ||||
result = 31 * result + coursePackName.hashCode() | result = 31 * result + coursePackName.hashCode() | ||||
result = 31 * result + cover.contentHashCode() | result = 31 * result + cover.contentHashCode() | ||||
result = 31 * result + summary.hashCode() | result = 31 * result + summary.hashCode() | ||||
result = 31 * result + subjectId | result = 31 * result + subjectId | ||||
result = 31 * result + coursePackType | result = 31 * result + coursePackType | ||||
result = 31 * result + inCoursePackPosition | |||||
result = 31 * result + childrenCourses.hashCode() | result = 31 * result + childrenCourses.hashCode() | ||||
result = 31 * result + learnProgress.hashCode() | |||||
return result | return result | ||||
} | } | ||||
} | } |
import appApi.AppApi | import appApi.AppApi | ||||
import com.suliang.common.util.AppGlobals | import com.suliang.common.util.AppGlobals | ||||
import com.suliang.common.util.DateUtil | |||||
import com.suliang.common.util.file.FileUtil | import com.suliang.common.util.file.FileUtil | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.data.bean.course.CoursePack | import com.xkl.cdl.data.bean.course.CoursePack | ||||
import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
import com.xkl.cdl.data.bean.course.Lesson | import com.xkl.cdl.data.bean.course.Lesson | ||||
import java.io.* | import java.io.* | ||||
import java.lang.Exception | |||||
import java.math.BigDecimal | import java.math.BigDecimal | ||||
import java.math.RoundingMode | import java.math.RoundingMode | ||||
import java.text.DateFormat | |||||
import java.text.DecimalFormat | import java.text.DecimalFormat | ||||
import java.text.SimpleDateFormat | |||||
import java.util.* | |||||
import java.util.zip.ZipFile | import java.util.zip.ZipFile | ||||
import java.util.zip.ZipInputStream | import java.util.zip.ZipInputStream | ||||
} ?: 0 | } ?: 0 | ||||
} | } | ||||
// TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 | |||||
//间隔时间单位 | |||||
private val reviewIntervalUnit = "day" | |||||
//间隔单位时间 | |||||
private val reviewTime = IntArray(7){ | |||||
when(it){ | |||||
0 -> 1 | |||||
1 -> 2 | |||||
2 -> 3 | |||||
3 -> 5 | |||||
4 -> 7 | |||||
5 -> 10 | |||||
else -> 15 | |||||
} | |||||
} | |||||
/** | |||||
* 计算是否需要仅需复习 | |||||
* @param currentReviewNumber String 当前词复习的次数 | |||||
* @param currentReviewTime String 当前词复习的时间 | |||||
* @param currentTime Long 用以计算的当前时间 | |||||
* @return Boolean true:需要复习 false:不需要复习 | |||||
*/ | |||||
fun calculateIsNeedInReview(calendar:Calendar,currentReviewNumber : Int, currentReviewTime : String, currentTime : Long) : Boolean { | |||||
if (currentReviewNumber >= reviewTime.size) return false | |||||
try { | |||||
//转换设置当前的复习时间 | |||||
calendar.time = DateUtil.format(currentReviewTime,DateUtil.FORMAT_1) | |||||
//与当前时间的间隔 | |||||
val intervalTime = currentTime - calendar.timeInMillis | |||||
//单位转换 : 给一个提前量的时间,提前一分钟 | |||||
return intervalTime >= when(reviewIntervalUnit){ | |||||
"minute" -> reviewTime[currentReviewNumber] * 60000 | |||||
"hour" -> reviewTime[currentReviewNumber] * 60 * 60000 | |||||
else -> reviewTime[currentReviewNumber] * 24 * 60 * 60000 | |||||
} - 60000 | |||||
}catch (e:Exception){ | |||||
e.printStackTrace() | |||||
} | |||||
return false | |||||
} | |||||
} | } |
lessonPositionInList = positionIndex | lessonPositionInList = positionIndex | ||||
this.wordIds = wordIds //内容 | this.wordIds = wordIds //内容 | ||||
totalNumber = this.wordIds.size //总数 | totalNumber = this.wordIds.size //总数 | ||||
correctNumber = detail.right.getOrElse(key, { 0 }) //正确数 | |||||
errorNumber = detail.wrong.getOrElse(key, { 0 }) //错误数 | |||||
correctNumber = detail.right.getOrElse(key, { 0 }).toInt() //正确数 | |||||
errorNumber = detail.wrong.getOrElse(key, { 0 }).toInt() //错误数 | |||||
beforeTestScore = detail.before.getOrElse(key, { AppConstants.NOT_DOING }) //课时学前测试成绩 | beforeTestScore = detail.before.getOrElse(key, { AppConstants.NOT_DOING }) //课时学前测试成绩 | ||||
afterTestScore = detail.after.getOrElse(key, { AppConstants.NOT_DOING }) //课时学后测试成绩 | afterTestScore = detail.after.getOrElse(key, { AppConstants.NOT_DOING }) //课时学后测试成绩 | ||||
this.lessonType = lessonType | this.lessonType = lessonType |
package com.xkl.cdl.data.repository | package com.xkl.cdl.data.repository | ||||
import appApi.AppApi | |||||
import com.google.protobuf.ProtocolStringList | |||||
import com.googlecode.protobuf.format.JsonFormat | import com.googlecode.protobuf.format.JsonFormat | ||||
import com.suliang.common.extension.io2Io | |||||
import com.suliang.common.util.file.FileUtil | import com.suliang.common.util.file.FileUtil | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.data.bean.course.CourseDetail | import com.xkl.cdl.data.bean.course.CourseDetail | ||||
import com.xkl.cdl.data.bean.course.Lesson | import com.xkl.cdl.data.bean.course.Lesson | ||||
import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import com.xkl.cdl.module.XKLApplication | |||||
import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
import mqComsumerV1.Struct | import mqComsumerV1.Struct | ||||
import java.io.File | import java.io.File | ||||
* Describe: 数据提供 | * Describe: 数据提供 | ||||
*/ | */ | ||||
object DataRepository { | object DataRepository { | ||||
// TODO: 2022/6/1 需自己实现获取课程收藏数据,同时需自己处理保存数据 | |||||
/** 获取课程的收藏本 */ | /** 获取课程的收藏本 */ | ||||
fun getCourseCollect() : Observable<HashMap<String,Long>>{ | fun getCourseCollect() : Observable<HashMap<String,Long>>{ | ||||
return Observable.create{ | return Observable.create{ | ||||
} | } | ||||
/** 获取复习的内容 */ | /** 获取复习的内容 */ | ||||
fun getReviewData() : Observable<Array<String>> { | |||||
fun getReviewData(subjectId : Int,coursePackId : Long,courseId : Long) : Observable<ProtocolStringList> { | |||||
return Observable.create{ | return Observable.create{ | ||||
mutableListOf<String>() | |||||
it.onNext(Array<String>(1){"1"}) | |||||
val wordList = XKLApplication.mobileCache.getWordList(subjectId.toLong(), coursePackId, courseId, 2) | |||||
val parseFrom = wordList?.let { | |||||
AppApi.GetWordListResponse.parseFrom(wordList) | |||||
}?: AppApi.GetWordListResponse.newBuilder().build() | |||||
it.onNext(parseFrom.wrongList) | |||||
it.onComplete() | it.onComplete() | ||||
} | } | ||||
} | } | ||||
/** 获取课程的详情 */ | /** 获取课程的详情 */ | ||||
fun getCourseStatistics(subjectId:Int,coursePackId:Long,courseId:Long): Observable<CourseDetail>{ | |||||
fun getCourseDetails(subjectId:Int, coursePackId:Long, courseId:Long): Observable<CourseDetail>{ | |||||
return Observable.create{ | return Observable.create{ | ||||
// 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() | |||||
val pbCourseDetail = XKLApplication.mobileCache.courseDetail(subjectId.toLong(), coursePackId, courseId).let { | |||||
AppApi.CourseDetailResponse .parseFrom(it).detail | |||||
} | |||||
val courseDetail = CourseDetail().apply { | |||||
courseLearnProgress = pbCourseDetail.s //课程学习进度 | |||||
st_before = pbCourseDetail.stBefore //学前总成绩 : -1代表没有进行学前总测试 | |||||
st_after = pbCourseDetail.stAfter //学后总成绩 : -1代表没有进行学后总测试 | |||||
before = HashMap(pbCourseDetail.beforeMap) //章节学前测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | |||||
after = HashMap(pbCourseDetail.afterMap) //章节学后测试成绩,key=>{chapter_id}_{lesson_id} value=>成绩 | |||||
right = HashMap(pbCourseDetail.rightMap) //正确条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
wrong = HashMap(pbCourseDetail.wrongMap) //错误条目数,key=>{chapter_id}_{lesson_id} value=>条目数量 | |||||
lesson_learn_point = HashMap( | |||||
pbCourseDetail.chapterLpMap) //课时学习点 key=>{chapter_id}_{lesson_id} value=>{entity_id) | |||||
exam_w_r_list = HashMap( | |||||
pbCourseDetail.examWRListMap) //课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false | |||||
course_learn_point = pbCourseDetail.lp //课程学习进度点 {chapter_id}_{lesson_id}_{entity_id} | |||||
vp = HashMap(pbCourseDetail.vpMap) //视频播放点,记录最新的就行 时间点 key=>video_id value=>{时间点} | |||||
ct = pbCourseDetail.ct //课程已学词汇量 | |||||
e = pbCourseDetail.e //学习效率 | |||||
valid = HashMap(pbCourseDetail.validMap) //有效学习时长,单位毫秒 key=>分时标记,value=>时长 | |||||
review = HashMap(pbCourseDetail.reviewMap) //有效复习时长,单位毫秒 key=>分时标记,value=>时长 | |||||
total = HashMap(pbCourseDetail.totalMap) //总时长,单位毫秒 key=>分时标记,value=>时长 | |||||
current_week_total_durations = pbCourseDetail.currentWeekTotalDurations | |||||
last_e = pbCourseDetail.lastE //上周期学习效率 | |||||
temporary_words = HashMap( | |||||
pbCourseDetail.temporaryWordsMap) //课程错误本,重学会删除 key=>{chapter_id}_{lesson_id}_{entity_id} value=> first learn time | |||||
// exercise_schedule: HashMap<Long, Double> = HashMap(pbCourseDetail.exerciseScheduleMap) //课程练习进度(仅作文有效) | |||||
// rl: Int = 0 //课程重学次数;有值表示是重新学,默认不是重新学习,对应数值表示第几次重学 用于辨音,拼写判断是否解锁, | |||||
// chapter_rl: HashMap<String, Long> = hashMapOf() //章节重学次数,key =>{chapter_id}_{lesson_id} value=> relearn times | |||||
} | } | ||||
it.onNext(courseDetail) | it.onNext(courseDetail) | ||||
it.onComplete() | it.onComplete() | ||||
// T这里自己使用的缓存 | |||||
// val file = File(FileUtil.getSaveDirPath("appcache"), "${subjectId}_${coursePackId}_${courseId}") | |||||
// val courseDetail = if (file.exists()){ | |||||
// FileUtil.bytesToObject(FileUtil.readFile(file)) as CourseDetail | |||||
// }else{ | |||||
// CourseDetail() | |||||
// } | |||||
} | } | ||||
} | } | ||||
//计算词汇量和学习效率 | //计算词汇量和学习效率 | ||||
calcCourseVocabularyAndEfficiency(subjectId,coursePackId,courseId) | calcCourseVocabularyAndEfficiency(subjectId,coursePackId,courseId) | ||||
} | } | ||||
// TODO: 2022/4/29 调用保存方法 | |||||
try { | |||||
XKLApplication.mobileCache.parseData(record.build().toByteArray()) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
return false | |||||
} | |||||
var fileName = "" | |||||
/*var fileName = "" | |||||
//写入文件 | //写入文件 | ||||
if (record.examCount > 0 ){ //当前为测试 | if (record.examCount > 0 ){ //当前为测试 | ||||
val s = when (record.getExam(0).type.toInt()) { //测试类型 | val s = when (record.getExam(0).type.toInt()) { //测试类型 | ||||
//序列化输出 | //序列化输出 | ||||
val string = JsonFormat.printToString(record.build()) | val string = JsonFormat.printToString(record.build()) | ||||
val saveArray = record.build().toByteArray() | val saveArray = record.build().toByteArray() | ||||
val saveStringName = "${fileName}_jsonString.txt" | val saveStringName = "${fileName}_jsonString.txt" | ||||
FileUtil.writeBytesToFile(it,saveStringName,string.toByteArray()) | FileUtil.writeBytesToFile(it,saveStringName,string.toByteArray()) | ||||
val saveByteArrayName = "${fileName}_byteArray.txt" | val saveByteArrayName = "${fileName}_byteArray.txt" | ||||
FileUtil.writeBytesToFile(it,saveByteArrayName,saveArray) | FileUtil.writeBytesToFile(it,saveByteArrayName,saveArray) | ||||
} | |||||
}*/ | |||||
return true | return true | ||||
} | } | ||||
// TODO: 2022/6/1 计算词汇量和效率可以在需要的时候进行计算后再获取 | |||||
/** | /** | ||||
* 计算当前词汇量 与 学习效率 | * 计算当前词汇量 与 学习效率 | ||||
*/ | */ | ||||
public fun calcCourseVocabularyAndEfficiency( projectId:Long, packId:Long, courseId:Long) { | |||||
private fun calcCourseVocabularyAndEfficiency( projectId:Long, packId:Long, courseId:Long) { | |||||
Observable.create<Boolean> { | |||||
try { | |||||
XKLApplication.mobileCache.calcCurrentVocabulary(projectId) //词汇量 | |||||
XKLApplication.mobileCache.calcEfficiency(projectId,packId,courseId) //效率 | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
} | |||||
it.onComplete() | |||||
}.compose(io2Io()).subscribe() | |||||
} | } | ||||
} | } |
import android.app.Application | import android.app.Application | ||||
import com.suliang.common.util.LogUtil | import com.suliang.common.util.LogUtil | ||||
import com.suliang.common.util.file.FileUtil | |||||
import com.tencent.mmkv.MMKV | import com.tencent.mmkv.MMKV | ||||
import io.reactivex.rxjava3.exceptions.UndeliverableException | import io.reactivex.rxjava3.exceptions.UndeliverableException | ||||
import io.reactivex.rxjava3.functions.Consumer | import io.reactivex.rxjava3.functions.Consumer | ||||
import io.reactivex.rxjava3.plugins.RxJavaPlugins | import io.reactivex.rxjava3.plugins.RxJavaPlugins | ||||
import mobile_cache.MobileCache | |||||
import mobile_cache.Mobile_cache | |||||
import net.sqlcipher.database.SQLiteDatabase | import net.sqlcipher.database.SQLiteDatabase | ||||
import java.io.File | |||||
import java.io.IOException | import java.io.IOException | ||||
import java.lang.IllegalArgumentException | |||||
import java.lang.IllegalStateException | |||||
import java.lang.NullPointerException | |||||
import java.util.* | import java.util.* | ||||
/** | /** | ||||
* Describe: | * Describe: | ||||
*/ | */ | ||||
class XKLApplication : Application() { | class XKLApplication : Application() { | ||||
companion object{ | |||||
val mobileCache:MobileCache by lazy { | |||||
val file : String = File(FileUtil.getSaveDirFile("db"), "mydb").absolutePath | |||||
Mobile_cache.new_(file) | |||||
} | |||||
} | |||||
override fun onCreate() { | override fun onCreate() { | ||||
super.onCreate() | super.onCreate() | ||||
SQLiteDatabase.loadLibs(this) | SQLiteDatabase.loadLibs(this) | ||||
// ImageLoader.mStrategy = GlideLoaderStrategy() | |||||
LogUtil.e(UUID.randomUUID().toString().replace("-","")) | LogUtil.e(UUID.randomUUID().toString().replace("-","")) | ||||
//初始MMKV存储 | //初始MMKV存储 | ||||
val rootDir = MMKV.initialize(this) | val rootDir = MMKV.initialize(this) | ||||
LogUtil.e(rootDir) | LogUtil.e(rootDir) | ||||
setRxJavaErrorHandler() | setRxJavaErrorHandler() | ||||
// HookMobileCache().hook() | |||||
} | } | ||||
/*** | /*** | ||||
* 避免 调用多次onError。正常来说第一次onError会走正常的Observer处理,其他会走ErrorHandler。通过此方法捕捉多次的error | * 避免 调用多次onError。正常来说第一次onError会走正常的Observer处理,其他会走ErrorHandler。通过此方法捕捉多次的error | ||||
*/ | */ |
} | } | ||||
/** | /** | ||||
* 添加到收藏 | |||||
* 取消收藏 | |||||
* @return MutableLiveData<Long> | * @return MutableLiveData<Long> | ||||
*/ | */ | ||||
fun removeCollect() : MutableLiveData<Long> { | fun removeCollect() : MutableLiveData<Long> { | ||||
} | } | ||||
fun saveData() { | fun saveData() { | ||||
// TODO: 2022/5/20 保存记录点 如果学习完成,则设置进度点和修改为学习完成 | |||||
Observable.create<Boolean> { emitter -> | Observable.create<Boolean> { emitter -> | ||||
val record = Struct.Record.newBuilder().apply { | val record = Struct.Record.newBuilder().apply { | ||||
addEntity(Struct.LearnEntity.newBuilder().apply { | addEntity(Struct.LearnEntity.newBuilder().apply { |
import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import com.xkl.cdl.data.repository.DataRepository | import com.xkl.cdl.data.repository.DataRepository | ||||
import com.xkl.cdl.module.XKLApplication | |||||
import com.xkl.videoplayer.bean.PineMediaPlayerBean | import com.xkl.videoplayer.bean.PineMediaPlayerBean | ||||
import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
import io.reactivex.rxjava3.functions.BiFunction | |||||
import mqComsumerV1.Struct | import mqComsumerV1.Struct | ||||
uploadDate.value = true | uploadDate.value = true | ||||
return | return | ||||
} | } | ||||
// TODO: 2022/5/26 保存视频的播放时间 | |||||
Observable.create<Boolean> { emitter -> | |||||
Observable.zip( | |||||
Observable.create<Boolean> { | |||||
try { | |||||
//保存视频播放时间 | |||||
XKLApplication.mobileCache.setVideoPoint(lesson.subjectId.toLong(), lesson.coursePackId, lesson.courseId, lesson.wordIds[0], currentPlayTime.toString()) | |||||
it.onNext(true) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
it.onNext(false) | |||||
} | |||||
it.onComplete() | |||||
}, | |||||
Observable.create<Boolean> { emitter -> | |||||
//保存数据 | |||||
val record = Struct.Record.newBuilder().apply { | val record = Struct.Record.newBuilder().apply { | ||||
//进度点 | //进度点 | ||||
addEntity(Struct.LearnEntity.newBuilder().apply { | addEntity(Struct.LearnEntity.newBuilder().apply { | ||||
} | } | ||||
emitter.onNext(DataRepository.saveRecord(record)) | emitter.onNext(DataRepository.saveRecord(record)) | ||||
emitter.onComplete() | emitter.onComplete() | ||||
}.compose(diskIo2Main()).subscribe { | |||||
}, { t1, t2 -> | |||||
t1 && t2 | |||||
}).compose(diskIo2Main()).subscribe { | |||||
if (!it){ | |||||
LogUtil.e("视频数据保存有误") | |||||
return@subscribe | |||||
} | |||||
lesson.videoPlayTime = currentPlayTime | lesson.videoPlayTime = currentPlayTime | ||||
LogUtil.e("当前播放时间:$currentPlayTime") | LogUtil.e("当前播放时间:$currentPlayTime") | ||||
when{ | when{ |
/** 测试完成 : 弹窗显示 */ | /** 测试完成 : 弹窗显示 */ | ||||
private fun testOver() { | private fun testOver() { | ||||
// TODO: 2022/5/17 作文测试弹窗 | |||||
//对话框信息实体 | //对话框信息实体 | ||||
val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_OVER).apply { | val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_OVER).apply { | ||||
examType = vm.intentData.examType | examType = vm.intentData.examType |
private fun saveData() { | private fun saveData() { | ||||
showHideLoading(true) | showHideLoading(true) | ||||
Observable.create<Boolean> { | Observable.create<Boolean> { | ||||
viewModelScope.launch { | |||||
delay(1000) | |||||
DataRepository.saveRecord(record) | |||||
it.onNext(true) | |||||
it.onComplete() | |||||
} | |||||
// TODO: 2022/4/14 传递保存record信息 | |||||
val saveRecord = DataRepository.saveRecord(record) | |||||
it.onNext(saveRecord) | |||||
it.onComplete() | |||||
}.compose(diskIo2Main()).subscribe({ | }.compose(diskIo2Main()).subscribe({ | ||||
showHideLoading(false) | showHideLoading(false) | ||||
sendEventBus() //返回发送数据 | sendEventBus() //返回发送数据 |
/** 横幅 自动播放 与 复习时使用 */ | /** 横幅 自动播放 与 复习时使用 */ | ||||
private fun initBanner() { | private fun initBanner() { | ||||
// TODO: 2022/4/25 初始化横幅,默认隐藏 | |||||
// 初始化横幅,默认隐藏 | |||||
if (vm.learnData.isAutoPlay) { | if (vm.learnData.isAutoPlay) { | ||||
binding.tvBanner.apply { | binding.tvBanner.apply { | ||||
visibility = View.VISIBLE | visibility = View.VISIBLE |
fun saveData() { | fun saveData() { | ||||
showHideLoading(true) | showHideLoading(true) | ||||
Observable.create<Boolean> { | Observable.create<Boolean> { | ||||
viewModelScope.launch { | |||||
delay(1000) | |||||
it.onNext(true) | |||||
} | |||||
// TODO: 2022/4/14 传递保存record信息 | |||||
// record 已经实例化并已经将数据保存 | // record 已经实例化并已经将数据保存 | ||||
if (!saveInit) { | if (!saveInit) { | ||||
//自动播放不修改课时信息 | //自动播放不修改课时信息 | ||||
record.addDuration(saveCurrentLearnDuration()) | record.addDuration(saveCurrentLearnDuration()) | ||||
saveInit = true | saveInit = true | ||||
} | } | ||||
DataRepository.saveRecord(record) | |||||
// LogUtil.e(JsonFormat.printToString(record.build())) | |||||
it.onNext(DataRepository.saveRecord(record)) | |||||
it.onComplete() | |||||
}.compose(diskIo2Main()).subscribe({ | }.compose(diskIo2Main()).subscribe({ | ||||
showHideLoading(false) | showHideLoading(false) | ||||
sendEventBus() //返回发送数据 | sendEventBus() //返回发送数据 |
import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | ||||
/** | /** | ||||
* 课程中心 | |||||
* 课程包主页中心 | |||||
*/ | */ | ||||
class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CoursePackMainActivityViewModel>() { | class CoursePackMainActivity : BaseActivityVM<ActivityCourseMainBinding, CoursePackMainActivityViewModel>() { | ||||
//子课程对应的Fragment | //子课程对应的Fragment | ||||
private var childFragments = mutableListOf<Fragment>() | private var childFragments = mutableListOf<Fragment>() | ||||
// //更多按钮的弹窗显示 | |||||
// private var moreDialog : BottomSheetDialog? = null | |||||
//自动播放次数的弹窗选择 | //自动播放次数的弹窗选择 | ||||
private var autoPlaySeletDialog : BottomSheetDialog? = null | private var autoPlaySeletDialog : BottomSheetDialog? = null | ||||
} | } | ||||
} | } | ||||
override fun onStop() { | |||||
super.onStop() | |||||
//如果是中文项目,更新课程包的进度 | |||||
if (vm.coursePack.subjectId == AppConstants.SUBJECT_CHINESE) { | |||||
vm.coursePack.learnProgress = vm.coursePack.childrenCourses[0].courseLearnProgress | |||||
} | |||||
} | |||||
/** ViewModel Factory工厂 */ | /** ViewModel Factory工厂 */ | ||||
inner class ViewModelFactory(private val subjectId : Int, private val coursePackInPosition : Int) : | inner class ViewModelFactory(private val subjectId : Int, private val coursePackInPosition : Int) : |
package com.xkl.cdl.module.m_center_learn | package com.xkl.cdl.module.m_center_learn | ||||
import androidx.lifecycle.LifecycleOwner | |||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import com.suliang.common.base.viewmodel.BaseViewModel | import com.suliang.common.base.viewmodel.BaseViewModel | ||||
import com.xkl.cdl.data.AppConstants | |||||
import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
/** | /** | ||||
//设置显示当前课程的进度值和显示内容 | //设置显示当前课程的进度值和显示内容 | ||||
val currentCourseProgress = MutableLiveData<Double>() | val currentCourseProgress = MutableLiveData<Double>() | ||||
override fun onStop(owner : LifecycleOwner) { | |||||
super.onStop(owner) | |||||
//如果是中文项目,更新课程包的进度 | |||||
if (coursePack.subjectId == AppConstants.SUBJECT_CHINESE) { | |||||
coursePack.learnProgress = coursePack.childrenCourses[0].courseLearnProgress | |||||
} | |||||
} | |||||
} | } |
//TabLayout 与 ViewPager2 进行关联, 并进行tab设值 | //TabLayout 与 ViewPager2 进行关联, 并进行tab设值 | ||||
TabLayoutMediator(binding.tabLayout, binding.viewPager2) { tab, position -> | TabLayoutMediator(binding.tabLayout, binding.viewPager2) { tab, position -> | ||||
tab.setCustomView(layoutInflater.inflate(R.layout.textview_only,binding.tabLayout,false)) | |||||
tab.customView?.let { | |||||
(it as TextView).setText(vm.mProjectTitles[position]) | |||||
tab.customView = layoutInflater.inflate(R.layout.textview_only, binding.tabLayout, false).apply { | |||||
(this as TextView).setText(vm.mProjectTitles[position]) | |||||
} | } | ||||
}.attach() | }.attach() | ||||
} | } | ||||
} | } | ||||
// /** 搜索框 输入监听 */ | |||||
// binding.editTextSearch.setOnEditorActionListener { v, actionId, event -> | |||||
// if (actionId == EditorInfo.IME_ACTION_SEARCH){ | |||||
// //隐藏键盘 | |||||
// KeyboardUtil.hideKeyboard(v) | |||||
// //赋值,通知 子 Fragment 进行更新 | |||||
// v.text.toString() | |||||
// | |||||
// true | |||||
// }else { | |||||
// false | |||||
// } | |||||
// } | |||||
} | } | ||||
override fun loadData() { | override fun loadData() { |
vm.allLesson[learnEventData.leesonPositionIndex].let { | vm.allLesson[learnEventData.leesonPositionIndex].let { | ||||
val key = "${it.chapterId}_${it.lessonId}" | val key = "${it.chapterId}_${it.lessonId}" | ||||
vm.courseDetail.before.put(key, it.beforeTestScore) | vm.courseDetail.before.put(key, it.beforeTestScore) | ||||
vm.courseDetail.wrong.put(key, it.errorNumber) | |||||
vm.courseDetail.wrong.put(key, it.errorNumber.toLong()) | |||||
learnEventData.newErrorMap?.let { it1 -> | learnEventData.newErrorMap?.let { it1 -> | ||||
vm.courseDetail.exam_w_r_list.putAll(it1) | vm.courseDetail.exam_w_r_list.putAll(it1) | ||||
} | } | ||||
//单词类 | //单词类 | ||||
AppConstants.LESSON_TYPE_WORD ->{ | AppConstants.LESSON_TYPE_WORD ->{ | ||||
vm.courseDetail.run { | vm.courseDetail.run { | ||||
wrong[key] = it.errorNumber //更新错误数 | |||||
right[key] = it.correctNumber //更新正确数 | |||||
wrong[key] = it.errorNumber.toLong() //更新错误数 | |||||
right[key] = it.correctNumber.toLong() //更新正确数 | |||||
lesson_learn_point[key] = it.wordIds[it.learnedIndex] //更新课时学习点 | lesson_learn_point[key] = it.wordIds[it.learnedIndex] //更新课时学习点 | ||||
course_learn_point = "${key}_${it.wordIds[it.learnedIndex]}" //更新课程学习点 | course_learn_point = "${key}_${it.wordIds[it.learnedIndex]}" //更新课程学习点 | ||||
} | } | ||||
} | } | ||||
//知识点 | //知识点 | ||||
AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE -> vm.courseDetail.run { | AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE -> vm.courseDetail.run { | ||||
wrong[key] = it.errorNumber //更新错误数 | |||||
right[key] = it.correctNumber //更新正确数 | |||||
wrong[key] = it.errorNumber.toLong() //更新错误数 | |||||
right[key] = it.correctNumber.toLong() //更新正确数 | |||||
lesson_learn_point[key] = it.wordIds[it.learnedIndex] //更新课时学习点 | lesson_learn_point[key] = it.wordIds[it.learnedIndex] //更新课时学习点 | ||||
course_learn_point = "${key}_${it.wordIds[it.learnedIndex]}" //更新课程学习点 | course_learn_point = "${key}_${it.wordIds[it.learnedIndex]}" //更新课程学习点 | ||||
} | } | ||||
//学后测试结束,弹窗动作 课时重新学习 | //学后测试结束,弹窗动作 课时重新学习 | ||||
AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN -> { | AppConstants.ACTION_LESSON_AFTER_TEST_RELEARN -> { | ||||
//课时学后测试,点击重学 | //课时学后测试,点击重学 | ||||
// TODO: 2022/4/22 清除当前课时数据,并更新当前课时,后进入学习界面 | |||||
vm.allLesson[learnEventData.leesonPositionIndex].learnIsOver = false | vm.allLesson[learnEventData.leesonPositionIndex].learnIsOver = false | ||||
vm.relearnLesson(learnEventData.leesonPositionIndex).observe(this) { | vm.relearnLesson(learnEventData.leesonPositionIndex).observe(this) { | ||||
//item更新 | //item更新 | ||||
dialog.dismissAllowingStateLoss() | dialog.dismissAllowingStateLoss() | ||||
when (action) { | when (action) { | ||||
AppConstants.DIALOG_START_LEARN -> { //跳过测试 继续学习 | AppConstants.DIALOG_START_LEARN -> { //跳过测试 继续学习 | ||||
// TODO: 2022/4/21 进入学习界面 | |||||
// TODO: 2022/4/21 进入学习界面 ,不能跳过测试,必须学习 | |||||
} | } | ||||
// 开始测试 | // 开始测试 | ||||
AppConstants.DIALOG_START_TEST -> startLessonTest(lesson, AppConstants.TEST_TYPE_BEFORE, it) | AppConstants.DIALOG_START_TEST -> startLessonTest(lesson, AppConstants.TEST_TYPE_BEFORE, it) |
* 改变加载的子Fragment 单词类 | * 改变加载的子Fragment 单词类 | ||||
*/ | */ | ||||
private fun changeChildrenFragmentForWord() { | private fun changeChildrenFragmentForWord() { | ||||
// TODO: 2022/5/5 复习页面加载 | |||||
currentFragment = vm.courseDetail.let { | currentFragment = vm.courseDetail.let { | ||||
when{ | when{ | ||||
vm.reviewDataList.size > 0 -> CourseReviewFragment.newInstanceFromLearningCenter() //有复习 | |||||
it.st_before == AppConstants.NOT_DOING -> CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL) //学前总测未做 | it.st_before == AppConstants.NOT_DOING -> CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_BEFORE_TOTAL) //学前总测未做 | ||||
it.courseLearnProgress != AppConstants.DOING_OVER -> CourseLessonFragment.newInstance() //学习未完成 | it.courseLearnProgress != AppConstants.DOING_OVER -> CourseLessonFragment.newInstance() //学习未完成 | ||||
else -> CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL) //学习完成,学后总测试界面 | else -> CourseTotalTestFragment.newInstance(AppConstants.TEST_TYPE_AFTER_TOTAL) //学习完成,学后总测试界面 | ||||
* 改变加载的子Fragment 作文 | * 改变加载的子Fragment 作文 | ||||
*/ | */ | ||||
private fun changeChildrenFragmentForComposition() { | private fun changeChildrenFragmentForComposition() { | ||||
// TODO: 2022/5/5 复习页面加载 CourseReviewFragment.newInstance() | |||||
currentFragment = vm.courseDetail.let { | |||||
CourseLessonFragment.newInstance() | |||||
currentFragment = when { | |||||
vm.reviewDataList.size > 0 -> CourseReviewFragment.newInstanceFromLearningCenter() //复习 | |||||
else -> CourseLessonFragment.newInstance() //目录 | |||||
} | } | ||||
replaceFragment(R.id.layout_root, currentFragment) | replaceFragment(R.id.layout_root, currentFragment) | ||||
} | } |
import androidx.lifecycle.LifecycleOwner | import androidx.lifecycle.LifecycleOwner | ||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import com.google.common.base.Joiner | import com.google.common.base.Joiner | ||||
import com.google.protobuf.ProtocolStringList | |||||
import com.suliang.common.base.viewmodel.BaseViewModel | import com.suliang.common.base.viewmodel.BaseViewModel | ||||
import com.suliang.common.extension.diskIo2DiskIo | import com.suliang.common.extension.diskIo2DiskIo | ||||
import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
import com.xkl.cdl.data.repository.DataRepository | import com.xkl.cdl.data.repository.DataRepository | ||||
import com.xkl.cdl.module.XKLApplication | |||||
import com.xkl.cdl.module.m_center_learn.CoursePackMainActivityViewModel | 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.core.Observable | ||||
import io.reactivex.rxjava3.core.Scheduler | |||||
import io.reactivex.rxjava3.functions.BiFunction | import io.reactivex.rxjava3.functions.BiFunction | ||||
import io.reactivex.rxjava3.schedulers.Schedulers | import io.reactivex.rxjava3.schedulers.Schedulers | ||||
import mqComsumerV1.Struct | import mqComsumerV1.Struct | ||||
import java.io.File | import java.io.File | ||||
import java.util.* | import java.util.* | ||||
import kotlin.collections.ArrayList | |||||
import kotlin.collections.HashMap | import kotlin.collections.HashMap | ||||
/** | /** | ||||
lateinit var collectList : HashMap<String, Long> | lateinit var collectList : HashMap<String, Long> | ||||
/** 复习的数据 */ | /** 复习的数据 */ | ||||
lateinit var reviewDataList : MutableList<String> | |||||
lateinit var reviewDataList : MutableList<LearnWord> | |||||
/* 复习数据是否进行了内容赋值,如果进行了赋值,则直接复习,如果没有进行赋值,需要在复习前,进行查询赋值 */ | |||||
var isAssignmentReviewData = false | |||||
/** 课程所有课时 */ | /** 课程所有课时 */ | ||||
lateinit var allLesson : List<Lesson> | lateinit var allLesson : List<Lesson> | ||||
//获取课程的章节数据 | //获取课程的章节数据 | ||||
fun loadMain() : MutableLiveData<Boolean> { | fun loadMain() : MutableLiveData<Boolean> { | ||||
val mutableLiveData = MutableLiveData<Boolean>() | val mutableLiveData = MutableLiveData<Boolean>() | ||||
Observable.zip(DataRepository.getCourseStatistics(course.subjectId, course.coursePackId, course.courseId).flatMap { | |||||
Observable.zip(DataRepository.getCourseDetails(course.subjectId, course.coursePackId, course.courseId).flatMap { | |||||
courseDetail = it | courseDetail = it | ||||
course.courseLearnProgress = it.courseLearnProgress | course.courseLearnProgress = it.courseLearnProgress | ||||
coursePackMainActivityVM.currentCourseProgress.postValue(course.courseLearnProgress) | coursePackMainActivityVM.currentCourseProgress.postValue(course.courseLearnProgress) | ||||
}.flatMap { | }.flatMap { | ||||
allLesson = it | allLesson = it | ||||
return@flatMap DataRepository.getCourseCollect() | return@flatMap DataRepository.getCourseCollect() | ||||
}, DataRepository.getReviewData(), | |||||
BiFunction<HashMap<String, Long>, Array<String>, Boolean> { t1 : HashMap<String, Long>?, t2 : Array<String>? -> | |||||
// TODO: 2022/5/5 初始化需要复习的数据 | |||||
}, DataRepository.getReviewData(course.subjectId, course.coursePackId, course.courseId), | |||||
BiFunction<HashMap<String, Long>, ProtocolStringList, Boolean> { t1 : HashMap<String, Long>, t2 : ProtocolStringList -> | |||||
//保存课程的收藏本数据 | |||||
collectList = t1 | |||||
//初始化保存需要复习的数据 | |||||
initReviewData(t2) | |||||
true | true | ||||
}).compose(diskIo2Main()).subscribe { | }).compose(diskIo2Main()).subscribe { | ||||
mutableLiveData.value = it | mutableLiveData.value = it | ||||
return mutableLiveData | return mutableLiveData | ||||
} | } | ||||
/** | |||||
* 初始化复习的数据 | |||||
* @param rev Array<String> 需要复习的数据 value 格式 {project_id}_{pack_id}_{course_id}_{chapter_id}_{lesson_id}_{entity_id}_{review_num}_{Y-m-d H:i:s}_{Y-m-d H:i:s} | |||||
*/ | |||||
private fun initReviewData(rev : ProtocolStringList) { | |||||
if (!this::reviewDataList.isInitialized) { | |||||
reviewDataList = mutableListOf() | |||||
} | |||||
reviewDataList.clear() | |||||
//当前时间戳 | |||||
val currentTime = System.currentTimeMillis() | |||||
//日历 | |||||
val calendar = Calendar.getInstance(Locale.CHINA) | |||||
//循环赋值保存需要复习的数据 | |||||
rev.forEach { | |||||
val splitValue = it.split("_") //拆分为数组 | |||||
//判断是否能够进入复习 | |||||
val isNeedInReview = CourseManager.calculateIsNeedInReview(calendar, splitValue[6].toInt(), splitValue[7], | |||||
currentTime) | |||||
if (isNeedInReview) { | |||||
// lessonType为非准确的赋值,需要在查询具体详情数据的时候,在对lessonType进行具体赋值 | |||||
reviewDataList.add( | |||||
LearnWord(splitValue[0].toInt(), splitValue[1].toLong(), splitValue[2].toLong(), course.coursePackType, | |||||
course.courseType, splitValue[3].toLong(), splitValue[4].toLong(), splitValue[5].toLong(), true, | |||||
0).apply { | |||||
reviewNum = splitValue[6].toInt() | |||||
}) | |||||
} | |||||
} | |||||
} | |||||
/** 课程包主页上的更多按钮点击是否有效 */ | /** 课程包主页上的更多按钮点击是否有效 */ | ||||
fun showMoreIsEnable() : Boolean { | fun showMoreIsEnable() : Boolean { | ||||
return when (course.courseType) { | return when (course.courseType) { | ||||
fun modifyLessonErrorNumber() { | fun modifyLessonErrorNumber() { | ||||
//重设detail中的错误数, exam_w_r_list为所有的测试前错误,因为时学前总测,所以,可以根据这个字段来计算每个课时的错误数 | //重设detail中的错误数, exam_w_r_list为所有的测试前错误,因为时学前总测,所以,可以根据这个字段来计算每个课时的错误数 | ||||
//记录错误数: key :chapterId_lessonId value :错误数 | //记录错误数: key :chapterId_lessonId value :错误数 | ||||
val errorNumber = hashMapOf<String, Int>() | |||||
val errorNumber = hashMapOf<String, Long>() | |||||
courseDetail.exam_w_r_list.keys.forEach { | courseDetail.exam_w_r_list.keys.forEach { | ||||
val split = it.split("_") | val split = it.split("_") | ||||
if (split.size == 3) { | if (split.size == 3) { | ||||
//更新lesson中的错误数 | //更新lesson中的错误数 | ||||
allLesson.forEach { | allLesson.forEach { | ||||
val key = "${it.chapterId}_${it.lessonId}" | val key = "${it.chapterId}_${it.lessonId}" | ||||
it.errorNumber = errorNumber.getOrElse(key, { 0 }) | |||||
it.errorNumber = errorNumber.getOrElse(key, { 0 }).toInt() | |||||
} | } | ||||
} | } | ||||
val subjectProgress = CourseManager.calculateSubjectProgressWithCourseLessonRelearn(course.subjectId, course.coursePackId, | val subjectProgress = CourseManager.calculateSubjectProgressWithCourseLessonRelearn(course.subjectId, course.coursePackId, | ||||
course.courseId, courseProgress) | course.courseId, courseProgress) | ||||
Observable.fromCallable { | Observable.fromCallable { | ||||
// TODO: 2022/5/5 进行数据清除和保存 | |||||
XKLApplication.mobileCache.relearn(course.subjectId.toLong(),course.coursePackId,course.courseId,allLesson[lessonPositionIndex].chapterId, | |||||
allLesson[lessonPositionIndex].lessonId, | |||||
courseProgress,0.0,subjectProgress) | |||||
}.compose(diskIo2DiskIo()).subscribe { | }.compose(diskIo2DiskIo()).subscribe { | ||||
//更新lesson | //更新lesson | ||||
val lesson = allLesson[lessonPositionIndex].apply { | val lesson = allLesson[lessonPositionIndex].apply { | ||||
val subjectProgress = CourseManager.calculateSubjectProgressWithCourseRelearn(course.subjectId, course.coursePackId, | val subjectProgress = CourseManager.calculateSubjectProgressWithCourseRelearn(course.subjectId, course.coursePackId, | ||||
course.courseId) | course.courseId) | ||||
Observable.fromCallable { | Observable.fromCallable { | ||||
// TODO: 2022/5/5 调用课程重学 重新请求详情 | |||||
val file = File(FileUtil.getSaveDirPath("appcache"), "${course.subjectId}_${course.coursePackId}_${course.courseId}") | |||||
if (file.exists()) { | |||||
file.delete() | |||||
} | |||||
// 调用课程重学 后会再次重新调用loadMain | |||||
XKLApplication.mobileCache.relearn(course.subjectId.toLong(),course.coursePackId,course.courseId,0, | |||||
0, 0.0,0.0,subjectProgress) | |||||
}.compose(diskIo2DiskIo()).subscribe { | }.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) | result.postValue(true) | ||||
} | } | ||||
return result | return result | ||||
} | } | ||||
// TODO: 2022/5/6 这里在退出时进行了统计数据缓存保存,在loadMain的时候进行了read缓存 ,后期需要清除 | |||||
override fun onDestroy(owner : LifecycleOwner) { | |||||
if (owner is CourseMainFragment) { | |||||
LogUtil.e("${this.toString().substringAfterLast(".")} 保存文件 onDestroy") | |||||
try { | |||||
val objectToBytes = FileUtil.objectToBytes(courseDetail) | |||||
FileUtil.writeBytesToFile(FileUtil.getSaveDirPath("appcache"), | |||||
"${course.subjectId}_${course.coursePackId}_${course.courseId}", objectToBytes) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
LogUtil.e("${javaClass} 保存文件异常失败") | |||||
} | |||||
} | |||||
super.onDestroy(owner) | |||||
} | |||||
/* // 这里在退出时进行了统计数据缓存保存,在loadMain的时候进行了read缓存 ,后期需要清除 | |||||
override fun onDestroy(owner : LifecycleOwner) { | |||||
if (owner is CourseMainFragment) { | |||||
LogUtil.e("${this.toString().substringAfterLast(".")} 保存文件 onDestroy") | |||||
try { | |||||
val objectToBytes = FileUtil.objectToBytes(courseDetail) | |||||
FileUtil.writeBytesToFile(FileUtil.getSaveDirPath("appcache"), | |||||
"${course.subjectId}_${course.coursePackId}_${course.courseId}", objectToBytes) | |||||
} catch (e : Exception) { | |||||
e.printStackTrace() | |||||
LogUtil.e("${javaClass} 保存文件异常失败") | |||||
} | |||||
} | |||||
super.onDestroy(owner) | |||||
}*/ | |||||
/** | /** | ||||
* 单词类,自动播放,查询自动播放使用的单词 | * 单词类,自动播放,查询自动播放使用的单词 | ||||
// TODO: 2022/5/19 查询课堂练习的收藏数据 需要给 CompositionReadingBean设置收藏id | // TODO: 2022/5/19 查询课堂练习的收藏数据 需要给 CompositionReadingBean设置收藏id | ||||
Observable.create<List<CompositionReadingBean>> { | Observable.create<List<CompositionReadingBean>> { | ||||
result.postValue(LearnData(entity).apply { | result.postValue(LearnData(entity).apply { | ||||
readingList = DBCourseManager.queryCompositionReading(dbControlBase,entity) | |||||
readingList = DBCourseManager.queryCompositionReading(dbControlBase, entity) | |||||
}) | }) | ||||
it.onComplete() | it.onComplete() | ||||
}.compose(diskIo2Main()).subscribe() | }.compose(diskIo2Main()).subscribe() |
package com.xkl.cdl.module.m_center_learn.coursechildren | package com.xkl.cdl.module.m_center_learn.coursechildren | ||||
import android.os.Bundle | |||||
import android.view.View | |||||
import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
import com.suliang.common.AppConfig | |||||
import com.suliang.common.base.fragment.BaseFragmentVM | import com.suliang.common.base.fragment.BaseFragmentVM | ||||
import com.suliang.common.extension.click | import com.suliang.common.extension.click | ||||
import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
import com.xkl.cdl.databinding.FragmentCourseReviewBinding | import com.xkl.cdl.databinding.FragmentCourseReviewBinding | ||||
/** | /** | ||||
* 课程章节目录 | |||||
* @property param1 String? | |||||
* @property param2 String? | |||||
* 复习界面 | |||||
* 加载此界面,需要传参 从备忘本进入的主页加载此界面,还是从学习中心进入的主页加载此界面,其显示将不同 | |||||
*/ | */ | ||||
class CourseReviewFragment : BaseFragmentVM<FragmentCourseReviewBinding, CourseMainFragmentViewModel>() { | class CourseReviewFragment : BaseFragmentVM<FragmentCourseReviewBinding, CourseMainFragmentViewModel>() { | ||||
companion object { | companion object { | ||||
/** | |||||
* 新建实例 | |||||
* @param pageSource Int 页面来源,默认为0,从学习中心加载, 1为从备忘本加载 | |||||
* @return CourseReviewFragment | |||||
*/ | |||||
@JvmStatic | |||||
fun newInstanceFromLearningCenter() : CourseReviewFragment { | |||||
return CourseReviewFragment() | |||||
} | |||||
/** | |||||
* 新建实例 | |||||
* @param pageSource Int 页面来源,默认为0,从学习中心加载, 1为从备忘本加载 | |||||
* @return CourseReviewFragment | |||||
*/ | |||||
@JvmStatic | @JvmStatic | ||||
fun newInstance() = CourseReviewFragment() | |||||
fun newInstanceFromMemo() : CourseReviewFragment { | |||||
val args = Bundle() | |||||
args.putInt(AppConfig.INTENT_1, 1) | |||||
val fragment = CourseReviewFragment() | |||||
fragment.arguments = args | |||||
return fragment | |||||
} | |||||
} | } | ||||
override fun initFragment() { | override fun initFragment() { | ||||
//获取页面来源 0 : 学习中心进入的加载复习界面 其他为备忘本进入加载的复习数据界面 | |||||
val pageSource : Int = arguments?.getInt(AppConfig.INTENT_1) ?: 0 | |||||
when (vm.reviewDataList.size) { | |||||
0 -> if (pageSource != 0) { | |||||
//备忘本无复习数据加载 | |||||
initMemoData() | |||||
binding.tvStartReview.visibility = View.GONE | |||||
binding.tvSeeMemo.visibility = View.VISIBLE | |||||
} | |||||
else -> { //有复习数据加载 | |||||
initReviewData() | |||||
when (pageSource) { | |||||
0 -> { | |||||
binding.tvSeeMemo.visibility = View.GONE | |||||
binding.tvStartReview.visibility = View.VISIBLE | |||||
} | |||||
else -> { | |||||
binding.tvStartReview.visibility = View.VISIBLE | |||||
binding.tvSeeMemo.visibility = View.VISIBLE | |||||
} | |||||
} | |||||
} | |||||
} | |||||
//开始复习 | |||||
binding.tvStartReview.click { | |||||
showToast("开始复习") | |||||
if (vm.isAssignmentReviewData){ //已经赋值,直接赋值跳转 | |||||
}else{ //没有赋值,需要进行 | |||||
} | |||||
} | |||||
//查看备忘本 | |||||
binding.tvSeeMemo.click { | |||||
showToast("查看备忘本") | |||||
} | |||||
} | |||||
private fun initReviewData() { | |||||
//根据课程类型进行显示 | //根据课程类型进行显示 | ||||
binding.tvTips.text = when(vm.course.courseType){ | |||||
binding.tvTips.text = when (vm.course.courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> "你将进行 [认读] 课程智能复习" | AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> "你将进行 [认读] 课程智能复习" | ||||
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> "你将进行 [辨音] 课程智能复习" | AppConstants.COURSE_TYPE_ENGLISH_VOICE -> "你将进行 [辨音] 课程智能复习" | ||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> "你将进行 [拼写] 课程智能复习" | AppConstants.COURSE_TYPE_ENGLISH_SPELL -> "你将进行 [拼写] 课程智能复习" | ||||
else -> "你将进行课程智能复习" | else -> "你将进行课程智能复习" | ||||
} | } | ||||
binding.tvReviewCount.text = String.format("本次智能复习数%d",vm.course.courseReviewNumber) | |||||
//开始测试事件 | |||||
binding.tvStartReview.click { | |||||
showToast("开始复习") | |||||
binding.tvReviewCount.text = String.format("本次智能复习数%d", vm.reviewDataList.size) | |||||
} | |||||
private fun initMemoData() { | |||||
binding.tvTips.text = when (vm.course.courseType) { | |||||
AppConstants.COURSE_TYPE_ENGLISH_DISCERN -> "[认读] 课程加入备忘本数据共123条" | |||||
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> "[辨音] 课程加入备忘本数据共123条" | |||||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> "[拼写] 课程加入备忘本数据共123条" | |||||
else -> "课程加入备忘本数据共123条" | |||||
} | } | ||||
binding.tvReviewCount.visibility = View.GONE | |||||
} | } | ||||
override fun loadData() { | override fun loadData() { | ||||
} | } | ||||
override fun initViewModel(): CourseMainFragmentViewModel { | |||||
override fun initViewModel() : CourseMainFragmentViewModel { | |||||
return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java] | return ViewModelProvider(requireParentFragment())[CourseMainFragmentViewModel::class.java] | ||||
} | } | ||||
} | } |
package com.xkl.cdl.module.m_memo | package com.xkl.cdl.module.m_memo | ||||
import android.os.Bundle | |||||
import androidx.fragment.app.Fragment | |||||
import android.view.LayoutInflater | |||||
import android.view.View | |||||
import android.view.ViewGroup | |||||
import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager | |||||
import com.suliang.common.base.fragment.BaseFragmentVM | import com.suliang.common.base.fragment.BaseFragmentVM | ||||
import com.xkl.cdl.R | |||||
import com.xkl.cdl.databinding.FragmentMemoBinding | import com.xkl.cdl.databinding.FragmentMemoBinding | ||||
import com.xkl.cdl.databinding.FragmentMyBinding | |||||
import com.xkl.cdl.module.main.MainActivityViewModel | import com.xkl.cdl.module.main.MainActivityViewModel | ||||
// TODO: Rename parameter arguments, choose names that match | |||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER | |||||
private const val ARG_PARAM1 = "param1" | |||||
private const val ARG_PARAM2 = "param2" | |||||
/** | /** | ||||
* A simple [Fragment] subclass. | |||||
* Use the [MemoFragment.newInstance] factory method to | |||||
* create an instance of this fragment. | |||||
*/ | |||||
class MemoFragment : BaseFragmentVM<FragmentMemoBinding, MainActivityViewModel>(){ | |||||
// TODO: Rename and change types of parameters | |||||
private var param1: String? = null | |||||
private var param2: String? = null | |||||
override fun onCreate(savedInstanceState: Bundle?) { | |||||
super.onCreate(savedInstanceState) | |||||
arguments?.let { | |||||
param1 = it.getString(ARG_PARAM1) | |||||
param2 = it.getString(ARG_PARAM2) | |||||
} | |||||
} | |||||
override fun onCreateView( | |||||
inflater: LayoutInflater, container: ViewGroup?, | |||||
savedInstanceState: Bundle? | |||||
): View? { | |||||
// Inflate the layout for this fragment | |||||
return inflater.inflate(R.layout.fragment_memo, container, false) | |||||
} | |||||
* author suliang | |||||
* create 2022/5/30 16:08 | |||||
* Describe: 备忘本 | |||||
*/ | |||||
class MemoFragment : BaseFragmentVM<FragmentMemoBinding, MemoFragmentViewModel>(){ | |||||
companion object { | companion object { | ||||
/** | |||||
* Use this factory method to create a new instance of | |||||
* this fragment using the provided parameters. | |||||
* | |||||
* @param param1 Parameter 1. | |||||
* @param param2 Parameter 2. | |||||
* @return A new instance of fragment MemoFragment. | |||||
*/ | |||||
// TODO: Rename and change types and number of parameters | |||||
@JvmStatic | @JvmStatic | ||||
fun newInstance() = MemoFragment() | fun newInstance() = MemoFragment() | ||||
} | } | ||||
override fun initViewModel(): MemoFragmentViewModel { | |||||
return ViewModelProvider(this)[MemoFragmentViewModel::class.java].apply { | |||||
mainActivityViewModel = ViewModelProvider(requireActivity())[MainActivityViewModel::class.java] | |||||
} | |||||
} | |||||
override fun initFragment() { | override fun initFragment() { | ||||
binding.rv.run { | |||||
layoutManager = StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL) | |||||
adapter = vm.adapter | |||||
} | |||||
} | } | ||||
override fun loadData() { | override fun loadData() { | ||||
/** 搜索内容变化监听 */ | |||||
vm.etSearchLiveData.observe(this){ | |||||
} | |||||
} | } | ||||
override fun initViewModel(): MainActivityViewModel { | |||||
return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java] | |||||
override fun onResume() { | |||||
super.onResume() | |||||
//查询数据 | |||||
vm.queryData() | |||||
} | } | ||||
} | } |
package com.xkl.cdl.module.m_memo | |||||
import androidx.lifecycle.MutableLiveData | |||||
import appApi.AppApi | |||||
import com.googlecode.protobuf.format.JsonFormat | |||||
import com.suliang.common.base.viewmodel.BaseViewModel | |||||
import com.suliang.common.extension.diskIo2DiskIo | |||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.adapter.AdapterCoursePackWithMemo | |||||
import com.xkl.cdl.data.bean.MemoCoursePack | |||||
import com.xkl.cdl.module.XKLApplication | |||||
import com.xkl.cdl.module.main.MainActivity | |||||
import com.xkl.cdl.module.main.MainActivityViewModel | |||||
import io.reactivex.rxjava3.core.Observable | |||||
/** | |||||
* author suliang | |||||
* create 2022/5/30 16:47 | |||||
* Describe: 备忘本的VM 持有activity的viewmodel | |||||
*/ | |||||
class MemoFragmentViewModel : BaseViewModel() { | |||||
lateinit var mainActivityViewModel : MainActivityViewModel | |||||
/* 课程包的备忘本数据 */ | |||||
val memoCoursePackList = mutableListOf<MemoCoursePack>() | |||||
val etSearchLiveData = MutableLiveData<String>() | |||||
val adapter = AdapterCoursePackWithMemo(this).apply { | |||||
needShowEmptyView = true | |||||
} | |||||
/** | |||||
* 查询课程的错误数据结果 | |||||
*/ | |||||
fun queryData() { | |||||
Observable.create<ByteArray> { | |||||
//参数: 科目 课程包id 课程id category 1 获取正确的,2获取错误的,3正确错误都获取 | |||||
val wordList = XKLApplication.mobileCache.getWordList(0, 0, 0, 2) | |||||
it.onNext(wordList) | |||||
it.onComplete() | |||||
}.compose(diskIo2DiskIo()).subscribe({ | |||||
AppApi.GetWordListResponse.parseFrom(it).wrongList?.forEach { wrong -> | |||||
} | |||||
//赋值集合 | |||||
//列表刷新 | |||||
}, { | |||||
it.printStackTrace() | |||||
}) | |||||
} | |||||
} |
override fun initActivity(savedInstanceState: Bundle?) { | override fun initActivity(savedInstanceState: Bundle?) { | ||||
//加载Fragment并显示 | |||||
loadFragment(R.id.layout_container, -1, mMemo, mStatistics, mLearnCenter, mServiceCenter, mMy) | |||||
//点击事件 | //点击事件 | ||||
binding.layoutNavContainer.setOnCheckedChangeListener { group, checkedId -> | binding.layoutNavContainer.setOnCheckedChangeListener { group, checkedId -> | ||||
when (checkedId) { | when (checkedId) { | ||||
} | } | ||||
override fun loadData() { | override fun loadData() { | ||||
//加载初始化数据 | |||||
vm.loadInit().observe(this){ | |||||
binding.layoutNavContainer.check(R.id.nav_learnCenter) | |||||
} | |||||
//加载Fragment并显示 | |||||
loadFragment(R.id.layout_container, 2, mMemo, mStatistics, mLearnCenter, mServiceCenter, mMy) | |||||
binding.layoutNavContainer.check(R.id.nav_learnCenter) | |||||
} | } | ||||
} | } |
package com.xkl.cdl.module.main | package com.xkl.cdl.module.main | ||||
import androidx.fragment.app.Fragment | |||||
import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||
import androidx.lifecycle.viewModelScope | |||||
import com.suliang.common.base.viewmodel.BaseViewModel | import com.suliang.common.base.viewmodel.BaseViewModel | ||||
import com.suliang.common.util.LogUtil | |||||
import com.xkl.cdl.R | |||||
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment | |||||
import kotlinx.coroutines.delay | |||||
import kotlinx.coroutines.launch | |||||
/** | /** | ||||
* author suliang | * author suliang | ||||
* 进行用户信息的判断,加载用户课程 | * 进行用户信息的判断,加载用户课程 | ||||
*/ | */ | ||||
class MainActivityViewModel: BaseViewModel() { | class MainActivityViewModel: BaseViewModel() { | ||||
/** 进入程序加载完毕监听 */ | |||||
val mainInitLiveData = MutableLiveData<Boolean>() | |||||
/*** | /*** | ||||
* 进行初始化加载 | * 进行初始化加载 | ||||
*/ | */ | ||||
fun loadInit(): MutableLiveData<Boolean> { | |||||
// fun loadInit(): MutableLiveData<Boolean> { | |||||
//1、查询用户的课程数据 | //1、查询用户的课程数据 | ||||
//设置进入课程管理类中 | //设置进入课程管理类中 | ||||
// viewModelScope.launch { | // viewModelScope.launch { | ||||
// showHideLoading(false) | // showHideLoading(false) | ||||
// //通知Activity 加载完成 | // //通知Activity 加载完成 | ||||
// } | // } | ||||
return MutableLiveData<Boolean>().apply { postValue(true) } | |||||
} | |||||
// return MutableLiveData<Boolean>().apply { postValue(true) } | |||||
// } | |||||
//2、计算用户的复习数据 | //2、计算用户的复习数据 | ||||
//3、统计数据 | //3、统计数据 |
import android.annotation.SuppressLint | import android.annotation.SuppressLint | ||||
import android.os.Bundle | import android.os.Bundle | ||||
import appApi.AppApi | |||||
import com.googlecode.protobuf.format.JsonFormat | |||||
import com.suliang.common.base.activity.BaseActivity | import com.suliang.common.base.activity.BaseActivity | ||||
import com.suliang.common.util.LogUtil | |||||
import com.suliang.common.util.thread.AppExecutors | import com.suliang.common.util.thread.AppExecutors | ||||
import com.xkl.cdl.data.AppConstants | |||||
import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
import com.xkl.cdl.data.manager.db.DbCoursePackManager | import com.xkl.cdl.data.manager.db.DbCoursePackManager | ||||
import com.xkl.cdl.databinding.ActivitySplashBinding | import com.xkl.cdl.databinding.ActivitySplashBinding | ||||
import com.xkl.cdl.module.XKLApplication | |||||
import com.xkl.cdl.module.main.MainActivity | import com.xkl.cdl.module.main.MainActivity | ||||
import io.reactivex.rxjava3.core.Observable | |||||
import java.util.* | |||||
import java.util.concurrent.TimeUnit | import java.util.concurrent.TimeUnit | ||||
@SuppressLint("CustomSplashScreen") | @SuppressLint("CustomSplashScreen") | ||||
class SplashActivity : BaseActivity<ActivitySplashBinding>(){ | |||||
override fun onCreate(savedInstanceState: Bundle?) { | |||||
class SplashActivity : BaseActivity<ActivitySplashBinding>() { | |||||
override fun onCreate(savedInstanceState : Bundle?) { | |||||
if (!isTaskRoot) { | if (!isTaskRoot) { | ||||
finish() | finish() | ||||
return | return | ||||
} | } | ||||
super.onCreate(savedInstanceState) | super.onCreate(savedInstanceState) | ||||
} | } | ||||
override fun initActivity(savedInstanceState: Bundle?) { | |||||
override fun initActivity(savedInstanceState : Bundle?) { | |||||
} | } | ||||
override fun loadData() { | override fun loadData() { | ||||
// try { | |||||
// val file: String = File(FileUtil.getSaveDirFile("db"), "mydb").absolutePath | |||||
// val mobile = Mobile_cache.new_(file) | |||||
// mobile.delete() | |||||
// println(" -------------> " + mobile.get("abc")) | |||||
// | |||||
// } catch (e: Exception) { | |||||
// e.printStackTrace() | |||||
// } | |||||
// learnDialog = LearnDialog().apply { | |||||
// show(supportFragmentManager,javaClass.name) | |||||
// } | |||||
// LogUtil.e("Dialog -- > ${learnDialog.hashCode()}") | |||||
// SpUtils.instance.encode("my","abcdefgxxxxx") | |||||
// SpUtils.instance.remove("my") | |||||
// println("---------------" + SpUtils.instance.decode("my",String::class.java)) | |||||
// | |||||
// if (true) return | |||||
showHideLoading(true) | showHideLoading(true) | ||||
AppExecutors.io.execute { | |||||
AppExecutors.diskIO.execute { | |||||
//读取课程数据 | //读取课程数据 | ||||
// TODO: 2022/5/16 读取课程的sort信息进行保存,针对作文课程,同时需要设置其课程包的进度 | |||||
//用户的sort信息 | |||||
XKLApplication.mobileCache.courseSorted(AppConstants.SUBJECT_ENGLISH.toLong())?.let { value -> | |||||
val parseFrom = AppApi.CourseSortedResponse.parseFrom(value).toBuilder() | |||||
CourseManager.mSortInfoList.put(AppConstants.SUBJECT_ENGLISH, parseFrom.listBuilderList) | |||||
} | |||||
XKLApplication.mobileCache.courseSorted(AppConstants.SUBJECT_CHINESE.toLong())?.let { value -> | |||||
val parseFrom = AppApi.CourseSortedResponse.parseFrom(value).toBuilder() | |||||
CourseManager.mSortInfoList.put(AppConstants.SUBJECT_CHINESE, parseFrom.listBuilderList) | |||||
} | |||||
// TODO: 2022/3/22 读取当前app绑定的课程数据, | // TODO: 2022/3/22 读取当前app绑定的课程数据, | ||||
DbCoursePackManager().queryBindingCoursePack("262,261,264,136,547,615,516,411") | DbCoursePackManager().queryBindingCoursePack("262,261,264,136,547,615,516,411") | ||||
//复制课程的数据库到对应位置 | //复制课程的数据库到对应位置 | ||||
}, 1, TimeUnit.SECONDS) | }, 1, TimeUnit.SECONDS) | ||||
} | } | ||||
} | } | ||||
// lateinit var learnDialog :LearnDialog | |||||
// lateinit var learnDialog1: LearnDialog | |||||
// override fun rightClick() { | |||||
// if (!this::learnDialog1.isInitialized) { | |||||
// learnDialog1 = LearnDialog() | |||||
// } | |||||
// LogUtil.e("Dialog 1 -- > ${learnDialog1.hashCode()}") | |||||
// learnDialog1.show(supportFragmentManager,javaClass.name) | |||||
// } | |||||
// | |||||
// override fun leftClick() { | |||||
// learnDialog1.dismiss() | |||||
// } | |||||
} | } |
android:layout_width="wrap_content" | android:layout_width="wrap_content" | ||||
android:layout_height="wrap_content" | android:layout_height="wrap_content" | ||||
android:layout_marginTop="4dp" | android:layout_marginTop="4dp" | ||||
android:textColor="@color/main_text_color" | |||||
android:textColor="@color/theme_color" | |||||
android:textSize="@dimen/smallSize" | android:textSize="@dimen/smallSize" | ||||
app:layout_constraintEnd_toEndOf="parent" | app:layout_constraintEnd_toEndOf="parent" | ||||
app:layout_constraintStart_toStartOf="parent" | app:layout_constraintStart_toStartOf="parent" | ||||
app:layout_constraintTop_toBottomOf="@+id/tv_tips" | app:layout_constraintTop_toBottomOf="@+id/tv_tips" | ||||
tools:text="本次智能复习数%d" /> | tools:text="本次智能复习数%d" /> | ||||
<Button | |||||
<com.google.android.material.button.MaterialButton | |||||
android:id="@+id/tv_start_review" | android:id="@+id/tv_start_review" | ||||
style="@style/common_button_style" | style="@style/common_button_style" | ||||
android:text="@string/start_review" | android:text="@string/start_review" | ||||
app:cornerRadius="8dp" | app:cornerRadius="8dp" | ||||
app:layout_constraintBottom_toBottomOf="parent" | app:layout_constraintBottom_toBottomOf="parent" | ||||
app:layout_constraintEnd_toEndOf="parent" | app:layout_constraintEnd_toEndOf="parent" | ||||
app:layout_constraintStart_toEndOf="@+id/tv_see_memo" | |||||
app:layout_constraintTop_toBottomOf="@+id/tv_tips" | |||||
android:layout_marginStart="12dp" | |||||
app:layout_goneMarginStart="38dp" | |||||
/> | |||||
<com.google.android.material.button.MaterialButton | |||||
android:id="@+id/tv_see_memo" | |||||
style="@style/common_button_style" | |||||
android:text="@string/start_see_memo" | |||||
app:cornerRadius="8dp" | |||||
app:layout_constraintStart_toStartOf="parent" | app:layout_constraintStart_toStartOf="parent" | ||||
app:layout_constraintTop_toBottomOf="@+id/tv_tips" /> | |||||
app:layout_constraintEnd_toStartOf="@+id/tv_start_review" | |||||
app:layout_constraintTop_toBottomOf="@+id/tv_tips" | |||||
android:layout_marginEnd="0dp" | |||||
app:layout_goneMarginEnd="38dp" | |||||
android:backgroundTint="@color/translation" | |||||
app:strokeColor="@color/theme_color" | |||||
app:strokeWidth="@dimen/line_height" | |||||
android:textColor="@color/theme_color" | |||||
android:visibility="gone" | |||||
tools:visibility="visible" | |||||
/> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> | </androidx.constraintlayout.widget.ConstraintLayout> |
<?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
<layout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:tools="http://schemas.android.com/tools" | xmlns:tools="http://schemas.android.com/tools" | ||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent" | |||||
tools:context=".module.m_memo.MemoFragment"> | |||||
xmlns:app="http://schemas.android.com/apk/res-auto"> | |||||
<!-- TODO: Update blank fragment layout --> | |||||
<TextView | |||||
<data> | |||||
<variable | |||||
name="vm" | |||||
type="com.xkl.cdl.module.m_memo.MemoFragmentViewModel" /> | |||||
</data> | |||||
<androidx.constraintlayout.widget.ConstraintLayout | |||||
android:layout_width="match_parent" | android:layout_width="match_parent" | ||||
android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
android:text="@string/hello_blank_fragment" /> | |||||
tools:context=".module.m_memo.MemoFragment"> | |||||
<View | |||||
android:id="@+id/v_top" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="@dimen/title_bar_height" | |||||
app:layout_constraintTop_toTopOf="parent" | |||||
android:background="@color/white" /> | |||||
<TextView | |||||
android:id="@+id/tv_memo" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
app:layout_constraintTop_toTopOf="@+id/v_top" | |||||
app:layout_constraintBottom_toBottomOf="@+id/v_top" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
android:layout_marginStart="@dimen/global_spacing" | |||||
android:textColor="@color/main_text_color" | |||||
android:textStyle="bold" | |||||
android:text="@string/memo" /> | |||||
<com.suliang.common.widget.InputSearchEditText | |||||
android:id="@+id/edit_text_search" | |||||
android:layout_width="0dp" | |||||
android:layout_height="36dp" | |||||
app:layout_constraintStart_toEndOf="@+id/tv_memo" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintTop_toTopOf="@+id/v_top" | |||||
app:layout_constraintBottom_toBottomOf="@+id/v_top" | |||||
android:layout_marginStart="@dimen/global_spacing" | |||||
android:layout_marginEnd="@dimen/global_spacing" | |||||
android:background="@drawable/et_search_bg" | |||||
android:paddingStart="@dimen/global_spacing" | |||||
android:paddingEnd="@dimen/global_spacing" | |||||
android:gravity="center_vertical" | |||||
android:maxLines="1" | |||||
android:singleLine="true" | |||||
android:drawablePadding="4dp" | |||||
android:textColor="@color/main_text_color" | |||||
android:textSize="@dimen/smallSize" | |||||
android:hint="请输入课程名称..." | |||||
android:text="@={vm.etSearchLiveData}" | |||||
/> | |||||
<androidx.recyclerview.widget.RecyclerView | |||||
android:id="@+id/rv" | |||||
android:layout_width="0dp" | |||||
android:layout_height="0dp" | |||||
app:layout_constraintTop_toBottomOf="@+id/v_top" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
android:background="@color/white_1" | |||||
android:overScrollMode="never" | |||||
android:scrollbars="none" /> | |||||
</FrameLayout> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> | |||||
</layout> |
android:id="@+id/tab_discern" | android:id="@+id/tab_discern" | ||||
android:layout_width="wrap_content" | android:layout_width="wrap_content" | ||||
android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
android:drawableStart="@drawable/ic_discern" | |||||
android:drawableStart="@drawable/ic_course_discern" | |||||
android:text="认读" | android:text="认读" | ||||
bind:svgColor="@{@color/theme_color}" | bind:svgColor="@{@color/theme_color}" | ||||
android:textColor="@color/theme_color" | android:textColor="@color/theme_color" | ||||
android:id="@+id/tab_spell" | android:id="@+id/tab_spell" | ||||
android:layout_width="wrap_content" | android:layout_width="wrap_content" | ||||
android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
android:drawableStart="@drawable/ic_spell" | |||||
android:drawableStart="@drawable/ic_course_spell" | |||||
bind:svgColor="@{@color/theme_color}" | bind:svgColor="@{@color/theme_color}" | ||||
android:textColor="@color/theme_color" | android:textColor="@color/theme_color" | ||||
android:text="拼写" | android:text="拼写" | ||||
android:id="@+id/tab_voice" | android:id="@+id/tab_voice" | ||||
android:layout_width="wrap_content" | android:layout_width="wrap_content" | ||||
android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
android:drawableStart="@drawable/ic_voice" | |||||
android:drawableStart="@drawable/ic_course_voice" | |||||
android:text="辨音" | android:text="辨音" | ||||
bind:svgColor="@{@color/theme_color}" | bind:svgColor="@{@color/theme_color}" | ||||
android:textColor="@color/theme_color" | android:textColor="@color/theme_color" |
<?xml version="1.0" encoding="utf-8"?> | |||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent" | |||||
android:layout_margin="5dp" | |||||
android:background="@drawable/shape_rounder_12_white" | |||||
android:padding="8dp" | |||||
android:paddingBottom="12dp"> | |||||
<com.google.android.material.imageview.ShapeableImageView | |||||
android:id="@+id/img_course_pack_cover" | |||||
style="@style/roundedCornerStyle" | |||||
android:layout_width="0dp" | |||||
android:layout_height="0dp" | |||||
app:layout_constraintHeight_min="128dp" | |||||
android:layout_marginEnd="8dp" | |||||
android:scaleType="centerCrop" | |||||
app:layout_constraintDimensionRatio="h,102:136" | |||||
app:layout_constraintEnd_toStartOf="@+id/barrier" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<androidx.constraintlayout.widget.Barrier | |||||
android:id="@+id/barrier" | |||||
android:layout_width="1dp" | |||||
android:layout_height="wrap_content" | |||||
app:barrierDirection="right" | |||||
app:constraint_referenced_ids="img_course_pack_cover" /> | |||||
<com.google.android.material.imageview.ShapeableImageView | |||||
android:id="@+id/img_course_icon_1" | |||||
android:layout_width="40dp" | |||||
android:layout_height="40dp" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toEndOf="@+id/barrier" | |||||
app:layout_constraintTop_toTopOf="parent" | |||||
app:layout_constraintBottom_toTopOf="@+id/img_course_icon_2" | |||||
app:strokeWidth="10dp" | |||||
style="@style/roundedCornerStyle"/> | |||||
<com.google.android.material.imageview.ShapeableImageView | |||||
android:id="@+id/img_course_icon_2" | |||||
android:layout_width="40dp" | |||||
android:layout_height="40dp" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toEndOf="@+id/barrier" | |||||
app:layout_constraintTop_toBottomOf="@+id/img_course_icon_1" | |||||
app:layout_constraintBottom_toTopOf="@+id/img_course_icon_3" | |||||
app:strokeWidth="10dp" | |||||
android:visibility="invisible" | |||||
style="@style/roundedCornerStyle"/> | |||||
<com.google.android.material.imageview.ShapeableImageView | |||||
android:id="@+id/img_course_icon_3" | |||||
android:layout_width="40dp" | |||||
android:layout_height="40dp" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toEndOf="@+id/barrier" | |||||
app:layout_constraintTop_toBottomOf="@+id/img_course_icon_2" | |||||
app:layout_constraintBottom_toBottomOf="@+id/img_course_pack_cover" | |||||
app:strokeWidth="10dp" | |||||
android:visibility="invisible" | |||||
style="@style/roundedCornerStyle" | |||||
/> | |||||
<TextView | |||||
android:id="@+id/tv_course_pack_name" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
app:layout_constraintTop_toBottomOf="@+id/img_course_pack_cover" /> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> |
android:layout_marginTop="8dp" | android:layout_marginTop="8dp" | ||||
android:layout_marginEnd="8dp" | android:layout_marginEnd="8dp" | ||||
android:padding="3dp" | android:padding="3dp" | ||||
android:src="@drawable/ic_discern" | |||||
android:src="@drawable/ic_course_discern" | |||||
android:visibility="gone" | android:visibility="gone" | ||||
app:layout_constraintEnd_toStartOf="@+id/image_view_type_spell" | app:layout_constraintEnd_toStartOf="@+id/image_view_type_spell" | ||||
app:layout_constraintHorizontal_bias="0" | app:layout_constraintHorizontal_bias="0" | ||||
android:layout_marginTop="8dp" | android:layout_marginTop="8dp" | ||||
android:layout_marginEnd="8dp" | android:layout_marginEnd="8dp" | ||||
android:padding="3dp" | android:padding="3dp" | ||||
android:src="@drawable/ic_spell" | |||||
android:src="@drawable/ic_course_spell" | |||||
android:visibility="gone" | android:visibility="gone" | ||||
app:layout_constraintEnd_toStartOf="@+id/image_view_type_voice" | app:layout_constraintEnd_toStartOf="@+id/image_view_type_voice" | ||||
app:layout_constraintStart_toEndOf="@+id/image_view_type_discern" | app:layout_constraintStart_toEndOf="@+id/image_view_type_discern" | ||||
android:layout_marginTop="8dp" | android:layout_marginTop="8dp" | ||||
android:layout_marginEnd="8dp" | android:layout_marginEnd="8dp" | ||||
android:padding="3dp" | android:padding="3dp" | ||||
android:src="@drawable/ic_voice" | |||||
android:src="@drawable/ic_course_voice" | |||||
android:visibility="gone" | android:visibility="gone" | ||||
app:layout_constraintEnd_toEndOf="parent" | app:layout_constraintEnd_toEndOf="parent" | ||||
app:layout_constraintStart_toEndOf="@+id/image_view_type_spell" | app:layout_constraintStart_toEndOf="@+id/image_view_type_spell" |
<string name="quit_auto_play_title">你确定要退出自动播放吗?</string> | <string name="quit_auto_play_title">你确定要退出自动播放吗?</string> | ||||
<string name="quit_auto_play_title_over">本课程自动播放完毕</string> | <string name="quit_auto_play_title_over">本课程自动播放完毕</string> | ||||
<string name="course_introduction">课程简介</string> | <string name="course_introduction">课程简介</string> | ||||
<string name="start_see_memo">查看备忘本</string> | |||||
</resources> | </resources> |
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
android:width="18dp" | |||||
android:height="18dp" | |||||
android:viewportWidth="28" | |||||
android:viewportHeight="28"> | |||||
<path | |||||
android:pathData="M24.1111,1.8667C25.228,1.8667 26.1333,2.772 26.1333,3.8889L26.1333,24.1111C26.1333,25.228 25.228,26.1333 24.1111,26.1333L3.8889,26.1333C2.772,26.1333 1.8667,25.228 1.8667,24.1111L1.8667,3.8889C1.8667,2.772 2.772,1.8667 3.8889,1.8667L24.1111,1.8667ZM10.0247,11.2095L5.9111,11.2095L5.9111,12.9379L8.279,12.9379L8.279,19.0737C8.279,19.4367 8.1235,19.7478 7.8123,20.007L8.5037,21.6317C9.8346,20.8194 11.0963,19.9033 12.2716,18.8663L11.7877,16.9823C11.1654,17.5527 10.5778,18.054 10.0247,18.5033L10.0247,11.2095ZM20.758,6.7675L12.2543,6.7675L12.2543,8.4959L19.0296,8.4959L19.0296,11.9527L12.963,11.9527L12.963,19.7996C12.963,20.9577 13.516,21.5453 14.6568,21.5453L19.1679,21.5453C20.2741,21.5453 20.9827,21.2688 21.3111,20.7502C21.6568,20.1972 21.916,19.0219 22.0889,17.2416L20.2914,16.6539L20.257,17.1922C20.1895,18.1274 20.0972,18.7799 19.9802,19.1601C19.842,19.6095 19.4617,19.8515 18.8741,19.8515L15.4519,19.8515C14.9679,19.8169 14.7259,19.5577 14.7259,19.0737L14.7259,13.6811L20.758,13.6811L20.758,6.7675ZM8.3136,6.2144L7.0346,7.4589C8.2617,8.3577 9.2123,9.2046 9.8691,9.9996L11.1136,8.7379C10.3358,7.9083 9.4025,7.0614 8.3136,6.2144Z" | |||||
android:strokeWidth="1" | |||||
android:fillColor="#8757E6" | |||||
android:fillType="evenOdd" | |||||
android:strokeColor="#00000000"/> | |||||
</vector> |
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
android:width="18dp" | |||||
android:height="18dp" | |||||
android:viewportWidth="22" | |||||
android:viewportHeight="22"> | |||||
<path | |||||
android:fillColor="#F7874F" | |||||
android:fillType="evenOdd" | |||||
android:pathData="M18.9444,1.4667C19.822,1.4667 20.5333,2.178 20.5333,3.0556L20.5333,18.9444C20.5333,19.822 19.822,20.5333 18.9444,20.5333L3.0556,20.5333C2.178,20.5333 1.4667,19.822 1.4667,18.9444L1.4667,3.0556C1.4667,2.178 2.178,1.4667 3.0556,1.4667L18.9444,1.4667ZM11.2645,12.5261C10.6269,13.9912 9.8537,15.2529 8.9584,16.2974L10.2064,17.2063C11.1017,16.0668 11.8614,14.6967 12.5126,13.123L11.2645,12.5261ZM14.968,12.4583L13.8149,13.1909C14.7916,14.6288 15.5649,15.9447 16.1346,17.1385L17.3556,16.2839C16.7994,15.1986 15.999,13.9234 14.968,12.4583ZM7.846,8.5649L4.6444,8.5649L4.6444,9.9215L6.4758,9.9215L6.4758,14.7374C6.4758,15.0222 6.3537,15.2664 6.1231,15.4699L6.6657,16.7451C7.6018,16.1075 8.4836,15.3885 9.3246,14.5746L8.9312,13.0959C8.5514,13.4757 8.1851,13.8285 7.846,14.1405L7.846,8.5649ZM16.4873,5.2142L9.8537,5.2142L9.8537,11.97L16.4873,11.97L16.4873,5.2142ZM15.0629,6.5843L15.0629,10.6134L11.2645,10.6134L11.2645,6.5843L15.0629,6.5843ZM6.5437,4.6444L5.5533,5.6212C6.503,6.3266 7.2491,6.9778 7.7646,7.6018L8.7277,6.625C8.1308,5.9739 7.3983,5.3092 6.5437,4.6444Z" | |||||
android:strokeWidth="1" | |||||
android:strokeColor="#00000000" /> | |||||
</vector> |
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
android:width="18dp" | |||||
android:height="18dp" | |||||
android:viewportWidth="112" | |||||
android:viewportHeight="112"> | |||||
<path | |||||
android:fillColor="#EB54D8" | |||||
android:pathData="M10.5,10.5l-2.5,2.4 0,43.1 0,43.1 2.5,2.4 2.4,2.5 43.1,-0 43.1,-0 2.4,-2.5 2.5,-2.4 0,-43.1 0,-43.1 -2.5,-2.4 -2.4,-2.5 -43.1,-0 -43.1,-0 -2.4,2.5zM64,28.5c-5.3,5.4 -7,6.5 -9.7,6.5 -1.8,-0 -3.3,-0.2 -3.3,-0.5 0,-0.3 1.7,-3.2 3.7,-6.5l3.8,-6 6,-0 5.9,-0 -6.4,6.5zM68.7,40c7.5,3.4 8.3,5.8 8.3,25.7l0,17.3 -4.5,-0c-3.8,-0 -4.5,-0.3 -4.5,-1.9 0,-1.8 -0.3,-1.8 -4.6,0.6 -5.6,3.1 -15.1,3.6 -20.1,1 -6.3,-3.3 -8.3,-12.5 -4,-18.7 3.5,-5.2 8.7,-7.3 18.9,-7.8 9.8,-0.5 10.8,-1.4 6.7,-6.6 -1.7,-2.2 -2.8,-2.6 -7,-2.6 -4.9,-0 -8.9,2.3 -8.9,5.1 0,1.1 -9.4,0.8 -10.6,-0.3 -0.8,-0.9 2.1,-7.1 4.4,-9.1 5.3,-4.8 18.4,-6.2 25.9,-2.7z" | |||||
android:strokeColor="#00000000" /> | |||||
<path | |||||
android:fillColor="#EB54D8" | |||||
android:pathData="M53,64.7c-3,1.1 -5,3.7 -5,6.4 0,7.2 13.7,6.3 17.5,-1.1 2.7,-5.3 2.2,-6 -4.7,-5.9 -3.5,-0 -7,0.3 -7.8,0.6z" | |||||
android:strokeColor="#00000000" /> | |||||
</vector> |
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
android:width="18dp" | |||||
android:height="18dp" | |||||
android:viewportWidth="112" | |||||
android:viewportHeight="112"> | |||||
<path | |||||
android:fillColor="#8757E6" | |||||
android:pathData="M10,10c-1.9,1.9 -2,3.3 -2,46 0,42.7 0.1,44.1 2,46 1.9,1.9 3.3,2 46,2 42.7,-0 44.1,-0.1 46,-2 1.9,-1.9 2,-3.3 2,-46 0,-42.7 -0.1,-44.1 -2,-46 -1.9,-1.9 -3.3,-2 -46,-2 -42.7,-0 -44.1,0.1 -46,2zM54.3,34.8l3.5,2 4.9,-2.5c4,-2.1 5.8,-2.4 11,-2 7.7,0.6 12.9,3.2 17,8.6 5.4,7 5.6,15.1 0.3,17.8 -1.6,0.8 -7,1.3 -15.2,1.3 -12.2,-0 -12.8,0.1 -12.8,2 0,9.8 12.9,13.3 20.9,5.7 4.3,-4.1 6.4,-5 8.4,-3.4 2.5,2.1 2.6,4.5 0.4,7.9 -6.3,9.3 -23.4,11.6 -33.9,4.4l-3.6,-2.4 -6.1,3.1c-8.2,4 -15.5,4.7 -21.3,1.8 -5.4,-2.6 -7.8,-6.5 -7.8,-12.6 0,-4.1 0.5,-5.2 3.5,-8 3.4,-3.3 5.1,-3.9 22.5,-7.6 5.1,-1.1 5.1,-1.1 4.5,-4.2 -0.9,-4.1 -3,-5.7 -7.6,-5.7 -5.2,-0 -7.9,1.5 -11.1,6.1 -3.3,4.7 -6.9,5.2 -9.4,1.4 -1.5,-2.2 -1.5,-3 -0.3,-6.2 2.7,-6.9 10.5,-10.5 21.6,-10 4.9,0.3 8.2,1 10.6,2.5z" | |||||
android:strokeColor="#00000000" /> | |||||
<path | |||||
android:fillColor="#8757E6" | |||||
android:pathData="M68.5,42.2c-3,1.6 -5.5,5 -5.5,7.5 0,2.2 0.3,2.3 10,2.3 6.6,-0 10,-0.4 10,-1.1 0,-0.6 -0.7,-2.6 -1.5,-4.4 -2.4,-4.9 -8.3,-6.9 -13,-4.3z" | |||||
android:strokeColor="#00000000" /> | |||||
<path | |||||
android:fillColor="#8757E6" | |||||
android:pathData="M43,59.2c-10.6,2.7 -13.3,5.8 -9.2,10.6 2.9,3.4 8.8,3.3 13.1,-0.3 2.2,-1.9 3.2,-3.8 3.7,-7.1 0.3,-2.5 0.5,-4.6 0.3,-4.8 -0.2,-0.2 -3.8,0.6 -7.9,1.6z" | |||||
android:strokeColor="#00000000" /> | |||||
</vector> |
<vector xmlns:android="http://schemas.android.com/apk/res/android" | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
android:width="18dp" | android:width="18dp" | ||||
android:height="18dp" | android:height="18dp" | ||||
android:tint="#40A540" | |||||
android:viewportWidth="24" | android:viewportWidth="24" | ||||
android:viewportHeight="24"> | android:viewportHeight="24"> | ||||
<path | <path | ||||
android:fillColor="@android:color/white" | |||||
android:fillColor="#40A540" | |||||
android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" /> | android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" /> | ||||
</vector> | </vector> |
* create 2022/4/1 18:02 | * create 2022/4/1 18:02 | ||||
* Describe: https://yuzhiqiang.blog.csdn.net/article/details/88233525 | * Describe: https://yuzhiqiang.blog.csdn.net/article/details/88233525 | ||||
*/ | */ | ||||
/** | |||||
* 单线程 : 只有diskIo单线程 | |||||
* @return ObservableTransformer<T, T> | |||||
*/ | |||||
fun <T> diskIo2DiskIo(): ObservableTransformer<T, T> { | fun <T> diskIo2DiskIo(): ObservableTransformer<T, T> { | ||||
return ObservableTransformer { upstream -> | return ObservableTransformer { upstream -> | ||||
upstream!!.subscribeOn(Schedulers.from(AppExecutors.diskIO)) | upstream!!.subscribeOn(Schedulers.from(AppExecutors.diskIO)) | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 多线程 | |||||
* @return ObservableTransformer<T, T> | |||||
*/ | |||||
fun <T> io2Io(): ObservableTransformer<T, T> { | |||||
return ObservableTransformer { upstream -> | |||||
upstream!!.subscribeOn(Schedulers.from(AppExecutors.io)) | |||||
.observeOn(Schedulers.from(AppExecutors.io)) | |||||
} | |||||
} | |||||
/** | |||||
* 多线程 | |||||
* @return ObservableTransformer<T, T> | |||||
*/ | |||||
fun <T> io2Main(): ObservableTransformer<T, T> { | |||||
return ObservableTransformer { upstream -> | |||||
upstream!!.subscribeOn(Schedulers.from(AppExecutors.io)) | |||||
.observeOn(Schedulers.from(AppExecutors.mainThread)) | |||||
} | |||||
} | |||||
fun <T> diskIo2Main(): ObservableTransformer<T, T> { | fun <T> diskIo2Main(): ObservableTransformer<T, T> { | ||||
return ObservableTransformer { upstream -> | return ObservableTransformer { upstream -> | ||||
upstream!!.subscribeOn(Schedulers.from(AppExecutors.diskIO)) | upstream!!.subscribeOn(Schedulers.from(AppExecutors.diskIO)) |
fun format(formatValue : Long, format : String) : String { | fun format(formatValue : Long, format : String) : String { | ||||
return SimpleDateFormat(format).format(formatValue) | return SimpleDateFormat(format).format(formatValue) | ||||
} | } | ||||
/** | |||||
* 格式化字符串格式时间为日期格式 | |||||
* @param formatValue String 字符串格式的日期 | |||||
* @param format String 字符串格式样式,如 "yyyy-MM-dd HH:mm:ss" | |||||
* @return Date 日期格式 | |||||
*/ | |||||
@SuppressLint("SimpleDateFormat") | |||||
@Throws(Exception::class) | |||||
@JvmStatic | |||||
fun format(formatValue:String, format : String):Date{ | |||||
return SimpleDateFormat(format).parse(formatValue) | |||||
} | |||||
/** | /** | ||||
* 获取时间段 | * 获取时间段 |