Fix style issues after leaving timer and rotation breaking timers
This commit is contained in:
parent
cb284b800d
commit
f21754a0be
12 changed files with 267 additions and 173 deletions
|
@ -9,7 +9,8 @@ data class IntervalDuration(
|
|||
val seconds: Long = 0
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "%02d:%02d:%02d".format(hours, minutes, seconds)
|
||||
return if (hours > 0) "%02d:%02d:%02d".format(hours, minutes, seconds)
|
||||
else "%02d:%02d".format(minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,9 +20,10 @@ fun IntervalDuration.toMillis(): Long {
|
|||
TimeUnit.SECONDS.toMillis(seconds)
|
||||
}
|
||||
|
||||
private const val SECONDS_IN_HOUR = 3600
|
||||
private const val SECONDS_IN_MINUTE = 60
|
||||
|
||||
fun Long.toIntervalDuration(): IntervalDuration {
|
||||
val SECONDS_IN_HOUR = 3600
|
||||
val SECONDS_IN_MINUTE = 60
|
||||
|
||||
if (this < 1000) {
|
||||
return IntervalDuration(0, 0, 0)
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.wbrawner.trainterval
|
|||
|
||||
import android.app.Application
|
||||
import androidx.room.Room
|
||||
import com.wbrawner.trainterval.activetimer.ActiveTimerViewModel
|
||||
import com.wbrawner.trainterval.timerform.TimerFormViewModel
|
||||
import com.wbrawner.trainterval.timerlist.TimerListViewModel
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
|
@ -46,10 +45,6 @@ val traintervalModule = module {
|
|||
TimerFormViewModel(get(parameters = { parametersOf("TimerFormStore") }), get())
|
||||
}
|
||||
|
||||
factory {
|
||||
ActiveTimerViewModel(get(parameters = { parametersOf("ActiveTimerStore") }), get())
|
||||
}
|
||||
|
||||
factory<Logger> { params ->
|
||||
AndroidLogger(params.component1())
|
||||
}
|
||||
|
|
|
@ -7,25 +7,31 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.wbrawner.trainterval.Logger
|
||||
import com.wbrawner.trainterval.R
|
||||
import com.wbrawner.trainterval.model.IntervalTimerDao
|
||||
import kotlinx.android.synthetic.main.fragment_active_timer.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class ActiveTimerFragment : Fragment() {
|
||||
|
||||
private var coroutineScope: CoroutineScope? = null
|
||||
private val activeTimerViewModel: ActiveTimerViewModel by inject()
|
||||
private val activeTimerViewModel: ActiveTimerViewModel by activityViewModels()
|
||||
private val logger: Logger by inject(parameters = { parametersOf("ActiveTimerStore") })
|
||||
private val timerDao: IntervalTimerDao by inject()
|
||||
private var timerId: Long = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
timerId = requireArguments().getLong("timerId")
|
||||
timerId = requireArguments().getLong(EXTRA_TIMER_ID)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
|
@ -56,35 +62,46 @@ class ActiveTimerFragment : Fragment() {
|
|||
is IntervalTimerActiveState.ExitState -> findNavController().navigateUp()
|
||||
}
|
||||
})
|
||||
activeTimerViewModel.init(timerId)
|
||||
activeTimerViewModel.init(logger, timerDao, timerId)
|
||||
}
|
||||
skipPreviousButton.setOnClickListener {
|
||||
coroutineScope!!.launch {
|
||||
activeTimerViewModel.goBack()
|
||||
}
|
||||
activeTimerViewModel.goBack()
|
||||
}
|
||||
playPauseButton.setOnClickListener {
|
||||
coroutineScope!!.launch {
|
||||
activeTimerViewModel.toggleTimer()
|
||||
}
|
||||
activeTimerViewModel.toggleTimer()
|
||||
}
|
||||
skipNextButton.setOnClickListener {
|
||||
coroutineScope!!.launch {
|
||||
activeTimerViewModel.skipAhead()
|
||||
}
|
||||
activeTimerViewModel.skipAhead()
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderLoading() {
|
||||
progressBar.visibility = View.VISIBLE
|
||||
timerLayout.visibility = View.GONE
|
||||
timerLayout.referencedIds.forEach {
|
||||
view?.findViewById<View>(it)?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderTimer(state: IntervalTimerActiveState.TimerRunningState) {
|
||||
progressBar.visibility = View.GONE
|
||||
timerLayout.visibility = View.VISIBLE
|
||||
timerLayout.referencedIds.forEach {
|
||||
view?.findViewById<View>(it)?.visibility = View.VISIBLE
|
||||
}
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.title = state.timerName
|
||||
val backgroundColor = resources.getColor(state.timerBackground, context?.theme)
|
||||
timerBackground.setBackgroundColor(backgroundColor)
|
||||
playPauseButton.setImageDrawable(requireContext().getDrawable(state.playPauseIcon))
|
||||
timeRemaining.text = state.timeRemaining
|
||||
timerSets.text = getString(
|
||||
R.string.timer_sets_formatted,
|
||||
state.currentSet,
|
||||
state.totalSets
|
||||
)
|
||||
timerRounds.text = getString(
|
||||
R.string.timer_rounds_formatted,
|
||||
state.currentRound,
|
||||
state.totalRounds
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package com.wbrawner.trainterval.activetimer
|
||||
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.wbrawner.trainterval.Logger
|
||||
import com.wbrawner.trainterval.R
|
||||
import com.wbrawner.trainterval.activetimer.IntervalTimerActiveState.LoadingState
|
||||
|
@ -11,93 +13,83 @@ import com.wbrawner.trainterval.model.IntervalTimer
|
|||
import com.wbrawner.trainterval.model.IntervalTimerDao
|
||||
import com.wbrawner.trainterval.model.Phase
|
||||
import com.wbrawner.trainterval.toIntervalDuration
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ActiveTimerViewModel(
|
||||
private val logger: Logger,
|
||||
private val timerDao: IntervalTimerDao
|
||||
) : ViewModel() {
|
||||
class ActiveTimerViewModel : ViewModel() {
|
||||
val timerState: MutableLiveData<IntervalTimerActiveState> = MutableLiveData(LoadingState)
|
||||
private var timerJob: Job? = null
|
||||
private lateinit var timer: IntervalTimer
|
||||
private lateinit var logger: Logger
|
||||
private var timerComplete = false
|
||||
private var timerRunning = false
|
||||
private var currentPhase = Phase.WARM_UP
|
||||
private var currentSet = 1
|
||||
private var currentRound = 1
|
||||
private var timeRemaining: Long = 0
|
||||
|
||||
suspend fun init(timerId: Long) {
|
||||
logger.d(message = "Initializing with Timer id $timerId")
|
||||
timer = timerDao.getById(timerId)
|
||||
timeRemaining = timer.warmUpDuration
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timerRunning,
|
||||
timeRemaining.toIntervalDuration().toString(),
|
||||
currentSet,
|
||||
timer.sets,
|
||||
currentRound,
|
||||
timer.cycles
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun toggleTimer() {
|
||||
if (timerRunning) {
|
||||
timerJob?.cancel()
|
||||
timerRunning = false
|
||||
suspend fun init(
|
||||
logger: Logger,
|
||||
timerDao: IntervalTimerDao,
|
||||
timerId: Long
|
||||
) {
|
||||
this.logger = logger
|
||||
if (timerJob == null || timer.id != timerId) {
|
||||
logger.d(message = "Initializing with Timer id $timerId")
|
||||
timer = timerDao.getById(timerId)
|
||||
timeRemaining = timer.warmUpDuration
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timerRunning,
|
||||
timeRemaining.toIntervalDuration().toString(),
|
||||
timer,
|
||||
timeRemaining,
|
||||
currentSet,
|
||||
timer.sets,
|
||||
currentRound,
|
||||
timer.cycles
|
||||
currentPhase,
|
||||
timerJob != null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
startTimer()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun startTimer() {
|
||||
coroutineScope {
|
||||
timerJob = launch {
|
||||
timerRunning = true
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timerRunning,
|
||||
timeRemaining.toIntervalDuration().toString(),
|
||||
currentSet,
|
||||
timer.sets,
|
||||
currentRound,
|
||||
timer.cycles
|
||||
)
|
||||
fun toggleTimer() {
|
||||
if (timerJob != null) {
|
||||
timerJob?.cancel()
|
||||
timerJob = null
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timer,
|
||||
timeRemaining,
|
||||
currentSet,
|
||||
currentRound,
|
||||
currentPhase,
|
||||
timerJob != null
|
||||
)
|
||||
while (coroutineContext.isActive && timerRunning) {
|
||||
)
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
startTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startTimer() {
|
||||
viewModelScope.launch {
|
||||
timerJob = launch {
|
||||
updateTimer()
|
||||
while (coroutineContext.isActive && timerJob != null) {
|
||||
delay(1_000)
|
||||
timeRemaining -= 1_000
|
||||
if (timeRemaining <= 0) {
|
||||
goForward()
|
||||
}
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timerRunning,
|
||||
timeRemaining.toIntervalDuration().toString(),
|
||||
currentSet,
|
||||
timer.sets,
|
||||
currentRound,
|
||||
timer.cycles
|
||||
)
|
||||
)
|
||||
updateTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun skipAhead() {
|
||||
fun skipAhead() {
|
||||
timerJob?.cancel()
|
||||
when (currentPhase) {
|
||||
Phase.COOL_DOWN -> {
|
||||
|
@ -107,11 +99,26 @@ class ActiveTimerViewModel(
|
|||
goForward()
|
||||
}
|
||||
}
|
||||
if (timerRunning) {
|
||||
if (timerJob != null) {
|
||||
startTimer()
|
||||
} else {
|
||||
updateTimer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTimer() {
|
||||
timerState.postValue(
|
||||
TimerRunningState(
|
||||
timer,
|
||||
timeRemaining,
|
||||
currentSet,
|
||||
currentRound,
|
||||
currentPhase,
|
||||
timerJob != null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun goForward() {
|
||||
timerComplete = currentPhase == Phase.COOL_DOWN
|
||||
when (currentPhase) {
|
||||
|
@ -147,12 +154,14 @@ class ActiveTimerViewModel(
|
|||
timeRemaining = timer.lowIntensityDuration
|
||||
}
|
||||
Phase.COOL_DOWN -> {
|
||||
timerRunning = false
|
||||
timeRemaining = 0
|
||||
timerJob?.cancel()
|
||||
timerJob = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun goBack() {
|
||||
fun goBack() {
|
||||
timerJob?.cancel()
|
||||
when (currentPhase) {
|
||||
Phase.WARM_UP -> {
|
||||
|
@ -169,11 +178,11 @@ class ActiveTimerViewModel(
|
|||
timeRemaining = timer.restDuration
|
||||
}
|
||||
else -> {
|
||||
currentSet--
|
||||
currentPhase = Phase.HIGH_INTENSITY
|
||||
timeRemaining = timer.highIntensityDuration
|
||||
}
|
||||
}
|
||||
timeRemaining = timer.highIntensityDuration
|
||||
}
|
||||
Phase.HIGH_INTENSITY -> {
|
||||
currentPhase = Phase.LOW_INTENSITY
|
||||
|
@ -190,8 +199,10 @@ class ActiveTimerViewModel(
|
|||
timeRemaining = timer.highIntensityDuration
|
||||
}
|
||||
}
|
||||
if (timerRunning) {
|
||||
if (timerJob != null) {
|
||||
startTimer()
|
||||
} else {
|
||||
updateTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,14 +213,33 @@ class ActiveTimerViewModel(
|
|||
sealed class IntervalTimerActiveState {
|
||||
object LoadingState : IntervalTimerActiveState()
|
||||
class TimerRunningState(
|
||||
timerRunning: Boolean,
|
||||
val timerName: String,
|
||||
val timeRemaining: String,
|
||||
val currentSet: Int,
|
||||
val totalSets: Int,
|
||||
val currentRound: Int,
|
||||
val totalRounds: Int,
|
||||
val timerComplete: Boolean = false,
|
||||
@DrawableRes val playPauseIcon: Int = if (timerRunning) R.drawable.ic_pause else R.drawable.ic_play_arrow
|
||||
) : IntervalTimerActiveState()
|
||||
@ColorRes val timerBackground: Int,
|
||||
@DrawableRes val playPauseIcon: Int
|
||||
) : IntervalTimerActiveState() {
|
||||
constructor(
|
||||
timer: IntervalTimer,
|
||||
timeRemaining: Long,
|
||||
currentSet: Int,
|
||||
currentRound: Int,
|
||||
phase: Phase,
|
||||
timerRunning: Boolean
|
||||
) : this(
|
||||
timerName = timer.name,
|
||||
timeRemaining = timeRemaining.toIntervalDuration().toString(),
|
||||
currentSet = currentSet,
|
||||
currentRound = currentRound,
|
||||
totalSets = timer.sets,
|
||||
totalRounds = timer.cycles,
|
||||
timerBackground = phase.colorRes,
|
||||
playPauseIcon = if (timerRunning) R.drawable.ic_pause else R.drawable.ic_play_arrow
|
||||
)
|
||||
}
|
||||
|
||||
object ExitState : IntervalTimerActiveState()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.wbrawner.trainterval.model
|
||||
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.room.*
|
||||
import com.wbrawner.trainterval.R
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
@ -18,12 +20,12 @@ data class IntervalTimer(
|
|||
val cycles: Int = 1
|
||||
)
|
||||
|
||||
enum class Phase {
|
||||
WARM_UP,
|
||||
LOW_INTENSITY,
|
||||
HIGH_INTENSITY,
|
||||
REST,
|
||||
COOL_DOWN,
|
||||
enum class Phase(@ColorRes val colorRes: Int) {
|
||||
WARM_UP(R.color.colorSurface),
|
||||
LOW_INTENSITY(R.color.colorSurfaceLowIntensity),
|
||||
HIGH_INTENSITY(R.color.colorSurfaceHighIntensity),
|
||||
REST(R.color.colorSurfaceRest),
|
||||
COOL_DOWN(R.color.colorSurfaceCoolDown),
|
||||
}
|
||||
|
||||
@Dao
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.fragment.app.FragmentContainerView 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:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
app:defaultNavHost="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navGraph="@navigation/nav_graph"
|
||||
tools:context=".MainActivity" />
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<LinearLayout 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:id="@+id/timerBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:fitsSystemWindows="true"
|
||||
android:keepScreenOn="true"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.wbrawner.trainterval.activetimer.ActiveTimerFragment">
|
||||
|
||||
|
@ -12,82 +15,125 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#00000000"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:elevation="0dp"
|
||||
app:elevation="0dp">
|
||||
android:padding="16dp"
|
||||
app:elevation="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/background_rounded_corners"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
app:title="@string/app_name" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/timerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="playPauseButton,timerSets,timerRounds,timeRemaining,skipNextButton,skipPreviousButton" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timeRemaining"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline2"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="00:00" />
|
||||
<TextView
|
||||
android:id="@+id/timerSets"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/timerRounds"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="Set: 4/5" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/skipPreviousButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/skip_previous"
|
||||
android:src="@drawable/ic_skip_previous"
|
||||
app:layout_constraintEnd_toStartOf="@+id/playPauseButton"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining" />
|
||||
<TextView
|
||||
android:id="@+id/timerRounds"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/timerSets"
|
||||
tools:text="Round: 4/5" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/playPauseButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/start_timer"
|
||||
app:layout_constraintEnd_toStartOf="@+id/skipNextButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/skipPreviousButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining"
|
||||
tools:src="@drawable/ic_play_arrow" />
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/timerInfo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="top"
|
||||
app:constraint_referenced_ids="timerSets,timerRounds" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/skipNextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/skip_next"
|
||||
android:src="@drawable/ic_skip_next"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/playPauseButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<TextView
|
||||
android:id="@+id/timeRemaining"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline2"
|
||||
android:textColor="@color/colorOnSurface"
|
||||
app:layout_constraintBottom_toTopOf="@+id/playPauseButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="00:00" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/skipPreviousButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/skip_previous"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_skip_previous"
|
||||
app:layout_constraintBottom_toTopOf="@+id/timerInfo"
|
||||
app:layout_constraintEnd_toStartOf="@+id/playPauseButton"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/playPauseButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/start_timer"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toTopOf="@+id/timerInfo"
|
||||
app:layout_constraintEnd_toStartOf="@+id/skipNextButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/skipPreviousButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining"
|
||||
tools:src="@drawable/ic_play_arrow" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/skipNextButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:contentDescription="@string/skip_next"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_skip_next"
|
||||
app:layout_constraintBottom_toTopOf="@+id/timerInfo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/playPauseButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/timeRemaining"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:fillViewport="true"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="com.wbrawner.trainterval.timerform.TimerFormFragment">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
android:animateLayoutChanges="true"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.wbrawner.trainterval.timerlist.TimerListFragment">
|
||||
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#6200EE</color>
|
||||
<color name="colorPrimaryDark">#3700B3</color>
|
||||
<color name="colorAccent">#03DAC5</color>
|
||||
<color name="colorPrimary">#FFEB3B</color>
|
||||
<color name="colorPrimaryDark">#F9A825</color>
|
||||
<color name="colorAccent">#F57C00</color>
|
||||
<color name="colorOnSurface">#111111</color>
|
||||
<color name="colorSurface">#FFFFFF</color>
|
||||
<color name="colorSurfaceStroke">#F1F1F1</color>
|
||||
<color name="colorSurfaceWarmUp">@color/colorSurface</color>
|
||||
<color name="colorSurfaceLowIntensity">#F06292</color>
|
||||
<color name="colorSurfaceHighIntensity">#81C784</color>
|
||||
<color name="colorSurfaceRest">#FFF176</color>
|
||||
<color name="colorSurfaceCoolDown">#64B5F6</color>
|
||||
</resources>
|
||||
|
|
|
@ -18,4 +18,6 @@
|
|||
<string name="rest_duration">Rest Duration</string>
|
||||
<string name="title_item_list">Items</string>
|
||||
<string name="title_item_detail">Item Detail</string>
|
||||
<string name="timer_sets_formatted">Set: %1$d/%2$d</string>
|
||||
<string name="timer_rounds_formatted">Round: %1$d/%2$d</string>
|
||||
</resources>
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:statusBarColor">?android:windowBackground</item>
|
||||
<item name="statusBarBackground">?android:windowBackground</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar">
|
||||
|
|
Loading…
Reference in a new issue