diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index baf56fc..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- xmlns:android
-
- ^$
-
-
-
-
-
-
-
-
- xmlns:.*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*:id
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- .*:name
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- name
-
- ^$
-
-
-
-
-
-
-
-
- style
-
- ^$
-
-
-
-
-
-
-
-
- .*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*
-
- http://schemas.android.com/apk/res/android
-
-
- ANDROID_ATTRIBUTE_ORDER
-
-
-
-
-
-
- .*
-
- .*
-
-
- BY_NAME
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codestyles/Project.xml b/.idea/codestyles/Project.xml
deleted file mode 100644
index adef587..0000000
--- a/.idea/codestyles/Project.xml
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- xmlns:android
-
- ^$
-
-
-
-
-
-
-
-
- xmlns:.*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*:id
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- .*:name
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- name
-
- ^$
-
-
-
-
-
-
-
-
- style
-
- ^$
-
-
-
-
-
-
-
-
- .*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*
-
- http://schemas.android.com/apk/res/android
-
-
- ANDROID_ATTRIBUTE_ORDER
-
-
-
-
-
-
- .*
-
- .*
-
-
- BY_NAME
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index bee4a02..7bfef59 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 90c87b2..059de90 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -102,6 +102,8 @@ dependencies {
implementation "org.koin:koin-android:$koin_version"
testImplementation "org.koin:koin-test:$koin_version"
+ implementation 'com.robinhood.ticker:ticker:2.0.2'
+
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
diff --git a/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerFragment.kt b/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerFragment.kt
index f7c9601..ac9c8f8 100644
--- a/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerFragment.kt
+++ b/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerFragment.kt
@@ -1,5 +1,7 @@
package com.wbrawner.trainterval.activetimer
+import android.animation.ArgbEvaluator
+import android.animation.ValueAnimator
import android.content.Context
import android.media.AudioManager
import android.media.SoundPool
@@ -16,6 +18,7 @@ import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import androidx.navigation.fragment.findNavController
+import com.robinhood.ticker.TickerUtils
import com.google.android.gms.wearable.*
import com.wbrawner.trainterval.Logger
import com.wbrawner.trainterval.R
@@ -89,6 +92,9 @@ class ActiveTimerFragment : Fragment(), MessageClient.OnMessageReceivedListener
it.setSupportActionBar(toolbar)
it.supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
+ timeRemaining.setCharacterLists(TickerUtils.provideNumberList() + ":")
+ timerSets.setCharacterLists(TickerUtils.provideNumberList())
+ timerRounds.setCharacterLists(TickerUtils.provideNumberList())
coroutineScope = CoroutineScope(Dispatchers.Main)
coroutineScope!!.launch {
activeTimerViewModel.timerState.observe(viewLifecycleOwner, Observer { state ->
@@ -131,7 +137,19 @@ class ActiveTimerFragment : Fragment(), MessageClient.OnMessageReceivedListener
}
(activity as? AppCompatActivity)?.supportActionBar?.title = state.timerName
val backgroundColor = resources.getColor(state.phase.colorRes, context?.theme)
- timerBackground.setBackgroundColor(backgroundColor)
+ Log.d("ActiveTimerFragment", "State: $state")
+ state.previousPhase?.let {
+ val previousBackgroundColor = resources.getColor(it.colorRes, context?.theme)
+ val colorAnimation =
+ ValueAnimator.ofObject(ArgbEvaluator(), previousBackgroundColor, backgroundColor)
+ colorAnimation.duration = 250
+ colorAnimation.addUpdateListener { animator ->
+ timerBackground.setBackgroundColor(
+ animator.animatedValue as Int
+ )
+ }
+ colorAnimation.start()
+ } ?: timerBackground.setBackgroundColor(backgroundColor)
playPauseButton.setImageDrawable(
requireContext().getDrawable(
if (state.isRunning) R.drawable.ic_pause
diff --git a/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerViewModel.kt b/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerViewModel.kt
index cb7d306..1245a4d 100644
--- a/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerViewModel.kt
+++ b/app/src/main/java/com/wbrawner/trainterval/activetimer/ActiveTimerViewModel.kt
@@ -39,7 +39,7 @@ class ActiveTimerViewModel : ViewModel() {
currentRound = timer.cycles
timeRemaining = timer.warmUpDuration
currentPhase = Phase.WARM_UP
- updateTimer()
+ updateTimer(null)
}
}
@@ -47,34 +47,27 @@ class ActiveTimerViewModel : ViewModel() {
if (timerJob != null) {
timerJob?.cancel()
timerJob = null
- timerState.postValue(
- TimerRunningState(
- timer,
- timeRemaining,
- currentSet,
- currentRound,
- currentPhase,
- timerJob != null
- )
- )
+ updateTimer(null)
} else {
viewModelScope.launch {
- startTimer()
+ startTimer(null)
}
}
}
- private fun startTimer() {
+ private fun startTimer(previousPhase: Phase?) {
viewModelScope.launch {
timerJob = launch {
- updateTimer()
+ updateTimer(previousPhase)
while (coroutineContext.isActive && timerJob != null) {
delay(1_000)
timeRemaining -= 1_000
+ // We need to recalculate the previous phase on each iteration
+ val previousPhaseOngoing = currentPhase
if (timeRemaining <= 0) {
goForward()
}
- updateTimer()
+ updateTimer(if (previousPhaseOngoing != currentPhase) previousPhaseOngoing else null)
}
}
}
@@ -82,22 +75,24 @@ class ActiveTimerViewModel : ViewModel() {
fun skipAhead() {
timerJob?.cancel()
+ var previousPhase: Phase? = null
when (currentPhase) {
Phase.COOL_DOWN -> {
timeRemaining = 0
}
else -> {
+ previousPhase = currentPhase
goForward()
}
}
if (timerJob != null) {
- startTimer()
+ startTimer(previousPhase)
} else {
- updateTimer()
+ updateTimer(previousPhase)
}
}
- private fun updateTimer() {
+ private fun updateTimer(previousPhase: Phase?) {
timerState.postValue(
TimerRunningState(
timer,
@@ -105,6 +100,7 @@ class ActiveTimerViewModel : ViewModel() {
currentSet,
currentRound,
currentPhase,
+ previousPhase,
timerJob != null
)
)
@@ -154,6 +150,7 @@ class ActiveTimerViewModel : ViewModel() {
fun goBack() {
timerJob?.cancel()
+ var previousPhase: Phase = currentPhase
when (currentPhase) {
Phase.WARM_UP -> {
timeRemaining = timer.warmUpDuration
@@ -191,9 +188,9 @@ class ActiveTimerViewModel : ViewModel() {
}
}
if (timerJob != null) {
- startTimer()
+ startTimer(previousPhase)
} else {
- updateTimer()
+ updateTimer(previousPhase)
}
}
}
diff --git a/app/src/main/res/layout/fragment_active_timer.xml b/app/src/main/res/layout/fragment_active_timer.xml
index f1312fd..241b879 100644
--- a/app/src/main/res/layout/fragment_active_timer.xml
+++ b/app/src/main/res/layout/fragment_active_timer.xml
@@ -55,7 +55,7 @@
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
android:textColor="@color/colorOnSurface" />
-
-
-