11package com.example.util.simpletimetracker.feature_statistics_detail.customView
22
3+ import android.animation.Animator
4+ import android.animation.ValueAnimator
35import android.annotation.SuppressLint
46import android.content.Context
57import android.graphics.Canvas
@@ -36,6 +38,7 @@ class SeriesCalendarView @JvmOverloads constructor(
3638 // Attrs
3739 private var legendTextSize: Float = 0f
3840 private var legendTextColor: Int = 0
41+ private var selectedCellColor: Int = 0
3942 // Attrs
4043
4144 private val columnsCount: Int = 26
@@ -51,11 +54,18 @@ class SeriesCalendarView @JvmOverloads constructor(
5154 private var chartFullWidth: Float = 0f
5255 private var cellNotPresentColorAlpha = 0.2f
5356 private var cellPresentColorAlphaBase = 0.6f
57+ private var selectedCell: Data ? = null
58+ private var selectedCellAlpha: Int = 0
59+ private var selectedCellAnimator: Animator ? = null
60+ private val selectedCellWidthRatio: Float = 0.3f
61+ private val selectedCellAnimationDurationMs: Long = 3_000
62+ private val selectedCellStartAlpha: Float = 0.4f
5463 private var listener: (ViewData , Coordinates ) -> Unit = { _, _ -> }
5564
5665 private val cellPresentPaint: Paint = Paint ()
5766 private val cellNotPresentPaint: Paint = Paint ()
5867 private val legendTextPaint: Paint = Paint ()
68+ private val selectedCellPaint: Paint = Paint ()
5969
6070 private val singleTapDetector = SingleTapDetector (
6171 context = context,
@@ -108,6 +118,7 @@ class SeriesCalendarView @JvmOverloads constructor(
108118
109119 calculateDimensions()
110120 drawCells(canvas, w, h)
121+ drawSelectedCell(canvas)
111122 }
112123
113124 @SuppressLint(" ClickableViewAccessibility" )
@@ -160,6 +171,8 @@ class SeriesCalendarView @JvmOverloads constructor(
160171 getDimensionPixelSize(R .styleable.SeriesCalendarView_seriesLegendTextSize , 14 ).toFloat()
161172 legendTextColor =
162173 getColor(R .styleable.SeriesCalendarView_seriesLegendTextColor , Color .BLACK )
174+ selectedCellColor =
175+ getColor(R .styleable.SeriesCalendarView_seriesSelectedCellColor , Color .BLACK )
163176 }
164177 }
165178
@@ -180,10 +193,15 @@ class SeriesCalendarView @JvmOverloads constructor(
180193 color = legendTextColor
181194 textSize = legendTextSize
182195 }
196+ selectedCellPaint.apply {
197+ isAntiAlias = true
198+ style = Paint .Style .FILL
199+ }
183200 }
184201
185202 private fun initEditMode () {
186203 if (isInEditMode) {
204+ setCellColor(Color .RED )
187205 (30 downTo 1 ).toList()
188206 .map { ViewData .Present (0 , " " , ViewData .ColorLevel .THREE ) }
189207 .let { setData(it, rowsCount) }
@@ -257,6 +275,27 @@ class SeriesCalendarView @JvmOverloads constructor(
257275 }
258276 }
259277
278+ private fun drawSelectedCell (canvas : Canvas ) {
279+ val selectedCell = selectedCell ? : return
280+
281+ selectedCellPaint.color = if (selectedCell.cell is ViewData .Present ) {
282+ Color .WHITE
283+ } else {
284+ selectedCellColor
285+ }
286+ selectedCellPaint.alpha = selectedCellAlpha
287+
288+ val boxWidth = selectedCell.boxRight - selectedCell.boxLeft
289+ val boxHeight = selectedCell.boxBottom - selectedCell.boxTop
290+
291+ canvas.drawCircle(
292+ selectedCell.boxLeft + boxWidth / 2f ,
293+ selectedCell.boxTop + boxHeight / 2f ,
294+ boxWidth * selectedCellWidthRatio / 2f ,
295+ selectedCellPaint,
296+ )
297+ }
298+
260299 private fun getPresentCellFinalAlpha (colorLevel : ViewData .ColorLevel ): Int {
261300 val maxLevel = ViewData .ColorLevel .entries.size
262301 val alphaCoefficient = if (maxLevel > 1 ) {
@@ -268,12 +307,32 @@ class SeriesCalendarView @JvmOverloads constructor(
268307 return (255 * baseAlpha).toInt()
269308 }
270309
310+ private fun animateSelectedCell () {
311+ val from = 255 * selectedCellStartAlpha
312+ val animator = ValueAnimator .ofInt(from.toInt(), 0 )
313+ .also { selectedCellAnimator = it }
314+
315+ animator.duration = selectedCellAnimationDurationMs
316+ animator.addUpdateListener {
317+ selectedCellAlpha = it.animatedValue as ? Int
318+ ? : return @addUpdateListener
319+ invalidate()
320+ }
321+ animator.start()
322+ }
323+
324+ private fun cancelSelectedCellAnimation () {
325+ selectedCellAnimator?.cancel()
326+ selectedCell = null
327+ }
328+
271329 @Suppress(" UNUSED_PARAMETER" )
272330 private fun onSwipe (offset : Float , direction : SwipeDetector .Direction , event : MotionEvent ) {
273331 if (direction.isHorizontal()) {
274332 parent.requestDisallowInterceptTouchEvent(true )
275333 panFactor = lastPanFactor + offset
276334 coercePan()
335+ cancelSelectedCellAnimation()
277336 invalidate()
278337 }
279338 }
@@ -287,6 +346,7 @@ class SeriesCalendarView @JvmOverloads constructor(
287346 }?.let {
288347 val globalRect = Rect ()
289348 getGlobalVisibleRect(globalRect)
349+ selectedCell = it
290350 listener(
291351 it.cell,
292352 // Calculate from the bottom, because when view is half scrolled on the top,
@@ -299,6 +359,7 @@ class SeriesCalendarView @JvmOverloads constructor(
299359 bottom = globalRect.bottom - height + it.boxBottom.toInt(),
300360 ),
301361 )
362+ animateSelectedCell()
302363 }
303364 }
304365
0 commit comments