From b1db301a12aafcc4a480efd91e02311927ce6871 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Wed, 12 Jul 2017 18:24:48 -0700 Subject: [PATCH] add ability to set segment duration and set progress manually. add getter for completed segments --- .../segmentedprogressbar/DrawingTimer.java | 24 ++ .../SegmentedProgressBar.kt | 380 +++++++++--------- 2 files changed, 220 insertions(+), 184 deletions(-) diff --git a/library/src/main/java/com/carlosmuvi/segmentedprogressbar/DrawingTimer.java b/library/src/main/java/com/carlosmuvi/segmentedprogressbar/DrawingTimer.java index 7440733..3988bc8 100644 --- a/library/src/main/java/com/carlosmuvi/segmentedprogressbar/DrawingTimer.java +++ b/library/src/main/java/com/carlosmuvi/segmentedprogressbar/DrawingTimer.java @@ -14,6 +14,8 @@ public class DrawingTimer { private int currentTick = 0; private Listener listener; private TimerState timerState = TimerState.IDLE; + private long lastTimeInMilliseconds = 0; + public DrawingTimer() { handler = new Handler(); @@ -29,6 +31,28 @@ public void start(long timeInMilliseconds) { } } + public void setDuration(long timeInMilliseconds) { + if (timerState == TimerState.IDLE) { + this.totalTicks = (int) (timeInMilliseconds / tickTimeInMilliseconds); + } + } + + public void setProgress(final long timeInMilliseconds) { + handler.post(new Runnable() { + @Override public void run() { + //if tick is the same do not update + if (timeInMilliseconds == lastTimeInMilliseconds) { + return; + } + lastTimeInMilliseconds = timeInMilliseconds; + currentTick = (int) (timeInMilliseconds / tickTimeInMilliseconds); + listener.onTick(currentTick, totalTicks); + if (currentTick >= totalTicks) { + reset(); + } + } + }); + } private void runDrawingTask() { handler.post(new Runnable() { @Override public void run() { diff --git a/library/src/main/java/com/carlosmuvi/segmentedprogressbar/SegmentedProgressBar.kt b/library/src/main/java/com/carlosmuvi/segmentedprogressbar/SegmentedProgressBar.kt index c600035..b4020d0 100644 --- a/library/src/main/java/com/carlosmuvi/segmentedprogressbar/SegmentedProgressBar.kt +++ b/library/src/main/java/com/carlosmuvi/segmentedprogressbar/SegmentedProgressBar.kt @@ -14,188 +14,200 @@ import android.view.View class SegmentedProgressBar : View { - private var lastCompletedSegment = 0 - private var currentSegmentProgressInPx = 0 - - private lateinit var containerRectanglePaint: Paint - private lateinit var fillRectanglePaint: Paint - private lateinit var drawingTimer: DrawingTimer - private lateinit var properties: PropertiesModel - - constructor(context: Context) : super(context) { - initView() - } - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - initView(attrs) - } - - private fun initView(attrs: AttributeSet? = null) { - initDrawingTimer() - initPropertiesModel(attrs) - containerRectanglePaint = buildContainerRectanglePaint(properties.containerColor) - fillRectanglePaint = buildFillRectanglePaint(properties.fillColor) - } - - private fun initPropertiesModel(attrs: AttributeSet?) { - properties = PropertiesModel(context, attrs) - } - - private fun initDrawingTimer() { - drawingTimer = DrawingTimer() - drawingTimer.setListener { currentTicks, totalTicks -> - val segmentWidth = segmentWidth - - currentSegmentProgressInPx = currentTicks * segmentWidth / totalTicks - if (totalTicks <= currentTicks) { - lastCompletedSegment++ - currentSegmentProgressInPx = 0 - } - invalidate() - } - } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - drawContainerRectangles(canvas) - drawCompletedRectangles(canvas) - drawCurrentRectangle(canvas) - } - - /* - EXPOSED ATTRIBUTE METHODS - */ - - fun setContainerColor(@ColorInt color: Int) { - containerRectanglePaint = buildContainerRectanglePaint(color) - } - - fun setFillColor(@ColorInt color: Int) { - fillRectanglePaint = buildFillRectanglePaint(color) - } - - fun setSegmentCount(segmentCount: Int) { - properties.segmentCount = segmentCount - } - - /* - EXPOSED ACTION METHODS - */ - - fun playSegment(timeInMilliseconds: Long) { - if (!drawingTimer.isRunning) { - drawingTimer.start(timeInMilliseconds) - } - } - - fun pause() { - drawingTimer.pause() - } - - fun setCompletedSegments(completedSegments: Int) { - if (completedSegments <= properties.segmentCount) { - currentSegmentProgressInPx = 0 - drawingTimer.reset() - lastCompletedSegment = completedSegments - invalidate() - } - } - - fun reset() { - setCompletedSegments(0) - } - - /* - PRIVATE METHODS - */ - private fun drawContainerRectangles(canvas: Canvas) { - val segmentWidth = segmentWidth - - var leftX = 0 - var rightX = leftX + segmentWidth - val topY = 0 - val botY = height - - for (i in 0..properties.segmentCount - 1) { - drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), - containerRectanglePaint) - leftX = leftX + segmentWidth + properties.segmentGapWidth - rightX = leftX + segmentWidth - } - } - - private fun drawCompletedRectangles(canvas: Canvas) { - val segmentWidth = segmentWidth - - var leftX = 0 - var rightX = leftX + segmentWidth - val topY = 0 - val botY = height - - for (i in 0..lastCompletedSegment - 1) { - drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), fillRectanglePaint) - leftX = leftX + segmentWidth + properties.segmentGapWidth - rightX = leftX + segmentWidth - } - } - - private fun drawCurrentRectangle(canvas: Canvas) { - val segmentWidth = segmentWidth - - val leftX = lastCompletedSegment * (segmentWidth + properties.segmentGapWidth) - val rightX = leftX + currentSegmentProgressInPx - val topY = 0 - val botY = height - drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), fillRectanglePaint) - } - - private fun drawRoundedRect(canvas: Canvas, left: Float, top: Float, right: Float, bottom: Float, paint: Paint) { - - val path = Path() - var rx = 6f - if (rx < 0) rx = 0f - var ry = 6f - if (ry < 0) ry = 0f - val width = right - left - val height = bottom - top - if (rx > width / 2) rx = width / 2 - if (ry > height / 2) ry = height / 2 - val widthMinusCorners = width - 2 * rx - val heightMinusCorners = height - 2 * ry - - with(path) { - moveTo(right, top + ry) - rQuadTo(0f, -ry, -rx, -ry)//top-right corner - rLineTo(-widthMinusCorners, 0f) - rQuadTo(-rx, 0f, -rx, ry) //top-left corner - rLineTo(0f, heightMinusCorners) - - rQuadTo(0f, ry, rx, ry)//bottom-left corner - rLineTo(widthMinusCorners, 0f) - rQuadTo(rx, 0f, rx, -ry) //bottom-right corner - - rLineTo(0f, -heightMinusCorners) - - close() - } - - canvas.drawPath(path, paint) - } - - private fun buildFillRectanglePaint(@ColorInt color: Int): Paint { - val paint = Paint() - paint.color = color - paint.style = Paint.Style.FILL - return paint - } - - private fun buildContainerRectanglePaint(@ColorInt color: Int): Paint { - val paint = Paint() - paint.color = color - paint.style = Paint.Style.FILL - return paint - } - - private val segmentWidth: Int - get() = width / properties.segmentCount - properties.segmentGapWidth + private var lastCompletedSegment = 0 + private var currentSegmentProgressInPx = 0 + + private lateinit var containerRectanglePaint: Paint + private lateinit var fillRectanglePaint: Paint + private lateinit var drawingTimer: DrawingTimer + private lateinit var properties: PropertiesModel + + constructor(context: Context) : super(context) { + initView() + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + initView(attrs) + } + + private fun initView(attrs: AttributeSet? = null) { + initDrawingTimer() + initPropertiesModel(attrs) + containerRectanglePaint = buildContainerRectanglePaint(properties.containerColor) + fillRectanglePaint = buildFillRectanglePaint(properties.fillColor) + } + + private fun initPropertiesModel(attrs: AttributeSet?) { + properties = PropertiesModel(context, attrs) + } + + private fun initDrawingTimer() { + drawingTimer = DrawingTimer() + drawingTimer.setListener { currentTicks, totalTicks -> + val segmentWidth = segmentWidth + + currentSegmentProgressInPx = currentTicks * segmentWidth / totalTicks + if (totalTicks <= currentTicks) { + lastCompletedSegment++ + currentSegmentProgressInPx = 0 + } + invalidate() + } + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + drawContainerRectangles(canvas) + drawCompletedRectangles(canvas) + drawCurrentRectangle(canvas) + } + + /* + EXPOSED ATTRIBUTE METHODS + */ + + fun setContainerColor(@ColorInt color: Int) { + containerRectanglePaint = buildContainerRectanglePaint(color) + } + + fun setFillColor(@ColorInt color: Int) { + fillRectanglePaint = buildFillRectanglePaint(color) + } + + fun setSegmentCount(segmentCount: Int) { + properties.segmentCount = segmentCount + } + + /* + EXPOSED ACTION METHODS + */ + + fun playSegment(timeInMilliseconds: Long) { + if (!drawingTimer.isRunning) { + drawingTimer.start(timeInMilliseconds) + } + } + + fun setSegmentDuration(timeInMilliseconds: Long) { + drawingTimer.setDuration(timeInMilliseconds) + } + + fun setSegmentProgress(timeInMilliseconds: Long) { + drawingTimer.setProgress(timeInMilliseconds) + } + + fun pause() { + drawingTimer.pause() + } + + fun setCompletedSegments(completedSegments: Int) { + if (completedSegments <= properties.segmentCount) { + currentSegmentProgressInPx = 0 + drawingTimer.reset() + lastCompletedSegment = completedSegments + invalidate() + } + } + + fun getCompletedSegments(): Int { + return lastCompletedSegment + } + + fun reset() { + setCompletedSegments(0) + } + + /* + PRIVATE METHODS + */ + private fun drawContainerRectangles(canvas: Canvas) { + val segmentWidth = segmentWidth + + var leftX = 0 + var rightX = leftX + segmentWidth + val topY = 0 + val botY = height + + for (i in 0..properties.segmentCount - 1) { + drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), + containerRectanglePaint) + leftX = leftX + segmentWidth + properties.segmentGapWidth + rightX = leftX + segmentWidth + } + } + + private fun drawCompletedRectangles(canvas: Canvas) { + val segmentWidth = segmentWidth + + var leftX = 0 + var rightX = leftX + segmentWidth + val topY = 0 + val botY = height + + for (i in 0..lastCompletedSegment - 1) { + drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), fillRectanglePaint) + leftX = leftX + segmentWidth + properties.segmentGapWidth + rightX = leftX + segmentWidth + } + } + + private fun drawCurrentRectangle(canvas: Canvas) { + val segmentWidth = segmentWidth + + val leftX = lastCompletedSegment * (segmentWidth + properties.segmentGapWidth) + val rightX = leftX + currentSegmentProgressInPx + val topY = 0 + val botY = height + drawRoundedRect(canvas, leftX.toFloat(), topY.toFloat(), rightX.toFloat(), botY.toFloat(), fillRectanglePaint) + } + + private fun drawRoundedRect(canvas: Canvas, left: Float, top: Float, right: Float, bottom: Float, paint: Paint) { + + val path = Path() + var rx = 6f + if (rx < 0) rx = 0f + var ry = 6f + if (ry < 0) ry = 0f + val width = right - left + val height = bottom - top + if (rx > width / 2) rx = width / 2 + if (ry > height / 2) ry = height / 2 + val widthMinusCorners = width - 2 * rx + val heightMinusCorners = height - 2 * ry + + with(path) { + moveTo(right, top + ry) + rQuadTo(0f, -ry, -rx, -ry)//top-right corner + rLineTo(-widthMinusCorners, 0f) + rQuadTo(-rx, 0f, -rx, ry) //top-left corner + rLineTo(0f, heightMinusCorners) + + rQuadTo(0f, ry, rx, ry)//bottom-left corner + rLineTo(widthMinusCorners, 0f) + rQuadTo(rx, 0f, rx, -ry) //bottom-right corner + + rLineTo(0f, -heightMinusCorners) + + close() + } + + canvas.drawPath(path, paint) + } + + private fun buildFillRectanglePaint(@ColorInt color: Int): Paint { + val paint = Paint() + paint.color = color + paint.style = Paint.Style.FILL + return paint + } + + private fun buildContainerRectanglePaint(@ColorInt color: Int): Paint { + val paint = Paint() + paint.color = color + paint.style = Paint.Style.FILL + return paint + } + + private val segmentWidth: Int + get() = width / properties.segmentCount - properties.segmentGapWidth }