| @@ -33,10 +33,17 @@ | |||
| <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_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_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_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_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_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" /> | |||
| @@ -49,6 +56,7 @@ | |||
| <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/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_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" /> | |||
| @@ -73,6 +81,7 @@ | |||
| <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/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_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" /> | |||
| @@ -89,6 +98,8 @@ | |||
| <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_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_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" /> | |||
| @@ -120,11 +131,13 @@ | |||
| <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_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_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_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_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_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" /> | |||
| @@ -132,6 +145,7 @@ | |||
| <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/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_only.xml" value="0.49773550724637683" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" /> | |||
| @@ -146,6 +160,7 @@ | |||
| <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_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_icon___.xml" value="0.287962962962963" /> | |||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_menu.xml" value="0.4036458333333333" /> | |||
| @@ -119,6 +119,8 @@ dependencies { | |||
| implementation customDependencies.CalendarView | |||
| // FlexBoxLayoutManager | |||
| implementation customDependencies.FlexBoxLayoutManager | |||
| //图标 | |||
| implementation customDependencies.Chart | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| 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) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| 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 //背景 | |||
| } | |||
| @@ -449,4 +449,15 @@ object CourseManager { | |||
| return false | |||
| } | |||
| /** 获取课程的数量 */ | |||
| fun getTotalCourseSize() : Int { | |||
| var result = 0 | |||
| subjectWithCoursePackMap.forEach { entry -> | |||
| entry.value.forEach { coursePack -> | |||
| result += coursePack.childrenCourses.size | |||
| } | |||
| } | |||
| return result | |||
| } | |||
| } | |||
| @@ -206,4 +206,15 @@ object DataRepository { | |||
| } | |||
| } | |||
| /** 获取词条数统计 */ | |||
| 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() | |||
| } | |||
| } | |||
| } | |||
| @@ -59,7 +59,7 @@ class TestDetailActivity : BaseActivityVM<ActivityTestDetailBinding,TestDetailVi | |||
| private fun initScore():String{ | |||
| return when(vm.courseType){ | |||
| 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>" | |||
| } | |||
| } | |||
| @@ -1,72 +1,287 @@ | |||
| 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.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.extension.click | |||
| import com.suliang.common.extension.loadFragment | |||
| import com.suliang.common.extension.setHtml | |||
| 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.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 { | |||
| /** | |||
| * 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 | |||
| fun newInstance() = StaticsFragment() | |||
| } | |||
| override fun initViewModel() : StaticsFragmentViewModel { | |||
| return ViewModelProvider(this)[StaticsFragmentViewModel::class.java] | |||
| } | |||
| 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() { | |||
| //监听图表项目切换变化 | |||
| 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 | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,302 @@ | |||
| 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 "" | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| 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("") | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| 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); | |||
| } | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| <?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> | |||
| @@ -0,0 +1,64 @@ | |||
| <?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> | |||
| @@ -0,0 +1,7 @@ | |||
| <?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> | |||
| @@ -0,0 +1,5 @@ | |||
| <?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> | |||
| @@ -0,0 +1,5 @@ | |||
| <?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> | |||
| @@ -0,0 +1,5 @@ | |||
| <?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> | |||
| @@ -0,0 +1,5 @@ | |||
| <?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> | |||
| @@ -0,0 +1,24 @@ | |||
| <?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> | |||
| @@ -1,14 +1,218 @@ | |||
| <?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" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| android:background="@color/white_1" | |||
| android:orientation="vertical" | |||
| tools:context=".module.m_statics.StaticsFragment"> | |||
| <!-- TODO: Update blank fragment layout --> | |||
| <TextView | |||
| android:id="@+id/tv_title" | |||
| 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> | |||
| @@ -0,0 +1,60 @@ | |||
| <?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> | |||
| @@ -0,0 +1,72 @@ | |||
| <?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> | |||
| @@ -0,0 +1,23 @@ | |||
| <?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> | |||
| @@ -0,0 +1,12 @@ | |||
| <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> | |||
| @@ -0,0 +1,12 @@ | |||
| <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> | |||
| @@ -0,0 +1,12 @@ | |||
| <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> | |||
| @@ -0,0 +1,12 @@ | |||
| <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> | |||
| @@ -0,0 +1,12 @@ | |||
| <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> | |||
| @@ -110,7 +110,9 @@ ext { | |||
| //精美日历 calendarview https://github.com/huanghaibin-dev/CalendarView | |||
| CalendarView : "com.haibin:calendarview:3.7.1", | |||
| //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" | |||
| ] | |||
| @@ -26,7 +26,7 @@ android { | |||
| } | |||
| debug { | |||
| buildConfigField("Boolean","LOG_ENABLE","true") | |||
| buildConfigField("Boolean","SHOW_LIFECYCLER_LOG","false") | |||
| buildConfigField("Boolean","SHOW_LIFECYCLER_LOG","true") | |||
| minifyEnabled false | |||
| proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |||
| } | |||
| @@ -18,7 +18,7 @@ class NumberUtils { | |||
| * 小数: n个0,保留n位小数,不足部分,0填充 | |||
| * | |||
| * @param value Double 格式化的数字 | |||
| * @param format String 格式化格式 | |||
| * @param format String 格式化格式 例0.0 | |||
| * @return String 返回字符串内容 | |||
| */ | |||
| @JvmStatic | |||
| @@ -27,5 +27,20 @@ class NumberUtils { | |||
| roundingMode = RoundingMode.HALF_UP | |||
| }.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) | |||
| } | |||
| } | |||
| } | |||