@@ -65,6 +65,7 @@ | |||
<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/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_learn_base.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" /> | |||
@@ -79,6 +80,7 @@ | |||
<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_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/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" /> | |||
@@ -132,6 +134,9 @@ | |||
<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_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_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" /> |
@@ -1,7 +1,7 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:tools="http://schemas.android.com/tools" | |||
package="com.xkl.cdl"> | |||
package="com.xkl.cdl" > | |||
<application | |||
android:name=".module.XKLApplication" | |||
@@ -11,7 +11,13 @@ | |||
android:roundIcon="@mipmap/ic_launcher_round" | |||
android:supportsRtl="true" | |||
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 | |||
android:name=".module.m_service_center.TestDetailActivity" | |||
android:exported="true" /> | |||
@@ -48,7 +54,7 @@ | |||
android:configChanges="orientation|keyboardHidden|screenSize" | |||
android:exported="true" | |||
android:screenOrientation="portrait" | |||
android:theme="@style/Theme.Splash"> | |||
android:theme="@style/Theme.Splash" > | |||
<intent-filter> | |||
<action android:name="android.intent.action.MAIN" /> | |||
@@ -0,0 +1,97 @@ | |||
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 = "——" | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
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)) | |||
} | |||
} | |||
} | |||
} |
@@ -34,7 +34,7 @@ class DataTransferHolder private constructor(){ | |||
@Suppress("UNCHECKED_CAST") | |||
fun <T> getData(key : String = AppConfig.INTENT_1) : T{ | |||
return (dataMap[key] as T).also { | |||
clear() | |||
dataMap.remove(key) | |||
} | |||
} | |||
@@ -0,0 +1,11 @@ | |||
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) { | |||
} |
@@ -1,7 +1,5 @@ | |||
package com.xkl.cdl.data.bean.course | |||
import androidx.databinding.BaseObservable | |||
/** | |||
* author suliang | |||
* create 2022/3/22 10:08 |
@@ -2,6 +2,7 @@ package com.xkl.cdl.data.binding | |||
import android.graphics.drawable.Drawable | |||
import android.widget.ImageView | |||
import android.widget.ProgressBar | |||
import android.widget.TextView | |||
import androidx.databinding.BindingAdapter | |||
import com.suliang.common.util.DrawableUti | |||
@@ -82,6 +83,42 @@ object BindingAdapter { | |||
} | |||
} | |||
/** | |||
* 统计课程文字显示的进度格式化 | |||
* @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 | |||
} | |||
} | |||
} |
@@ -82,31 +82,41 @@ object CourseManager { | |||
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 inputStream = AppGlobals.application.resources.assets.open(assetFileName) | |||
val zipInputStream = ZipInputStream(inputStream) | |||
var count = 0 | |||
var count = 0 | |||
val buffer = ByteArray(5120) | |||
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 | |||
}?.let { file -> | |||
//文件不存在 ,复制当前文件进入该文件 | |||
if (!file.exists()){ | |||
//文件不存在 ,复制当前文件进入该文件 | |||
if (!file.exists()) { | |||
file.parentFile?.let { parentFile -> | |||
if (!parentFile.exists()) parentFile.mkdirs() | |||
} | |||
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() | |||
} | |||
@@ -114,8 +124,9 @@ object CourseManager { | |||
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()) { | |||
FileUtil.copyAsset(it.dbPathName, file) | |||
@@ -284,6 +295,29 @@ object CourseManager { | |||
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> | |||
@@ -410,9 +444,10 @@ object CourseManager { | |||
// TODO: 2022/6/2 时间需改为day 开发期间用于调式,故意设此值 | |||
//间隔时间单位 | |||
private val reviewIntervalUnit = "hour" | |||
//间隔单位时间 | |||
private val reviewTime = IntArray(7){ | |||
when(it){ | |||
private val reviewTime = IntArray(7) { | |||
when (it) { | |||
0 -> 1 | |||
1 -> 2 | |||
2 -> 3 | |||
@@ -430,20 +465,23 @@ object CourseManager { | |||
* @param currentTime Long 用以计算的当前时间 | |||
* @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 | |||
try { | |||
//转换设置当前的复习时间 | |||
calendar.time = DateUtil.format(currentReviewTime,DateUtil.FORMAT_1) | |||
calendar.time = DateUtil.format(currentReviewTime, DateUtil.FORMAT_1) | |||
//与当前时间的间隔 | |||
val intervalTime = currentTime - calendar.timeInMillis | |||
//单位转换 : 给一个提前量的时间,提前一分钟 | |||
return intervalTime >= when(reviewIntervalUnit){ | |||
return intervalTime >= when (reviewIntervalUnit) { | |||
"minute" -> reviewTime[currentReviewNumber] * 60000 | |||
"hour" -> reviewTime[currentReviewNumber] * 60 * 60000 | |||
else -> reviewTime[currentReviewNumber] * 24 * 60 * 60000 | |||
else -> reviewTime[currentReviewNumber] * 24 * 60 * 60000 | |||
} - 60000 | |||
}catch (e:Exception){ | |||
} catch (e : Exception) { | |||
e.printStackTrace() | |||
} | |||
return false |
@@ -113,13 +113,13 @@ object DBCourseManager { | |||
correctNumber = detail.right.getOrElse(key, { 0 }).toInt() //正确数 | |||
errorNumber = detail.wrong.getOrElse(key, { 0 }).toInt() //错误数 | |||
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 | |||
} | |||
// 学习位置 | |||
// id集合中的学习entity的位置, 作文的视频、知识点测试,不以这个为标准 | |||
val learnIndex = wordIds.indexOf(detail.lesson_learn_point.getOrElse(key, { -1 })) //学习位置,当前位置为已学 | |||
lesson.learnedIndex = learnIndex | |||
// 注:针对口语对话课时,如果没有学习完,是不会设置进度点的。 todo 分课程类型设置进度点 口语未做判断处理 | |||
lesson.learnIsOver = when (base.coursePackType) { | |||
//作文课时,需要根据课时属性,判断本课时是否学习完成 | |||
@@ -157,9 +157,9 @@ object DBCourseManager { | |||
positionIndex += 1 | |||
// TODO: 2022/5/9 对课时数量进行限制,课时太多,开发人员不好进行测试 | |||
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) { | |||
break |
@@ -0,0 +1,450 @@ | |||
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() | |||
} | |||
} |
@@ -0,0 +1,254 @@ | |||
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) | |||
} | |||
} |
@@ -1,14 +1,11 @@ | |||
package com.xkl.cdl.module.m_statics | |||
import android.graphics.Typeface | |||
import android.text.Html | |||
import android.text.SpannableString | |||
import android.text.Spanned | |||
import android.text.style.StyleSpan | |||
import androidx.core.content.ContextCompat | |||
import androidx.lifecycle.ViewModelProvider | |||
import androidx.recyclerview.widget.GridLayoutManager | |||
import appApi.AppApi.EntityCount | |||
import com.github.mikephil.charting.components.* | |||
import com.github.mikephil.charting.data.Entry | |||
import com.github.mikephil.charting.data.LineData | |||
@@ -18,7 +15,6 @@ import com.github.mikephil.charting.highlight.Highlight | |||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet | |||
import com.github.mikephil.charting.listener.OnChartValueSelectedListener | |||
import com.github.mikephil.charting.renderer.LineChartRenderer | |||
import com.google.android.material.tabs.TabLayout | |||
import com.lxj.xpopup.XPopup | |||
import com.lxj.xpopup.enums.PopupPosition | |||
import com.suliang.common.base.fragment.BaseFragmentVM | |||
@@ -26,12 +22,11 @@ import com.suliang.common.extension.click | |||
import com.suliang.common.extension.loadFragment | |||
import com.suliang.common.extension.setHtml | |||
import com.xkl.cdl.R | |||
import com.xkl.cdl.adapter.AdapterStaticsTime | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.databinding.FragmentStaticsBinding | |||
import com.xkl.cdl.widget.MyMarkerView | |||
class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StaticsFragmentViewModel>() { | |||
class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StatisticsFragmentViewModel>() { | |||
companion object { | |||
@JvmStatic | |||
@@ -39,18 +34,20 @@ class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StaticsFragmentVi | |||
} | |||
override fun initViewModel() : StaticsFragmentViewModel { | |||
return ViewModelProvider(this)[StaticsFragmentViewModel::class.java] | |||
override fun initViewModel() : StatisticsFragmentViewModel { | |||
return ViewModelProvider(this)[StatisticsFragmentViewModel::class.java] | |||
} | |||
override fun initFragment() { | |||
//添加碎片 | |||
loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment()) | |||
loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment.newInstance(0)) | |||
//detail | |||
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 | |||
binding.tvChartSubjectChoose.click { | |||
XPopup.Builder(requireContext()).apply { | |||
@@ -124,7 +121,7 @@ class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StaticsFragmentVi | |||
///设置时间统计的选中项 | |||
childFragmentManager.findFragmentByTag(StatisticsTimeTopFragment::javaClass.name)?.run { | |||
//设置时间统计的选中项 | |||
(this as StatisticsTimeTopFragment).binding.tabLayoutTime.getTabAt(0)?.select() | |||
(this as StatisticsTimeTopFragment).loadData() | |||
} | |||
//图表设置 | |||
vm.chartChooseProjectIdLiveData.value = vm.chartChooseProjectIdLiveData.value |
@@ -0,0 +1,146 @@ | |||
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 "" | |||
} | |||
} |
@@ -1,10 +1,13 @@ | |||
package com.xkl.cdl.module.m_statics | |||
import android.os.Bundle | |||
import androidx.lifecycle.ViewModelProvider | |||
import androidx.recyclerview.widget.GridLayoutManager | |||
import com.google.android.material.tabs.TabLayout | |||
import com.suliang.common.AppConfig | |||
import com.suliang.common.base.fragment.BaseFragmentVM | |||
import com.xkl.cdl.adapter.AdapterStaticsTime | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.databinding.FragmentStatisticsTimeTopBinding | |||
/** | |||
@@ -12,22 +15,33 @@ import com.xkl.cdl.databinding.FragmentStatisticsTimeTopBinding | |||
* create 2022/6/24 17:24 | |||
* 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() { | |||
vm.projectId = requireArguments().getInt(AppConfig.INTENT_1,0) | |||
initTabLayout() | |||
//rv | |||
binding.rvTime.apply { | |||
layoutManager = GridLayoutManager(requireContext(), 2) | |||
adapter = AdapterStaticsTime() | |||
} | |||
} | |||
override fun loadData() { | |||
//监听时间选项变化 | |||
vm.timeStatisticsPositionLiveData.observe(this) { position -> | |||
if (!vm.isInitStatisticsResponse()) { | |||
@@ -42,9 +56,15 @@ class StatisticsTimeTopFragment : BaseFragmentVM<FragmentStatisticsTimeTopBindin | |||
} | |||
} | |||
override fun loadData() { | |||
//设置选中加载数据 | |||
vm.timeStatisticsPositionLiveData.value = binding.tabLayoutTime.selectedTabPosition | |||
} | |||
private fun initTabLayout() { | |||
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) |
@@ -1,39 +1,26 @@ | |||
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 StaticsFragmentViewModel : BaseViewModel() { | |||
class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
/**顶部统计信息*/ | |||
/** 时间统计选择位置 */ | |||
var projectId = 0 //默认全部 | |||
val timeStatisticsPositionLiveData = MutableLiveData<Int>() | |||
lateinit var statisticsResponse : AppApi.StatisticsCenterResponse | |||
var timeValuesList : MutableList<MutableList<TimeStatisticItem>> = mutableListOf() | |||
//chart选中 itemId | |||
var chartChooseProjectIdLiveData = MutableLiveData<Int>(0) | |||
//图标初始完成 | |||
val chartLineInitLiveData = MutableLiveData<Boolean>() | |||
fun isInitStatisticsResponse() : Boolean { | |||
return this::statisticsResponse.isInitialized | |||
} | |||
@@ -42,7 +29,7 @@ class StaticsFragmentViewModel : BaseViewModel() { | |||
fun getStatistics() : MutableLiveData<Boolean> { | |||
val result = MutableLiveData<Boolean>() | |||
Observable.fromCallable { | |||
val statisticsCenter = XKLApplication.mobileCache.statisticsCenter(0, 0) | |||
val statisticsCenter = XKLApplication.mobileCache.statisticsCenter(projectId.toLong(), 0) | |||
val parseFrom = AppApi.StatisticsCenterResponse.parseFrom(statisticsCenter) | |||
return@fromCallable parseFrom | |||
}.compose(diskIo2Main()).subscribe({ | |||
@@ -184,119 +171,4 @@ class StaticsFragmentViewModel : BaseViewModel() { | |||
} | |||
} | |||
/**获取词条数据,进行图标数据实例 */ | |||
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 "" | |||
} | |||
} |
@@ -0,0 +1,87 @@ | |||
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) | |||
} | |||
} | |||
} |
@@ -0,0 +1,106 @@ | |||
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)) | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,681 @@ | |||
<?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> |
@@ -0,0 +1,69 @@ | |||
<?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> | |||
@@ -27,7 +27,7 @@ | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginTop="@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" /> | |||
<!-- android:name="com.xkl.cdl.module.m_statics.StatisticsTimeTopFragment"--> | |||
@@ -140,7 +140,7 @@ | |||
android:layout_marginEnd="@dimen/global_spacing" | |||
android:background="@drawable/shape_rounder_12_white" | |||
android:padding="12dp" | |||
app:layout_constraintDimensionRatio="h,343:243" | |||
app:layout_constraintDimensionRatio="343:243" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/layout_english"> | |||
@@ -193,14 +193,15 @@ | |||
android:insetTop="0dp" | |||
android:insetBottom="0dp" | |||
android:minWidth="124dp" | |||
android:text="全部科目" | |||
android:text="全部项目" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/smallerSize" | |||
app:layout_constraintBottom_toBottomOf="@+id/chart_title" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toTopOf="@+id/chart_title" | |||
app:strokeColor="@color/gray_1" | |||
app:strokeWidth="@dimen/line_height" /> | |||
app:strokeWidth="@dimen/line_height" | |||
app:cornerRadius="4dp"/> | |||
<com.github.mikephil.charting.charts.LineChart | |||
android:id="@+id/chart" |
@@ -23,7 +23,7 @@ | |||
app:layout_constraintHeight_min="128dp" | |||
android:layout_marginEnd="8dp" | |||
android:scaleType="centerCrop" | |||
app:layout_constraintDimensionRatio="h,102:136" | |||
app:layout_constraintDimensionRatio="102:136" | |||
app:layout_constraintEnd_toStartOf="@+id/barrier" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> |
@@ -20,7 +20,7 @@ | |||
android:layout_height="0dp" | |||
android:orientation="vertical" | |||
android:paddingStart="12dp" | |||
app:layout_constraintDimensionRatio="h,154:100" | |||
app:layout_constraintDimensionRatio="154:100" | |||
app:layout_constraintTop_toTopOf="parent"> | |||
<TextView |
@@ -0,0 +1,42 @@ | |||
<?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> |
@@ -0,0 +1,86 @@ | |||
<?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> |
@@ -0,0 +1,208 @@ | |||
<?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> |
@@ -0,0 +1,20 @@ | |||
<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> |