Change the roll bahavior (state to shared) after levelup.
This commit is contained in:
parent
03dbd7aad6
commit
db98fbede7
5 changed files with 84 additions and 52 deletions
|
|
@ -2,6 +2,7 @@ package com.pixelized.desktop.lwa.repository.resources
|
|||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import com.pixelized.desktop.lwa.ui.composable.image.ImagerModelConverter
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.readRawBytes
|
||||
|
|
@ -9,15 +10,17 @@ import org.jetbrains.skia.Image
|
|||
|
||||
class ImageResourcesRepository(
|
||||
private val httpClient: HttpClient,
|
||||
private val googleImageConverter: ImagerModelConverter,
|
||||
) {
|
||||
suspend fun load(url: String): ImageBitmap {
|
||||
try {
|
||||
val byteArray = httpClient.get(url).readRawBytes()
|
||||
val unwrapUri = googleImageConverter.unwrap(model = url)
|
||||
val byteArray = httpClient.get(unwrapUri).readRawBytes()
|
||||
val skiaImage = Image.makeFromEncoded(byteArray)
|
||||
return skiaImage.toComposeImageBitmap()
|
||||
} catch (_: Exception) {
|
||||
// TODO proper exception handling (error bus ?)
|
||||
return ImageBitmap(width = 0, height = 0)
|
||||
return ImageBitmap(width = 1, height = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,17 @@ class ImagerModelConverter {
|
|||
model: Any?,
|
||||
): Any? {
|
||||
return when (model) {
|
||||
is String -> googleDriveUrlRegex.find(model)?.let {
|
||||
val id = it.groupValues.getOrNull(1)
|
||||
"$workingGoogleDriveUri$id"
|
||||
} ?: model
|
||||
is String -> unwrap(model = model)
|
||||
else -> model
|
||||
}
|
||||
}
|
||||
|
||||
fun unwrap(
|
||||
model: String,
|
||||
): String {
|
||||
return googleDriveUrlRegex.find(model)?.let {
|
||||
val id = it.groupValues.getOrNull(1)
|
||||
"$workingGoogleDriveUri$id"
|
||||
} ?: model
|
||||
}
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ fun CharacterRibbon(
|
|||
)
|
||||
}
|
||||
CharacterRibbonRoll(
|
||||
value = viewModel.roll(characterSheetId = it.characterSheetId).value,
|
||||
roll = viewModel.roll(characterSheetId = it.characterSheetId),
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = it.levelUp,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon
|
||||
|
||||
import androidx.compose.material.MaterialTheme
|
||||
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.compose.runtime.remember
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
|
|
@ -18,17 +11,18 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
|||
import com.pixelized.desktop.lwa.repository.settings.model.Settings
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.common.CharacterRibbonRollUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.common.CharacterRibbonUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.protocol.websocket.RollEvent.Critical
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import java.text.Collator
|
||||
|
||||
|
|
@ -41,7 +35,7 @@ abstract class CharacterRibbonViewModel(
|
|||
private val ribbonFactory: CharacterRibbonFactory,
|
||||
) : ViewModel() {
|
||||
|
||||
private val rolls = hashMapOf<String, MutableState<CharacterRibbonRollUio?>>()
|
||||
private val rollFlowCache = hashMapOf<String, SharedFlow<CharacterRibbonRollUio?>>()
|
||||
|
||||
abstract fun fetch(
|
||||
campaign: Campaign,
|
||||
|
|
@ -119,40 +113,35 @@ abstract class CharacterRibbonViewModel(
|
|||
.getOrNull(index)
|
||||
?.characterSheetId
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun roll(
|
||||
characterSheetId: String,
|
||||
): State<CharacterRibbonRollUio?> {
|
||||
val colorScheme = MaterialTheme.lwa.colorScheme
|
||||
val state = remember(characterSheetId) {
|
||||
rolls.getOrPut(characterSheetId) { mutableStateOf(null) }
|
||||
}
|
||||
|
||||
LaunchedEffect(characterSheetId) {
|
||||
): SharedFlow<CharacterRibbonRollUio?> {
|
||||
return rollFlowCache.getOrPut(key = characterSheetId) {
|
||||
combine(
|
||||
settingsRepository.settingsFlow(),
|
||||
rollHistoryRepository.rolls(),
|
||||
rollHistoryRepository.rolls().filter { it.characterSheetId == characterSheetId },
|
||||
) { settings, roll ->
|
||||
if (settings.portrait.dynamicDice && characterSheetId == roll.characterSheetId) {
|
||||
state.value = CharacterRibbonRollUio(
|
||||
if (settings.portrait.dynamicDice.not()) return@combine null
|
||||
|
||||
CharacterRibbonRollUio(
|
||||
rollId = roll.uuid,
|
||||
hideDelay = settings.portrait.dynamicDiceDelay,
|
||||
characterSheetId = characterSheetId,
|
||||
value = roll.rollValue,
|
||||
tint = when (roll.critical) {
|
||||
Critical.CRITICAL_SUCCESS -> colorScheme.portrait.criticalSuccess
|
||||
Critical.SPECIAL_SUCCESS -> colorScheme.portrait.spacialSuccess
|
||||
Critical.SUCCESS -> colorScheme.portrait.success
|
||||
Critical.FAILURE -> colorScheme.portrait.failure
|
||||
Critical.CRITICAL_FAILURE -> colorScheme.portrait.criticalFailure
|
||||
null -> colorScheme.portrait.default
|
||||
critical = when (roll.critical) {
|
||||
Critical.CRITICAL_SUCCESS -> CharacterRibbonRollUio.Critical.CRITICAL_SUCCESS
|
||||
Critical.SPECIAL_SUCCESS -> CharacterRibbonRollUio.Critical.SPECIAL_SUCCESS
|
||||
Critical.SUCCESS -> CharacterRibbonRollUio.Critical.SUCCESS
|
||||
Critical.FAILURE -> CharacterRibbonRollUio.Critical.FAILURE
|
||||
Critical.CRITICAL_FAILURE -> CharacterRibbonRollUio.Critical.CRITICAL_FAILURE
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
}
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
return state
|
||||
}.shareIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,16 +23,19 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.saveable.SaverScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.pixelized.desktop.lwa.ui.theme.color.LwaColors
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
|
||||
|
|
@ -45,8 +48,17 @@ data class CharacterRibbonRollUio(
|
|||
val hideDelay: Int,
|
||||
val characterSheetId: String,
|
||||
val value: Int?,
|
||||
val tint: Color?,
|
||||
)
|
||||
val critical: Critical?,
|
||||
) {
|
||||
@Stable
|
||||
enum class Critical {
|
||||
CRITICAL_SUCCESS,
|
||||
SPECIAL_SUCCESS,
|
||||
SUCCESS,
|
||||
FAILURE,
|
||||
CRITICAL_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class CharacterRibbonRollAnimation(
|
||||
|
|
@ -87,14 +99,30 @@ class CharacterRibbonRollAnimation(
|
|||
fun CharacterRibbonRoll(
|
||||
modifier: Modifier = Modifier,
|
||||
size: DpSize = MaterialTheme.lwa.dimen.portrait.minimized,
|
||||
value: CharacterRibbonRollUio?,
|
||||
roll: Flow<CharacterRibbonRollUio?>,
|
||||
) {
|
||||
val rollValue = roll.collectAsStateWithLifecycle(initialValue = null)
|
||||
|
||||
CharacterRibbonRoll(
|
||||
modifier = modifier,
|
||||
size = size,
|
||||
roll = rollValue,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterRibbonRoll(
|
||||
modifier: Modifier = Modifier,
|
||||
size: DpSize = MaterialTheme.lwa.dimen.portrait.minimized,
|
||||
portrait: LwaColors.Portrait = MaterialTheme.lwa.colorScheme.portrait,
|
||||
roll: State<CharacterRibbonRollUio?>,
|
||||
) {
|
||||
AnimatedContent(
|
||||
modifier = modifier
|
||||
.width(width = size.width)
|
||||
.aspectRatio(ratio = 1f)
|
||||
.graphicsLayer { clip = false },
|
||||
targetState = value,
|
||||
targetState = roll.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn()
|
||||
val exit = fadeOut()
|
||||
|
|
@ -106,9 +134,15 @@ fun CharacterRibbonRoll(
|
|||
rollDelay = it?.hideDelay ?: 1000,
|
||||
)
|
||||
val color = animateColorAsState(
|
||||
targetValue = it?.tint ?: Color.Transparent,
|
||||
targetValue = when (it?.critical) {
|
||||
CharacterRibbonRollUio.Critical.CRITICAL_SUCCESS -> portrait.criticalSuccess
|
||||
CharacterRibbonRollUio.Critical.SPECIAL_SUCCESS -> portrait.spacialSuccess
|
||||
CharacterRibbonRollUio.Critical.SUCCESS -> portrait.success
|
||||
CharacterRibbonRollUio.Critical.FAILURE -> portrait.failure
|
||||
CharacterRibbonRollUio.Critical.CRITICAL_FAILURE -> portrait.criticalFailure
|
||||
null -> portrait.default
|
||||
}
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.graphicsLayer {
|
||||
this.alpha = animation.animatedAlpha.value
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue