| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/progressbar_countdown_time.xml" value="0.45740740740740743" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/progressbar_countdown_time.xml" value="0.45740740740740743" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/selector_memo_review_bg.xml" value="0.5010416666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/selector_memo_review_bg.xml" value="0.5010416666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/selector_memo_test_bg.xml" value="0.5010416666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/selector_memo_test_bg.xml" value="0.5010416666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shadow_layer.xml" value="0.4876923076923077" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_cicler_24_c3d69b.xml" value="0.49333333333333335" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_cicler_24_c3d69b.xml" value="0.49333333333333335" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_cicler_24_ffcc99.xml" value="0.49333333333333335" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_cicler_24_ffcc99.xml" value="0.49333333333333335" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_cicler_6_red.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_o_red.xml" value="0.36203703703703705" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_o_red.xml" value="0.36203703703703705" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_red_badge.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_12_white.xml" value="0.5140625" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_12_white.xml" value="0.5140625" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_4_green_a5.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_4_purple_a5.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_4_red.xml" value="0.4953125" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_4_theme_a5.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_solid_green1.xml" value="0.5010416666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_solid_green1.xml" value="0.5010416666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_solider_gray_1.xml" value="0.5010416666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_solider_gray_1.xml" value="0.5010416666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_stroke_gray1.xml" value="0.503125" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_stroke_gray1.xml" value="0.503125" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_switch_thumb.xml" value="0.14074074074074075" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_switch_thumb.xml" value="0.14074074074074075" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_switch_track.xml" value="0.26851851851851855" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_switch_track.xml" value="0.26851851851851855" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/spoken_autoplay_btn_text_color_.xml" value="0.5140625" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/spoken_autoplay_btn_text_color_.xml" value="0.5140625" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/statictis_time_tab_bg.xml" value="0.1259259259259259" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_thumb_selector.xml" value="0.3768518518518518" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_thumb_selector.xml" value="0.3768518518518518" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_track_selector.xml" value="0.3768518518518518" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_track_selector.xml" value="0.3768518518518518" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/test_error_state_button_bg.xml" value="0.45740740740740743" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/test_error_state_button_bg.xml" value="0.45740740740740743" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_test_detail.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_test_detail.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/content_learn_base.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/content_learn_base.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/custom_marker_view.xml" value="0.23353596757852077" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_auto_play_select.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_auto_play_select.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_course_more.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_course_more.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_course_pack_introducation.xml" value="0.1956521739130435" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_bottom_course_pack_introducation.xml" value="0.1956521739130435" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.25" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_memo.xml" value="0.25" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_statics.xml" value="0.33" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_statistics_time_top.xml" value="0.10833333333333334" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_word_choose_content.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_word_choose_content.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_literacy.xml" value="0.5" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_literacy.xml" value="0.5" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.27717391304347827" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_task_image.xml" value="0.23353596757852077" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_task_image.xml" value="0.23353596757852077" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail.xml" value="0.348731884057971" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail.xml" value="0.348731884057971" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option.xml" value="0.348731884057971" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option.xml" value="0.348731884057971" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option_2.xml" value="0.348731884057971" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_test_detail_option_2.xml" value="0.348731884057971" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_video_adapter.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_video_adapter.xml" value="0.67" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_xpopup_statistics_choose_subject.xml" value="0.21965579710144928" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_course_progress.xml" value="0.25" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_course_progress.xml" value="0.25" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_coursepack.xml" value="0.43500866551126516" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_coursepack.xml" value="0.43500866551126516" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_memo_list_item_english_header.xml" value="0.2373353596757852" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_memo_list_item_english_header.xml" value="0.2373353596757852" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_memo_list_item_pinyin_header.xml" value="0.5" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_memo_list_item_pinyin_header.xml" value="0.5" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_recyclerview_smart_refresh_layout.xml" value="0.34427083333333336" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/merge_recyclerview_smart_refresh_layout.xml" value="0.34427083333333336" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/smart_refresh_header.xml" value="0.34427083333333336" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/smart_refresh_header.xml" value="0.34427083333333336" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/statics_tab_top_radiobutton.xml" value="0.20833333333333334" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview.xml" value="0.49773550724637683" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview.xml" value="0.49773550724637683" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview_only.xml" value="0.49773550724637683" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview_only.xml" value="0.49773550724637683" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_voice.xml" value="0.35555555555555557" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_course_voice.xml" value="0.35555555555555557" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_discern.xml" value="0.5061538461538462" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_discern.xml" value="0.5061538461538462" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_down.xml" value="0.503125" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_down.xml" value="0.503125" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_english.xml" value="0.4973958333333333" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_horuns.xml" value="0.503125" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_horuns.xml" value="0.503125" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_icon___.xml" value="0.287962962962963" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_icon___.xml" value="0.287962962962963" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_menu.xml" value="0.4036458333333333" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_menu.xml" value="0.4036458333333333" /> |
| implementation customDependencies.CalendarView | implementation customDependencies.CalendarView | ||||
| // FlexBoxLayoutManager | // FlexBoxLayoutManager | ||||
| implementation customDependencies.FlexBoxLayoutManager | implementation customDependencies.FlexBoxLayoutManager | ||||
| //图标 | |||||
| implementation customDependencies.Chart | |||||
| } | } |
| package com.xkl.cdl.adapter | |||||
| import android.view.ViewGroup | |||||
| import androidx.core.content.ContextCompat | |||||
| import com.suliang.common.base.adapter.BaseAdapterViewHolder | |||||
| import com.suliang.common.base.adapter.BaseRVAdapter | |||||
| import com.xkl.cdl.R | |||||
| import com.xkl.cdl.data.bean.TimeStatisticItem | |||||
| import com.xkl.cdl.databinding.ItemStaticsForTimeBinding | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/6/23 14:34 | |||||
| * Describe: | |||||
| */ | |||||
| class AdapterStaticsTime:BaseRVAdapter<TimeStatisticItem>() { | |||||
| override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | |||||
| return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_statics_for_time)) | |||||
| } | |||||
| override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | |||||
| (holder.binding as ItemStaticsForTimeBinding).run { | |||||
| getItem(position).let { | |||||
| layout.setBackgroundResource(it.backGround) | |||||
| tvName.text = it.name | |||||
| tvContent.text = it.time | |||||
| tvUnit.text = it.unit | |||||
| tvState.run { | |||||
| text = it.incr | |||||
| if (it.incrTextColor != 0) { | |||||
| setTextColor(ContextCompat.getColor(context,it.incrTextColor)) | |||||
| } | |||||
| setCompoundDrawablesWithIntrinsicBounds(it.imgDrawable,0,0,0) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| package com.xkl.cdl.data.bean | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/6/23 14:38 | |||||
| * Describe: | |||||
| */ | |||||
| class TimeStatisticItem { | |||||
| var name : String ="" //标题 | |||||
| var unit : String = "" //显示单位 | |||||
| var time : String = "" //显示时间内容 | |||||
| var incr : String = "" //增量 | |||||
| var imgDrawable : Int = 0 //drawableStart值 | |||||
| var incrTextColor: Int = 0 //增量颜色 | |||||
| var backGround : Int = 0 //背景 | |||||
| } |
| return false | return false | ||||
| } | } | ||||
| /** 获取课程的数量 */ | |||||
| fun getTotalCourseSize() : Int { | |||||
| var result = 0 | |||||
| subjectWithCoursePackMap.forEach { entry -> | |||||
| entry.value.forEach { coursePack -> | |||||
| result += coursePack.childrenCourses.size | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| } | } |
| } | } | ||||
| } | } | ||||
| /** 获取词条数统计 */ | |||||
| fun getStatisticsChartData(projectId:Int): Observable<AppApi.EntityCountListResponse> { | |||||
| return Observable.create { | |||||
| //近90天词条数统计 | |||||
| val entityCountList = XKLApplication.mobileCache.entityCountList(projectId.toLong(), 0) | |||||
| val parseFrom = AppApi.EntityCountListResponse.parseFrom(entityCountList) | |||||
| it.onNext(parseFrom) | |||||
| it.onComplete() | |||||
| } | |||||
| } | |||||
| } | } |
| private fun initScore():String{ | private fun initScore():String{ | ||||
| return when(vm.courseType){ | return when(vm.courseType){ | ||||
| AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> "完成" | AppConstants.COURSE_TYPE_ENGLISH_SPOKEN -> "完成" | ||||
| else -> "${vm.learnExam.score}<small><small><small>分</small></small></small>" | |||||
| else -> "${vm.learnExam.score.toInt()}<small><small><small>分</small></small></small>" | |||||
| } | } | ||||
| } | } | ||||
| package com.xkl.cdl.module.m_statics | package com.xkl.cdl.module.m_statics | ||||
| import android.os.Bundle | |||||
| import androidx.fragment.app.Fragment | |||||
| import android.view.LayoutInflater | |||||
| import android.view.View | |||||
| import android.view.ViewGroup | |||||
| 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.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 | |||||
| import com.github.mikephil.charting.data.LineDataSet | |||||
| import com.github.mikephil.charting.formatter.ValueFormatter | |||||
| 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 | import com.suliang.common.base.fragment.BaseFragmentVM | ||||
| 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.R | ||||
| import com.xkl.cdl.databinding.FragmentMyBinding | |||||
| import com.xkl.cdl.adapter.AdapterStaticsTime | |||||
| import com.xkl.cdl.data.AppConstants | |||||
| import com.xkl.cdl.databinding.FragmentStaticsBinding | import com.xkl.cdl.databinding.FragmentStaticsBinding | ||||
| import com.xkl.cdl.module.main.MainActivityViewModel | |||||
| // TODO: Rename parameter arguments, choose names that match | |||||
| // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER | |||||
| private const val ARG_PARAM1 = "param1" | |||||
| private const val ARG_PARAM2 = "param2" | |||||
| /** | |||||
| * A simple [Fragment] subclass. | |||||
| * Use the [StaticsFragment.newInstance] factory method to | |||||
| * create an instance of this fragment. | |||||
| */ | |||||
| class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, MainActivityViewModel>() { | |||||
| // TODO: Rename and change types of parameters | |||||
| private var param1: String? = null | |||||
| private var param2: String? = null | |||||
| override fun onCreate(savedInstanceState: Bundle?) { | |||||
| super.onCreate(savedInstanceState) | |||||
| arguments?.let { | |||||
| param1 = it.getString(ARG_PARAM1) | |||||
| param2 = it.getString(ARG_PARAM2) | |||||
| } | |||||
| } | |||||
| override fun onCreateView( | |||||
| inflater: LayoutInflater, container: ViewGroup?, | |||||
| savedInstanceState: Bundle? | |||||
| ): View? { | |||||
| // Inflate the layout for this fragment | |||||
| return inflater.inflate(R.layout.fragment_statics, container, false) | |||||
| } | |||||
| import com.xkl.cdl.widget.MyMarkerView | |||||
| class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, StaticsFragmentViewModel>() { | |||||
| companion object { | companion object { | ||||
| /** | |||||
| * Use this factory method to create a new instance of | |||||
| * this fragment using the provided parameters. | |||||
| * | |||||
| * @param param1 Parameter 1. | |||||
| * @param param2 Parameter 2. | |||||
| * @return A new instance of fragment StaticsFragment. | |||||
| */ | |||||
| // TODO: Rename and change types and number of parameters | |||||
| @JvmStatic | @JvmStatic | ||||
| fun newInstance() = StaticsFragment() | fun newInstance() = StaticsFragment() | ||||
| } | } | ||||
| override fun initViewModel() : StaticsFragmentViewModel { | |||||
| return ViewModelProvider(this)[StaticsFragmentViewModel::class.java] | |||||
| } | |||||
| override fun initFragment() { | override fun initFragment() { | ||||
| //添加碎片 | |||||
| loadFragment(R.id.fragment_top_time,0,StatisticsTimeTopFragment()) | |||||
| //detail | |||||
| binding.layoutEnglish.click { | |||||
| // TODO: 2022/6/24 进入详情 | |||||
| } | |||||
| binding.layoutChinese.click { } | |||||
| //chart change | |||||
| binding.tvChartSubjectChoose.click { | |||||
| XPopup.Builder(requireContext()).apply { | |||||
| hasShadowBg(false) | |||||
| atView(it) | |||||
| popupPosition(PopupPosition.Bottom) | |||||
| hasStatusBar(true) | |||||
| isLightStatusBar(true) | |||||
| }.asAttachList(initChartSubjectChooseValue(), intArrayOf(), { position, text -> | |||||
| if (binding.tvChartSubjectChoose.text.toString() != text) { | |||||
| binding.tvChartSubjectChoose.text = text | |||||
| vm.chartChooseProjectIdLiveData.value = when (text) { | |||||
| "英语" -> AppConstants.SUBJECT_ENGLISH | |||||
| "语文" -> AppConstants.SUBJECT_CHINESE | |||||
| else -> 0 | |||||
| } | |||||
| } | |||||
| }, 0, R.layout.item_xpopup_statistics_choose_subject).show() | |||||
| } | |||||
| initChart() | |||||
| } | } | ||||
| override fun loadData() { | override fun loadData() { | ||||
| //监听图表项目切换变化 | |||||
| vm.chartChooseProjectIdLiveData.observe(this) { | |||||
| //获取词条数据,进行图标数据实例 | |||||
| vm.getStatisticsChartData(it) | |||||
| } | |||||
| //监听图标数据初始结果 | |||||
| vm.chartLineInitLiveData.observe(this) { | |||||
| when { | |||||
| !it -> binding.chart.setNoDataText("暂无数据") | |||||
| else -> { | |||||
| setChartData() | |||||
| val lineData = LineData(vm.linDataSet_new, vm.linDataSet_review).apply { | |||||
| setValueTextColor(ContextCompat.getColor(requireContext(), R.color.white)) | |||||
| setValueTextSize(9f) | |||||
| } | |||||
| //渐变设置 | |||||
| lineData.dataSets.forEach { | |||||
| //设置折线顺滑 | |||||
| (it as LineDataSet).run { | |||||
| mode = LineDataSet.Mode.HORIZONTAL_BEZIER | |||||
| setDrawValues(false) | |||||
| } | |||||
| } | |||||
| binding.chart.data = lineData | |||||
| //设置是否显示点 | |||||
| binding.chart.run { | |||||
| (renderer as LineChartRenderer).run { | |||||
| } | |||||
| //默认选中 | |||||
| vm.linDataSet_review?.let { | |||||
| highlightValue(it.values.size - 1f, 1) | |||||
| } | |||||
| //设置高亮x文字颜色 | |||||
| rendererXAxis | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| override fun onHiddenChanged(hidden : Boolean) { | |||||
| super.onHiddenChanged(hidden) | |||||
| if (!hidden){ | |||||
| ///设置时间统计的选中项 | |||||
| childFragmentManager.findFragmentByTag(StatisticsTimeTopFragment::javaClass.name)?.run { | |||||
| //设置时间统计的选中项 | |||||
| (this as StatisticsTimeTopFragment).binding.tabLayoutTime.getTabAt(0)?.select() | |||||
| } | |||||
| //图表设置 | |||||
| vm.chartChooseProjectIdLiveData.value = vm.chartChooseProjectIdLiveData.value | |||||
| } | |||||
| } | |||||
| private fun initChartSubjectChooseValue() : Array<String> { | |||||
| return when (binding.tvChartSubjectChoose.text.toString()) { | |||||
| "全部项目" -> arrayOf("英语", "语文") | |||||
| "英语" -> arrayOf("全部项目", "语文") | |||||
| else -> arrayOf("英语", "全部项目") | |||||
| } | |||||
| } | } | ||||
| private fun initChart() { | |||||
| binding.chart.run { | |||||
| description.isEnabled = false //no description text 描述隐藏 | |||||
| setTouchEnabled(true) // enable touch gesture | |||||
| isDragEnabled = true //滑动 | |||||
| setScaleEnabled(false) //紧张缩放 | |||||
| setDrawGridBackground(false) //不绘制网格 | |||||
| isHighlightPerDragEnabled = true //高亮显示 | |||||
| setPinchZoom(false) //缩放显示详细数字 | |||||
| isDoubleTapToZoomEnabled = false //双击缩放 | |||||
| setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) //背景 | |||||
| animateX(800) //动画时间 | |||||
| //隐藏legend | |||||
| legend.isEnabled = false | |||||
| override fun initViewModel(): MainActivityViewModel { | |||||
| return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java] | |||||
| // //线条描述 | |||||
| // legend.apply { | |||||
| // isEnabled = false | |||||
| // form = Legend.LegendForm.CIRCLE | |||||
| // verticalAlignment = Legend.LegendVerticalAlignment.TOP | |||||
| // horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT | |||||
| // setDrawInside(false) | |||||
| // } | |||||
| //右侧不显示 | |||||
| axisRight.isEnabled = false | |||||
| setOnChartValueSelectedListener(object : OnChartValueSelectedListener { | |||||
| override fun onValueSelected(e : Entry, h : Highlight) { | |||||
| binding.chart.data.dataSets.forEach { | |||||
| if (it.getEntryIndex(e) >= 0) { | |||||
| (binding.chart.marker as MyMarkerView).offsetX = if (e.x > 4) -300f else 300f | |||||
| binding.chart.moveViewToAnimated(it.getEntryIndex(e) - 4f, 100f, YAxis.AxisDependency.RIGHT, 500) | |||||
| } | |||||
| } | |||||
| } | |||||
| override fun onNothingSelected() { | |||||
| } | |||||
| }) | |||||
| //标记显示View | |||||
| val myMarkerView = MyMarkerView(context, R.layout.custom_marker_view) | |||||
| myMarkerView.chartView = this | |||||
| marker = myMarkerView | |||||
| myMarkerView.setValueCallback { tv, e -> | |||||
| val sets : List<ILineDataSet> = this.data.dataSets | |||||
| val dataSet1 = sets[0] | |||||
| val dataSet2 = sets[1] | |||||
| var index = dataSet1.getEntryIndex(e) | |||||
| if (index == -1) { | |||||
| index = dataSet2.getEntryIndex(e) | |||||
| } | |||||
| if (vm.entityCountList.size > index) { | |||||
| var str = """ | |||||
| ${vm.entityCountList[index].day} | |||||
| <font color='#8A8A99'> 新学词条数:</font> <font color='#3F51B5'> ${vm.entityCountList[index].n}</font><font color='#8A8A99'> 个 </font> | |||||
| <font color='#8A8A99'> 复习词条数:</font> <font color='#F26255'> ${vm.entityCountList[index].r}</font><font color='#8A8A99'> 个 </font> | |||||
| """.trimIndent() | |||||
| val spanString = SpannableString(str) | |||||
| val span = StyleSpan(Typeface.BOLD) | |||||
| spanString.setSpan(span, 0, vm.entityCountList[index].day.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | |||||
| str = str.replace("\n", "<br>") | |||||
| tv.setHtml(str) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private fun setChartData() { | |||||
| // LineChart 折线图 | |||||
| // LineData //线集合,所有折线已数组形式存放到此集合 | |||||
| // LineDataSet //点集合,即一条折线 | |||||
| // Entry //点 | |||||
| // XAxis //x轴 | |||||
| // YAxis //y轴 | |||||
| // Legend //图例 标识哪一条曲线 | |||||
| // LimitLine //限制线 | |||||
| // Description //描述 | |||||
| // List<Float> 存放数据的list列表 | |||||
| // List<Entry> 存放折线点的列表 | |||||
| // LineDataSet(List<Entry>,"步") 点集合,一条线 | |||||
| //x轴 | |||||
| binding.chart.xAxis.run { | |||||
| textSize = 11f //dp | |||||
| textColor = ContextCompat.getColor(requireContext(), R.color.gray_2) //颜色 | |||||
| //设置坐标轴的线条 | |||||
| setDrawGridLines(false) | |||||
| setDrawAxisLine(false) | |||||
| //x坐标最小间隔 | |||||
| granularity = 1f | |||||
| //x轴的最大,最小值 | |||||
| axisMinimum = -0.6f | |||||
| axisMaximum = vm.entityCountList.size - 0.1f | |||||
| isGranularityEnabled = true //间隔粒度控制 | |||||
| position = XAxis.XAxisPosition.BOTTOM_INSIDE //x标签位置 | |||||
| //设置x轴为字符串 | |||||
| valueFormatter = object : ValueFormatter() { | |||||
| override fun getFormattedValue(value : Float) : String { | |||||
| return vm.getxAxisValue(value) | |||||
| } | |||||
| } | |||||
| } | |||||
| //x轴一页可见个数 | |||||
| binding.chart.setVisibleXRange(0f, 6f) | |||||
| //左侧y轴 | |||||
| binding.chart.axisLeft.run { | |||||
| gridColor = ContextCompat.getColor(requireContext(), R.color.gray_1) | |||||
| textColor = ContextCompat.getColor(requireContext(), R.color.gray_2) | |||||
| textSize = 11f | |||||
| setDrawGridLines(true) | |||||
| setDrawAxisLine(false) | |||||
| // 设置最大最小值 | |||||
| when { | |||||
| vm.maxChart > 0 -> { | |||||
| axisMaximum = vm.getMaxY() | |||||
| axisMinimum = vm.getMinY() | |||||
| } | |||||
| else -> { | |||||
| axisMaximum = 5f | |||||
| axisMinimum = -0.9f | |||||
| } | |||||
| } | |||||
| } | |||||
| //右侧y轴 | |||||
| binding.chart.axisRight.run { | |||||
| textColor = ContextCompat.getColor(requireContext(), R.color.gray_2) | |||||
| // 设置最大最小值 | |||||
| when { | |||||
| vm.maxChart > 0 -> { | |||||
| axisMaximum = vm.getMaxY() | |||||
| axisMinimum = vm.getMinY() | |||||
| } | |||||
| else -> { | |||||
| axisMaximum = 5f | |||||
| axisMinimum = -0.9f | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } |
| 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() { | |||||
| /**顶部统计信息*/ | |||||
| /** 时间统计选择位置 */ | |||||
| 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 | |||||
| } | |||||
| /** 获取时间统计数据 */ | |||||
| fun getStatistics() : MutableLiveData<Boolean> { | |||||
| val result = MutableLiveData<Boolean>() | |||||
| Observable.fromCallable { | |||||
| val statisticsCenter = XKLApplication.mobileCache.statisticsCenter(0, 0) | |||||
| val parseFrom = AppApi.StatisticsCenterResponse.parseFrom(statisticsCenter) | |||||
| return@fromCallable parseFrom | |||||
| }.compose(diskIo2Main()).subscribe({ | |||||
| statisticsResponse = it | |||||
| initTimeStatic(it) | |||||
| result.value = true | |||||
| }, { | |||||
| it.printStackTrace() | |||||
| showToast(ToastEvent("数据获取失败")) | |||||
| result.value = false | |||||
| }) | |||||
| return result | |||||
| } | |||||
| private fun initTimeStatic(statisticsResponse : AppApi.StatisticsCenterResponse) { | |||||
| timeValuesList.clear() | |||||
| timeValuesList.add(initTimeStaticItem(statisticsResponse.total)) | |||||
| timeValuesList.add(initTimeStaticItem(statisticsResponse.today)) | |||||
| timeValuesList.add(initTimeStaticItem(statisticsResponse.week)) | |||||
| timeValuesList.add(initTimeStaticItem(statisticsResponse.month)) | |||||
| } | |||||
| private fun initTimeStaticItem(statistics : AppApi.Statistics) : MutableList<TimeStatisticItem> { | |||||
| val result = mutableListOf<TimeStatisticItem>() | |||||
| //有效学习时长 | |||||
| val timeStaticItem_1 = TimeStatisticItem().apply { | |||||
| name = "有效学习时长" | |||||
| backGround = R.drawable.shape_rounder_4_red_a5 | |||||
| } | |||||
| //计算显示使用的单位 | |||||
| if (statistics.sd != 0L) { | |||||
| val hour = statistics.sd / 3600000.0 | |||||
| val minute = statistics.sd / 60000.0 | |||||
| when { | |||||
| //大于1小时 | |||||
| hour > 1 -> { | |||||
| timeStaticItem_1.time =initShow(hour) | |||||
| timeStaticItem_1.unit = "小时" | |||||
| } | |||||
| //大于1分钟 | |||||
| minute > 1 -> { | |||||
| //取整和保留一位小数的值相同,则使用取整的值显示,否则使用保留小数的值显示 | |||||
| timeStaticItem_1.time =initShow(minute) | |||||
| timeStaticItem_1.unit = "分钟" | |||||
| } | |||||
| //小于1分钟 | |||||
| else -> { | |||||
| timeStaticItem_1.time = "" | |||||
| timeStaticItem_1.unit = "不足1分钟" | |||||
| } | |||||
| } | |||||
| }else{ | |||||
| timeStaticItem_1.time = "0" | |||||
| timeStaticItem_1.unit = "" | |||||
| } | |||||
| //增量不为0 | |||||
| if (statistics.sdIncr != 0L ){ | |||||
| val hour_1 = statistics.sdIncr / 3600000.0 | |||||
| val minute_1 = statistics.sdIncr / 60000.0 | |||||
| val sencond = statistics.sdIncr / 1000 | |||||
| when { | |||||
| //大于1小时 | |||||
| abs(hour_1) > 1 -> timeStaticItem_1.incr = if(statistics.sdIncr > 0) "${initShow(hour_1)}小时" else "-${initShow(abs(hour_1))}小时" | |||||
| //大于1分钟 | |||||
| abs(minute_1) > 1 -> timeStaticItem_1.incr = if(statistics.sdIncr > 0) "${initShow(minute_1)}分钟" else "-${initShow(abs(minute_1))}分钟" | |||||
| //小于1分钟 秒数 | |||||
| else -> timeStaticItem_1.incr = "${sencond}秒" | |||||
| } | |||||
| } | |||||
| initIncr(timeStaticItem_1,statistics.sdIncr.toDouble()) | |||||
| result.add(timeStaticItem_1) | |||||
| //综合学习效率 | |||||
| val timeStaticItem_2 = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_theme_a5 | |||||
| name = "综合学习效率" | |||||
| unit = "%" | |||||
| time = initShow(statistics.se) | |||||
| initIncr(this,statistics.seIncr) | |||||
| } | |||||
| result.add(timeStaticItem_2) | |||||
| //已学课程 | |||||
| val timeStaticItem_3 = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_green_a5 | |||||
| name = "已学课程" | |||||
| unit = "/${CourseManager.getTotalCourseSize()}个" | |||||
| time = "${statistics.sc}" | |||||
| initIncr(this,statistics.scIncr.toDouble()) | |||||
| } | |||||
| result.add(timeStaticItem_3) | |||||
| //已学进度 | |||||
| val timeStaticItem_4 = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_purple_a5 | |||||
| name = "已学进度" | |||||
| unit = "%" | |||||
| time = initShow(statistics.ts) | |||||
| initIncr(this,statistics.tsIncr) | |||||
| } | |||||
| result.add(timeStaticItem_4) | |||||
| return result | |||||
| } | |||||
| /** 格式化数据,决定显示小数还是不显示 */ | |||||
| private fun initShow(value:Double):String{ | |||||
| //保留一位小数 向下取舍 | |||||
| val formatFloor = NumberUtils.formatFloor(value, "0.0") | |||||
| val toDouble = formatFloor.toDouble() | |||||
| //取整 | |||||
| val formatFloor_1 = NumberUtils.formatFloor(value, "0") | |||||
| val toDouble_1 = formatFloor.toDouble() | |||||
| //取整和保留一位小数的值相同,则使用取整的值显示,否则使用保留小数的值显示 | |||||
| return when (toDouble_1) { | |||||
| toDouble -> formatFloor_1 | |||||
| else -> formatFloor | |||||
| } | |||||
| } | |||||
| /**实例化增量图标和颜色与正负*/ | |||||
| private fun initIncr(timeStaticItem_1 : TimeStatisticItem, sdIncr : Double) { | |||||
| timeStaticItem_1.run { | |||||
| when{ | |||||
| sdIncr == 0.0 -> { | |||||
| incr = "" | |||||
| imgDrawable = R.drawable.ic_keep | |||||
| } | |||||
| sdIncr > 0 -> { | |||||
| imgDrawable = R.drawable.ic_rise | |||||
| incrTextColor = R.color.green_1 | |||||
| incr = "+$incr" | |||||
| } | |||||
| else -> { | |||||
| imgDrawable = R.drawable.ic_decline | |||||
| incrTextColor = R.color.red_1 | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /**获取词条数据,进行图标数据实例 */ | |||||
| 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 "" | |||||
| } | |||||
| } |
| package com.xkl.cdl.module.m_statics | |||||
| import androidx.lifecycle.ViewModelProvider | |||||
| import androidx.recyclerview.widget.GridLayoutManager | |||||
| import com.google.android.material.tabs.TabLayout | |||||
| import com.suliang.common.base.fragment.BaseFragmentVM | |||||
| import com.xkl.cdl.adapter.AdapterStaticsTime | |||||
| import com.xkl.cdl.databinding.FragmentStatisticsTimeTopBinding | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/6/24 17:24 | |||||
| * Describe: | |||||
| */ | |||||
| class StatisticsTimeTopFragment : BaseFragmentVM<FragmentStatisticsTimeTopBinding, StaticsFragmentViewModel>() { | |||||
| override fun initViewModel() : StaticsFragmentViewModel { | |||||
| return ViewModelProvider(requireParentFragment())[StaticsFragmentViewModel::class.java] | |||||
| } | |||||
| override fun initFragment() { | |||||
| initTabLayout() | |||||
| //rv | |||||
| binding.rvTime.apply { | |||||
| layoutManager = GridLayoutManager(requireContext(), 2) | |||||
| adapter = AdapterStaticsTime() | |||||
| } | |||||
| } | |||||
| override fun loadData() { | |||||
| //监听时间选项变化 | |||||
| vm.timeStatisticsPositionLiveData.observe(this) { position -> | |||||
| if (!vm.isInitStatisticsResponse()) { | |||||
| vm.getStatistics().observe(this) { | |||||
| if (it) { | |||||
| (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | |||||
| } | |||||
| } | |||||
| } | |||||
| private fun initTabLayout() { | |||||
| binding.tabLayoutTime.run { | |||||
| addTab(this.newTab().setText("全部时间"), false) | |||||
| addTab(this.newTab().setText("今日"), false) | |||||
| addTab(this.newTab().setText("本周"), false) | |||||
| addTab(this.newTab().setText("本月"), false) | |||||
| addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { | |||||
| override fun onTabSelected(tab : TabLayout.Tab) { | |||||
| vm.timeStatisticsPositionLiveData.value = binding.tabLayoutTime.selectedTabPosition | |||||
| } | |||||
| override fun onTabUnselected(tab : TabLayout.Tab?) { | |||||
| print("") | |||||
| } | |||||
| override fun onTabReselected(tab : TabLayout.Tab?) { | |||||
| print("") | |||||
| } | |||||
| }) | |||||
| } | |||||
| } | |||||
| } |
| package com.xkl.cdl.widget; | |||||
| import android.annotation.SuppressLint; | |||||
| import android.content.Context; | |||||
| import android.graphics.Canvas; | |||||
| import android.widget.TextView; | |||||
| import com.github.mikephil.charting.charts.LineChart; | |||||
| import com.github.mikephil.charting.components.MarkerView; | |||||
| import com.github.mikephil.charting.data.Entry; | |||||
| import com.github.mikephil.charting.highlight.Highlight; | |||||
| import com.github.mikephil.charting.utils.MPPointF; | |||||
| import com.xkl.cdl.R; | |||||
| /** | |||||
| * Custom implementation of the MarkerView. | |||||
| * | |||||
| * @author Philipp Jahoda | |||||
| */ | |||||
| @SuppressLint("ViewConstructor") | |||||
| public class MyMarkerView extends MarkerView { | |||||
| private final TextView tvContent; | |||||
| private ValueOnListener valueonListener; | |||||
| //x 绘制偏移量 | |||||
| private float offsetX ; | |||||
| public void setValueCallback( ValueOnListener listener){ | |||||
| this.valueonListener = listener; | |||||
| } | |||||
| public void setOffsetX(float offsetX) { | |||||
| this.offsetX = offsetX; | |||||
| } | |||||
| public float getOffsetX() { | |||||
| return offsetX; | |||||
| } | |||||
| public MyMarkerView(Context context, int layoutResource) { | |||||
| super(context, layoutResource); | |||||
| tvContent = findViewById(R.id.tvContent); | |||||
| } | |||||
| @Override | |||||
| public MPPointF getOffset() { | |||||
| return new MPPointF(-(getWidth() / 2), -getHeight()); | |||||
| } | |||||
| // runs every time the MarkerView is redrawn, can be used to update the | |||||
| // content (user-interface) | |||||
| @Override | |||||
| public void refreshContent(Entry e, Highlight highlight) { | |||||
| if (valueonListener!= null) | |||||
| valueonListener.getFormValue(tvContent,e); | |||||
| super.refreshContent(e, highlight); | |||||
| } | |||||
| // runs every time the MarkerView is redrawn, can be used to update the | |||||
| // content (user-interface) | |||||
| public interface ValueOnListener { | |||||
| void getFormValue(TextView view , Entry e); | |||||
| } | |||||
| @Override | |||||
| public void draw(Canvas canvas, float posX, float posY) { | |||||
| float newPosX = posX + getOffsetX(); | |||||
| MPPointF offset = getOffsetForDrawingAtPoint(newPosX, posY); | |||||
| int saveId = canvas.save(); | |||||
| // translate to the correct position and draw | |||||
| canvas.translate(newPosX + offset.x, posY + offset.y ); | |||||
| draw(canvas); | |||||
| canvas.restoreToCount(saveId); | |||||
| } | |||||
| } |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <selector xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <item android:state_selected="true"> | |||||
| <shape android:shape="rectangle"> | |||||
| <solid android:color="@color/theme_color"/> | |||||
| <corners android:radius="4dp"/> | |||||
| </shape> | |||||
| </item> | |||||
| <item android:state_selected="false" android:drawable="@color/translation"/> | |||||
| </selector> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <item> | |||||
| <shape android:shape="rectangle"> | |||||
| <padding | |||||
| android:bottom="1dp" | |||||
| android:left="1dp" | |||||
| android:right="1dp" | |||||
| /> | |||||
| <solid android:color="#0DCCCCCC" /> | |||||
| <corners android:radius="8dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| <item> | |||||
| <shape android:shape="rectangle"> | |||||
| <padding | |||||
| android:bottom="1dp" | |||||
| android:left="1dp" | |||||
| android:right="1dp" | |||||
| /> | |||||
| <solid android:color="#10CCCCCC" /> | |||||
| <corners android:radius="8dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| <item> | |||||
| <shape android:shape="rectangle"> | |||||
| <padding | |||||
| android:bottom="1dp" | |||||
| android:left="1dp" | |||||
| android:right="1dp" | |||||
| /> | |||||
| <solid android:color="#15CCCCCC" /> | |||||
| <corners android:radius="8dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| <item> | |||||
| <shape android:shape="rectangle"> | |||||
| <padding | |||||
| android:bottom="1dp" | |||||
| android:left="1dp" | |||||
| android:right="1dp" | |||||
| /> | |||||
| <solid android:color="#20CCCCCC" /> | |||||
| <corners android:radius="8dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| <item> | |||||
| <shape android:shape="rectangle"> | |||||
| <padding | |||||
| android:bottom="1dp" | |||||
| android:left="1dp" | |||||
| android:right="1dp" | |||||
| android:top="1dp" /> | |||||
| <solid android:color="#30CCCCCC" /> | |||||
| <corners android:radius="8dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| <item> | |||||
| <shape> | |||||
| <solid android:color="#FFFFFF" /> | |||||
| <corners android:radius="4dp" /> | |||||
| </shape> | |||||
| </item> | |||||
| </layer-list> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:shape="oval"> | |||||
| <solid android:color="@color/red_1"/> | |||||
| <size android:width="6dp" | |||||
| android:height="6dp"/> | |||||
| </shape> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <corners android:radius="4dp"/> | |||||
| <solid android:color="#0D52CC52"/> | |||||
| </shape> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <corners android:radius="4dp"/> | |||||
| <solid android:color="#0D8757E6"/> | |||||
| </shape> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <corners android:radius="4dp"/> | |||||
| <solid android:color="#0DF26255"/> | |||||
| </shape> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <corners android:radius="4dp"/> | |||||
| <solid android:color="#0D5082E6"/> | |||||
| </shape> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:background="@drawable/shadow_layer"> | |||||
| <TextView | |||||
| android:id="@+id/tvContent" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_centerVertical="true" | |||||
| android:layout_margin="3dp" | |||||
| android:paddingLeft="5dp" | |||||
| android:paddingRight="5dp" | |||||
| android:paddingBottom="3dp" | |||||
| android:elevation="4dp" | |||||
| android:text="afafafa\ndada" | |||||
| android:singleLine="false" | |||||
| android:lineSpacingMultiplier="1.2" | |||||
| android:textColor="@android:color/background_dark" | |||||
| android:textSize="13sp" /> | |||||
| </RelativeLayout> |
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| <androidx.constraintlayout.widget.ConstraintLayout 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" | xmlns:tools="http://schemas.android.com/tools" | ||||
| android:layout_width="match_parent" | android:layout_width="match_parent" | ||||
| android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
| android:background="@color/white_1" | |||||
| android:orientation="vertical" | |||||
| tools:context=".module.m_statics.StaticsFragment"> | tools:context=".module.m_statics.StaticsFragment"> | ||||
| <!-- TODO: Update blank fragment layout --> | |||||
| <TextView | <TextView | ||||
| android:id="@+id/tv_title" | |||||
| android:layout_width="match_parent" | android:layout_width="match_parent" | ||||
| android:layout_height="match_parent" | |||||
| android:text="@string/hello_blank_fragment" /> | |||||
| android:layout_height="@dimen/title_bar_height" | |||||
| android:background="@color/white" | |||||
| android:gravity="center" | |||||
| android:text="学习统计" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/bigSize" | |||||
| android:textStyle="bold" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| </FrameLayout> | |||||
| <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="h,343:275" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_title" /> | |||||
| <!-- android:name="com.xkl.cdl.module.m_statics.StatisticsTimeTopFragment"--> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout_english" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="72dp" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginTop="12dp" | |||||
| android:background="@drawable/shape_rounder_12_white" | |||||
| app:layout_constraintEnd_toStartOf="@+id/layout_chinese" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/fragment_top_time"> | |||||
| <ImageView | |||||
| android:id="@+id/iv_english" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginEnd="8dp" | |||||
| android:src="@drawable/ic_english" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| app:layout_constraintEnd_toStartOf="@+id/tv_english_" | |||||
| app:layout_constraintHorizontal_chainStyle="packed" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_english" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:text="英语统计" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/normalSize" | |||||
| app:layout_constraintBottom_toTopOf="@+id/tv_english_" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_english_" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintVertical_chainStyle="packed" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_english_" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="2dp" | |||||
| android:text="英语课程学习情况" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toEndOf="@+id/iv_english" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_english" /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout_chinese" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="72dp" | |||||
| android:layout_marginStart="12dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:background="@drawable/shape_rounder_12_white" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toEndOf="@+id/layout_english" | |||||
| app:layout_constraintTop_toTopOf="@+id/layout_english"> | |||||
| <ImageView | |||||
| android:id="@+id/iv_chinese" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginEnd="8dp" | |||||
| android:src="@drawable/ic_chinese" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| app:layout_constraintEnd_toStartOf="@+id/tv_chinese_" | |||||
| app:layout_constraintHorizontal_chainStyle="packed" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_chinese" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:text="语文统计" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/normalSize" | |||||
| app:layout_constraintBottom_toTopOf="@+id/tv_chinese_" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_chinese_" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintVertical_chainStyle="packed" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_chinese_" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="2dp" | |||||
| android:text="语文课程学习情况" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toEndOf="@+id/iv_chinese" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_chinese" /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="0dp" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginTop="12dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:background="@drawable/shape_rounder_12_white" | |||||
| android:padding="12dp" | |||||
| app:layout_constraintDimensionRatio="h,343:243" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/layout_english"> | |||||
| <TextView | |||||
| android:id="@+id/chart_title" | |||||
| 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_constraintLeft_toLeftOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_flag_1" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="8dp" | |||||
| android:drawableLeft="@drawable/shape_cicler_6_red" | |||||
| android:drawablePadding="5dp" | |||||
| android:drawableTint="@color/theme_color" | |||||
| android:text="新学词条数" | |||||
| android:textColor="#ff323233" | |||||
| android:textSize="12sp" | |||||
| app:layout_constraintStart_toStartOf="@+id/chart_title" | |||||
| app:layout_constraintTop_toBottomOf="@+id/chart_title" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_flag_2" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginLeft="24dp" | |||||
| android:drawableLeft="@drawable/shape_cicler_6_red" | |||||
| android:drawablePadding="5dp" | |||||
| android:text="复习词条数" | |||||
| android:textColor="#ff323233" | |||||
| android:textSize="12sp" | |||||
| app:layout_constraintStart_toEndOf="@+id/tv_flag_1" | |||||
| app:layout_constraintTop_toTopOf="@+id/tv_flag_1" /> | |||||
| <com.google.android.material.button.MaterialButton | |||||
| android:id="@+id/tv_chart_subject_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" | |||||
| 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" /> | |||||
| <com.github.mikephil.charting.charts.LineChart | |||||
| android:id="@+id/chart" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="0dp" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_flag_1" /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <layout xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| xmlns:tools="http://schemas.android.com/tools"> | |||||
| <data> | |||||
| </data> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout_time" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="match_parent" | |||||
| android:background="@drawable/shape_rounder_12_white" | |||||
| android:padding="12dp"> | |||||
| <com.google.android.material.tabs.TabLayout | |||||
| android:id="@+id/tab_layout_time" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| android:background="@drawable/shape_rounder_4_theme_a5" | |||||
| app:tabIndicatorHeight="0dp" | |||||
| app:tabGravity="fill" | |||||
| app:tabMode="fixed" | |||||
| app:tabRippleColor="@color/translation" | |||||
| app:tabTextColor="@color/gray_2" | |||||
| app:tabSelectedTextColor="@color/white" | |||||
| app:tabBackground="@drawable/select_statictis_time_tab_bg"> | |||||
| <!-- <com.google.android.material.tabs.TabItem--> | |||||
| <!-- android:layout_width="wrap_content"--> | |||||
| <!-- android:layout_height="wrap_content"--> | |||||
| <!-- android:text="全部时间" />--> | |||||
| <!-- <com.google.android.material.tabs.TabItem--> | |||||
| <!-- android:layout_width="wrap_content"--> | |||||
| <!-- android:layout_height="wrap_content"--> | |||||
| <!-- android:text="今天"/>--> | |||||
| <!-- <com.google.android.material.tabs.TabItem--> | |||||
| <!-- android:layout_width="wrap_content"--> | |||||
| <!-- android:layout_height="wrap_content"--> | |||||
| <!-- android:text="本周"/>--> | |||||
| <!-- <com.google.android.material.tabs.TabItem--> | |||||
| <!-- android:layout_width="wrap_content"--> | |||||
| <!-- android:layout_height="wrap_content"--> | |||||
| <!-- android:text="本月"/>--> | |||||
| </com.google.android.material.tabs.TabLayout> | |||||
| <androidx.recyclerview.widget.RecyclerView | |||||
| android:id="@+id/rv_time" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="0dp" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tab_layout_time" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| android:paddingEnd="12dp" /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </layout> |
| <?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:layout_marginTop="12dp" | |||||
| android:layout_marginStart="12dp" | |||||
| > | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="0dp" | |||||
| android:orientation="vertical" | |||||
| android:paddingStart="12dp" | |||||
| app:layout_constraintDimensionRatio="h,154:100" | |||||
| app:layout_constraintTop_toTopOf="parent"> | |||||
| <TextView | |||||
| android:id="@+id/tv_name" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| tools:text="有效学习时长" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintBottom_toTopOf="@+id/tv_content" | |||||
| app:layout_constraintVertical_chainStyle="packed"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_content" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="26dp" | |||||
| tools:text="100" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_name" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_name" | |||||
| app:layout_constraintBottom_toTopOf="@+id/tv_state"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_unit" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallSize" | |||||
| tools:text="%" | |||||
| app:layout_constraintStart_toEndOf="@id/tv_content" | |||||
| app:layout_constraintBaseline_toBaselineOf="@+id/tv_content"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_state" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textSize="@dimen/smallSize" | |||||
| tools:drawableStart="@drawable/ic_keep" | |||||
| android:gravity="center_vertical" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_content" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_name" | |||||
| app:layout_constraintBottom_toBottomOf="parent"/> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </layout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="100dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:orientation="horizontal" | |||||
| android:gravity="center" | |||||
| android:paddingTop="2dp" | |||||
| android:paddingBottom="2dp"> | |||||
| <ImageView | |||||
| android:id="@+id/iv_image" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:visibility="gone" | |||||
| /> | |||||
| <TextView | |||||
| android:id="@+id/tv_text" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| android:textColor="@color/main_text_color"/> | |||||
| </androidx.appcompat.widget.LinearLayoutCompat> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="32dp" | |||||
| android:height="32dp" | |||||
| android:viewportWidth="32" | |||||
| android:viewportHeight="32"> | |||||
| <path | |||||
| android:pathData="M23.2,5.6C24.0837,5.6 24.8,6.3163 24.8,7.2L24.8,28C24.8,28.8837 24.0837,29.6 23.2,29.6L5.6,29.6C4.7163,29.6 4,28.8837 4,28L4,7.2C4,6.3163 4.7163,5.6 5.6,5.6L23.2,5.6ZM25.6,2.4C26.8781,2.4 27.9229,3.3991 27.9959,4.659L28,4.8L28,25.6C28,26.0418 27.6418,26.4 27.2,26.4C26.7897,26.4 26.4516,26.0912 26.4054,25.6933L26.4,25.6L26.4,4.8C26.4,4.3897 26.0912,4.0516 25.6933,4.0054L25.6,4L8,4C7.5582,4 7.2,3.6418 7.2,3.2C7.2,2.7897 7.5088,2.4516 7.9067,2.4054L8,2.4L25.6,2.4ZM19.6497,17.2785C18.987,17.2785 18.4497,17.8157 18.4497,18.4785L18.4497,18.4785L18.4497,24.8785L18.4552,24.994C18.5134,25.6026 19.026,26.0785 19.6497,26.0785C20.3125,26.0785 20.8497,25.5412 20.8497,24.8785L20.8497,24.8785L20.8497,18.4785L20.8442,18.3629C20.7861,17.7544 20.2735,17.2785 19.6497,17.2785ZM9.2497,18.8785C8.587,18.8785 8.0497,19.4157 8.0497,20.0785L8.0497,20.0785L8.0497,24.8785L8.0552,24.994C8.1134,25.6026 8.626,26.0785 9.2497,26.0785C9.9125,26.0785 10.4497,25.5412 10.4497,24.8785L10.4497,24.8785L10.4497,20.0785L10.4442,19.9629C10.3861,19.3544 9.8735,18.8785 9.2497,18.8785ZM14.4,20.4C13.7373,20.4 13.2,20.9373 13.2,21.6L13.2,21.6L13.2,24.8L13.2055,24.9156C13.2636,25.5241 13.7762,26 14.4,26C15.0627,26 15.6,25.4627 15.6,24.8L15.6,24.8L15.6,21.6L15.5945,21.4844C15.5364,20.8759 15.0238,20.4 14.4,20.4ZM12.7473,10.7257C12.3927,10.2278 11.7108,10.0719 11.1706,10.3838L11.1706,10.3838L7.4,12.5608L7.3027,12.6233C6.8047,12.9779 6.6489,13.6598 6.9608,14.2L6.9608,14.2L7.0233,14.2973C7.3779,14.7953 8.0598,14.9511 8.6,14.6392L8.6,14.6392L11.3318,13.0619L13.1314,16.1799L13.1939,16.2773C13.5486,16.7752 14.2304,16.9311 14.7706,16.6192L14.7706,16.6192L20.6995,13.1962L20.7968,13.1336C21.2947,12.779 21.4506,12.0971 21.1387,11.5569L21.1387,11.5569L21.0762,11.4596C20.7216,10.9617 20.0397,10.8058 19.4995,11.1177L19.4995,11.1177L14.6102,13.9403L12.8099,10.823Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#40A540" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="16dp" | |||||
| android:height="16dp" | |||||
| android:viewportWidth="16" | |||||
| android:viewportHeight="16"> | |||||
| <path | |||||
| android:pathData="M9.4848,2C9.8698,2 10.1819,2.3058 10.1819,2.6831L10.1814,7.4649L12.8515,7.4649C13.044,7.4649 13.2,7.6179 13.2,7.8065C13.2,7.884 13.1731,7.9593 13.1236,8.0199L8.5443,13.6293C8.3038,13.9239 7.8652,13.9717 7.5645,13.736C7.5243,13.7045 7.4878,13.6687 7.4557,13.6293L2.8764,8.0199C2.7561,7.8726 2.7805,7.6576 2.9308,7.5398C2.9926,7.4913 3.0694,7.4649 3.1486,7.4649L5.8176,7.4642L5.8181,2.6831C5.8181,2.3058 6.1302,2 6.5152,2L9.4848,2Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#F26255" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="32dp" | |||||
| android:height="32dp" | |||||
| android:viewportWidth="32" | |||||
| android:viewportHeight="32"> | |||||
| <path | |||||
| android:pathData="M23.2,5.6C24.0837,5.6 24.8,6.3163 24.8,7.2L24.8,28C24.8,28.8837 24.0837,29.6 23.2,29.6L5.6,29.6C4.7163,29.6 4,28.8837 4,28L4,7.2C4,6.3163 4.7163,5.6 5.6,5.6L23.2,5.6ZM19.9629,19.4195C19.4508,19.4195 18.9975,19.5221 18.603,19.7274C18.2649,19.9034 17.9497,20.165 17.6573,20.5121L17.6573,20.5121L17.5131,20.6928L17.5131,20.4645L17.5055,20.3014C17.4904,20.1448 17.4525,20.0077 17.392,19.8901C17.3112,19.7332 17.204,19.6156 17.0702,19.5371C16.9364,19.4587 16.7864,19.4195 16.6203,19.4195C16.3481,19.4195 16.1336,19.5083 15.9767,19.6859C15.8423,19.8382 15.7654,20.0574 15.7462,20.3435L15.7462,20.3435L15.7414,20.4922L15.7414,25.9524L15.7468,26.1053C15.7683,26.4008 15.8541,26.6335 16.0044,26.8036C16.1797,27.002 16.4035,27.1012 16.6757,27.1012C16.9571,27.1012 17.1866,27.0054 17.3643,26.814C17.5165,26.6498 17.6035,26.4154 17.6253,26.1106L17.6253,26.1106L17.6307,25.9524L17.6307,23.5856L17.6324,23.3378C17.6415,22.7012 17.6871,22.2579 17.7691,22.0077C17.8983,21.6571 18.1013,21.3814 18.3781,21.1807C18.6549,20.98 18.9617,20.8797 19.2985,20.8797C19.8153,20.8797 20.1601,21.0446 20.3331,21.3745C20.4845,21.6631 20.5697,22.0639 20.5886,22.5769L20.5886,22.5769L20.5926,22.8036L20.5926,25.9524L20.598,26.1053C20.6195,26.4008 20.7054,26.6335 20.8556,26.8036C21.0309,27.002 21.2593,27.1012 21.5407,27.1012C21.8176,27.1012 22.0425,27.0043 22.2155,26.8105C22.3638,26.6444 22.4485,26.4105 22.4697,26.1088L22.4697,26.1088L22.475,25.9524L22.475,22.4368L22.4728,22.1965C22.4669,21.888 22.4492,21.6266 22.4196,21.4126C22.3827,21.145 22.302,20.8958 22.1774,20.6652C21.9837,20.2684 21.6907,19.9616 21.2985,19.7448C20.9064,19.5279 20.4612,19.4195 19.9629,19.4195ZM13.1601,16.7828L7.7345,16.7828L7.5663,16.7879C7.3504,16.8016 7.1677,16.8426 7.0183,16.9108C6.8314,16.9962 6.6941,17.1323 6.6065,17.3191C6.5364,17.4686 6.4943,17.6528 6.4803,17.8717L6.4803,17.8717L6.475,18.0423L6.475,25.6686L6.4796,25.829C6.501,26.1898 6.5975,26.457 6.7691,26.6306C6.9407,26.8041 7.2085,26.9018 7.5726,26.9235L7.5726,26.9235L7.7345,26.9281L13.3193,26.9281L13.4741,26.9219C13.7212,26.9011 13.9129,26.8282 14.0494,26.7032C14.2132,26.5533 14.2951,26.3584 14.2951,26.1185C14.2951,25.8693 14.2132,25.6698 14.0494,25.5198C13.9129,25.3949 13.7212,25.322 13.4741,25.3012L13.4741,25.3012L13.3193,25.2949L8.5304,25.2949L8.5304,22.4091L12.7933,22.4091L12.9456,22.4031C13.1878,22.3829 13.3723,22.3122 13.4992,22.1911C13.6515,22.0458 13.7276,21.8578 13.7276,21.6271C13.7276,21.3964 13.6503,21.2107 13.4958,21.07C13.367,20.9527 13.1829,20.8843 12.9436,20.8648L12.9436,20.8648L12.7933,20.8589L8.5304,20.8589L8.5304,18.3676L13.1601,18.3676L13.3169,18.3615C13.5665,18.3413 13.7576,18.2707 13.8902,18.1496C14.0494,18.0043 14.129,17.8116 14.129,17.5717C14.129,17.3364 14.0494,17.1461 13.8902,17.0008C13.7576,16.8797 13.5665,16.8091 13.3169,16.7889L13.3169,16.7889L13.1601,16.7828ZM25.6,2.4C26.8781,2.4 27.9229,3.3991 27.9959,4.659L28,4.8L28,25.6C28,26.0418 27.6418,26.4 27.2,26.4C26.7897,26.4 26.4516,26.0912 26.4054,25.6933L26.4,25.6L26.4,4.8C26.4,4.3897 26.0912,4.0516 25.6933,4.0054L25.6,4L8,4C7.5582,4 7.2,3.6418 7.2,3.2C7.2,2.7897 7.5088,2.4516 7.9067,2.4054L8,2.4L25.6,2.4ZM12.9736,9.1445C12.7347,8.823 12.2874,8.7247 11.9321,8.9298L11.9321,8.9298L6.5646,12.0287L6.4865,12.08C6.1651,12.319 6.0667,12.7662 6.2718,13.1215L6.2718,13.1215L6.3231,13.1996C6.5621,13.5211 7.0093,13.6195 7.3646,13.4144L7.3646,13.4144L12.0391,10.7156L14.0393,14.1795L14.0906,14.2576C14.3296,14.5791 14.7768,14.6775 15.1321,14.4724L15.1321,14.4724L22.2354,10.3713L22.3135,10.32C22.6349,10.081 22.7333,9.6338 22.5282,9.2785L22.5282,9.2785L22.4769,9.2004C22.2379,8.8789 21.7907,8.7805 21.4354,8.9856L21.4354,8.9856L15.0247,12.6868L13.0249,9.2226Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#F7874F" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="16dp" | |||||
| android:height="16dp" | |||||
| android:viewportWidth="16" | |||||
| android:viewportHeight="16"> | |||||
| <path | |||||
| android:pathData="M4.8,7.2L11.2,7.2A0.8,0.8 0,0 1,12 8L12,8A0.8,0.8 0,0 1,11.2 8.8L4.8,8.8A0.8,0.8 0,0 1,4 8L4,8A0.8,0.8 0,0 1,4.8 7.2z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#40A540" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="16dp" | |||||
| android:height="16dp" | |||||
| android:viewportWidth="16" | |||||
| android:viewportHeight="16"> | |||||
| <path | |||||
| android:pathData="M9.4848,13.8857C9.8698,13.8857 10.1819,13.5799 10.1819,13.2026L10.1814,8.4208L12.8515,8.4208C13.044,8.4208 13.2,8.2679 13.2,8.0792C13.2,8.0017 13.1731,7.9264 13.1236,7.8659L8.5443,2.2564C8.3038,1.9618 7.8652,1.914 7.5645,2.1497C7.5243,2.1812 7.4878,2.217 7.4557,2.2564L2.8764,7.8659C2.7561,8.0132 2.7805,8.2281 2.9308,8.3459C2.9926,8.3944 3.0694,8.4208 3.1486,8.4208L5.8176,8.4215L5.8181,13.2026C5.8181,13.5799 6.1302,13.8857 6.5152,13.8857L9.4848,13.8857Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#40A540" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| //精美日历 calendarview https://github.com/huanghaibin-dev/CalendarView | //精美日历 calendarview https://github.com/huanghaibin-dev/CalendarView | ||||
| CalendarView : "com.haibin:calendarview:3.7.1", | CalendarView : "com.haibin:calendarview:3.7.1", | ||||
| //google 流式布局 https://blog.csdn.net/ww897532167/article/details/85952498 https://github.com/google/flexbox-layout | //google 流式布局 https://blog.csdn.net/ww897532167/article/details/85952498 https://github.com/google/flexbox-layout | ||||
| FlexBoxLayoutManager : "com.google.android.flexbox:flexbox:3.0.0" | |||||
| FlexBoxLayoutManager : "com.google.android.flexbox:flexbox:3.0.0", | |||||
| //图表 | |||||
| Chart: "com.github.PhilJay:MPAndroidChart:v3.1.0" | |||||
| ] | ] | ||||
| } | } | ||||
| debug { | debug { | ||||
| buildConfigField("Boolean","LOG_ENABLE","true") | buildConfigField("Boolean","LOG_ENABLE","true") | ||||
| buildConfigField("Boolean","SHOW_LIFECYCLER_LOG","false") | |||||
| buildConfigField("Boolean","SHOW_LIFECYCLER_LOG","true") | |||||
| minifyEnabled false | minifyEnabled false | ||||
| proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||||
| } | } |
| * 小数: n个0,保留n位小数,不足部分,0填充 | * 小数: n个0,保留n位小数,不足部分,0填充 | ||||
| * | * | ||||
| * @param value Double 格式化的数字 | * @param value Double 格式化的数字 | ||||
| * @param format String 格式化格式 | |||||
| * @param format String 格式化格式 例0.0 | |||||
| * @return String 返回字符串内容 | * @return String 返回字符串内容 | ||||
| */ | */ | ||||
| @JvmStatic | @JvmStatic | ||||
| roundingMode = RoundingMode.HALF_UP | roundingMode = RoundingMode.HALF_UP | ||||
| }.format(value) | }.format(value) | ||||
| } | } | ||||
| /** | |||||
| * 数字格式化 舍弃模式,相当于直接截取 | |||||
| * 整数 : 0 有值为原来的值,没有值以0填充,如果是#则为原来的数值 | |||||
| * 小数: n个0,保留n位小数,不足部分,0填充 | |||||
| * | |||||
| * @param value Double 格式化的数字 | |||||
| * @param format String 格式化格式 例0.0 | |||||
| * @return String 返回字符串内容 | |||||
| */ | |||||
| fun formatFloor(value:Double,format : String): String{ | |||||
| return DecimalFormat(format).apply { | |||||
| roundingMode = RoundingMode.FLOOR | |||||
| }.format(value) | |||||
| } | |||||
| } | } | ||||
| } | } |