Refactor the RibbonViewModels to add an abstraction layer
This commit is contained in:
		
							parent
							
								
									27dba5438e
								
							
						
					
					
						commit
						a59444c610
					
				
					 3 changed files with 148 additions and 199 deletions
				
			
		| 
						 | 
					@ -0,0 +1,122 @@
 | 
				
			||||||
 | 
					package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.compose.runtime.Composable
 | 
				
			||||||
 | 
					import androidx.compose.runtime.LaunchedEffect
 | 
				
			||||||
 | 
					import androidx.compose.runtime.MutableState
 | 
				
			||||||
 | 
					import androidx.compose.runtime.Stable
 | 
				
			||||||
 | 
					import androidx.compose.runtime.State
 | 
				
			||||||
 | 
					import androidx.compose.runtime.mutableStateOf
 | 
				
			||||||
 | 
					import androidx.lifecycle.ViewModel
 | 
				
			||||||
 | 
					import androidx.lifecycle.viewModelScope
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitRollUio
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitUio
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterRibbonFactory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance
 | 
				
			||||||
 | 
					import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.SharingStarted
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.StateFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.combine
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.flatMapMerge
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.flowOf
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.launchIn
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.stateIn
 | 
				
			||||||
 | 
					import java.text.Collator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class CharacterRibbonViewModel(
 | 
				
			||||||
 | 
					    private val rollHistoryRepository: RollHistoryRepository,
 | 
				
			||||||
 | 
					    private val settingsRepository: SettingsRepository,
 | 
				
			||||||
 | 
					    characterRepository: CharacterSheetRepository,
 | 
				
			||||||
 | 
					    alterationRepository: AlterationRepository,
 | 
				
			||||||
 | 
					    campaignRepository: CampaignRepository,
 | 
				
			||||||
 | 
					    private val ribbonFactory: CharacterRibbonFactory,
 | 
				
			||||||
 | 
					) : ViewModel() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val rolls = hashMapOf<CharacterInstance.Id, MutableState<CharacterPortraitRollUio?>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract val Campaign.data: Map<CharacterInstance.Id, CharacterInstance>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This flow is a tad complex so there is an explanation of wtf it's about :
 | 
				
			||||||
 | 
					     * On a campaign update it go through every element of the abstract [data] map and either:
 | 
				
			||||||
 | 
					     * - build and flow of an empty list to handle the case where the map is empty.
 | 
				
			||||||
 | 
					     * - build a flow of flow bind to each character & alteration to update portrait details.
 | 
				
			||||||
 | 
					     * Then sort the result.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @OptIn(ExperimentalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    val characters: StateFlow<List<CharacterPortraitUio>> = campaignRepository.campaignFlow
 | 
				
			||||||
 | 
					        .flatMapMerge { campaign ->
 | 
				
			||||||
 | 
					            when (campaign.data.isEmpty()) {
 | 
				
			||||||
 | 
					                true -> flowOf(emptyList())
 | 
				
			||||||
 | 
					                else -> combine<CharacterPortraitUio?, List<CharacterPortraitUio>>(
 | 
				
			||||||
 | 
					                    flows = campaign.data.map { entry ->
 | 
				
			||||||
 | 
					                        combine(
 | 
				
			||||||
 | 
					                            characterRepository.characterDetailFlow(characterSheetId = entry.key.characterSheetId),
 | 
				
			||||||
 | 
					                            alterationRepository.alterationsFlow(characterInstanceId = entry.key),
 | 
				
			||||||
 | 
					                        ) { sheet, alterations ->
 | 
				
			||||||
 | 
					                            ribbonFactory.convertToPlayerPortraitUio(
 | 
				
			||||||
 | 
					                                characterSheet = sheet,
 | 
				
			||||||
 | 
					                                alterations = alterations,
 | 
				
			||||||
 | 
					                                characterInstanceId = entry.key,
 | 
				
			||||||
 | 
					                                characterInstance = entry.value,
 | 
				
			||||||
 | 
					                                enableDetail = settingsRepository.settings().isGM,
 | 
				
			||||||
 | 
					                                displayCharacterStats = settingsRepository.settings().isGM,
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    transform = { headers ->
 | 
				
			||||||
 | 
					                        headers.mapNotNull { it }
 | 
				
			||||||
 | 
					                            .sortedWith(compareBy(Collator.getInstance()) { it.name })
 | 
				
			||||||
 | 
					                            .toList()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .stateIn(
 | 
				
			||||||
 | 
					            scope = viewModelScope,
 | 
				
			||||||
 | 
					            started = SharingStarted.Eagerly,
 | 
				
			||||||
 | 
					            initialValue = emptyList()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Composable
 | 
				
			||||||
 | 
					    @Stable
 | 
				
			||||||
 | 
					    fun roll(
 | 
				
			||||||
 | 
					        characterId: CharacterInstance.Id,
 | 
				
			||||||
 | 
					    ): State<CharacterPortraitRollUio?> {
 | 
				
			||||||
 | 
					        val state = rolls.getOrPut(characterId) { mutableStateOf(null) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LaunchedEffect(characterId) {
 | 
				
			||||||
 | 
					            combine(
 | 
				
			||||||
 | 
					                settingsRepository.settingsFlow(),
 | 
				
			||||||
 | 
					                rollHistoryRepository.rolls,
 | 
				
			||||||
 | 
					            ) { settings, roll ->
 | 
				
			||||||
 | 
					                if (settings.dynamicDice &&
 | 
				
			||||||
 | 
					                    characterId.equals(roll.prefix, roll.characterSheetId, roll.instanceId)
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
 | 
					                    state.value = CharacterPortraitRollUio(
 | 
				
			||||||
 | 
					                        characterId = CharacterInstance.Id(
 | 
				
			||||||
 | 
					                            prefix = characterId.prefix,
 | 
				
			||||||
 | 
					                            characterSheetId = characterId.characterSheetId,
 | 
				
			||||||
 | 
					                            instanceId = characterId.instanceId,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        value = roll.rollValue,
 | 
				
			||||||
 | 
					                        label = roll.resultLabel?.split(" ")?.joinToString(separator = "\n") { it }
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }.launchIn(this)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return state
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun onPortraitRollRightClick(
 | 
				
			||||||
 | 
					        characterId: CharacterInstance.Id,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        rolls[characterId]?.value = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,114 +1,28 @@
 | 
				
			||||||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.npc
 | 
					package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.npc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import androidx.compose.runtime.Composable
 | 
					 | 
				
			||||||
import androidx.compose.runtime.LaunchedEffect
 | 
					 | 
				
			||||||
import androidx.compose.runtime.MutableState
 | 
					 | 
				
			||||||
import androidx.compose.runtime.Stable
 | 
					 | 
				
			||||||
import androidx.compose.runtime.State
 | 
					 | 
				
			||||||
import androidx.compose.runtime.mutableStateOf
 | 
					 | 
				
			||||||
import androidx.lifecycle.ViewModel
 | 
					 | 
				
			||||||
import androidx.lifecycle.viewModelScope
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
					import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
 | 
					import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
					import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
 | 
					import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
 | 
					import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitRollUio
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitUio
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterRibbonFactory
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterRibbonFactory
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.CharacterRibbonViewModel
 | 
				
			||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
					import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
				
			||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.SharingStarted
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.StateFlow
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.combine
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.flatMapMerge
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.flowOf
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.launchIn
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.stateIn
 | 
					 | 
				
			||||||
import java.text.Collator
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private typealias CharacterId = Campaign.CharacterInstance.Id
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NpcRibbonViewModel(
 | 
					class NpcRibbonViewModel(
 | 
				
			||||||
    private val rollHistoryRepository: RollHistoryRepository,
 | 
					    rollHistoryRepository: RollHistoryRepository,
 | 
				
			||||||
    private val settingsRepository: SettingsRepository,
 | 
					    settingsRepository: SettingsRepository,
 | 
				
			||||||
    characterRepository: CharacterSheetRepository,
 | 
					    characterRepository: CharacterSheetRepository,
 | 
				
			||||||
    alterationRepository: AlterationRepository,
 | 
					    alterationRepository: AlterationRepository,
 | 
				
			||||||
    campaignRepository: CampaignRepository,
 | 
					    campaignRepository: CampaignRepository,
 | 
				
			||||||
    private val ribbonFactory: CharacterRibbonFactory,
 | 
					    ribbonFactory: CharacterRibbonFactory,
 | 
				
			||||||
) : ViewModel() {
 | 
					) : CharacterRibbonViewModel(
 | 
				
			||||||
    private val rolls = hashMapOf<CharacterId, MutableState<CharacterPortraitRollUio?>>()
 | 
					    rollHistoryRepository = rollHistoryRepository,
 | 
				
			||||||
 | 
					    settingsRepository = settingsRepository,
 | 
				
			||||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
					    characterRepository = characterRepository,
 | 
				
			||||||
    val characters: StateFlow<List<CharacterPortraitUio>> = campaignRepository.campaignFlow
 | 
					    alterationRepository = alterationRepository,
 | 
				
			||||||
        .flatMapMerge { campaign ->
 | 
					    campaignRepository = campaignRepository,
 | 
				
			||||||
            if (campaign.npcs.isEmpty()) {
 | 
					    ribbonFactory = ribbonFactory,
 | 
				
			||||||
                flowOf(emptyList())
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                combine<CharacterPortraitUio?, List<CharacterPortraitUio>>(
 | 
					 | 
				
			||||||
                    flows = campaign.npcs.map { entry ->
 | 
					 | 
				
			||||||
                        combine(
 | 
					 | 
				
			||||||
                            characterRepository.characterDetailFlow(characterSheetId = entry.key.characterSheetId),
 | 
					 | 
				
			||||||
                            alterationRepository.alterationsFlow(characterInstanceId = entry.key),
 | 
					 | 
				
			||||||
                        ) { sheet, alterations ->
 | 
					 | 
				
			||||||
                            ribbonFactory.convertToPlayerPortraitUio(
 | 
					 | 
				
			||||||
                                characterSheet = sheet,
 | 
					 | 
				
			||||||
                                alterations = alterations,
 | 
					 | 
				
			||||||
                                characterInstanceId = entry.key,
 | 
					 | 
				
			||||||
                                characterInstance = entry.value,
 | 
					 | 
				
			||||||
                                enableDetail = settingsRepository.settings().isGM,
 | 
					 | 
				
			||||||
                                displayCharacterStats = settingsRepository.settings().isGM,
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    transform = { headers ->
 | 
					 | 
				
			||||||
                        headers.mapNotNull { it }
 | 
					 | 
				
			||||||
                            .sortedWith(compareBy(Collator.getInstance()) { it.name })
 | 
					 | 
				
			||||||
                            .toList()
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .stateIn(
 | 
					 | 
				
			||||||
            scope = viewModelScope,
 | 
					 | 
				
			||||||
            started = SharingStarted.Eagerly,
 | 
					 | 
				
			||||||
            initialValue = emptyList()
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Composable
 | 
					 | 
				
			||||||
    @Stable
 | 
					 | 
				
			||||||
    fun roll(
 | 
					 | 
				
			||||||
        characterId: Campaign.CharacterInstance.Id,
 | 
					 | 
				
			||||||
    ): State<CharacterPortraitRollUio?> {
 | 
					 | 
				
			||||||
        val state = rolls.getOrPut(characterId) { mutableStateOf(null) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        LaunchedEffect(characterId) {
 | 
					 | 
				
			||||||
            combine(
 | 
					 | 
				
			||||||
                settingsRepository.settingsFlow(),
 | 
					 | 
				
			||||||
                rollHistoryRepository.rolls,
 | 
					 | 
				
			||||||
            ) { settings, roll ->
 | 
					 | 
				
			||||||
                if (settings.dynamicDice &&
 | 
					 | 
				
			||||||
                    characterId.equals(roll.prefix, roll.characterSheetId, roll.instanceId)
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
                    state.value = CharacterPortraitRollUio(
 | 
					    override val Campaign.data get() = npcs
 | 
				
			||||||
                        characterId = Campaign.CharacterInstance.Id(
 | 
					 | 
				
			||||||
                            prefix = characterId.prefix,
 | 
					 | 
				
			||||||
                            characterSheetId = characterId.characterSheetId,
 | 
					 | 
				
			||||||
                            instanceId = characterId.instanceId,
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                        value = roll.rollValue,
 | 
					 | 
				
			||||||
                        label = roll.resultLabel?.split(" ")?.joinToString(separator = "\n") { it }
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }.launchIn(this)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return state
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun onPortraitRollRightClick(
 | 
					 | 
				
			||||||
        characterId: Campaign.CharacterInstance.Id,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        rolls[characterId]?.value = null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,115 +1,28 @@
 | 
				
			||||||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.player
 | 
					package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.player
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import androidx.compose.runtime.Composable
 | 
					 | 
				
			||||||
import androidx.compose.runtime.LaunchedEffect
 | 
					 | 
				
			||||||
import androidx.compose.runtime.MutableState
 | 
					 | 
				
			||||||
import androidx.compose.runtime.Stable
 | 
					 | 
				
			||||||
import androidx.compose.runtime.State
 | 
					 | 
				
			||||||
import androidx.compose.runtime.mutableStateOf
 | 
					 | 
				
			||||||
import androidx.lifecycle.ViewModel
 | 
					 | 
				
			||||||
import androidx.lifecycle.viewModelScope
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
					import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
 | 
					import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
					import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
 | 
					import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
 | 
					import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitRollUio
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitUio
 | 
					 | 
				
			||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterRibbonFactory
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterRibbonFactory
 | 
				
			||||||
 | 
					import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.CharacterRibbonViewModel
 | 
				
			||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
					import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
				
			||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.SharingStarted
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.StateFlow
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.combine
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.flatMapMerge
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.flowOf
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.launchIn
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.stateIn
 | 
					 | 
				
			||||||
import java.text.Collator
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private typealias CharacterId = Campaign.CharacterInstance.Id
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PlayerRibbonViewModel(
 | 
					class PlayerRibbonViewModel(
 | 
				
			||||||
    private val rollHistoryRepository: RollHistoryRepository,
 | 
					    rollHistoryRepository: RollHistoryRepository,
 | 
				
			||||||
    private val settingsRepository: SettingsRepository,
 | 
					    settingsRepository: SettingsRepository,
 | 
				
			||||||
    characterRepository: CharacterSheetRepository,
 | 
					    characterRepository: CharacterSheetRepository,
 | 
				
			||||||
    alterationRepository: AlterationRepository,
 | 
					    alterationRepository: AlterationRepository,
 | 
				
			||||||
    campaignRepository: CampaignRepository,
 | 
					    campaignRepository: CampaignRepository,
 | 
				
			||||||
    private val ribbonFactory: CharacterRibbonFactory,
 | 
					    ribbonFactory: CharacterRibbonFactory,
 | 
				
			||||||
) : ViewModel() {
 | 
					) : CharacterRibbonViewModel(
 | 
				
			||||||
 | 
					    rollHistoryRepository = rollHistoryRepository,
 | 
				
			||||||
    private val rolls = hashMapOf<CharacterId, MutableState<CharacterPortraitRollUio?>>()
 | 
					    settingsRepository = settingsRepository,
 | 
				
			||||||
 | 
					    characterRepository = characterRepository,
 | 
				
			||||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
					    alterationRepository = alterationRepository,
 | 
				
			||||||
    val characters: StateFlow<List<CharacterPortraitUio>> = campaignRepository.campaignFlow
 | 
					    campaignRepository = campaignRepository,
 | 
				
			||||||
        .flatMapMerge { campaign ->
 | 
					    ribbonFactory = ribbonFactory,
 | 
				
			||||||
            if (campaign.characters.isEmpty()) {
 | 
					 | 
				
			||||||
                flowOf(emptyList())
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                combine<CharacterPortraitUio?, List<CharacterPortraitUio>>(
 | 
					 | 
				
			||||||
                    flows = campaign.characters.map { entry ->
 | 
					 | 
				
			||||||
                        combine(
 | 
					 | 
				
			||||||
                            characterRepository.characterDetailFlow(characterSheetId = entry.key.characterSheetId),
 | 
					 | 
				
			||||||
                            alterationRepository.alterationsFlow(characterInstanceId = entry.key),
 | 
					 | 
				
			||||||
                        ) { sheet, alterations ->
 | 
					 | 
				
			||||||
                            ribbonFactory.convertToPlayerPortraitUio(
 | 
					 | 
				
			||||||
                                characterSheet = sheet,
 | 
					 | 
				
			||||||
                                alterations = alterations,
 | 
					 | 
				
			||||||
                                characterInstanceId = entry.key,
 | 
					 | 
				
			||||||
                                characterInstance = entry.value,
 | 
					 | 
				
			||||||
                                enableDetail = true,
 | 
					 | 
				
			||||||
                                displayCharacterStats = true,
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    transform = { headers ->
 | 
					 | 
				
			||||||
                        headers.mapNotNull { it }
 | 
					 | 
				
			||||||
                            .sortedWith(compareBy(Collator.getInstance()) { it.name })
 | 
					 | 
				
			||||||
                            .toList()
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .stateIn(
 | 
					 | 
				
			||||||
            scope = viewModelScope,
 | 
					 | 
				
			||||||
            started = SharingStarted.Eagerly,
 | 
					 | 
				
			||||||
            initialValue = emptyList()
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Composable
 | 
					 | 
				
			||||||
    @Stable
 | 
					 | 
				
			||||||
    fun roll(
 | 
					 | 
				
			||||||
        characterId: Campaign.CharacterInstance.Id,
 | 
					 | 
				
			||||||
    ): State<CharacterPortraitRollUio?> {
 | 
					 | 
				
			||||||
        val state = rolls.getOrPut(characterId) { mutableStateOf(null) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        LaunchedEffect(characterId) {
 | 
					 | 
				
			||||||
            combine(
 | 
					 | 
				
			||||||
                settingsRepository.settingsFlow(),
 | 
					 | 
				
			||||||
                rollHistoryRepository.rolls,
 | 
					 | 
				
			||||||
            ) { settings, roll ->
 | 
					 | 
				
			||||||
                if (settings.dynamicDice &&
 | 
					 | 
				
			||||||
                    characterId.equals(roll.prefix, roll.characterSheetId, roll.instanceId)
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
                    state.value = CharacterPortraitRollUio(
 | 
					    override val Campaign.data get() = characters
 | 
				
			||||||
                        characterId = Campaign.CharacterInstance.Id(
 | 
					 | 
				
			||||||
                            prefix = characterId.prefix,
 | 
					 | 
				
			||||||
                            characterSheetId = characterId.characterSheetId,
 | 
					 | 
				
			||||||
                            instanceId = characterId.instanceId,
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                        value = roll.rollValue,
 | 
					 | 
				
			||||||
                        label = roll.resultLabel?.split(" ")?.joinToString(separator = "\n") { it }
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }.launchIn(this)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return state
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun onPortraitRollRightClick(
 | 
					 | 
				
			||||||
        characterId: Campaign.CharacterInstance.Id,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        rolls[characterId]?.value = null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue