mirror of
https://github.com/SimpleMobileTools/Simple-Clock.git
synced 2025-04-02 04:40:54 +02:00
extract stopwatch logic to separated file
This commit is contained in:
parent
b41253f1b1
commit
20a59bfd1e
@ -4,45 +4,25 @@ import android.graphics.Bitmap
|
|||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.os.SystemClock
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.simplemobiletools.clock.R
|
import com.simplemobiletools.clock.R
|
||||||
import com.simplemobiletools.clock.activities.SimpleActivity
|
import com.simplemobiletools.clock.activities.SimpleActivity
|
||||||
import com.simplemobiletools.clock.adapters.StopwatchAdapter
|
import com.simplemobiletools.clock.adapters.StopwatchAdapter
|
||||||
|
import com.simplemobiletools.clock.extensions.config
|
||||||
import com.simplemobiletools.clock.extensions.formatStopwatchTime
|
import com.simplemobiletools.clock.extensions.formatStopwatchTime
|
||||||
import com.simplemobiletools.clock.helpers.SORT_BY_LAP
|
import com.simplemobiletools.clock.helpers.SORT_BY_LAP
|
||||||
import com.simplemobiletools.clock.helpers.SORT_BY_LAP_TIME
|
import com.simplemobiletools.clock.helpers.SORT_BY_LAP_TIME
|
||||||
import com.simplemobiletools.clock.helpers.SORT_BY_TOTAL_TIME
|
import com.simplemobiletools.clock.helpers.SORT_BY_TOTAL_TIME
|
||||||
|
import com.simplemobiletools.clock.helpers.Stopwatch
|
||||||
import com.simplemobiletools.clock.models.Lap
|
import com.simplemobiletools.clock.models.Lap
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||||
import kotlinx.android.synthetic.main.fragment_stopwatch.view.*
|
import kotlinx.android.synthetic.main.fragment_stopwatch.view.*
|
||||||
|
|
||||||
class StopwatchFragment : Fragment() {
|
class StopwatchFragment : Fragment() {
|
||||||
private val UPDATE_INTERVAL = 10L
|
|
||||||
private val WAS_RUNNING = "was_running"
|
|
||||||
private val TOTAL_TICKS = "total_ticks"
|
|
||||||
private val CURRENT_TICKS = "current_ticks"
|
|
||||||
private val LAP_TICKS = "lap_ticks"
|
|
||||||
private val CURRENT_LAP = "current_lap"
|
|
||||||
private val LAPS = "laps"
|
|
||||||
private val SORTING = "sorting"
|
|
||||||
|
|
||||||
private val updateHandler = Handler()
|
|
||||||
private var uptimeAtStart = 0L
|
|
||||||
private var totalTicks = 0
|
|
||||||
private var currentTicks = 0 // ticks that reset at pause
|
|
||||||
private var lapTicks = 0
|
|
||||||
private var currentLap = 1
|
|
||||||
private var isRunning = false
|
|
||||||
private var sorting = SORT_BY_LAP or SORT_DESCENDING
|
|
||||||
private var laps = ArrayList<Lap>()
|
|
||||||
|
|
||||||
private var storedTextColor = 0
|
private var storedTextColor = 0
|
||||||
|
|
||||||
@ -51,6 +31,8 @@ class StopwatchFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
storeStateVariables()
|
storeStateVariables()
|
||||||
|
val sorting = requireContext().config.stopwatchLapsSort
|
||||||
|
Lap.sorting = sorting
|
||||||
view = (inflater.inflate(R.layout.fragment_stopwatch, container, false) as ViewGroup).apply {
|
view = (inflater.inflate(R.layout.fragment_stopwatch, container, false) as ViewGroup).apply {
|
||||||
stopwatch_time.setOnClickListener {
|
stopwatch_time.setOnClickListener {
|
||||||
togglePlayPause()
|
togglePlayPause()
|
||||||
@ -78,20 +60,7 @@ class StopwatchFragment : Fragment() {
|
|||||||
|
|
||||||
stopwatch_lap.setOnClickListener {
|
stopwatch_lap.setOnClickListener {
|
||||||
stopwatch_sorting_indicators_holder.beVisible()
|
stopwatch_sorting_indicators_holder.beVisible()
|
||||||
if (laps.isEmpty()) {
|
Stopwatch.lap()
|
||||||
val lap = Lap(currentLap++, lapTicks * UPDATE_INTERVAL, totalTicks * UPDATE_INTERVAL)
|
|
||||||
laps.add(0, lap)
|
|
||||||
lapTicks = 0
|
|
||||||
} else {
|
|
||||||
laps.first().apply {
|
|
||||||
lapTime = lapTicks * UPDATE_INTERVAL
|
|
||||||
totalTime = totalTicks * UPDATE_INTERVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val lap = Lap(currentLap++, lapTicks * UPDATE_INTERVAL, totalTicks * UPDATE_INTERVAL)
|
|
||||||
laps.add(0, lap)
|
|
||||||
lapTicks = 0
|
|
||||||
updateLaps()
|
updateLaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +69,10 @@ class StopwatchFragment : Fragment() {
|
|||||||
changeSorting(it)
|
changeSorting(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Lap.sorting = sorting
|
|
||||||
stopwatch_list.adapter = stopwatchAdapter
|
stopwatch_list.adapter = stopwatchAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSortingIndicators()
|
updateSortingIndicators(sorting)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,64 +84,25 @@ class StopwatchFragment : Fragment() {
|
|||||||
if (storedTextColor != configTextColor) {
|
if (storedTextColor != configTextColor) {
|
||||||
stopwatchAdapter.updateTextColor(configTextColor)
|
stopwatchAdapter.updateTextColor(configTextColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stopwatch.addUpdateListener(updateListener)
|
||||||
|
updateLaps()
|
||||||
|
view.stopwatch_sorting_indicators_holder.beVisibleIf(Stopwatch.laps.isNotEmpty())
|
||||||
|
if (Stopwatch.laps.isNotEmpty()) {
|
||||||
|
updateSorting(Lap.sorting)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
storeStateVariables()
|
storeStateVariables()
|
||||||
}
|
Stopwatch.removeUpdateListener(updateListener)
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
if (isRunning && activity?.isChangingConfigurations == false) {
|
|
||||||
context?.toast(R.string.stopwatch_stopped)
|
|
||||||
}
|
|
||||||
isRunning = false
|
|
||||||
updateHandler.removeCallbacks(updateRunnable)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun storeStateVariables() {
|
private fun storeStateVariables() {
|
||||||
storedTextColor = requireContext().getProperTextColor()
|
storedTextColor = requireContext().getProperTextColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
|
||||||
outState.apply {
|
|
||||||
putBoolean(WAS_RUNNING, isRunning)
|
|
||||||
putInt(TOTAL_TICKS, totalTicks)
|
|
||||||
putInt(CURRENT_TICKS, currentTicks)
|
|
||||||
putInt(LAP_TICKS, lapTicks)
|
|
||||||
putInt(CURRENT_LAP, currentLap)
|
|
||||||
putInt(SORTING, sorting)
|
|
||||||
putString(LAPS, Gson().toJson(laps))
|
|
||||||
super.onSaveInstanceState(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
|
||||||
super.onViewStateRestored(savedInstanceState)
|
|
||||||
savedInstanceState?.apply {
|
|
||||||
isRunning = getBoolean(WAS_RUNNING, false)
|
|
||||||
totalTicks = getInt(TOTAL_TICKS, 0)
|
|
||||||
currentTicks = getInt(CURRENT_TICKS, 0)
|
|
||||||
lapTicks = getInt(LAP_TICKS, 0)
|
|
||||||
currentLap = getInt(CURRENT_LAP, 0)
|
|
||||||
sorting = getInt(SORTING, SORT_BY_LAP or SORT_DESCENDING)
|
|
||||||
|
|
||||||
val lapsToken = object : TypeToken<List<Lap>>() {}.type
|
|
||||||
laps = Gson().fromJson(getString(LAPS), lapsToken)
|
|
||||||
|
|
||||||
if (laps.isNotEmpty()) {
|
|
||||||
view.stopwatch_sorting_indicators_holder.beVisibleIf(laps.isNotEmpty())
|
|
||||||
updateSorting()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRunning) {
|
|
||||||
uptimeAtStart = SystemClock.uptimeMillis() - currentTicks * UPDATE_INTERVAL
|
|
||||||
updateStopwatchState(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupViews() {
|
private fun setupViews() {
|
||||||
val properPrimaryColor = requireContext().getProperPrimaryColor()
|
val properPrimaryColor = requireContext().getProperPrimaryColor()
|
||||||
view.apply {
|
view.apply {
|
||||||
@ -181,60 +110,30 @@ class StopwatchFragment : Fragment() {
|
|||||||
stopwatch_play_pause.background = resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, properPrimaryColor)
|
stopwatch_play_pause.background = resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, properPrimaryColor)
|
||||||
stopwatch_reset.applyColorFilter(requireContext().getProperTextColor())
|
stopwatch_reset.applyColorFilter(requireContext().getProperTextColor())
|
||||||
}
|
}
|
||||||
|
|
||||||
updateIcons()
|
|
||||||
updateDisplayedText()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateIcons() {
|
private fun updateIcons(state: Stopwatch.State) {
|
||||||
val drawableId = if (isRunning) R.drawable.ic_pause_vector else R.drawable.ic_play_vector
|
val drawableId = if (state == Stopwatch.State.RUNNING) R.drawable.ic_pause_vector else R.drawable.ic_play_vector
|
||||||
val iconColor = if (requireContext().getProperPrimaryColor() == Color.WHITE) Color.BLACK else Color.WHITE
|
val iconColor = if (requireContext().getProperPrimaryColor() == Color.WHITE) Color.BLACK else Color.WHITE
|
||||||
view.stopwatch_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
|
view.stopwatch_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun togglePlayPause() {
|
private fun togglePlayPause() {
|
||||||
isRunning = !isRunning
|
Stopwatch.toggle(true)
|
||||||
updateStopwatchState(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateStopwatchState(setUptimeAtStart: Boolean) {
|
|
||||||
updateIcons()
|
|
||||||
view.stopwatch_lap.beVisibleIf(isRunning)
|
|
||||||
|
|
||||||
if (isRunning) {
|
private fun updateDisplayedText(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) {
|
||||||
updateHandler.post(updateRunnable)
|
view.stopwatch_time.text = totalTime.formatStopwatchTime(useLongerMSFormat)
|
||||||
view.stopwatch_reset.beVisible()
|
if (Stopwatch.laps.isNotEmpty() && lapTime != -1L) {
|
||||||
if (setUptimeAtStart) {
|
stopwatchAdapter.updateLastField(lapTime, totalTime)
|
||||||
uptimeAtStart = SystemClock.uptimeMillis()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val prevSessionsMS = (totalTicks - currentTicks) * UPDATE_INTERVAL
|
|
||||||
val totalDuration = SystemClock.uptimeMillis() - uptimeAtStart + prevSessionsMS
|
|
||||||
updateHandler.removeCallbacksAndMessages(null)
|
|
||||||
view.stopwatch_time.text = totalDuration.formatStopwatchTime(true)
|
|
||||||
currentTicks = 0
|
|
||||||
totalTicks--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateDisplayedText() {
|
|
||||||
view.stopwatch_time.text = (totalTicks * UPDATE_INTERVAL).formatStopwatchTime(false)
|
|
||||||
if (currentLap > 1) {
|
|
||||||
stopwatchAdapter.updateLastField(lapTicks * UPDATE_INTERVAL, totalTicks * UPDATE_INTERVAL)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetStopwatch() {
|
private fun resetStopwatch() {
|
||||||
updateHandler.removeCallbacksAndMessages(null)
|
Stopwatch.reset()
|
||||||
isRunning = false
|
|
||||||
currentTicks = 0
|
|
||||||
totalTicks = 0
|
|
||||||
currentLap = 1
|
|
||||||
lapTicks = 0
|
|
||||||
laps.clear()
|
|
||||||
updateIcons()
|
|
||||||
stopwatchAdapter.updateItems(laps)
|
|
||||||
|
|
||||||
|
updateLaps()
|
||||||
view.apply {
|
view.apply {
|
||||||
stopwatch_reset.beGone()
|
stopwatch_reset.beGone()
|
||||||
stopwatch_lap.beGone()
|
stopwatch_lap.beGone()
|
||||||
@ -244,21 +143,22 @@ class StopwatchFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun changeSorting(clickedValue: Int) {
|
private fun changeSorting(clickedValue: Int) {
|
||||||
sorting = if (sorting and clickedValue != 0) {
|
val sorting = if (Lap.sorting and clickedValue != 0) {
|
||||||
sorting.flipBit(SORT_DESCENDING)
|
Lap.sorting.flipBit(SORT_DESCENDING)
|
||||||
} else {
|
} else {
|
||||||
clickedValue or SORT_DESCENDING
|
clickedValue or SORT_DESCENDING
|
||||||
}
|
}
|
||||||
updateSorting()
|
updateSorting(sorting)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSorting() {
|
private fun updateSorting(sorting: Int) {
|
||||||
updateSortingIndicators()
|
updateSortingIndicators(sorting)
|
||||||
Lap.sorting = sorting
|
Lap.sorting = sorting
|
||||||
|
requireContext().config.stopwatchLapsSort = sorting
|
||||||
updateLaps()
|
updateLaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSortingIndicators() {
|
private fun updateSortingIndicators(sorting: Int) {
|
||||||
var bitmap = requireContext().resources.getColoredBitmap(R.drawable.ic_sorting_triangle_vector, requireContext().getProperPrimaryColor())
|
var bitmap = requireContext().resources.getColoredBitmap(R.drawable.ic_sorting_triangle_vector, requireContext().getProperPrimaryColor())
|
||||||
view.apply {
|
view.apply {
|
||||||
stopwatch_sorting_indicator_1.beInvisibleIf(sorting and SORT_BY_LAP == 0)
|
stopwatch_sorting_indicator_1.beInvisibleIf(sorting and SORT_BY_LAP == 0)
|
||||||
@ -281,20 +181,18 @@ class StopwatchFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLaps() {
|
private fun updateLaps() {
|
||||||
stopwatchAdapter.updateItems(laps)
|
stopwatchAdapter.updateItems(Stopwatch.laps)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val updateRunnable = object : Runnable {
|
private val updateListener = object : Stopwatch.UpdateListener {
|
||||||
override fun run() {
|
override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) {
|
||||||
if (isRunning) {
|
updateDisplayedText(totalTime, lapTime, useLongerMSFormat)
|
||||||
if (totalTicks % 10 == 0) {
|
}
|
||||||
updateDisplayedText()
|
|
||||||
}
|
override fun onStateChanged(state: Stopwatch.State) {
|
||||||
totalTicks++
|
updateIcons(state)
|
||||||
currentTicks++
|
view.stopwatch_lap.beVisibleIf(state == Stopwatch.State.RUNNING)
|
||||||
lapTicks++
|
view.stopwatch_reset.beVisibleIf(state != Stopwatch.State.STOPPED)
|
||||||
updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import com.simplemobiletools.clock.models.TimerState
|
|||||||
import com.simplemobiletools.commons.extensions.getDefaultAlarmSound
|
import com.simplemobiletools.commons.extensions.getDefaultAlarmSound
|
||||||
import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
|
import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
|
||||||
import com.simplemobiletools.commons.helpers.BaseConfig
|
import com.simplemobiletools.commons.helpers.BaseConfig
|
||||||
|
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||||
|
|
||||||
class Config(context: Context) : BaseConfig(context) {
|
class Config(context: Context) : BaseConfig(context) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -81,4 +82,8 @@ class Config(context: Context) : BaseConfig(context) {
|
|||||||
var timerChannelId: String?
|
var timerChannelId: String?
|
||||||
get() = prefs.getString(TIMER_CHANNEL_ID, null)
|
get() = prefs.getString(TIMER_CHANNEL_ID, null)
|
||||||
set(id) = prefs.edit().putString(TIMER_CHANNEL_ID, id).apply()
|
set(id) = prefs.edit().putString(TIMER_CHANNEL_ID, id).apply()
|
||||||
|
|
||||||
|
var stopwatchLapsSort: Int
|
||||||
|
get() = prefs.getInt(STOPWATCH_LAPS_SORT_BY, SORT_BY_LAP or SORT_DESCENDING)
|
||||||
|
set(stopwatchLapsSort) = prefs.edit().putInt(STOPWATCH_LAPS_SORT_BY, stopwatchLapsSort).apply()
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ const val ALARM_LAST_CONFIG = "alarm_last_config"
|
|||||||
const val TIMER_LAST_CONFIG = "timer_last_config"
|
const val TIMER_LAST_CONFIG = "timer_last_config"
|
||||||
const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually"
|
const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually"
|
||||||
const val ALARMS_SORT_BY = "alarms_sort_by"
|
const val ALARMS_SORT_BY = "alarms_sort_by"
|
||||||
|
const val STOPWATCH_LAPS_SORT_BY = "stopwatch_laps_sort_by"
|
||||||
|
|
||||||
const val TABS_COUNT = 4
|
const val TABS_COUNT = 4
|
||||||
const val EDITED_TIME_ZONE_SEPARATOR = ":"
|
const val EDITED_TIME_ZONE_SEPARATOR = ":"
|
||||||
|
@ -0,0 +1,130 @@
|
|||||||
|
package com.simplemobiletools.clock.helpers
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.SystemClock
|
||||||
|
import com.simplemobiletools.clock.models.Lap
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
|
|
||||||
|
private const val UPDATE_INTERVAL = 10L
|
||||||
|
|
||||||
|
object Stopwatch {
|
||||||
|
|
||||||
|
private val updateHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var uptimeAtStart = 0L
|
||||||
|
private var totalTicks = 0
|
||||||
|
private var currentTicks = 0 // ticks that reset at pause
|
||||||
|
private var lapTicks = 0
|
||||||
|
private var currentLap = 1
|
||||||
|
val laps = ArrayList<Lap>()
|
||||||
|
var state = State.STOPPED
|
||||||
|
private set(value) {
|
||||||
|
field = value
|
||||||
|
for (listener in updateListeners) {
|
||||||
|
listener.onStateChanged(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var updateListeners = CopyOnWriteArraySet<UpdateListener>()
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
updateHandler.removeCallbacksAndMessages(null)
|
||||||
|
state = State.STOPPED
|
||||||
|
currentTicks = 0
|
||||||
|
totalTicks = 0
|
||||||
|
currentLap = 1
|
||||||
|
lapTicks = 0
|
||||||
|
laps.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggle(setUptimeAtStart: Boolean) {
|
||||||
|
if (state != State.RUNNING) {
|
||||||
|
state = State.RUNNING
|
||||||
|
updateHandler.post(updateRunnable)
|
||||||
|
if (setUptimeAtStart) {
|
||||||
|
uptimeAtStart = SystemClock.uptimeMillis()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state = State.PAUSED
|
||||||
|
val prevSessionsMS = (totalTicks - currentTicks) * UPDATE_INTERVAL
|
||||||
|
val totalDuration = SystemClock.uptimeMillis() - uptimeAtStart + prevSessionsMS
|
||||||
|
updateHandler.removeCallbacksAndMessages(null)
|
||||||
|
currentTicks = 0
|
||||||
|
totalTicks--
|
||||||
|
for (listener in updateListeners) {
|
||||||
|
listener.onUpdate(totalDuration, -1, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lap() {
|
||||||
|
if (laps.isEmpty()) {
|
||||||
|
val lap = Lap(currentLap++, lapTicks * UPDATE_INTERVAL, totalTicks * UPDATE_INTERVAL)
|
||||||
|
laps.add(0, lap)
|
||||||
|
lapTicks = 0
|
||||||
|
} else {
|
||||||
|
laps.first().apply {
|
||||||
|
lapTime = lapTicks * UPDATE_INTERVAL
|
||||||
|
totalTime = totalTicks * UPDATE_INTERVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val lap = Lap(currentLap++, lapTicks * UPDATE_INTERVAL, totalTicks * UPDATE_INTERVAL)
|
||||||
|
laps.add(0, lap)
|
||||||
|
lapTicks = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a update listener to the stopwatch. The listener gets the current state
|
||||||
|
* immediately after adding. To avoid memory leaks the listener should be removed
|
||||||
|
* from the stopwatch.
|
||||||
|
* @param updateListener the listener
|
||||||
|
*/
|
||||||
|
fun addUpdateListener(updateListener: UpdateListener) {
|
||||||
|
updateListeners.add(updateListener)
|
||||||
|
updateListener.onUpdate(
|
||||||
|
totalTicks * UPDATE_INTERVAL,
|
||||||
|
lapTicks * UPDATE_INTERVAL,
|
||||||
|
state != State.STOPPED
|
||||||
|
)
|
||||||
|
updateListener.onStateChanged(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the listener from the stopwatch
|
||||||
|
* @param updateListener the listener
|
||||||
|
*/
|
||||||
|
fun removeUpdateListener(updateListener: UpdateListener) {
|
||||||
|
updateListeners.remove(updateListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val updateRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (state == State.RUNNING) {
|
||||||
|
if (totalTicks % 10 == 0) {
|
||||||
|
for (listener in updateListeners) {
|
||||||
|
listener.onUpdate(
|
||||||
|
totalTicks * UPDATE_INTERVAL,
|
||||||
|
lapTicks * UPDATE_INTERVAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalTicks++
|
||||||
|
currentTicks++
|
||||||
|
lapTicks++
|
||||||
|
updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
RUNNING,
|
||||||
|
PAUSED,
|
||||||
|
STOPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateListener {
|
||||||
|
fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean)
|
||||||
|
fun onStateChanged(state: State)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user