Coverage Summary for Class: EditClickTrackViewModelImpl (com.vsevolodganin.clicktrack.edit)

Class Method, % Branch, % Line, % Instruction, %
EditClickTrackViewModelImpl 0% (0/32) 0% (0/8) 0% (0/53) 0% (0/546)
EditClickTrackViewModelImpl$1 0% (0/1) 0% (0/6) 0% (0/57)
EditClickTrackViewModelImpl$1$2 0% (0/1) 0% (0/1) 0% (0/6)
EditClickTrackViewModelImpl$1$invokeSuspend$$inlined$map$1 0% (0/2)
EditClickTrackViewModelImpl$1$invokeSuspend$$inlined$map$1$2 0% (0/1)
EditClickTrackViewModelImpl$1$invokeSuspend$$inlined$map$1$2$1
EditClickTrackViewModelImpl$onBackClick$$inlined$pop$default$1 0% (0/1)
EditClickTrackViewModelImpl$onBackClick$$inlined$pop$default$2 0% (0/1)
EditClickTrackViewModelImpl$onForwardClick$$inlined$replaceCurrent$default$1 0% (0/1)
EditClickTrackViewModelImpl$onForwardClick$$inlined$replaceCurrent$default$2 0% (0/1)
EditClickTrackViewModelImpl$special$$inlined$registerSaveStateFor$1 0% (0/1)
Total 0% (0/42) 0% (0/8) 0% (0/60) 0% (0/609)


 package com.vsevolodganin.clicktrack.edit
 
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.router.stack.pop
 import com.arkivanov.decompose.router.stack.replaceCurrent
 import com.vsevolodganin.clicktrack.ScreenConfiguration
 import com.vsevolodganin.clicktrack.ScreenStackNavigation
 import com.vsevolodganin.clicktrack.common.ClickTrackValidator
 import com.vsevolodganin.clicktrack.model.BeatsPerMinuteOffset
 import com.vsevolodganin.clicktrack.model.CueDuration
 import com.vsevolodganin.clicktrack.model.DefaultCue
 import com.vsevolodganin.clicktrack.model.NotePattern
 import com.vsevolodganin.clicktrack.model.TimeSignature
 import com.vsevolodganin.clicktrack.storage.ClickTrackRepository
 import com.vsevolodganin.clicktrack.utils.collection.immutable.move
 import com.vsevolodganin.clicktrack.utils.collection.immutable.remove
 import com.vsevolodganin.clicktrack.utils.collection.immutable.replace
 import com.vsevolodganin.clicktrack.utils.decompose.consumeSavedState
 import com.vsevolodganin.clicktrack.utils.decompose.coroutineScope
 import com.vsevolodganin.clicktrack.utils.decompose.registerSaveStateFor
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.flow.firstOrNull
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 import me.tatarka.inject.annotations.Assisted
 import me.tatarka.inject.annotations.Inject
 
 @Inject
 class EditClickTrackViewModelImpl(
     @Assisted componentContext: ComponentContext,
     @Assisted private val config: ScreenConfiguration.EditClickTrack,
     private val navigation: ScreenStackNavigation,
     private val clickTrackRepository: ClickTrackRepository,
     private val clickTrackValidator: ClickTrackValidator,
 ) : EditClickTrackViewModel, ComponentContext by componentContext {
     private val scope = coroutineScope()
     private val _state: MutableStateFlow<EditClickTrackState?> = MutableStateFlow(consumeSavedState())
 
     override val state: StateFlow<EditClickTrackState?> = _state
 
     init {
         registerSaveStateFor(state)
 
         scope.launch {
             _state.value = clickTrackRepository.getById(config.id)
                 .map { it?.toEditState(showForwardButton = config.isInitialEdit) }
                 .firstOrNull()
 
             _state
                 .drop(1)
                 .collectLatest(::onEditStateChange)
         }
     }
 
     override fun onBackClick() = navigation.pop()
 
     override fun onForwardClick() = navigation.replaceCurrent(ScreenConfiguration.PlayClickTrack(config.id))
 
     override fun onNameChange(name: String) = reduceState {
         copy(name = name)
     }
 
     override fun onLoopChange(loop: Boolean) = reduceState {
         copy(loop = loop)
     }
 
     override fun onTempoOffsetChange(offset: Int) = reduceState {
         copy(tempoOffset = BeatsPerMinuteOffset(offset))
     }
 
     override fun onAddNewCueClick() = reduceState {
         copy(cues = cues + DefaultCue.toEditState(index = cues.size))
     }
 
     override fun onCueRemove(index: Int) = reduceState {
         copy(cues = cues.remove(index))
     }
 
     override fun onCueNameChange(index: Int, name: String) = reduceState {
         copy(cues = cues.replace(index) { it.copy(name = name) })
     }
 
     override fun onCueBpmChange(index: Int, bpm: Int) = reduceState {
         copy(cues = cues.replace(index) { it.copy(bpm = bpm) })
     }
 
     override fun onCueTimeSignatureChange(index: Int, timeSignature: TimeSignature) = reduceState {
         copy(cues = cues.replace(index) { it.copy(timeSignature = timeSignature) })
     }
 
     override fun onCueDurationChange(index: Int, duration: CueDuration) = reduceState {
         copy(
             cues = cues.replace(index) {
                 when (duration) {
                     is CueDuration.Beats -> it.copy(beats = duration)
                     is CueDuration.Measures -> it.copy(measures = duration)
                     is CueDuration.Time -> it.copy(time = duration)
                 }
             },
         )
     }
 
     override fun onCueDurationTypeChange(index: Int, durationType: CueDuration.Type) = reduceState {
         copy(cues = cues.replace(index) { it.copy(activeDurationType = durationType) })
     }
 
     override fun onCuePatternChange(index: Int, pattern: NotePattern) = reduceState {
         copy(cues = cues.replace(index) { it.copy(pattern = pattern) })
     }
 
     private fun onEditStateChange(editState: EditClickTrackState?) {
         editState ?: return
 
         val validationResult = clickTrackValidator.validate(editState)
 
         clickTrackRepository.update(editState.id, validationResult.validClickTrack)
 
         reduceState {
             copy(
                 cues = cues.mapIndexed { index, cue ->
                     cue.copy(errors = validationResult.cueValidationResults[index].errors)
                 },
             )
         }
     }
 
     override fun onItemMoveFinished() {
         reduceState {
             copy(cues = cues.mapIndexed { index, cue -> cue.copy(displayPosition = (index + 1).toString()) })
         }
     }
 
     override fun onItemMove(from: Int, to: Int) {
         reduceState { copy(cues = cues.move(from, to)) }
     }
 
     private fun reduceState(reduce: EditClickTrackState.() -> EditClickTrackState) {
         _state.update { it?.reduce() }
     }
 }