Browse Source

statistics

master
suliang 2 years ago
parent
commit
529d608dfc
32 changed files with 2459 additions and 188 deletions
  1. 5
    0
      .idea/misc.xml
  2. 9
    3
      app/src/main/AndroidManifest.xml
  3. 97
    0
      app/src/main/java/com/xkl/cdl/adapter/AdapterStatisticsCourseChapterInfo.kt
  4. 40
    0
      app/src/main/java/com/xkl/cdl/adapter/AdapterSubjectCourseStatistics.kt
  5. 1
    1
      app/src/main/java/com/xkl/cdl/data/DataTransferHolder.kt
  6. 11
    0
      app/src/main/java/com/xkl/cdl/data/bean/StatisticsCourse.kt
  7. 0
    2
      app/src/main/java/com/xkl/cdl/data/bean/course/Course.kt
  8. 37
    0
      app/src/main/java/com/xkl/cdl/data/binding/BindingAdapter.kt
  9. 59
    21
      app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt
  10. 5
    5
      app/src/main/java/com/xkl/cdl/data/manager/db/DBCourseManager.kt
  11. 450
    0
      app/src/main/java/com/xkl/cdl/module/m_statics/CourseStatisticsDetailActivity.kt
  12. 254
    0
      app/src/main/java/com/xkl/cdl/module/m_statics/CourseStatisticsDetailViewModel.kt
  13. 9
    12
      app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragment.kt
  14. 146
    0
      app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsFragmentViewModel.kt
  15. 26
    6
      app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragment.kt
  16. 4
    132
      app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragmentViewModel.kt
  17. 87
    0
      app/src/main/java/com/xkl/cdl/module/m_statics/SubjectStatisticsDetailActivity.kt
  18. 106
    0
      app/src/main/java/com/xkl/cdl/widget/StatisticsICourseChangePopup.kt
  19. 681
    0
      app/src/main/res/layout/activity_course_statistics_detail.xml
  20. 69
    0
      app/src/main/res/layout/activity_subject_statistics.xml
  21. 5
    4
      app/src/main/res/layout/fragment_statics.xml
  22. 1
    1
      app/src/main/res/layout/item_memo.xml
  23. 1
    1
      app/src/main/res/layout/item_statics_for_time.xml
  24. 42
    0
      app/src/main/res/layout/item_statistics_bottom_course_change.xml
  25. 86
    0
      app/src/main/res/layout/item_statistics_course.xml
  26. 208
    0
      app/src/main/res/layout/item_statistics_course_chapter_info.xml
  27. BIN
      app/src/main/res/mipmap-xxxhdpi/statistics_testscore_equality_chart.png
  28. BIN
      app/src/main/res/mipmap-xxxhdpi/statistics_testscore_lower_chart.png
  29. BIN
      app/src/main/res/mipmap-xxxhdpi/statistics_testscore_nodata_chart.png
  30. BIN
      app/src/main/res/mipmap-xxxhdpi/statistics_testscore_noend_chart.png
  31. BIN
      app/src/main/res/mipmap-xxxhdpi/statistics_testscore_up_chart.png
  32. 20
    0
      app/svg/drawable/ic_change.xml

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

<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout-v23/include_main_learn_center_course_type_title.xml" value="0.4963768115942029" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout-v23/include_main_learn_center_course_type_title.xml" value="0.4963768115942029" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/_xpopup_ext_time_picker.xml" value="0.23632218844984804" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/_xpopup_ext_time_picker.xml" value="0.23632218844984804" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_main.xml" value="0.33" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_main.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_statistics_detail.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_exam_learn_spell.xml" value="0.47690217391304346" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_exam_learn_spell.xml" value="0.47690217391304346" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_base.xml" value="0.4979166666666667" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_base.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_memo_list_detail.xml" value="0.3621621621621622" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_memo_list_detail.xml" value="0.3621621621621622" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_memo_test.xml" value="0.25" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_memo_test.xml" value="0.25" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_subject_statistics.xml" value="0.23454913880445796" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_test_detail.xml" value="0.33" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_test_detail.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/content_learn_base.xml" value="0.4979166666666667" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/content_learn_base.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/custom_marker_view.xml" value="0.23353596757852077" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/custom_marker_view.xml" value="0.23353596757852077" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" />
<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_statics_for_time.xml" value="0.27717391304347827" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.27717391304347827" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statistics_bottom_course_change.xml" value="0.30842391304347827" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statistics_course.xml" value="0.33" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statistics_course_chapter_info.xml" value="0.5" />
<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_test_detail.xml" value="0.348731884057971" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail.xml" value="0.348731884057971" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option.xml" value="0.348731884057971" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option.xml" value="0.348731884057971" />

+ 9
- 3
app/src/main/AndroidManifest.xml View File

<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.xkl.cdl">
package="com.xkl.cdl" >


<application <application
android:name=".module.XKLApplication" android:name=".module.XKLApplication"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.XklLocal" android:theme="@style/Theme.XklLocal"
tools:ignore="LockedOrientationActivity">
tools:ignore="LockedOrientationActivity" >
<activity
android:name=".module.m_statics.CourseStatisticsDetailActivity"
android:exported="true" />
<activity
android:name=".module.m_statics.SubjectStatisticsDetailActivity"
android:exported="true" />
<activity <activity
android:name=".module.m_service_center.TestDetailActivity" android:name=".module.m_service_center.TestDetailActivity"
android:exported="true" /> android:exported="true" />
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true" android:exported="true"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/Theme.Splash">
android:theme="@style/Theme.Splash" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />



+ 97
- 0
app/src/main/java/com/xkl/cdl/adapter/AdapterStatisticsCourseChapterInfo.kt View File

package com.xkl.cdl.adapter

import android.view.View
import android.view.ViewGroup
import com.suliang.common.base.adapter.BaseAdapterViewHolder
import com.suliang.common.base.adapter.BaseRVAdapter
import com.suliang.common.databinding.ItemEmptyBinding
import com.suliang.common.extension.setHtml
import com.suliang.common.widget.NumberUtils
import com.xkl.cdl.R
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.databinding.ItemStatisticsCourseChapterInfoBinding

/**
* author suliang
* create 2022/7/1 10:27
* Describe: 统计详情下的章节学习情况
*/
class AdapterStatisticsCourseChapterInfo : BaseRVAdapter<Lesson>() {
override fun onBindEmptyViewHolder(holder : BaseAdapterViewHolder) {
(holder.binding as ItemEmptyBinding).apply {
imgEmpty.setImageResource(R.mipmap.empty_nothing)
tvContent.text = "没有课程进度"
}
}
override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder {
return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_statistics_course_chapter_info))
}
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) {
(holder.binding as ItemStatisticsCourseChapterInfoBinding).apply {
getItem(position).let {
when (it.courseType) {
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> {
tv1.text = "章节"
tv1Value.text = it.chapterName
tv2.text = "学习进度"
tv2Value.text = "${NumberUtils.formatHalfUp(it.beforeTestScore, "0.#")}%"
tv3.setHtml(
"<font color=\"#323232\">条目-</font><font color=\"#40A540\">正确</font>|<font color=\"#F26255\">错误</font>")
tv3Value.setHtml(
"<font color=\"#323232\">${it.totalNumber}-</font><font color=\"#40A540\">${it.correctNumber}</font>|<font color=\"#F26255\">${it.errorNumber}</font>")
tv4.text = "知识点测试"
if (it.afterTestScore != AppConstants.NOT_DOING) {
it.afterTestScore.toInt().let {
p4.progress = it
tv5Value.text = it.toString()
}
} else {
p4.visibility = View.GONE
tv4Value.text = "——"
}
View.GONE.let {
v5.visibility = it
tv5.visibility = it
tv5Value.visibility = it
p5.visibility = it
}
}
else -> {
tv1Value.text = it.lessonName
tv2.text = "学习进度"
tv2Value.text = NumberUtils.formatHalfUp(
it.wordIds.subList(0, it.learnedIndex + 1).size / it.totalNumber.toDouble(), "0.#%")
tv3.setHtml(
"<font color=\"#323232\">条目-</font><font color=\"#40A540\">正确</font> | <font color=\"#F26255\">错误</font>")
tv3Value.setHtml(
"<font color=\"#323232\">${it.totalNumber}-</font><font color=\"#40A540\">${it.correctNumber}</font> | <font color=\"#F26255\">${it.errorNumber}</font>")
tv4.text = "课时学前测试"
tv5.text = "课时学前测试"
if (it.beforeTestScore != AppConstants.NOT_DOING) {
it.beforeTestScore.toInt().let {
p4.progress = it
tv4Value.text = it.toString()
}
} else {
p4.visibility = View.GONE
tv4Value.text = "——"
}
if (it.afterTestScore != AppConstants.NOT_DOING) {
it.afterTestScore.toInt().let {
p5.progress = it
tv5Value.text = it.toString()
}
} else {
p5.visibility = View.GONE
tv5Value.text = "——"
}
}
}
}
}
}
}

+ 40
- 0
app/src/main/java/com/xkl/cdl/adapter/AdapterSubjectCourseStatistics.kt View File

package com.xkl.cdl.adapter

import android.view.ViewGroup
import com.suliang.common.base.adapter.BaseAdapterViewHolder
import com.suliang.common.base.adapter.BaseRVAdapter
import com.suliang.common.databinding.ItemEmptyBinding
import com.suliang.common.extension.click
import com.xkl.cdl.R
import com.xkl.cdl.data.bean.StatisticsCourse
import com.xkl.cdl.data.bean.course.Course
import com.xkl.cdl.databinding.ItemStatisticsCourseBinding

/**
* author suliang
* create 2022/6/27 14:24
* Describe:
*/
class AdapterSubjectCourseStatistics : BaseRVAdapter<StatisticsCourse>() {
override fun onBindEmptyViewHolder(holder : BaseAdapterViewHolder) {
(holder.binding as ItemEmptyBinding).apply {
imgEmpty.setImageResource( R.mipmap.empty_nothing )
tvContent.text = "没有可分析的课程"
}
}
override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder {
return BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_statistics_course))
}
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) {
(holder.binding as ItemStatisticsCourseBinding).course = getItem(position)
holder.binding.root.click {
if (onItemClickIsInitialized()){
onItemClick.invoke(it,position,getItem(position))
}
}
}
}

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

@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T> getData(key : String = AppConfig.INTENT_1) : T{ fun <T> getData(key : String = AppConfig.INTENT_1) : T{
return (dataMap[key] as T).also { return (dataMap[key] as T).also {
clear()
dataMap.remove(key)
} }
} }



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

package com.xkl.cdl.data.bean

import com.xkl.cdl.data.bean.course.Course

/**
* author suliang
* create 2022/6/27 14:42
* Describe: 统计课程item
*/
class StatisticsCourse(val course:Course,val cover: ByteArray) {
}

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

package com.xkl.cdl.data.bean.course package com.xkl.cdl.data.bean.course


import androidx.databinding.BaseObservable

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

+ 37
- 0
app/src/main/java/com/xkl/cdl/data/binding/BindingAdapter.kt View File



import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
import com.suliang.common.util.DrawableUti import com.suliang.common.util.DrawableUti
} }
} }


/**
* 统计课程文字显示的进度格式化
* @param view TextView
* @param learnProgress Double
*/
@BindingAdapter("courseStatisticsLearnProgressTextViewFormat")
@JvmStatic
fun courseStatisticsLearnProgressTextViewFormat(view: TextView,learnProgress:Double){
view.text = when{
learnProgress == 0.0 -> "0%"
learnProgress < 0.1 -> "0.1%"
learnProgress < 100 -> {
DecimalFormat("#.#").apply {
roundingMode = RoundingMode.DOWN
}.format(learnProgress) + "%"
}
else -> "100%"
}
}
/**
* 课程统计进度条显示时的进度,最大进度值 1000
* @param view ProgressBar
* @param learnProgress Double 默认为百分进度
*/
@BindingAdapter("courseStatisticsLearnProgressFormat")
@JvmStatic
fun courseStatisticsLearnProgressFormat(view: ProgressBar,learnProgress:Double){
val p = learnProgress * 10 //进度值改千分进度
view.progress = when{
p == 0.0 -> 0
p < 0.1 -> 1
p < 1000 -> p.toInt()
else -> 1000
}
}





} }

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

coursePack.childrenCourses.forEach { coursePack.childrenCourses.forEach {
//如果是作文,作文需要检查数据库,同时需要检查其下的图片、视频和关键帧 //如果是作文,作文需要检查数据库,同时需要检查其下的图片、视频和关键帧
if (it.subjectId == AppConstants.SUBJECT_CHINESE && it.coursePackType == AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION){
if (it.subjectId == AppConstants.SUBJECT_CHINESE && it.coursePackType == AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION) {
val assetFileName = it.dbPathName.substringBeforeLast(".") + ".zip" val assetFileName = it.dbPathName.substringBeforeLast(".") + ".zip"
val inputStream = AppGlobals.application.resources.assets.open(assetFileName) val inputStream = AppGlobals.application.resources.assets.open(assetFileName)
val zipInputStream = ZipInputStream(inputStream) val zipInputStream = ZipInputStream(inputStream)
var count = 0
var count = 0
val buffer = ByteArray(5120) val buffer = ByteArray(5120)
var nextEntry = zipInputStream.nextEntry var nextEntry = zipInputStream.nextEntry
while (nextEntry != null){
when{
nextEntry.name.endsWith(".mp4.png") -> File(FilePathManager.getMp4PngRootPath(),"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${nextEntry.name.substringAfterLast("/")}")
nextEntry.name.endsWith(".mp4") -> File(FilePathManager.getMp4RootPath(),"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${nextEntry.name.substringAfterLast("/")}")
nextEntry.name.endsWith(".png") -> File(FilePathManager.getPngRootPath(),"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${nextEntry.name.substringAfterLast("/")}")
nextEntry.name.endsWith(".db") -> File(FilePathManager.getDbRootPath(),"${entry.key}/${coursePack.coursePackId}/${it.courseId}/course.db")
while (nextEntry != null) {
when {
nextEntry.name.endsWith(".mp4.png") -> File(FilePathManager.getMp4PngRootPath(),
"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${
nextEntry.name.substringAfterLast("/")
}")
nextEntry.name.endsWith(".mp4") -> File(FilePathManager.getMp4RootPath(),
"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${
nextEntry.name.substringAfterLast("/")
}")
nextEntry.name.endsWith(".png") -> File(FilePathManager.getPngRootPath(),
"${entry.key}/${coursePack.coursePackId}/${it.courseId}/${
nextEntry.name.substringAfterLast("/")
}")
nextEntry.name.endsWith(".db") -> File(FilePathManager.getDbRootPath(),
"${entry.key}/${coursePack.coursePackId}/${it.courseId}/course.db")
else -> null else -> null
}?.let { file -> }?.let { file ->
//文件不存在 ,复制当前文件进入该文件
if (!file.exists()){
//文件不存在 ,复制当前文件进入该文件
if (!file.exists()) {
file.parentFile?.let { parentFile -> file.parentFile?.let { parentFile ->
if (!parentFile.exists()) parentFile.mkdirs() if (!parentFile.exists()) parentFile.mkdirs()
} }
val outputStream = BufferedOutputStream(FileOutputStream(file)) val outputStream = BufferedOutputStream(FileOutputStream(file))
while ((zipInputStream.read(buffer).also { count = it }) != -1 ){
outputStream.write(buffer,0,count)
while ((zipInputStream.read(buffer).also { count = it }) != -1) {
outputStream.write(buffer, 0, count)
} }
outputStream.close() outputStream.close()
} }
nextEntry = zipInputStream.nextEntry nextEntry = zipInputStream.nextEntry
} }
}else{ //其他的项目只需要复制和检查数据库
val file = File(FilePathManager.getDbRootPath(), "${entry.key}/${coursePack.coursePackId}/${it.courseId}/course.db")
} else { //其他的项目只需要复制和检查数据库
val file = File(FilePathManager.getDbRootPath(),
"${entry.key}/${coursePack.coursePackId}/${it.courseId}/course.db")
//不存在,复制,存在则不操作 //不存在,复制,存在则不操作
if (!file.exists()) { if (!file.exists()) {
FileUtil.copyAsset(it.dbPathName, file) FileUtil.copyAsset(it.dbPathName, file)
return totalProgress / chapterTotalSize * 100 return totalProgress / chapterTotalSize * 100
} }
/**
* 作文课程单章节的进度计算
* @param allLesson List<Lesson> 章节所有课时
*/
fun calculateCompositionChapterProgress(allLesson : List<Lesson>) : Double {
var lessonSize = 0
var chapterProgressSize = 0.0
//循环
allLesson.forEach {
//单章节内的进度累加
if (it.lessonType != AppConstants.LESSON_TYPE_COMPOSITION_TASK) {
lessonSize += 1
//章节添加课时进度
chapterProgressSize += if (it.learnIsOver) 1.0 else if (it.lessonType == AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE) {
//知识点的进度设置,设置该课时总进度为 1
if (it.learnedIndex == -1) 0.0 else (it.learnedIndex + 1.0) / it.wordIds.size
} else 0.0
}
}
//计算进度
return chapterProgressSize / lessonSize * 100
}
/** /**
* 口语课程的进度计算 * 口语课程的进度计算
* @param allLesson List<Lesson> * @param allLesson List<Lesson>
// TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 // TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值
//间隔时间单位 //间隔时间单位
private val reviewIntervalUnit = "hour" private val reviewIntervalUnit = "hour"
//间隔单位时间 //间隔单位时间
private val reviewTime = IntArray(7){
when(it){
private val reviewTime = IntArray(7) {
when (it) {
0 -> 1 0 -> 1
1 -> 2 1 -> 2
2 -> 3 2 -> 3
* @param currentTime Long 用以计算的当前时间 * @param currentTime Long 用以计算的当前时间
* @return Boolean true:需要复习 false:不需要复习 * @return Boolean true:需要复习 false:不需要复习
*/ */
fun calculateIsNeedInReview(calendar:Calendar,currentReviewNumber : Int, currentReviewTime : String, currentTime : Long) : Boolean {
fun calculateIsNeedInReview(calendar : Calendar,
currentReviewNumber : Int,
currentReviewTime : String,
currentTime : Long) : Boolean {
if (currentReviewNumber >= reviewTime.size) return false if (currentReviewNumber >= reviewTime.size) return false
try { try {
//转换设置当前的复习时间 //转换设置当前的复习时间
calendar.time = DateUtil.format(currentReviewTime,DateUtil.FORMAT_1)
calendar.time = DateUtil.format(currentReviewTime, DateUtil.FORMAT_1)
//与当前时间的间隔 //与当前时间的间隔
val intervalTime = currentTime - calendar.timeInMillis val intervalTime = currentTime - calendar.timeInMillis
//单位转换 : 给一个提前量的时间,提前一分钟 //单位转换 : 给一个提前量的时间,提前一分钟
return intervalTime >= when(reviewIntervalUnit){
return intervalTime >= when (reviewIntervalUnit) {
"minute" -> reviewTime[currentReviewNumber] * 60000 "minute" -> reviewTime[currentReviewNumber] * 60000
"hour" -> reviewTime[currentReviewNumber] * 60 * 60000 "hour" -> reviewTime[currentReviewNumber] * 60 * 60000
else -> reviewTime[currentReviewNumber] * 24 * 60 * 60000
else -> reviewTime[currentReviewNumber] * 24 * 60 * 60000
} - 60000 } - 60000
}catch (e:Exception){
} catch (e : Exception) {
e.printStackTrace() e.printStackTrace()
} }
return false return false

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

correctNumber = detail.right.getOrElse(key, { 0 }).toInt() //正确数 correctNumber = detail.right.getOrElse(key, { 0 }).toInt() //正确数
errorNumber = detail.wrong.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
} }
// 学习位置 // 学习位置
// id集合中的学习entity的位置, 作文的视频、知识点测试,不以这个为标准 // id集合中的学习entity的位置, 作文的视频、知识点测试,不以这个为标准
val learnIndex = wordIds.indexOf(detail.lesson_learn_point.getOrElse(key, { -1 })) //学习位置,当前位置为已学 val learnIndex = wordIds.indexOf(detail.lesson_learn_point.getOrElse(key, { -1 })) //学习位置,当前位置为已学
lesson.learnedIndex = learnIndex
// 注:针对口语对话课时,如果没有学习完,是不会设置进度点的。 todo 分课程类型设置进度点 口语未做判断处理 // 注:针对口语对话课时,如果没有学习完,是不会设置进度点的。 todo 分课程类型设置进度点 口语未做判断处理
lesson.learnIsOver = when (base.coursePackType) { lesson.learnIsOver = when (base.coursePackType) {
//作文课时,需要根据课时属性,判断本课时是否学习完成 //作文课时,需要根据课时属性,判断本课时是否学习完成
positionIndex += 1 positionIndex += 1
// TODO: 2022/5/9 对课时数量进行限制,课时太多,开发人员不好进行测试 // TODO: 2022/5/9 对课时数量进行限制,课时太多,开发人员不好进行测试
val needBreak = when (base.coursePackType) { val needBreak = when (base.coursePackType) {
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION -> positionIndex == 6 //保留十个课时
AppConstants.COURSEPACK_TYPE_ENGLISH_SPOKEN -> positionIndex == 4 //保留六个课时
else -> positionIndex == 1 //保留三个课时
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION -> positionIndex == 10 //保留十个课时
AppConstants.COURSEPACK_TYPE_ENGLISH_SPOKEN -> positionIndex == 6 //保留六个课时
else -> positionIndex == 3 //保留三个课时
} }
if (needBreak) { if (needBreak) {
break break

+ 450
- 0
app/src/main/java/com/xkl/cdl/module/m_statics/CourseStatisticsDetailActivity.kt View File

package com.xkl.cdl.module.m_statics

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.formatter.ValueFormatter
import com.lxj.xpopup.XPopup
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.extension.click
import com.suliang.common.extension.setHtml
import com.suliang.common.widget.NumberUtils
import com.xkl.cdl.R
import com.xkl.cdl.adapter.AdapterStatisticsCourseChapterInfo
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.bean.course.CourseDetail
import com.xkl.cdl.databinding.ActivityCourseStatisticsDetailBinding
import com.xkl.cdl.widget.MyMarkerView
import com.xkl.cdl.widget.StatisticsICourseChangePopup
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.abs

/**
* author suliang
* create 2022/6/27 9:42
* Describe: 课程的统计详情
*/
class CourseStatisticsDetailActivity : BaseActivityVM<ActivityCourseStatisticsDetailBinding, CourseStatisticsDetailViewModel>() {
override fun initViewModel() : CourseStatisticsDetailViewModel {
return ViewModelProvider(this)[CourseStatisticsDetailViewModel::class.java]
}
private lateinit var pupCourseChangeView : StatisticsICourseChangePopup
override fun initActivity(savedInstanceState : Bundle?) {
binding.titleBar.onBackClick = { _ -> finish() }
binding.course = vm.currentStatisCourse
initChart()
binding.rvChapterInfo.apply {
layoutManager = LinearLayoutManager(this@CourseStatisticsDetailActivity,LinearLayoutManager.VERTICAL,false)
adapter = AdapterStatisticsCourseChapterInfo()
}
if (vm.statisticsCourseList.size <= 1){
binding.ivChangeCourse.visibility = View.INVISIBLE
}else{
// TODO: 2022/7/1 弹窗实例失败
//课程切换弹窗
binding.ivChangeCourse.click {
if (!this::pupCourseChangeView.isInitialized){
pupCourseChangeView = StatisticsICourseChangePopup(this).apply {
data = vm.statisticsCourseList
checkPostion = vm.checkedPosition
onAdapterItemClick = { position,item ->
vm.checkedPosition = position
vm.currentStatisCourse = item
loadData()
}
}
}
XPopup.Builder(this).asCustom(pupCourseChangeView).show()
}
}
vm.courseDetailLiveData.observe(this) {
when {
//英语界面显示
vm.isShowAsEnglish(vm.dbControlBase.subjectId, vm.dbControlBase.coursePackType) -> {
//已学课堂练习 进度布局隐藏
binding.ranking3.visibility = View.GONE
//测试成绩对比
initTestTotalScore(it.st_before, it.st_after)
//学习效率初始
initEfficient(it.e, it.last_e)
//学习时长统计
initDurationTime(it)
}
//作文界面显示
else -> {
binding.layoutTestScore.visibility = View.GONE
binding.layoutEfficient.visibility = View.GONE
initDurationTime(it)
}
}
}
/**课程进度 章节学习情况显示*/
vm.courseLessonLiveData.observe(this){
when(vm.currentStatisCourse.course.courseType){
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> {
binding.ranking1.setProgressNumber(vm.learnLessonSize / vm.totalLessonSize.toFloat() * 100)
binding.tvRanking1Flag.text = "已学章节"
binding.tvRanking1Value.setHtml("<font color=\"#40A540\"><b>${vm.learnLessonSize}</b></font>/${vm.totalLessonSize}")
binding.ranking2.setProgressNumber(vm.learnWordNumber/vm.totalWordNumber.toFloat() * 100 )
binding.tvRanking2Flag.text = "已学知识点"
binding.tvRanking2Value.setHtml("<font color=\"#5082E6\"><b>${vm.learnWordNumber}</b></font>/${vm.totalWordNumber}")
binding.ranking3.setProgressNumber(vm.learnRadingSize/vm.totalRadingSize.toFloat() * 100)
binding.tvRanking3Flag.text = "已学课堂练习"
binding.tvRanking3Value.setHtml("<font color=\"#8757E6\"><b>${vm.learnRadingSize}</b></font>/${vm.totalRadingSize}")
}
else -> {
binding.ranking1.setProgressNumber(vm.learnLessonSize / vm.totalLessonSize.toFloat() * 100)
binding.tvRanking1Flag.text = "已学课时"
binding.tvRanking1Value.setHtml("<font color=\"#40A540\"><b>${vm.learnLessonSize}</b></font>/${vm.totalLessonSize}")
binding.ranking2.setProgressNumber(vm.learnWordNumber/vm.totalWordNumber.toFloat() * 100)
binding.tvRanking2Flag.text = "已学词汇量"
binding.tvRanking2Value.setHtml("<font color=\"#5082E6\"><b>${vm.learnWordNumber}</b></font>/${vm.totalWordNumber}")
binding.ranking3.visibility = View.GONE
}
}
//根据生成的数据,进行选择器的实现
when(vm.chapterList.size){
0,1 -> binding.tvChapterChoose.visibility = View.GONE
else -> binding.tvChapterChoose.visibility = if(vm.chapterList[0].size > 0){
binding.tvChapterChoose.text = vm.chapterList[0][0].chapterName
View.VISIBLE
}else {
View.GONE
}
}
//通知刷新列表
vm.rvChapterChangeLiveData.value = 0
}
//章节切换
vm.rvChapterChangeLiveData.observe(this){
if(vm.chapterList.size > it){
(binding.rvChapterInfo.adapter as AdapterStatisticsCourseChapterInfo).apply {
needShowEmptyView = false
setData(vm.chapterList[it])
}
}else{
(binding.rvChapterInfo.adapter as AdapterStatisticsCourseChapterInfo).apply {
needShowEmptyView = true
setData(null)
}
}
}
}
/**
* 初始化数据图
*/
private fun initChart() {
binding.barChart.apply {
description.isEnabled = false
setMaxVisibleValueCount(40)
setScaleEnabled(false) //禁止缩放
setDrawGridBackground(false)
setDrawBarShadow(false)
setDrawValueAboveBar(false)
isHighlightFullBarEnabled = true
xAxis.apply {
isEnabled = true
setDrawGridLines(false)
setDrawAxisLine(false)
//自定义设置x轴显示value
valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value : Float) : String {
return vm.getTimeNode(value.toInt()) }
}
//设置x坐标显示个数
granularity = 1f
textSize = 11f
textColor = Color.parseColor("#8A8A99")
position = XAxis.XAxisPosition.BOTTOM_INSIDE
}
axisLeft.apply {
gridColor = Color.parseColor("#E6E2E2")
textColor = Color.parseColor("#8A8A99")
setDrawAxisLine(false)
// granularity = 1f
setLabelCount(4, false) // force 6 labels
valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value : Float) : String {
return NumberUtils.formatFloor(value.toDouble(),"0.#")
}
}
}
axisRight.isEnabled = false
legend.isEnabled = false
//标签
setDrawMarkers(true)
val mv = MyMarkerView(this@CourseStatisticsDetailActivity, R.layout.custom_marker_view)
mv.chartView = this // For bounds control
this.marker = mv // Set the marker to the chart
mv.setValueCallback { tv, e ->
val dataSets = this.data.dataSets
for (iBarDataSet in dataSets) {
//设置value框的偏移量
mv.offsetX = 240f
val entryIndex = iBarDataSet.getEntryIndex(e as BarEntry)
if (entryIndex >= 0) {
this.setDrawMarkers(true)
if (e.getX() >= 2) {
//放左边
mv.offsetX = -400f
} else {
//放右边
mv.offsetX =400f
}
//分钟数转换为毫秒
val valid = (e.yVals[0] * 60000.0).toLong()
val review = (e.yVals[1]* 60000.0).toLong()
val free = (e.yVals[2] * 60000.0).toLong()
val str : String = "<b><font>${vm.getTimeNode(entryIndex)}<font></b>" +
"<br><font color=\'#8A8A99\'>有效学习时长:</font> <font color=\'#F7874F\'>${formatTime(valid)}</font><font color=\'#8A8A99\'>${formatTimeUnit(valid)}</font>" +
"<br><font color=\'#8A8A99\'>有效复习时长:</font> <font color=\'#40A540\'>${formatTime(review)}</font><font color=\'#8A8A99\'>${formatTimeUnit(review)}</font>\n" +
"<br><font color=\'#8A8A99\'>空闲时长:</font> <font color=\'#5082E6\'> ${formatTime(free)}</font><font color=\'#8A8A99\'>${formatTimeUnit(free)}</font>"
tv.setHtml(str)
}
}
}
}
}
override fun loadData() {
vm.getCourseDetailInfo()
}
/**
* 测试成绩对比
* @param stBefore Double
* @param stAfter Double
*/
private fun initTestTotalScore(stBefore : Double, stAfter : Double) {
var tc = R.color.green_1 //tvTestState文字显示颜色
var res = R.drawable.ic_rise //tvTestState前缀图标
var tv = "+?" //tvTestState显示文字
var ivRes = 0 //ivTestState 背景资源
var tvBefore = "" //学前值
var tvAfter = "" //学后值
when {
//学前学后总测试都没做
stBefore == AppConstants.NOT_DOING && stAfter == AppConstants.NOT_DOING -> {
ivRes = R.mipmap.statistics_testscore_nodata_chart
tvBefore = "未测"
tvAfter = "未测"
}
//学前学后总测都做完
stBefore != AppConstants.NOT_DOING && stAfter != AppConstants.NOT_DOING -> {
//差距
val instance = stAfter - stBefore
when {
instance == 0.0 -> {
tv = "+0"
ivRes = R.mipmap.statistics_testscore_equality_chart
}
instance > 0 -> {
tv = "+${NumberUtils.formatFloor(instance, "0.#")}"
ivRes = R.mipmap.statistics_testscore_up_chart
}
else -> {
tc = R.color.red_1
res = R.drawable.ic_decline
tv = "-${NumberUtils.formatFloor(abs(instance), "0.#")}"
ivRes = R.mipmap.statistics_testscore_lower_chart
}
}
tvBefore = "${stBefore.toInt()}分"
tvAfter = "${stAfter.toInt()}分"
}
//学前总测做了,学后总测没做
stAfter == AppConstants.NOT_DOING -> {
ivRes = R.mipmap.statistics_testscore_noend_chart
tvBefore = "${stBefore.toInt()}分"
tvAfter = "未测"
}
}
binding.ivTestState.setBackgroundResource(ivRes)
binding.tvTestState.apply {
setTextColor(ContextCompat.getColor(this@CourseStatisticsDetailActivity, tc))
setCompoundDrawablesWithIntrinsicBounds(res, 0, 0, 0)
text = tv
}
binding.tvBeforeTotal.text = tvBefore
binding.tvAfterTotal.text = tvAfter
}
/**
* 学习效率
* @param e Double
* @param lastE Double
*/
private fun initEfficient(e : Double, lastE : Double) {
when (vm.currentStatisCourse.course.courseType) {
//口语隐藏效率
AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> binding.layoutEfficient.visibility = View.GONE
else -> {
binding.rankingEfficient.setProgressNumber(e.toFloat())
binding.tvEfficient.text = "${NumberUtils.formatHalfUp(e, "0.##")}%"
binding.tvEfficientState.apply {
val instance = lastE - e
when {
//增长
instance >= 0 -> {
setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_rise, 0, 0, 0)
setTextColor(ContextCompat.getColor(this@CourseStatisticsDetailActivity, R.color.green_1))
text = "+${NumberUtils.formatHalfUp(instance, "0.##")}%"
}
//下降
else -> {
setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_decline, 0, 0, 0)
setTextColor(ContextCompat.getColor(this@CourseStatisticsDetailActivity, R.color.red_1))
text = "-${NumberUtils.formatHalfUp(abs(instance), "0.##")}%"
}
}
}
}
}
}
/**学习时长统计*/
@SuppressLint("SetTextI18n")
private fun initDurationTime(detail : CourseDetail) {
//总时长趋势
val value = "${formatTime(abs(detail.current_week_total_durations))}${
formatTimeUnit(abs(detail.current_week_total_durations))
}"
when {
detail.current_week_total_durations >= 0 -> {
binding.tvDurationState.apply {
setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_rise, 0, 0, 0)
text = "+$value"
}
}
else -> {
binding.tvDurationState.apply {
setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_rise, 0, 0, 0)
text = "-$value"
}
}
}
var totalTime = 0L
var validTotalTime = 0L
var reviewTotalTime = 0L
val chartValueList = mutableListOf<MutableList<Long>>()
for (i in 1 until 5L) {
val total = detail.total.getOrElse(i, { 0 })
val valid = detail.valid.getOrElse(i, { 0 })
val review = detail.review.getOrElse(i, { 0 })
totalTime += total
validTotalTime += valid
reviewTotalTime += review
//图表模型值
chartValueList.add(mutableListOf(valid, review, total - valid - review))
}
val freeTotalTime = totalTime - validTotalTime - reviewTotalTime
//设置时长
binding.tvTotalDuration.text = formatTime(totalTime)
binding.tvTotalDurationUnit.text = formatTimeUnit(totalTime)
binding.tvValidTime.text = formatTime(validTotalTime)
binding.tvValidTimeUnit.text = formatTimeUnit(validTotalTime)
binding.tvReviewTime.text = formatTime(reviewTotalTime)
binding.tvReviewTimeUnit.text = formatTimeUnit(reviewTotalTime)
binding.tvFreeTime.text = formatTime(freeTotalTime)
binding.tvFreeTimeUnit.text = formatTimeUnit(freeTotalTime)
//更新图表值
setChartDate(chartValueList)
}
/** 格式化时间值 */
private fun formatTime(time : Long) : String {
val hour_1 = time / 3600000.0
val minute_1 = time / 60000.0
return when {
//大于1小时
hour_1 > 1 -> "${NumberUtils.formatFloor(hour_1, "0.##")}"
//大于1分钟
minute_1 > 1 -> "${NumberUtils.formatFloor(minute_1, "0.##")}"
//小于1分钟 秒数
else -> ""
}
}
/**格式化单位*/
private fun formatTimeUnit(time : Long) : String {
val hour_1 = time / 3600000.0
val minute_1 = time / 60000.0
return when {
//大于1小时
hour_1 > 1 -> "小时"
//大于1分钟
minute_1 > 1 -> "分钟"
//小于1分钟 秒数
else -> "不足1分钟"
}
}
/**
* 设置统计图的数据
* @param list
*/
private fun setChartDate(chartValueList : MutableList<MutableList<Long>>) {
val barChart = binding.barChart
val values = ArrayList<BarEntry>()
var max = 0f
chartValueList.forEachIndexed { i,it ->
val valid = if (it[0] >= 0) it[0]/60000.0f else 0f
val review = if (it[1] >= 0) it[1]/60000.0f else 0f
val free = if (it[2] >= 0) it[2]/60000.0f else 0f
val sum = valid + review + free
if (sum > max) {
max = sum
}
//数据由毫秒转换为了分钟数
values.add(BarEntry(i.toFloat(), floatArrayOf(valid, review, free), null))
}
if (max <= 0) {
barChart.setNoDataText("暂无数据")
barChart.clear()
return
}
val set1 : BarDataSet
if (barChart.data != null && barChart.data.dataSetCount > 0){
set1 = barChart.data.getDataSetByIndex(0) as BarDataSet
set1.values = values
barChart.data.notifyDataChanged()
barChart.notifyDataSetChanged()
}else{
set1 = BarDataSet(values,"")
set1.setDrawIcons(false)
set1.setDrawValues(false)
set1.colors = vm.getColors().toMutableList()
val data = BarData(set1)
data.barWidth = 0.5f
barChart.data = data
}
barChart.setFitBars(true)
barChart.invalidate()
}
}

+ 254
- 0
app/src/main/java/com/xkl/cdl/module/m_statics/CourseStatisticsDetailViewModel.kt View File

package com.xkl.cdl.module.m_statics

import androidx.lifecycle.MutableLiveData
import com.github.mikephil.charting.utils.ColorTemplate
import com.suliang.common.AppConfig
import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.util.thread.AppExecutors
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.bean.StatisticsCourse
import com.xkl.cdl.data.bean.course.Course
import com.xkl.cdl.data.bean.course.CourseDetail
import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.DbControlBase
import com.xkl.cdl.data.repository.DataRepository
import io.reactivex.rxjava3.schedulers.Schedulers

/**
* author suliang
* create 2022/6/28 11:29
* Describe:
*/
class CourseStatisticsDetailViewModel : BaseViewModel() {
//课程列表
val statisticsCourseList = DataTransferHolder.instance.getData<MutableList<StatisticsCourse>>(AppConfig.INTENT_1)
//选择课程
var checkedPosition = DataTransferHolder.instance.getData<Int>(AppConfig.INTENT_2)
//当前操作课程
var currentStatisCourse = statisticsCourseList[checkedPosition]
val dbControlBase : DbControlBase
get() {
val course : Course = currentStatisCourse.course
return DbControlBase(course.subjectId, course.coursePackId, course.coursePackType, course.courseId, course.courseType)
}
//当前课程统计信息
val courseDetailLiveData = MutableLiveData<CourseDetail>()
//当前课程课时信息初始结束
val courseLessonLiveData = MutableLiveData<Boolean>()
//rv选择章节position
val rvChapterChangeLiveData = MutableLiveData<Int>()
/**获取课程统计详情*/
fun getCourseDetailInfo() {
val course = currentStatisCourse.course
DataRepository.getCourseDetails(course.subjectId, course.coursePackId, course.courseId).map {
//测试成绩对比、学习效率 和 学习时长统计中的总时间趋势
courseDetailLiveData.postValue(it)
//获取课时信息
DBCourseManager.queryAllLesson(dbControlBase, it)
}.subscribeOn(Schedulers.from(AppExecutors.diskIO)).subscribe({
initLessons(it)
}, {
showToast(ToastEvent("数据查询失败"))
})
}
/**是否显示为英语的界面
* 语文的识字、拼音和英语显示是一致的 只有作文显示不一致
* */
fun isShowAsEnglish(subjectId : Int, coursePackType : Int) : Boolean {
return subjectId == AppConstants.SUBJECT_ENGLISH || coursePackType != AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION
}
/**透过下标获取不同的时间点*/
fun getTimeNode(entryIndex : Int) : String {
return when (entryIndex) {
0 -> "6:00-12:00"
1 -> "12:00-18:00"
2 -> "18:00-24:00"
else -> "0:00-6:00"
}
}
/*----------------------设置统计图表中需要的一些方法 Start-------------------------------------------------------------------------------------------*/
/**
* 获取最大值
*
* @return
*/
fun getMaxY(max : Int) : Float {
//设置坐标轴最大值和最小值
var temp = max / 5
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (max % 5 > 0) 1 else 0) * 1
}
return (temp * 5 + temp / 2.0).toFloat()
}
/**
* 获取最小值
*
* @return
*/
fun getMinY(max : Int) : Float {
//设置坐标轴最大值和最小值
var temp = max / 5
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (max % 5 > 0) 1 else 0) * 1
}
return (-(temp - temp / 2.0) - if (temp / 2.5 == 0.0) 0.3 else temp / 2.5).toFloat()
}
val XUEKAOLE_COLORS_STATISTIC = intArrayOf(ColorTemplate.rgb("#F7874F"), ColorTemplate.rgb("#40A540"),
ColorTemplate.rgb("#5082E6"))
/**
* 获取柱状图的颜色
* @return
*/
fun getColors() : IntArray {
// have as many colors as stack-values per entry
val colors = IntArray(3)
System.arraycopy(XUEKAOLE_COLORS_STATISTIC, 0, colors, 0, 3)
return colors
}
var learnLessonSize = 0 //已学课时 作文:已学章节数
var totalLessonSize = 0 //总课时 作文:总章节数
var learnWordNumber = 0 //已学词汇数 作文:已学知识点数量
var totalWordNumber = 0 //总词汇量 作文: 总知识点个数
var learnRadingSize = 0 //已学课堂练习数
var totalRadingSize = 0 //课堂练习总数
val chapterList = mutableListOf<MutableList<Lesson>>() //用于显示的章节课时的学习情况

private fun initLessons(list : List<Lesson>) {
learnLessonSize = 0 //已学课时 作文:已学章节数
totalLessonSize = 0 //总课时 作文:总章节数
learnWordNumber = 0 //已学词汇数 作文:已学知识点数量
totalWordNumber = 0 //总词汇量 作文: 总知识点个数
learnRadingSize = 0 //已学课堂练习数
totalRadingSize = 0 //课堂练习总数
chapterList.clear()
var previousChapterId = -1L //记录上一个章节的id
var currentChapterList = mutableListOf<Lesson>() //记录一个章节的课时
when(dbControlBase.courseType){
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> {
for (i in list.size -1 downTo 0) {
val lesson = list[i]
//转换为章节集合
when(lesson.chapterId){
//同一章节
previousChapterId -> {
currentChapterList.add(lesson)
}
//不同章节
else -> {
currentChapterList = mutableListOf()
currentChapterList.add(lesson)
chapterList.add(currentChapterList)
previousChapterId = lesson.chapterId
}
}
}
//总章节数
totalLessonSize = chapterList.size
val chapterListNew = mutableListOf<Lesson>()
//组合章节结果, 转换为lesson用于显示
chapterList.forEach {
val lesson = it[0]
//将课时组装为课时
val newLesson = Lesson(lesson.subjectId,lesson.coursePackId,lesson.coursePackType,lesson.courseId,lesson.courseType,lesson.chapterId,lesson.chapterName,lesson.lessonId,lesson.lessonName)
//计算各种数量
it.forEach {
when(it.lessonType){
AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE -> { //知识点学习
newLesson.totalNumber = it.totalNumber
newLesson.errorNumber = it.errorNumber
newLesson.correctNumber = it.correctNumber
totalWordNumber += it.totalNumber
learnWordNumber += if (it.learnIsOver) it.totalNumber else lesson.wordIds.subList(0,lesson.learnedIndex+1).size
}
AppConstants.LESSON_TYPE_COMPOSITION_EXAM -> { //知识点测试,成绩在detail的after中
newLesson.afterTestScore = it.afterTestScore
}
AppConstants.LESSON_TYPE_COMPOSITION_READING -> { //课堂练习
totalRadingSize += it.totalNumber
learnRadingSize += if (it.learnIsOver) it.totalNumber else it.wordIds.subList(0,it.learnedIndex + 1).size //已学数
}
}
}
//计算该章节的进度
val chapterProgress = CourseManager.calculateCompositionChapterProgress(it)
if (chapterProgress !=0.0){
learnLessonSize += 1
newLesson.beforeTestScore = chapterProgress //使用学前测试字段记录 章节进度
chapterListNew.add(newLesson)
}
}
chapterList.clear()
chapterList.addAll(mutableListOf(chapterListNew))
}
//英语
else -> {
totalLessonSize = list.size //总课时数
//使用倒叙循环
for (i in list.size -1 downTo 0) {
val lesson = list.get(i)
if (lesson.lessonType != AppConstants.LESSON_TYPE_DIALOGUE) { //口语对话练习不添加为总数,不添加到列表显示
totalWordNumber += lesson.totalNumber //累加总数
//做了学前测试,则学习课时+1
if (lesson.beforeTestScore != AppConstants.NOT_DOING) {
learnLessonSize += 1
//做了学前测试,才有可能进行了课时单词的学习,计算已学单词数
if (lesson.learnedIndex != -1) {
learnWordNumber += if (lesson.learnIsOver) lesson.totalNumber else lesson.wordIds.subList(0,
lesson.learnedIndex + 1).size
}
//统计已学章节的内容,用于显示章节的学习情况
when (lesson.chapterId) {
//同一章节
previousChapterId -> currentChapterList.add(lesson)
else -> {
currentChapterList = mutableListOf()
currentChapterList.add(lesson)
chapterList.add(currentChapterList)
previousChapterId = lesson.chapterId
}
}
}
}else if (lesson.learnIsOver){ //口语对话课时,学习完成,则添加一个已学课时数
learnLessonSize += 1
}
}
}
}
//通知更新
courseLessonLiveData.postValue(true)
}
}

+ 9
- 12
app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragment.kt View File

package com.xkl.cdl.module.m_statics package com.xkl.cdl.module.m_statics


import android.graphics.Typeface import android.graphics.Typeface
import android.text.Html
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
import android.text.style.StyleSpan import android.text.style.StyleSpan
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import appApi.AppApi.EntityCount
import com.github.mikephil.charting.components.* import com.github.mikephil.charting.components.*
import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
import com.github.mikephil.charting.listener.OnChartValueSelectedListener import com.github.mikephil.charting.listener.OnChartValueSelectedListener
import com.github.mikephil.charting.renderer.LineChartRenderer import com.github.mikephil.charting.renderer.LineChartRenderer
import com.google.android.material.tabs.TabLayout
import com.lxj.xpopup.XPopup import com.lxj.xpopup.XPopup
import com.lxj.xpopup.enums.PopupPosition import com.lxj.xpopup.enums.PopupPosition
import com.suliang.common.base.fragment.BaseFragmentVM import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.extension.loadFragment import com.suliang.common.extension.loadFragment
import com.suliang.common.extension.setHtml import com.suliang.common.extension.setHtml
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.adapter.AdapterStaticsTime
import com.xkl.cdl.data.AppConstants import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.databinding.FragmentStaticsBinding import com.xkl.cdl.databinding.FragmentStaticsBinding
import com.xkl.cdl.widget.MyMarkerView import com.xkl.cdl.widget.MyMarkerView


class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StaticsFragmentViewModel>() {
class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StatisticsFragmentViewModel>() {
companion object { companion object {
@JvmStatic @JvmStatic
} }
override fun initViewModel() : StaticsFragmentViewModel {
return ViewModelProvider(this)[StaticsFragmentViewModel::class.java]
override fun initViewModel() : StatisticsFragmentViewModel {
return ViewModelProvider(this)[StatisticsFragmentViewModel::class.java]
} }
override fun initFragment() { override fun initFragment() {
//添加碎片 //添加碎片
loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment())
loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment.newInstance(0))
//detail //detail
binding.layoutEnglish.click { binding.layoutEnglish.click {
// TODO: 2022/6/24 进入详情
SubjectStatisticsDetailActivity.newInstance(requireContext(),AppConstants.SUBJECT_ENGLISH)
}
binding.layoutChinese.click {
SubjectStatisticsDetailActivity.newInstance(requireContext(),AppConstants.SUBJECT_CHINESE)
} }
binding.layoutChinese.click { }
//chart change //chart change
binding.tvChartSubjectChoose.click { binding.tvChartSubjectChoose.click {
XPopup.Builder(requireContext()).apply { XPopup.Builder(requireContext()).apply {
///设置时间统计的选中项 ///设置时间统计的选中项
childFragmentManager.findFragmentByTag(StatisticsTimeTopFragment::javaClass.name)?.run { childFragmentManager.findFragmentByTag(StatisticsTimeTopFragment::javaClass.name)?.run {
//设置时间统计的选中项 //设置时间统计的选中项
(this as StatisticsTimeTopFragment).binding.tabLayoutTime.getTabAt(0)?.select()
(this as StatisticsTimeTopFragment).loadData()
} }
//图表设置 //图表设置
vm.chartChooseProjectIdLiveData.value = vm.chartChooseProjectIdLiveData.value vm.chartChooseProjectIdLiveData.value = vm.chartChooseProjectIdLiveData.value

+ 146
- 0
app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsFragmentViewModel.kt View File

package com.xkl.cdl.module.m_statics

import android.graphics.Color
import androidx.lifecycle.MutableLiveData
import appApi.AppApi
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.utils.ColorTemplate
import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.thread.AppExecutors
import com.suliang.common.widget.NumberUtils
import com.xkl.cdl.R
import com.xkl.cdl.data.bean.TimeStatisticItem
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.module.XKLApplication
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlin.math.abs
import kotlin.math.max

class StatisticsFragmentViewModel : BaseViewModel() {
//chart选中 itemId
var chartChooseProjectIdLiveData = MutableLiveData<Int>(0)
//图标初始完成
val chartLineInitLiveData = MutableLiveData<Boolean>()
/**获取词条数据,进行图标数据实例 */
fun getStatisticsChartData(projectId:Int) {
DataRepository.getStatisticsChartData(projectId)
.subscribeOn(Schedulers.from(AppExecutors.diskIO))
.observeOn(Schedulers.from(AppExecutors.io))
.subscribe({
//进行图标数据处理
entityCountList.clear()
entityCountList.addAll(it.entityCountListList)
initChartLine(it.entityCountListList)
},{
it.printStackTrace()
showToast(ToastEvent("统计数据获取失败"))
})
}
val entityCountList: MutableList<AppApi.EntityCount> = mutableListOf()
var maxChart = 0L
var linDataSet_new : LineDataSet? = null //折线1 : 新学词条
var linDataSet_review : LineDataSet? = null //折线2 : 复习词条
private fun initChartLine(list: List<AppApi.EntityCount>){
maxChart = 0L
linDataSet_new = null
linDataSet_review = null
val entrys_new = mutableListOf<Entry>() //新学点集合
val entrys_review = mutableListOf<Entry>() //复习点集合
list.forEachIndexed { index, it ->
entrys_new.add(Entry(index.toFloat(),it.n.toFloat()))
entrys_review.add(Entry(index.toFloat(),it.r.toFloat()))
maxChart = when{
it.n > it.r -> max(maxChart, it.n)
else -> max(maxChart, it.r)
}
}
if (list.isEmpty()){
chartLineInitLiveData.postValue(false)
return
}
linDataSet_new = LineDataSet(entrys_new, "新学词条数").apply {
axisDependency = YAxis.AxisDependency.RIGHT
color = Color.parseColor("#5082E6")
lineWidth = 2f
circleRadius = 5f
circleHoleRadius = 3f
setCircleColor(Color.parseColor("#5082E6"))
fillAlpha = 65
fillColor = ColorTemplate.getHoloBlue()
highLightColor = Color.parseColor("#1A5082E6")
highlightLineWidth = 18f
setDrawCircleHole(true)
setDrawHorizontalHighlightIndicator(false)
setDrawVerticalHighlightIndicator(true)
}
linDataSet_review = LineDataSet(entrys_review, "复习词条数").apply {
axisDependency = YAxis.AxisDependency.RIGHT
color = Color.parseColor("#F25255")
lineWidth = 2f
circleRadius = 5f
circleHoleRadius = 3f
setCircleColor(Color.parseColor("#F25255"))
fillAlpha = 65
fillColor = Color.RED
highLightColor = Color.parseColor("#1A5082E6")
highlightLineWidth = 18f
setDrawCircleHole(true)
setDrawHorizontalHighlightIndicator(false)
}
chartLineInitLiveData.postValue(true)
}
/** 获取y轴的最大值 */
fun getMaxY(): Float{
//设置坐标轴最大值和最小值
var temp : Int = (maxChart / 5).toInt()
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (maxChart % 5 > 0) 1 else 0) * 1
}
return (temp * 5 + temp / 2.0).toFloat()
}
/**获取y轴的最小值*/
fun getMinY():Float{
//设置坐标轴最大值和最小值
var temp : Int = (maxChart / 5).toInt()
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (maxChart % 5 > 0) 1 else 0) * 1
}
return (-(temp - temp / 2.0) - if (temp / 2.5 == 0.0) 0.3 else temp / 2.5).toFloat()
}
/** 获取为x显示的值 */
fun getxAxisValue(value : Float) : String {
if (entityCountList.size > value){
val entity = entityCountList[value.toInt()]
val split = entity.day.split("-")
return if (split[2].equals("01")) "${split[1]}月" else split[2]
}
return ""
}
}

+ 26
- 6
app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragment.kt View File

package com.xkl.cdl.module.m_statics package com.xkl.cdl.module.m_statics


import android.os.Bundle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.suliang.common.AppConfig
import com.suliang.common.base.fragment.BaseFragmentVM import com.suliang.common.base.fragment.BaseFragmentVM
import com.xkl.cdl.adapter.AdapterStaticsTime import com.xkl.cdl.adapter.AdapterStaticsTime
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.databinding.FragmentStatisticsTimeTopBinding import com.xkl.cdl.databinding.FragmentStatisticsTimeTopBinding


/** /**
* create 2022/6/24 17:24 * create 2022/6/24 17:24
* Describe: * Describe:
*/ */
class StatisticsTimeTopFragment : BaseFragmentVM<FragmentStatisticsTimeTopBinding, StaticsFragmentViewModel>() {
class StatisticsTimeTopFragment : BaseFragmentVM<FragmentStatisticsTimeTopBinding, StatisticsTimeTopFragmentViewModel>() {
override fun initViewModel() : StaticsFragmentViewModel {
return ViewModelProvider(requireParentFragment())[StaticsFragmentViewModel::class.java]
companion object{
fun newInstance(projectId : Int) : StatisticsTimeTopFragment {
val args = Bundle()
args.putInt(AppConfig.INTENT_1, projectId)
val fragment = StatisticsTimeTopFragment()
fragment.arguments = args
return fragment
}
}
override fun initViewModel() : StatisticsTimeTopFragmentViewModel {
return ViewModelProvider(this)[StatisticsTimeTopFragmentViewModel::class.java]
} }
override fun initFragment() { override fun initFragment() {
vm.projectId = requireArguments().getInt(AppConfig.INTENT_1,0)
initTabLayout() initTabLayout()
//rv //rv
binding.rvTime.apply { binding.rvTime.apply {
layoutManager = GridLayoutManager(requireContext(), 2) layoutManager = GridLayoutManager(requireContext(), 2)
adapter = AdapterStaticsTime() adapter = AdapterStaticsTime()
} }
}
override fun loadData() {
//监听时间选项变化 //监听时间选项变化
vm.timeStatisticsPositionLiveData.observe(this) { position -> vm.timeStatisticsPositionLiveData.observe(this) { position ->
if (!vm.isInitStatisticsResponse()) { if (!vm.isInitStatisticsResponse()) {
} }
} }
override fun loadData() {
//设置选中加载数据
vm.timeStatisticsPositionLiveData.value = binding.tabLayoutTime.selectedTabPosition
}
private fun initTabLayout() { private fun initTabLayout() {
binding.tabLayoutTime.run { binding.tabLayoutTime.run {
addTab(this.newTab().setText("全部时间"), false)
addTab(this.newTab().setText("全部时间"), true)
addTab(this.newTab().setText("今日"), false) addTab(this.newTab().setText("今日"), false)
addTab(this.newTab().setText("本周"), false) addTab(this.newTab().setText("本周"), false)
addTab(this.newTab().setText("本月"), false) addTab(this.newTab().setText("本月"), false)

app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragmentViewModel.kt → app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragmentViewModel.kt View File

package com.xkl.cdl.module.m_statics package com.xkl.cdl.module.m_statics


import android.graphics.Color
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import appApi.AppApi import appApi.AppApi
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.utils.ColorTemplate
import com.suliang.common.base.activity.ToastEvent import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.base.viewmodel.BaseViewModel import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.extension.diskIo2Main import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.thread.AppExecutors
import com.suliang.common.widget.NumberUtils import com.suliang.common.widget.NumberUtils
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.data.bean.TimeStatisticItem import com.xkl.cdl.data.bean.TimeStatisticItem
import com.xkl.cdl.data.manager.CourseManager import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.module.XKLApplication import com.xkl.cdl.module.XKLApplication
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max


class StaticsFragmentViewModel : BaseViewModel() {
class StatisticsTimeTopFragmentViewModel : BaseViewModel() {
/**顶部统计信息*/ /**顶部统计信息*/
/** 时间统计选择位置 */ /** 时间统计选择位置 */
var projectId = 0 //默认全部
val timeStatisticsPositionLiveData = MutableLiveData<Int>() val timeStatisticsPositionLiveData = MutableLiveData<Int>()
lateinit var statisticsResponse : AppApi.StatisticsCenterResponse lateinit var statisticsResponse : AppApi.StatisticsCenterResponse
var timeValuesList : MutableList<MutableList<TimeStatisticItem>> = mutableListOf() var timeValuesList : MutableList<MutableList<TimeStatisticItem>> = mutableListOf()
//chart选中 itemId
var chartChooseProjectIdLiveData = MutableLiveData<Int>(0)
//图标初始完成
val chartLineInitLiveData = MutableLiveData<Boolean>()

fun isInitStatisticsResponse() : Boolean { fun isInitStatisticsResponse() : Boolean {
return this::statisticsResponse.isInitialized return this::statisticsResponse.isInitialized
} }
fun getStatistics() : MutableLiveData<Boolean> { fun getStatistics() : MutableLiveData<Boolean> {
val result = MutableLiveData<Boolean>() val result = MutableLiveData<Boolean>()
Observable.fromCallable { Observable.fromCallable {
val statisticsCenter = XKLApplication.mobileCache.statisticsCenter(0, 0)
val statisticsCenter = XKLApplication.mobileCache.statisticsCenter(projectId.toLong(), 0)
val parseFrom = AppApi.StatisticsCenterResponse.parseFrom(statisticsCenter) val parseFrom = AppApi.StatisticsCenterResponse.parseFrom(statisticsCenter)
return@fromCallable parseFrom return@fromCallable parseFrom
}.compose(diskIo2Main()).subscribe({ }.compose(diskIo2Main()).subscribe({
} }
} }
/**获取词条数据,进行图标数据实例 */
fun getStatisticsChartData(projectId:Int) {
DataRepository.getStatisticsChartData(projectId)
.subscribeOn(Schedulers.from(AppExecutors.diskIO))
.observeOn(Schedulers.from(AppExecutors.io))
.subscribe({
//进行图标数据处理
entityCountList.clear()
entityCountList.addAll(it.entityCountListList)
initChartLine(it.entityCountListList)
},{
it.printStackTrace()
showToast(ToastEvent("统计数据获取失败"))
})
}
val entityCountList: MutableList<AppApi.EntityCount> = mutableListOf()
var maxChart = 0L
var linDataSet_new : LineDataSet? = null //折线1 : 新学词条
var linDataSet_review : LineDataSet? = null //折线2 : 复习词条
private fun initChartLine(list: List<AppApi.EntityCount>){
maxChart = 0L
linDataSet_new = null
linDataSet_review = null
val entrys_new = mutableListOf<Entry>() //新学点集合
val entrys_review = mutableListOf<Entry>() //复习点集合
list.forEachIndexed { index, it ->
entrys_new.add(Entry(index.toFloat(),it.n.toFloat()))
entrys_review.add(Entry(index.toFloat(),it.r.toFloat()))
maxChart = when{
it.n > it.r -> max(maxChart, it.n)
else -> max(maxChart, it.r)
}
}
if (list.isEmpty()){
chartLineInitLiveData.postValue(false)
return
}
linDataSet_new = LineDataSet(entrys_new, "新学词条数").apply {
axisDependency = YAxis.AxisDependency.RIGHT
color = Color.parseColor("#5082E6")
lineWidth = 2f
circleRadius = 5f
circleHoleRadius = 3f
setCircleColor(Color.parseColor("#5082E6"))
fillAlpha = 65
fillColor = ColorTemplate.getHoloBlue()
highLightColor = Color.parseColor("#1A5082E6")
highlightLineWidth = 18f
setDrawCircleHole(true)
setDrawHorizontalHighlightIndicator(false)
setDrawVerticalHighlightIndicator(true)
}
linDataSet_review = LineDataSet(entrys_review, "复习词条数").apply {
axisDependency = YAxis.AxisDependency.RIGHT
color = Color.parseColor("#F25255")
lineWidth = 2f
circleRadius = 5f
circleHoleRadius = 3f
setCircleColor(Color.parseColor("#F25255"))
fillAlpha = 65
fillColor = Color.RED
highLightColor = Color.parseColor("#1A5082E6")
highlightLineWidth = 18f
setDrawCircleHole(true)
setDrawHorizontalHighlightIndicator(false)
}
chartLineInitLiveData.postValue(true)
}
/** 获取y轴的最大值 */
fun getMaxY(): Float{
//设置坐标轴最大值和最小值
var temp : Int = (maxChart / 5).toInt()
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (maxChart % 5 > 0) 1 else 0) * 1
}
return (temp * 5 + temp / 2.0).toFloat()
}
/**获取y轴的最小值*/
fun getMinY():Float{
//设置坐标轴最大值和最小值
var temp : Int = (maxChart / 5).toInt()
temp = if (temp >= 1000) {
(temp / 1000 + if (temp % 1000 > 0) 1 else 0) * 1000
} else if (temp >= 100) {
(temp / 100 + if (temp % 100 > 0) 1 else 0) * 100
} else if (temp >= 10) {
(temp / 10 + if (temp % 10 > 0) 1 else 0) * 10
} else {
(temp + if (maxChart % 5 > 0) 1 else 0) * 1
}
return (-(temp - temp / 2.0) - if (temp / 2.5 == 0.0) 0.3 else temp / 2.5).toFloat()
}
/** 获取为x显示的值 */
fun getxAxisValue(value : Float) : String {
if (entityCountList.size > value){
val entity = entityCountList[value.toInt()]
val split = entity.day.split("-")
return if (split[2].equals("01")) "$split[1]月" else split[2]
}
return ""
}
} }

+ 87
- 0
app/src/main/java/com/xkl/cdl/module/m_statics/SubjectStatisticsDetailActivity.kt View File

package com.xkl.cdl.module.m_statics

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.suliang.common.AppConfig
import com.suliang.common.base.activity.BaseActivity
import com.suliang.common.extension.loadFragment
import com.xkl.cdl.R
import com.xkl.cdl.adapter.AdapterSubjectCourseStatistics
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.bean.StatisticsCourse
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.databinding.ActivitySubjectStatisticsBinding

/**
* author suliang
* create 2022/6/27 9:40
* Describe: 统计项目下的课程列表详情
*/
class SubjectStatisticsDetailActivity : BaseActivity<ActivitySubjectStatisticsBinding>() {
companion object {
fun newInstance(context : Context, projectId : Int) {
val intent = Intent(context,SubjectStatisticsDetailActivity::class.java).apply {
putExtra(AppConfig.INTENT_1,projectId)
}
context.startActivity(intent)
}
}
private var projectId = 0
private lateinit var adapter: AdapterSubjectCourseStatistics
private var statisticsCourseList = mutableListOf<StatisticsCourse>()
override fun initActivity(savedInstanceState : Bundle?) {
projectId = intent.getIntExtra(AppConfig.INTENT_1,0)
when(projectId){
AppConstants.SUBJECT_ENGLISH -> binding.titleBar.setTitleTextValue("英语统计")
AppConstants.SUBJECT_CHINESE -> binding.titleBar.setTitleTextValue("语文统计")
}
binding.titleBar.onBackClick = { _ -> finish()}
//添加time统计fragment
loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment.newInstance(projectId))
//实例化课程Rv
binding.rvCourse.apply {
layoutManager = LinearLayoutManager(this@SubjectStatisticsDetailActivity,LinearLayoutManager.VERTICAL,false)
this@SubjectStatisticsDetailActivity.adapter = AdapterSubjectCourseStatistics()
this.adapter = this@SubjectStatisticsDetailActivity.adapter.apply {
onItemClick = { _, position,_ ->
DataTransferHolder.instance.putData(AppConfig.INTENT_1,statisticsCourseList)
DataTransferHolder.instance.putData(AppConfig.INTENT_2,position)
startActivity(CourseStatisticsDetailActivity::class.java)
}
}
this@SubjectStatisticsDetailActivity.adapter.needShowEmptyView
}
}
override fun loadData() {
val coursePackList = CourseManager.subjectWithCoursePackMap.get(projectId)
if (coursePackList.isNullOrEmpty()){
adapter.setData(emptyList<StatisticsCourse>().toMutableList())
}else{
//组合统计课程实体病设置进度值
val courseSortInfo = CourseManager.mSortInfoList.get(projectId)
coursePackList.forEach { coursePack ->
coursePack.childrenCourses.forEach { course ->
statisticsCourseList.add(StatisticsCourse(course,coursePack.cover))
run breaking@{
courseSortInfo?.forEach { courseInfo ->
if (course.coursePackId == courseInfo.packId && course.courseId == courseInfo.courseId){
course.courseLearnProgress = courseInfo.s
return@breaking
}
}
}
}
}
//设置列表数据
adapter.setData(statisticsCourseList)
}
}
}

+ 106
- 0
app/src/main/java/com/xkl/cdl/widget/StatisticsICourseChangePopup.kt View File

package com.xkl.cdl.widget

import android.content.Context
import android.graphics.Color
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.lxj.xpopup.core.BottomPopupView
import com.lxj.xpopup.util.XPopupUtils
import com.suliang.common.base.adapter.BaseAdapterViewHolder
import com.suliang.common.base.adapter.BaseRVAdapter
import com.suliang.common.extension.click
import com.xkl.cdl.R
import com.xkl.cdl.data.bean.StatisticsCourse
import com.xkl.cdl.data.binding.BindingAdapter
import com.xkl.cdl.databinding.ItemStatisticsBottomCourseChangeBinding

/**
* author suliang
* create 2022/7/1 16:41
* Describe:
*/
class StatisticsICourseChangePopup(context : Context) : BottomPopupView(context) {
lateinit var recyclerView: RecyclerView
var data = mutableListOf<StatisticsCourse>()
lateinit var onAdapterItemClick : (position:Int,item:StatisticsCourse) -> Unit
var checkPostion = - 1
private lateinit var rvAdapter: Adapter
override fun getImplLayoutId() : Int {
return R.layout.dialog_bottom_auto_play_select
}
override fun onCreate() {
super.onCreate()
findViewById<TextView>(R.id.tv_title).text = "请选择你要查看的课程"
recyclerView = findViewById(R.id.rv_repeat)
findViewById<ImageView>(R.id.iv_cancel).click {
dismiss()
}
rvAdapter = Adapter().apply {
checkPosition = checkPostion
onItemClick = {_,p,item ->
if (this@StatisticsICourseChangePopup::onAdapterItemClick.isInitialized){
onAdapterItemClick.invoke(p,item)
}
}
}
recyclerView.apply {
layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)
adapter = rvAdapter
}
rvAdapter.setData(data)
}
override fun getMaxHeight() : Int {
return (XPopupUtils.getScreenHeight(context) * .7f).toInt()
}
}

// TODO: 2022/7/1 适配器inflate 失败
internal class Adapter : BaseRVAdapter<StatisticsCourse>(){
var checkPosition = 0
override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder {
return BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_statistics_bottom_course_change))
}
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) {
(holder.binding as ItemStatisticsBottomCourseChangeBinding).run {
getItem(position).let {
tvName.text = it.course.courseTitle
BindingAdapter.courseStatisticsLearnProgressTextViewFormat(tvValue,it.course.courseLearnProgress)
}
when(position){
checkPosition -> {
layout.setBackgroundColor(Color.parseColor("0D5082E6"))
tvName.setTextColor(ContextCompat.getColor(context,R.color.theme_color))
tvValue.setTextColor(ContextCompat.getColor(context,R.color.theme_color))
}
else -> {
layout.setBackgroundColor(ContextCompat.getColor(context,R.color.translation))
tvName.setTextColor(ContextCompat.getColor(context,R.color.main_text_color))
tvValue.setTextColor(ContextCompat.getColor(context,R.color.gray_2))
}
}
}
holder.binding.root.click {
if (checkPosition != position){
notifyDataSetChanged()
if (onItemClickIsInitialized()){
onItemClick.invoke(it,position,getItem(position))
}
}
}
}
}

+ 681
- 0
app/src/main/res/layout/activity_course_statistics_detail.xml View File

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>

<variable
name="course"
type="com.xkl.cdl.data.bean.StatisticsCourse" />
</data>

<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white_1"
android:orientation="vertical"
tools:context=".module.m_statics.CourseStatisticsDetailActivity">

<com.suliang.common.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/title_bar_height"
app:barBackground="@color/white"
app:titleTextValue="@{course.course.courseTitle}"/>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/global_spacing">

<!--top title-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintTop_toTopOf="parent">

<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/img_course"
android:layout_width="52dp"
android:layout_height="0dp"
android:scaleType="fitXY"
app:imageByteArray="@{course.cover}"
app:layout_constraintDimensionRatio="52:72"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/roundedCornerStyle"
tools:src="@color/main_text_color" />

<ImageView
android:id="@+id/iv_change_course"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_change"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/tv_course_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="@dimen/global_spacing"
android:ellipsize="end"
android:maxLines="2"
android:text="@{course.course.courseTitle}"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintEnd_toStartOf="@+id/iv_change_course"
app:layout_constraintStart_toEndOf="@+id/img_course"
app:layout_constraintTop_toTopOf="@+id/img_course"
tools:text="kjdkjsdkgjaskdlgjsadgjasldgddddffddfdfdffddjsakldgjsdakg" />

<ProgressBar
android:id="@+id/progress_course"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="120dp"
android:layout_height="4dp"
android:layout_marginBottom="8dp"
android:max="1000"
android:progressDrawable="@drawable/progress_center"
android:progressTint="@color/theme_color"
app:courseStatisticsLearnProgressFormat="@{(int)course.course.courseLearnProgress}"
app:layout_constraintBottom_toBottomOf="@+id/img_course"
app:layout_constraintStart_toStartOf="@+id/tv_course_name"
tools:progress="40" />

<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginBottom="4dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:courseStatisticsLearnProgressTextViewFormat="@{(int)course.course.courseLearnProgress}"
app:layout_constraintBottom_toBottomOf="@+id/img_course"
app:layout_constraintStart_toEndOf="@+id/progress_course"
tools:text="10%" />

</androidx.constraintlayout.widget.ConstraintLayout>

<!--测试成绩-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_test_score"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintEnd_toStartOf="@+id/layout_efficient"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_top"
app:layout_goneMarginEnd="0dp">

<TextView
android:id="@+id/tv_test_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试成绩对比"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/iv_test_state"
android:layout_width="60dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/global_spacing"
app:layout_constraintDimensionRatio="60:92"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_test_flag" />

<TextView
android:id="@+id/tv_test_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toEndOf="@+id/iv_test_state"
app:layout_constraintTop_toTopOf="@+id/iv_test_state"
tools:text="+12" />

<TextView
android:id="@+id/tv_before_total_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学前总测试"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toStartOf="@+id/tv_test_state"
app:layout_constraintTop_toBottomOf="@+id/tv_test_state" />

<TextView
android:id="@+id/tv_before_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12分"
android:textColor="@color/theme_color"
android:textSize="@dimen/smallSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/tv_before_total_flag"
app:layout_constraintTop_toBottomOf="@+id/tv_before_total_flag" />

<TextView
android:id="@+id/tv_after_total_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学前总测试"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toStartOf="@+id/tv_before_total"
app:layout_constraintTop_toBottomOf="@+id/tv_before_total" />

<TextView
android:id="@+id/tv_after_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="14分"
android:textColor="@color/red_1"
android:textSize="@dimen/smallSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/tv_after_total_flag"
app:layout_constraintTop_toBottomOf="@+id/tv_after_total_flag" />


</androidx.constraintlayout.widget.ConstraintLayout>

<!--学习效率-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_efficient"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintBottom_toBottomOf="@+id/layout_test_score"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/layout_test_score"
app:layout_constraintTop_toTopOf="@+id/layout_test_score">

<TextView
android:id="@+id/tv_efficient_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学习效率"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.xkl.cdl.widget.MyRankingView
android:id="@+id/ranking_efficient"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:orientation="vertical"
app:backgroundColor="@color/translation"
app:borderWidth="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_efficient_flag"
app:normalColor="@color/gray_1"
app:progressColor="@color/red_2"
tools:progressNumber="20">

<TextView
android:id="@+id/tv_efficient"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12%" />

<TextView
android:id="@+id/tv_efficient_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:drawableStart="@drawable/ic_rise"
tools:text="+3.4%" />

</com.xkl.cdl.widget.MyRankingView>

</androidx.constraintlayout.widget.ConstraintLayout>

<!--学习时长分析-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_duration"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_test_score">

<TextView
android:id="@+id/tv_duration_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学习时长分析"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/tv_duration_flag_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="总学习时长"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_duration_flag" />
<!--总学习时长-->
<TextView
android:id="@+id/tv_total_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/main_text_color"
android:textSize="36dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_duration_flag_1"
tools:text="12.1" />

<TextView
android:id="@+id/tv_total_duration_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/normalSize"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_total_duration"
app:layout_constraintStart_toEndOf="@+id/tv_total_duration"
tools:text="小时" />

<TextView
android:id="@+id/tv_duration_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"
android:textColor="@color/main_text_color"
android:textSize="@dimen/normalSize"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_total_duration_unit"
app:layout_constraintStart_toEndOf="@+id/tv_total_duration_unit"
tools:drawableStart="@drawable/ic_rise"
tools:text="+3.4%" />

<TextView
android:id="@+id/tv_duration_range"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_duration_state"
app:layout_constraintStart_toEndOf="@+id/tv_duration_state"
android:text="(本周)" />

<TextView
android:id="@+id/tv_valid_time_flag"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="有效学习时长"
android:textColor="@color/red_2"
android:textSize="@dimen/smallerSize"
app:layout_constraintEnd_toStartOf="@+id/tv_review_time_flag"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_total_duration" />

<TextView
android:id="@+id/tv_review_time_flag"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="有效复习时长"
android:textColor="@color/green_1"
android:textSize="@dimen/smallerSize"
app:layout_constraintEnd_toStartOf="@+id/tv_free_time_flag"
app:layout_constraintStart_toEndOf="@+id/tv_valid_time_flag"
app:layout_constraintTop_toTopOf="@+id/tv_valid_time_flag" />

<TextView
android:id="@+id/tv_free_time_flag"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="空闲时长"
android:textColor="@color/theme_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_review_time_flag"
app:layout_constraintTop_toTopOf="@+id/tv_valid_time_flag" />

<TextView
android:id="@+id/tv_valid_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/red_2"
android:textSize="22dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/tv_valid_time_flag"
app:layout_constraintTop_toBottomOf="@+id/tv_valid_time_flag"
tools:text="12.1" />

<TextView
android:id="@+id/tv_valid_time_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@color/red_2"
android:textSize="@dimen/smallerSize"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_valid_time"
app:layout_constraintStart_toEndOf="@+id/tv_valid_time"
tools:text="小时" />
<TextView
android:id="@+id/tv_review_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/green_1"
android:textSize="22dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/tv_review_time_flag"
app:layout_constraintTop_toBottomOf="@+id/tv_review_time_flag"
tools:text="12.1" />

<TextView
android:id="@+id/tv_review_time_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@color/green_1"
android:textSize="@dimen/smallerSize"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_review_time"
app:layout_constraintStart_toEndOf="@+id/tv_review_time"
tools:text="小时" />

<TextView
android:id="@+id/tv_free_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/theme_color"
android:textSize="22dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/tv_free_time_flag"
app:layout_constraintTop_toBottomOf="@+id/tv_free_time_flag"
tools:text="12.1" />

<TextView
android:id="@+id/tv_free_time_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@color/theme_color"
android:textSize="@dimen/smallerSize"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/tv_free_time"
app:layout_constraintStart_toEndOf="@+id/tv_free_time"
tools:text="小时" />

<com.github.mikephil.charting.charts.BarChart
android:id="@+id/bar_chart"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="343:200"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_valid_time"
android:layout_marginTop="10dp"/>


</androidx.constraintlayout.widget.ConstraintLayout>


<!--课程进度-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_course_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_duration">

<TextView
android:id="@+id/tv_course_progress_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="课程进度"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@+id/tv_course_progress_flag"
android:background="@drawable/shape_rounder_8_stroke_gray1"
>
<com.xkl.cdl.widget.MyRankingView
android:id="@+id/ranking_1"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:orientation="vertical"
app:backgroundColor="@color/translation"
app:borderWidth="4dp"
app:normalColor="@color/gray_1"
app:progressColor="@color/green_1"
tools:progressNumber="20"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/ranking_2">

<TextView
android:id="@+id/tv_ranking_1_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray_2"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="已学章节" />

<TextView
android:id="@+id/tv_ranking_1_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/main_text_color"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1/12" />

</com.xkl.cdl.widget.MyRankingView>
<com.xkl.cdl.widget.MyRankingView
android:id="@+id/ranking_2"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:orientation="vertical"
app:backgroundColor="@color/translation"
app:borderWidth="4dp"
app:normalColor="@color/gray_1"
app:progressColor="@color/theme_color"
tools:progressNumber="20"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/ranking_1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/ranking_3">

<TextView
android:id="@+id/tv_ranking_2_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray_2"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="已学词汇量/已学知识点" />

<TextView
android:id="@+id/tv_ranking_2_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/main_text_color"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1/12" />

</com.xkl.cdl.widget.MyRankingView>
<com.xkl.cdl.widget.MyRankingView
android:id="@+id/ranking_3"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:orientation="vertical"
app:backgroundColor="@color/translation"
app:borderWidth="4dp"
app:normalColor="@color/gray_1"
app:progressColor="#8757E6"
tools:progressNumber="20"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/ranking_2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">

<TextView
android:id="@+id/tv_ranking_3_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray_2"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="已学课堂练习" />

<TextView
android:id="@+id/tv_ranking_3_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/main_text_color"
android:textSize="11dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1/12" />

</com.xkl.cdl.widget.MyRankingView>
</androidx.constraintlayout.widget.ConstraintLayout>




</androidx.constraintlayout.widget.ConstraintLayout>

<!--章节学习情况-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_chapter_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/shape_rounder_12_white"
android:padding="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_course_progress">

<TextView
android:id="@+id/tv_chapter_info_flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="章节学习情况"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.button.MaterialButton
android:id="@+id/tv_chapter_choose"
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:drawableEnd="@drawable/ic_down"
android:gravity="center"
android:insetTop="0dp"
android:insetBottom="0dp"
android:minWidth="124dp"
tools:text="第一章"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize"
app:layout_constraintBottom_toBottomOf="@+id/tv_chapter_info_flag"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_chapter_info_flag"
app:strokeColor="@color/gray_1"
app:strokeWidth="@dimen/line_height"
app:cornerRadius="4dp"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_chapter_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_chapter_info_flag"
android:layout_marginTop="6dp"/>


</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>


</androidx.appcompat.widget.LinearLayoutCompat>
</layout>

+ 69
- 0
app/src/main/res/layout/activity_subject_statistics.xml View File

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white_1"
android:orientation="vertical"
tools:context=".module.m_statics.SubjectStatisticsDetailActivity">

<com.suliang.common.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/title_bar_height"
app:barBackground="@color/white"/>


<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white_1">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_top_time"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/global_spacing"
android:layout_marginTop="@dimen/global_spacing"
android:layout_marginEnd="@dimen/global_spacing"
app:layout_constraintDimensionRatio="343:275"
app:layout_constraintTop_toTopOf="parent" />

<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/global_spacing"
android:background="@drawable/shape_rounder_12_white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fragment_top_time">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="课程综合分析"
android:textColor="@color/main_text_color"
android:textSize="@dimen/bigSize"
android:textStyle="bold" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_course"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.appcompat.widget.LinearLayoutCompat>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

</androidx.appcompat.widget.LinearLayoutCompat>




+ 5
- 4
app/src/main/res/layout/fragment_statics.xml View File

android:layout_marginStart="@dimen/global_spacing" android:layout_marginStart="@dimen/global_spacing"
android:layout_marginTop="@dimen/global_spacing" android:layout_marginTop="@dimen/global_spacing"
android:layout_marginEnd="@dimen/global_spacing" android:layout_marginEnd="@dimen/global_spacing"
app:layout_constraintDimensionRatio="h,343:275"
app:layout_constraintDimensionRatio="343:275"
app:layout_constraintTop_toBottomOf="@+id/tv_title" /> app:layout_constraintTop_toBottomOf="@+id/tv_title" />
<!-- android:name="com.xkl.cdl.module.m_statics.StatisticsTimeTopFragment"--> <!-- android:name="com.xkl.cdl.module.m_statics.StatisticsTimeTopFragment"-->


android:layout_marginEnd="@dimen/global_spacing" android:layout_marginEnd="@dimen/global_spacing"
android:background="@drawable/shape_rounder_12_white" android:background="@drawable/shape_rounder_12_white"
android:padding="12dp" android:padding="12dp"
app:layout_constraintDimensionRatio="h,343:243"
app:layout_constraintDimensionRatio="343:243"
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/layout_english"> app:layout_constraintTop_toBottomOf="@+id/layout_english">
android:insetTop="0dp" android:insetTop="0dp"
android:insetBottom="0dp" android:insetBottom="0dp"
android:minWidth="124dp" android:minWidth="124dp"
android:text="全部目"
android:text="全部目"
android:textColor="@color/main_text_color" android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize" android:textSize="@dimen/smallerSize"
app:layout_constraintBottom_toBottomOf="@+id/chart_title" app:layout_constraintBottom_toBottomOf="@+id/chart_title"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/chart_title" app:layout_constraintTop_toTopOf="@+id/chart_title"
app:strokeColor="@color/gray_1" app:strokeColor="@color/gray_1"
app:strokeWidth="@dimen/line_height" />
app:strokeWidth="@dimen/line_height"
app:cornerRadius="4dp"/>


<com.github.mikephil.charting.charts.LineChart <com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart" android:id="@+id/chart"

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

app:layout_constraintHeight_min="128dp" app:layout_constraintHeight_min="128dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="h,102:136"
app:layout_constraintDimensionRatio="102:136"
app:layout_constraintEnd_toStartOf="@+id/barrier" app:layout_constraintEnd_toStartOf="@+id/barrier"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />

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

android:layout_height="0dp" android:layout_height="0dp"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="12dp" android:paddingStart="12dp"
app:layout_constraintDimensionRatio="h,154:100"
app:layout_constraintDimensionRatio="154:100"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">


<TextView <TextView

+ 42
- 0
app/src/main/res/layout/item_statistics_bottom_course_change.xml View File

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingStart="@dimen/global_spacing"
android:paddingEnd="@dimen/global_spacing">

<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="@dimen/normalSize"
android:textColor="@color/main_text_color"
tools:text="课程名称"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_value" />

<TextView
android:id="@+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/normalSize"
android:textColor="@color/gray_2"
tools:text="12%"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

+ 86
- 0
app/src/main/res/layout/item_statistics_course.xml View File

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>
<variable
name="course"
type="com.xkl.cdl.data.bean.StatisticsCourse" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">

<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/img_course"
android:layout_width="54dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="54:72"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="14dp"
android:scaleType="fitXY"
tools:src="@color/main_text_color"
app:shapeAppearance="@style/roundedCornerStyle"
app:imageByteArray="@{course.cover}"/>

<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_right"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="12dp" />

<TextView
android:id="@+id/tv_course_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="2"
android:ellipsize="end"
android:textSize="@dimen/smallSize"
android:textColor="@color/main_text_color"
app:layout_constraintTop_toTopOf="@+id/img_course"
app:layout_constraintStart_toEndOf="@+id/img_course"
app:layout_constraintEnd_toStartOf="@+id/iv_arrow"
android:layout_marginEnd="@dimen/global_spacing"
android:layout_marginTop="4dp"
android:layout_marginStart="8dp"
tools:text="kjdkjsdkgjaskdlgjsadgjasldgddddffddfdfdffddjsakldgjsdakg"
android:text="@{course.course.courseTitle}"/>

<ProgressBar
android:id="@+id/progress_course"
android:layout_width="120dp"
android:layout_height="4dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_center"
android:progressTint="@color/theme_color"
android:max="1000"
tools:progress="40"
app:layout_constraintStart_toStartOf="@+id/tv_course_name"
app:layout_constraintBottom_toBottomOf="@+id/img_course"
android:layout_marginBottom="8dp"
app:courseStatisticsLearnProgressFormat="@{(int)course.course.courseLearnProgress}"/>

<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/img_course"
app:layout_constraintStart_toEndOf="@+id/progress_course"
android:textSize="@dimen/smallerSize"
android:textColor="@color/main_text_color"
android:layout_marginStart="12dp"
android:layout_marginBottom="4dp"
tools:text="10%"
app:courseStatisticsLearnProgressTextViewFormat="@{(int)course.course.courseLearnProgress}"/>


</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

+ 208
- 0
app/src/main/res/layout/item_statistics_course_chapter_info.xml View File

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_rounder_8_stroke_gray1">

<View
android:id="@+id/v_1"
android:layout_width="match_parent"
android:layout_height="38dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<View
android:id="@+id/v_2"
android:layout_width="match_parent"
android:layout_height="38dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/v_1" />

<View
android:id="@+id/v_3"
android:layout_width="match_parent"
android:layout_height="38dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/v_2" />

<View
android:id="@+id/v_4"
android:layout_width="match_parent"
android:layout_height="38dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/v_3" />

<View
android:id="@+id/v_5"
android:layout_width="match_parent"
android:layout_height="38dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/v_4" />

<TextView
android:id="@+id/tv_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="课时"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@+id/v_1"
app:layout_constraintEnd_toStartOf="@+id/tv_1_value"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/v_1" />

<TextView
android:id="@+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
tools:text="课时"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@+id/v_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/v_2" />

<TextView
android:id="@+id/tv_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
tools:text="课时"
tools:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@+id/v_3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/v_3" />

<TextView
android:id="@+id/tv_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
tools:text="课时"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@+id/v_4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/v_4" />

<TextView
android:id="@+id/tv_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
tools:text="课时"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@+id/v_5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/v_5" />

<TextView
android:id="@+id/tv_1_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@id/v_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_1"
app:layout_constraintTop_toTopOf="@+id/v_1"
tools:text="课时名称" />

<TextView
android:id="@+id/tv_2_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:textColor="@color/theme_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@id/v_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_1_value"
app:layout_constraintTop_toTopOf="@+id/v_2"
tools:text="课时名称" />

<TextView
android:id="@+id/tv_3_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@id/v_3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_1_value"
app:layout_constraintTop_toTopOf="@+id/v_3"
tools:text="课时名称" />


<ProgressBar
android:id="@+id/p_4"
android:layout_width="100dp"
android:layout_height="4dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_center"
android:progressTint="@color/red_2"
android:max="100"
tools:progress="80"
app:layout_constraintBottom_toBottomOf="@id/v_4"
app:layout_constraintEnd_toStartOf="@+id/tv_4_value"
app:layout_constraintStart_toStartOf="@id/tv_1_value"
app:layout_constraintTop_toTopOf="@+id/v_4" />

<TextView
android:id="@+id/tv_4_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
app:layout_goneMarginStart="0dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@id/v_4"
app:layout_constraintStart_toEndOf="@+id/p_4"
app:layout_constraintTop_toTopOf="@+id/v_4"
tools:text="20" />

<ProgressBar
android:id="@+id/p_5"
android:layout_width="100dp"
android:layout_height="4dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_center"
android:progressTint="@color/theme_color"
android:max="100"
tools:progress="80"
app:layout_constraintBottom_toBottomOf="@id/v_5"
app:layout_constraintEnd_toStartOf="@+id/tv_5_value"
app:layout_constraintStart_toStartOf="@id/tv_1_value"
app:layout_constraintTop_toTopOf="@+id/v_5" />

<TextView
android:id="@+id/tv_5_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
app:layout_goneMarginStart="0dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallSize"
app:layout_constraintBottom_toBottomOf="@id/v_5"
app:layout_constraintStart_toEndOf="@+id/p_5"
app:layout_constraintTop_toTopOf="@+id/v_5"
tools:text="20" />



</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

BIN
app/src/main/res/mipmap-xxxhdpi/statistics_testscore_equality_chart.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/statistics_testscore_lower_chart.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/statistics_testscore_nodata_chart.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/statistics_testscore_noend_chart.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/statistics_testscore_up_chart.png View File


+ 20
- 0
app/svg/drawable/ic_change.xml View File

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M0,0h20v20h-20z"
android:strokeAlpha="0"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="nonZero"
android:strokeColor="#00000000"
android:fillAlpha="0"/>
<path
android:pathData="M16.6251,11.9417L3.3749,11.9417C2.9836,11.9417 2.6667,12.2586 2.6667,12.6499C2.6667,12.7986 2.7127,12.9367 2.7906,13.05C2.8242,13.1297 2.8756,13.204 2.9393,13.2695L6.0607,16.3891C6.1988,16.5272 6.3794,16.5963 6.5617,16.5963C6.7441,16.5963 6.9247,16.5272 7.0628,16.3891C7.339,16.1129 7.339,15.665 7.0628,15.387L5.0303,13.3581L16.6234,13.3581C17.0146,13.3581 17.3316,13.0411 17.3316,12.6499C17.3316,12.2586 17.0164,11.9417 16.6251,11.9417L16.6251,11.9417ZM3.3749,8.6557L16.6251,8.6557C17.0164,8.6557 17.3333,8.3387 17.3333,7.9475C17.3333,7.7987 17.2873,7.6606 17.2094,7.5473C17.1846,7.4889 17.1492,7.4323 17.1067,7.3791L14.5537,4.2595C14.3058,3.9568 13.8596,3.9125 13.5569,4.1604C13.2541,4.4083 13.2099,4.8544 13.4578,5.1572L15.1627,7.2393L3.3749,7.2393C2.9836,7.2393 2.6667,7.5562 2.6667,7.9475C2.6667,8.3387 2.9836,8.6557 3.3749,8.6557L3.3749,8.6557Z"
android:strokeWidth="1"
android:fillColor="#323233"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

Loading…
Cancel
Save