Coverage Summary for Class: MetronomeViewModelImpl (com.vsevolodganin.clicktrack.metronome)

Class Method, % Branch, % Line, % Instruction, %
MetronomeViewModelImpl 0% (0/9) 0% (0/8) 0% (0/33) 0% (0/163)
MetronomeViewModelImpl$1 0% (0/1) 0% (0/4) 0% (0/7) 0% (0/31)
MetronomeViewModelImpl$onBackClick$$inlined$pop$default$1 0% (0/1)
MetronomeViewModelImpl$onBackClick$$inlined$pop$default$2 0% (0/1)
MetronomeViewModelImpl$special$$inlined$registerSaveStateFor$1 0% (0/1)
Total 0% (0/13) 0% (0/12) 0% (0/40) 0% (0/194)


 package com.vsevolodganin.clicktrack.metronome
 
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.router.stack.pop
 import com.vsevolodganin.clicktrack.ScreenStackNavigation
 import com.vsevolodganin.clicktrack.model.BeatsPerMinuteOffset
 import com.vsevolodganin.clicktrack.model.ClickTrackId
 import com.vsevolodganin.clicktrack.model.NotePattern
 import com.vsevolodganin.clicktrack.player.PlayerServiceAccess
 import com.vsevolodganin.clicktrack.storage.UserPreferencesRepository
 import com.vsevolodganin.clicktrack.utils.decompose.consumeSavedState
 import com.vsevolodganin.clicktrack.utils.decompose.coroutineScope
 import com.vsevolodganin.clicktrack.utils.decompose.registerSaveStateFor
 import com.vsevolodganin.clicktrack.utils.grabIf
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.flow.update
 import me.tatarka.inject.annotations.Assisted
 import me.tatarka.inject.annotations.Inject
 
 @Inject
 class MetronomeViewModelImpl(
     @Assisted componentContext: ComponentContext,
     private val navigation: ScreenStackNavigation,
     private val userPreferences: UserPreferencesRepository,
     private val playerServiceAccess: PlayerServiceAccess,
     private val bpmMeter: BpmMeter,
 ) : MetronomeViewModel, ComponentContext by componentContext {
     private val scope = coroutineScope()
 
     private val areOptionsExpanded: MutableStateFlow<Boolean>
 
     override val state: StateFlow<MetronomeState?>
 
     init {
         val initialState: MetronomeState? = consumeSavedState()
 
         areOptionsExpanded = MutableStateFlow(initialState?.areOptionsExpanded ?: false)
 
         state = combine(
             areOptionsExpanded,
             userPreferences.metronomeBpm.flow,
             userPreferences.metronomePattern.flow,
             playerServiceAccess.playbackState(),
         ) { areOptionsExpanded, bpm, pattern, playbackState ->
             val isPlaying = playbackState?.id is ClickTrackId.Builtin.Metronome
             MetronomeState(
                 bpm = bpm,
                 pattern = pattern,
                 isPlaying = isPlaying,
                 progress = grabIf(isPlaying) { playbackState?.progress },
                 areOptionsExpanded = areOptionsExpanded,
             )
         }.stateIn(scope, SharingStarted.Eagerly, initialState)
 
         registerSaveStateFor(state)
     }
 
     override fun onBackClick() = navigation.pop()
 
     override fun onToggleOptions() {
         areOptionsExpanded.update { !it }
     }
 
     override fun onOptionsExpandedChange(isOpened: Boolean) {
         areOptionsExpanded.value = isOpened
     }
 
     override fun onPatternChoose(pattern: NotePattern) {
         userPreferences.metronomePattern.value = pattern
         areOptionsExpanded.value = false
     }
 
     override fun onBpmChange(bpmDiff: BeatsPerMinuteOffset) {
         userPreferences.metronomeBpm.edit { it + bpmDiff }
     }
 
     override fun onTogglePlay() {
         val state = state.value ?: return
         if (state.isPlaying) {
             playerServiceAccess.stop()
         } else {
             playerServiceAccess.start(ClickTrackId.Builtin.Metronome)
         }
     }
 
     override fun onBpmMeterClick() {
         bpmMeter.addTap()
         bpmMeter.calculateBpm()?.let { newBpm ->
             userPreferences.metronomeBpm.value = newBpm
         }
     }
 }