Update players protrait and authentication animation
| 
						 | 
					@ -39,22 +39,30 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
 | 
				
			||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
 | 
					import androidx.compose.ui.tooling.preview.PreviewParameterProvider
 | 
				
			||||||
import androidx.compose.ui.unit.dp
 | 
					import androidx.compose.ui.unit.dp
 | 
				
			||||||
import com.pixelized.rplexicon.R
 | 
					import com.pixelized.rplexicon.R
 | 
				
			||||||
 | 
					import com.pixelized.rplexicon.model.Lexicon
 | 
				
			||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
					import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
				
			||||||
 | 
					import com.pixelized.rplexicon.utilitary.composable.stringResource
 | 
				
			||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
					import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Stable
 | 
					@Stable
 | 
				
			||||||
data class DropDownFieldUio<T>(
 | 
					data class DropDownFieldUio<T>(
 | 
				
			||||||
    @StringRes val label: Int,
 | 
					    @StringRes val label: Int,
 | 
				
			||||||
    val values: List<Pair<T, Int>>,
 | 
					    val values: List<T>,
 | 
				
			||||||
    val value: State<Pair<T?, String>>,
 | 
					    val value: State<T?>,
 | 
				
			||||||
    val onValueChange: (T?, String) -> Unit,
 | 
					    val valueLabel: @Composable (T) -> String,
 | 
				
			||||||
 | 
					    val onValueChange: (T?) -> Unit,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        fun <T> preview(@StringRes label: Int, id: T?, value: String) = DropDownFieldUio(
 | 
					        fun <T> preview(
 | 
				
			||||||
 | 
					            @StringRes label: Int,
 | 
				
			||||||
 | 
					            id: T?,
 | 
				
			||||||
 | 
					            valueLabel: @Composable (T) -> String,
 | 
				
			||||||
 | 
					        ) = DropDownFieldUio(
 | 
				
			||||||
            label = label,
 | 
					            label = label,
 | 
				
			||||||
            values = emptyList(),
 | 
					            values = emptyList(),
 | 
				
			||||||
            value = mutableStateOf(id to value),
 | 
					            value = mutableStateOf(id),
 | 
				
			||||||
            onValueChange = { _, _ -> },
 | 
					            valueLabel = valueLabel,
 | 
				
			||||||
 | 
					            onValueChange = { },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -70,7 +78,7 @@ fun <T> DropDownField(
 | 
				
			||||||
    ExposedDropdownMenuBox(
 | 
					    ExposedDropdownMenuBox(
 | 
				
			||||||
        modifier = modifier,
 | 
					        modifier = modifier,
 | 
				
			||||||
        expanded = expended,
 | 
					        expanded = expended,
 | 
				
			||||||
        onExpandedChange = { expended = !expended && field.value.value.first == null },
 | 
					        onExpandedChange = { expended = !expended && field.value.value == null },
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        OutlinedTextField(
 | 
					        OutlinedTextField(
 | 
				
			||||||
            modifier = Modifier.menuAnchor(),
 | 
					            modifier = Modifier.menuAnchor(),
 | 
				
			||||||
| 
						 | 
					@ -85,13 +93,13 @@ fun <T> DropDownField(
 | 
				
			||||||
            trailingIcon = {
 | 
					            trailingIcon = {
 | 
				
			||||||
                AnimatedContent(
 | 
					                AnimatedContent(
 | 
				
			||||||
                    modifier = Modifier.size(size = 48.dp),
 | 
					                    modifier = Modifier.size(size = 48.dp),
 | 
				
			||||||
                    targetState = field.value.value.first != null,
 | 
					                    targetState = field.value.value != null,
 | 
				
			||||||
                    transitionSpec = { fadeIn() with fadeOut() },
 | 
					                    transitionSpec = { fadeIn() with fadeOut() },
 | 
				
			||||||
                    label = "DropDownFieldTrailingIconAnimation",
 | 
					                    label = "DropDownFieldTrailingIconAnimation",
 | 
				
			||||||
                ) {
 | 
					                ) {
 | 
				
			||||||
                    when (it) {
 | 
					                    when (it) {
 | 
				
			||||||
                        true -> IconButton(
 | 
					                        true -> IconButton(
 | 
				
			||||||
                            onClick = { field.onValueChange(null, "") },
 | 
					                            onClick = { field.onValueChange(null) },
 | 
				
			||||||
                        ) {
 | 
					                        ) {
 | 
				
			||||||
                            Icon(
 | 
					                            Icon(
 | 
				
			||||||
                                modifier = Modifier.size(size = 18.dp),
 | 
					                                modifier = Modifier.size(size = 18.dp),
 | 
				
			||||||
| 
						 | 
					@ -116,7 +124,7 @@ fun <T> DropDownField(
 | 
				
			||||||
                focusedContainerColor = MaterialTheme.colorScheme.surface,
 | 
					                focusedContainerColor = MaterialTheme.colorScheme.surface,
 | 
				
			||||||
                unfocusedContainerColor = MaterialTheme.colorScheme.surface,
 | 
					                unfocusedContainerColor = MaterialTheme.colorScheme.surface,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            value = field.value.value.second,
 | 
					            value = field.value.value?.let { field.valueLabel(it) } ?: "",
 | 
				
			||||||
            onValueChange = {},
 | 
					            onValueChange = {},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,14 +133,13 @@ fun <T> DropDownField(
 | 
				
			||||||
            onDismissRequest = { expended = false },
 | 
					            onDismissRequest = { expended = false },
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            field.values.forEach {
 | 
					            field.values.forEach {
 | 
				
			||||||
                val label = stringResource(id = it.second)
 | 
					 | 
				
			||||||
                DropdownMenuItem(
 | 
					                DropdownMenuItem(
 | 
				
			||||||
                    onClick = {
 | 
					                    onClick = {
 | 
				
			||||||
                        expended = false
 | 
					                        expended = false
 | 
				
			||||||
                        field.onValueChange(it.first, label)
 | 
					                        field.onValueChange(it)
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    text = {
 | 
					                    text = {
 | 
				
			||||||
                        Text(text = label)
 | 
					                        Text(text = field.valueLabel(it))
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -144,7 +151,7 @@ fun <T> DropDownField(
 | 
				
			||||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
 | 
					@Preview(uiMode = UI_MODE_NIGHT_NO)
 | 
				
			||||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
					@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
				
			||||||
private fun DropDownFieldPreview(
 | 
					private fun DropDownFieldPreview(
 | 
				
			||||||
    @PreviewParameter(DropDownFieldPreviewProvider::class) preview: Pair<String?, String>,
 | 
					    @PreviewParameter(DropDownFieldPreviewProvider::class) preview: Lexicon.Race?,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    LexiconTheme {
 | 
					    LexiconTheme {
 | 
				
			||||||
        Surface {
 | 
					        Surface {
 | 
				
			||||||
| 
						 | 
					@ -153,16 +160,17 @@ private fun DropDownFieldPreview(
 | 
				
			||||||
                    .fillMaxWidth()
 | 
					                    .fillMaxWidth()
 | 
				
			||||||
                    .padding(all = 8.dp),
 | 
					                    .padding(all = 8.dp),
 | 
				
			||||||
                field = DropDownFieldUio(
 | 
					                field = DropDownFieldUio(
 | 
				
			||||||
                    label = R.string.lexicon_search,
 | 
					                    label = R.string.search_field_race,
 | 
				
			||||||
                    values = emptyList(),
 | 
					                    values = emptyList(),
 | 
				
			||||||
                    value = remember { mutableStateOf(preview) },
 | 
					                    value = remember { mutableStateOf(preview) },
 | 
				
			||||||
                    onValueChange = { _, _ -> },
 | 
					                    valueLabel = { stringResource(id = it) },
 | 
				
			||||||
 | 
					                    onValueChange = { },
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private class DropDownFieldPreviewProvider : PreviewParameterProvider<Pair<String?, String>> {
 | 
					private class DropDownFieldPreviewProvider : PreviewParameterProvider<Lexicon.Race?> {
 | 
				
			||||||
    override val values: Sequence<Pair<String?, String>> = sequenceOf(null to "", "" to "preview")
 | 
					    override val values: Sequence<Lexicon.Race?> = sequenceOf(null, Lexicon.Race.HALF_ORC)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ import androidx.compose.runtime.LaunchedEffect
 | 
				
			||||||
import androidx.compose.runtime.State
 | 
					import androidx.compose.runtime.State
 | 
				
			||||||
import androidx.compose.runtime.derivedStateOf
 | 
					import androidx.compose.runtime.derivedStateOf
 | 
				
			||||||
import androidx.compose.runtime.remember
 | 
					import androidx.compose.runtime.remember
 | 
				
			||||||
 | 
					import androidx.compose.runtime.saveable.rememberSaveable
 | 
				
			||||||
import androidx.compose.ui.Alignment
 | 
					import androidx.compose.ui.Alignment
 | 
				
			||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
import androidx.compose.ui.graphics.Brush
 | 
					import androidx.compose.ui.graphics.Brush
 | 
				
			||||||
| 
						 | 
					@ -145,7 +146,7 @@ private fun PartyBackground(
 | 
				
			||||||
    Gyroscope {
 | 
					    Gyroscope {
 | 
				
			||||||
        val balance = remember {
 | 
					        val balance = remember {
 | 
				
			||||||
            derivedStateOf {
 | 
					            derivedStateOf {
 | 
				
			||||||
                max(-1f, min(1f, this.gyroscope.value.roll))
 | 
					                max(-1f, min(1f, this.gyroscope.value.roll * 2.5f))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        val colorFilter = remember {
 | 
					        val colorFilter = remember {
 | 
				
			||||||
| 
						 | 
					@ -263,13 +264,13 @@ private fun PartyBackground(
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
private fun rememberPortrait(): List<Int> = remember {
 | 
					private fun rememberPortrait(): List<Int> = rememberSaveable {
 | 
				
			||||||
    listOf(
 | 
					    listOf(
 | 
				
			||||||
        R.drawable.im_tigrane,
 | 
					        R.drawable.im_tigrane,
 | 
				
			||||||
        R.drawable.im_unathana,
 | 
					        R.drawable.im_unathana,
 | 
				
			||||||
        R.drawable.im_brulkhai,
 | 
					        R.drawable.im_brulkhai,
 | 
				
			||||||
        R.drawable.im_nelia,
 | 
					 | 
				
			||||||
        R.drawable.im_leandre,
 | 
					        R.drawable.im_leandre,
 | 
				
			||||||
 | 
					        R.drawable.im_nelia,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -279,14 +280,14 @@ private fun animatedWeight(
 | 
				
			||||||
    amplitude: Float = E.toFloat(),
 | 
					    amplitude: Float = E.toFloat(),
 | 
				
			||||||
    divergence: Float = 0.95f,
 | 
					    divergence: Float = 0.95f,
 | 
				
			||||||
    position: Float,
 | 
					    position: Float,
 | 
				
			||||||
    step: Float = .16f,
 | 
					    step: Float = .10f,
 | 
				
			||||||
): Float {
 | 
					): Float {
 | 
				
			||||||
    val animatedWeight = animateFloatAsState(
 | 
					    val animatedWeight = animateFloatAsState(
 | 
				
			||||||
        targetValue = divergence * amplitude.pow(-(position - progress.value).pow(2f) / step) + (1f - divergence),
 | 
					        targetValue = divergence * amplitude.pow(-(position - progress.value).pow(2f) / step) + (1f - divergence),
 | 
				
			||||||
        label = "AnimatedBackgroundWeight",
 | 
					        label = "AnimatedBackgroundWeight",
 | 
				
			||||||
        animationSpec = spring(
 | 
					        animationSpec = spring(
 | 
				
			||||||
            dampingRatio = Spring.DampingRatioNoBouncy,
 | 
					            dampingRatio = Spring.DampingRatioNoBouncy,
 | 
				
			||||||
            stiffness = Spring.StiffnessLow,
 | 
					            stiffness = (Spring.StiffnessLow + Spring.StiffnessVeryLow) / 2f,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    return animatedWeight.value
 | 
					    return animatedWeight.value
 | 
				
			||||||
| 
						 | 
					@ -378,6 +379,8 @@ private fun rememeberGoogleStringResource(): AnnotatedString {
 | 
				
			||||||
private fun AuthenticationScreenContentPreview() {
 | 
					private fun AuthenticationScreenContentPreview() {
 | 
				
			||||||
    LexiconTheme {
 | 
					    LexiconTheme {
 | 
				
			||||||
        Surface {
 | 
					        Surface {
 | 
				
			||||||
 | 
					            PartyBackground()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            AuthenticationScreenContent(
 | 
					            AuthenticationScreenContent(
 | 
				
			||||||
                modifier = Modifier
 | 
					                modifier = Modifier
 | 
				
			||||||
                    .fillMaxSize()
 | 
					                    .fillMaxSize()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ package com.pixelized.rplexicon.ui.screens.search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
 | 
					import android.content.res.Configuration.UI_MODE_NIGHT_NO
 | 
				
			||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
 | 
					import android.content.res.Configuration.UI_MODE_NIGHT_YES
 | 
				
			||||||
import androidx.compose.foundation.ExperimentalFoundationApi
 | 
					 | 
				
			||||||
import androidx.compose.foundation.clickable
 | 
					import androidx.compose.foundation.clickable
 | 
				
			||||||
import androidx.compose.foundation.layout.Arrangement
 | 
					import androidx.compose.foundation.layout.Arrangement
 | 
				
			||||||
import androidx.compose.foundation.layout.Column
 | 
					import androidx.compose.foundation.layout.Column
 | 
				
			||||||
| 
						 | 
					@ -34,7 +33,6 @@ import androidx.compose.runtime.mutableStateOf
 | 
				
			||||||
import androidx.compose.runtime.remember
 | 
					import androidx.compose.runtime.remember
 | 
				
			||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
import androidx.compose.ui.graphics.Color
 | 
					import androidx.compose.ui.graphics.Color
 | 
				
			||||||
import androidx.compose.ui.platform.LocalContext
 | 
					 | 
				
			||||||
import androidx.compose.ui.res.painterResource
 | 
					import androidx.compose.ui.res.painterResource
 | 
				
			||||||
import androidx.compose.ui.res.stringResource
 | 
					import androidx.compose.ui.res.stringResource
 | 
				
			||||||
import androidx.compose.ui.tooling.preview.Preview
 | 
					import androidx.compose.ui.tooling.preview.Preview
 | 
				
			||||||
| 
						 | 
					@ -51,6 +49,7 @@ import com.pixelized.rplexicon.ui.composable.form.TextFieldUio
 | 
				
			||||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
 | 
					import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
 | 
				
			||||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterDetail
 | 
					import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterDetail
 | 
				
			||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
					import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
				
			||||||
 | 
					import com.pixelized.rplexicon.utilitary.composable.stringResource
 | 
				
			||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
					import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Stable
 | 
					@Stable
 | 
				
			||||||
| 
						 | 
					@ -81,8 +80,8 @@ fun SearchScreen(
 | 
				
			||||||
                screen.navigateToCharacterDetail(
 | 
					                screen.navigateToCharacterDetail(
 | 
				
			||||||
                    id = item.id,
 | 
					                    id = item.id,
 | 
				
			||||||
                    highlight = form.search.value.value.takeIf { it.isNotEmpty() },
 | 
					                    highlight = form.search.value.value.takeIf { it.isNotEmpty() },
 | 
				
			||||||
                    race = form.race.value.value.first,
 | 
					                    race = form.race.value.value,
 | 
				
			||||||
                    gender = form.gender.value.value.first,
 | 
					                    gender = form.gender.value.value,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            onBack = {
 | 
					            onBack = {
 | 
				
			||||||
| 
						 | 
					@ -95,7 +94,7 @@ fun SearchScreen(
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
 | 
					@OptIn(ExperimentalMaterial3Api::class)
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
private fun SearchScreenContent(
 | 
					private fun SearchScreenContent(
 | 
				
			||||||
    modifier: Modifier = Modifier,
 | 
					    modifier: Modifier = Modifier,
 | 
				
			||||||
| 
						 | 
					@ -178,21 +177,20 @@ private fun SearchScreenContent(
 | 
				
			||||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
					@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
				
			||||||
private fun SearchScreenContentPreview() {
 | 
					private fun SearchScreenContentPreview() {
 | 
				
			||||||
    LexiconTheme {
 | 
					    LexiconTheme {
 | 
				
			||||||
        val context = LocalContext.current
 | 
					 | 
				
			||||||
        Surface {
 | 
					        Surface {
 | 
				
			||||||
            SearchScreenContent(
 | 
					            SearchScreenContent(
 | 
				
			||||||
                modifier = Modifier.fillMaxSize(),
 | 
					                modifier = Modifier.fillMaxSize(),
 | 
				
			||||||
                form = SearchFormUio(
 | 
					                form = SearchFormUio(
 | 
				
			||||||
                    search = TextFieldUio.preview(R.string.search_field_search),
 | 
					                    search = TextFieldUio.preview(R.string.search_field_search),
 | 
				
			||||||
                    gender = DropDownFieldUio.preview(
 | 
					                    gender = DropDownFieldUio.preview(
 | 
				
			||||||
                        label = R.string.search_field_gender,
 | 
					 | 
				
			||||||
                        id = Lexicon.Gender.FEMALE,
 | 
					                        id = Lexicon.Gender.FEMALE,
 | 
				
			||||||
                        value = context.getString(R.string.gender_female),
 | 
					                        label = R.string.search_field_gender,
 | 
				
			||||||
 | 
					                        valueLabel = { stringResource(id = Lexicon.Gender.FEMALE) },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    race = DropDownFieldUio.preview(
 | 
					                    race = DropDownFieldUio.preview(
 | 
				
			||||||
                        label = R.string.search_field_race,
 | 
					 | 
				
			||||||
                        id = null,
 | 
					                        id = null,
 | 
				
			||||||
                        value = "",
 | 
					                        label = R.string.search_field_race,
 | 
				
			||||||
 | 
					                        valueLabel = { stringResource(id = Lexicon.Race.HALF_ORC) },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                items = remember {
 | 
					                items = remember {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ import com.pixelized.rplexicon.model.Lexicon.Race
 | 
				
			||||||
import com.pixelized.rplexicon.repository.LexiconRepository
 | 
					import com.pixelized.rplexicon.repository.LexiconRepository
 | 
				
			||||||
import com.pixelized.rplexicon.ui.composable.form.DropDownFieldUio
 | 
					import com.pixelized.rplexicon.ui.composable.form.DropDownFieldUio
 | 
				
			||||||
import com.pixelized.rplexicon.ui.composable.form.TextFieldUio
 | 
					import com.pixelized.rplexicon.ui.composable.form.TextFieldUio
 | 
				
			||||||
 | 
					import com.pixelized.rplexicon.utilitary.composable.stringResource
 | 
				
			||||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
					import dagger.hilt.android.lifecycle.HiltViewModel
 | 
				
			||||||
import javax.inject.Inject
 | 
					import javax.inject.Inject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,8 +19,8 @@ class SearchViewModel @Inject constructor(
 | 
				
			||||||
    repository: LexiconRepository,
 | 
					    repository: LexiconRepository,
 | 
				
			||||||
) : ViewModel() {
 | 
					) : ViewModel() {
 | 
				
			||||||
    private val _search = mutableStateOf("")
 | 
					    private val _search = mutableStateOf("")
 | 
				
			||||||
    private val _gender = mutableStateOf<Pair<Gender?, String>>(null to "")
 | 
					    private val _gender = mutableStateOf<Gender?>(null)
 | 
				
			||||||
    private val _race = mutableStateOf<Pair<Race?, String>>(null to "")
 | 
					    private val _race = mutableStateOf<Race?>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val form = SearchFormUio(
 | 
					    val form = SearchFormUio(
 | 
				
			||||||
        search = TextFieldUio(
 | 
					        search = TextFieldUio(
 | 
				
			||||||
| 
						 | 
					@ -31,15 +32,17 @@ class SearchViewModel @Inject constructor(
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        gender = DropDownFieldUio(
 | 
					        gender = DropDownFieldUio(
 | 
				
			||||||
            label = R.string.search_field_gender,
 | 
					            label = R.string.search_field_gender,
 | 
				
			||||||
            values = genders(),
 | 
					            values = Lexicon.Gender.values().toList(),
 | 
				
			||||||
            value = _gender,
 | 
					            value = _gender,
 | 
				
			||||||
            onValueChange = { id, value -> _gender.value = id to value },
 | 
					            valueLabel = { stringResource(id = it) },
 | 
				
			||||||
 | 
					            onValueChange = { id -> _gender.value = id },
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        race = DropDownFieldUio(
 | 
					        race = DropDownFieldUio(
 | 
				
			||||||
            label = R.string.search_field_race,
 | 
					            label = R.string.search_field_race,
 | 
				
			||||||
            values = races(),
 | 
					            values = Lexicon.Race.values().toList(),
 | 
				
			||||||
            value = _race,
 | 
					            value = _race,
 | 
				
			||||||
            onValueChange = { id, value -> _race.value = id to value },
 | 
					            valueLabel = { stringResource(id = it) },
 | 
				
			||||||
 | 
					            onValueChange = { id -> _race.value = id },
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,8 +50,8 @@ class SearchViewModel @Inject constructor(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val filter = derivedStateOf {
 | 
					    val filter = derivedStateOf {
 | 
				
			||||||
        data.filter { item ->
 | 
					        data.filter { item ->
 | 
				
			||||||
            val gender = _gender.value.first?.let { it == item.gender }
 | 
					            val gender = _gender.value?.let { it == item.gender }
 | 
				
			||||||
            val race = _race.value.first?.let { it == item.race }
 | 
					            val race = _race.value?.let { it == item.race }
 | 
				
			||||||
            val search = _search.value.takeIf { it.isNotEmpty() }?.let {
 | 
					            val search = _search.value.takeIf { it.isNotEmpty() }?.let {
 | 
				
			||||||
                val name = item.name.contains(_search.value, true)
 | 
					                val name = item.name.contains(_search.value, true)
 | 
				
			||||||
                val diminutive = item.diminutive?.contains(_search.value, true) == true
 | 
					                val diminutive = item.diminutive?.contains(_search.value, true) == true
 | 
				
			||||||
| 
						 | 
					@ -66,8 +69,8 @@ class SearchViewModel @Inject constructor(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun Lexicon.toSearchUio(
 | 
					    private fun Lexicon.toSearchUio(
 | 
				
			||||||
        search: String = _search.value,
 | 
					        search: String = _search.value,
 | 
				
			||||||
        highlightGender: Boolean = this.gender == _gender.value.first,
 | 
					        highlightGender: Boolean = this.gender == _gender.value,
 | 
				
			||||||
        highlightRace: Boolean = this.race == _race.value.first,
 | 
					        highlightRace: Boolean = this.race == _race.value,
 | 
				
			||||||
    ) = SearchItemUio(
 | 
					    ) = SearchItemUio(
 | 
				
			||||||
        id = this.id,
 | 
					        id = this.id,
 | 
				
			||||||
        name = this.name,
 | 
					        name = this.name,
 | 
				
			||||||
| 
						 | 
					@ -80,29 +83,4 @@ class SearchViewModel @Inject constructor(
 | 
				
			||||||
        highlightGender = highlightGender,
 | 
					        highlightGender = highlightGender,
 | 
				
			||||||
        highlightRace = highlightRace,
 | 
					        highlightRace = highlightRace,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					 | 
				
			||||||
    companion object {
 | 
					 | 
				
			||||||
        private fun genders() = listOf(
 | 
					 | 
				
			||||||
            Gender.MALE to R.string.gender_male,
 | 
					 | 
				
			||||||
            Gender.FEMALE to R.string.gender_female,
 | 
					 | 
				
			||||||
            Gender.UNDETERMINED to R.string.gender_undetermined,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private fun races() = listOf(
 | 
					 | 
				
			||||||
            Race.ELF to R.string.race_elf,
 | 
					 | 
				
			||||||
            Race.HALFLING to R.string.race_halfling,
 | 
					 | 
				
			||||||
            Race.HUMAN to R.string.race_human,
 | 
					 | 
				
			||||||
            Race.DWARF to R.string.race_dwarf,
 | 
					 | 
				
			||||||
            Race.HALF_ELF to R.string.race_half_elf,
 | 
					 | 
				
			||||||
            Race.HALF_ORC to R.string.race_half_orc,
 | 
					 | 
				
			||||||
            Race.DRAGONBORN to R.string.race_dragonborn,
 | 
					 | 
				
			||||||
            Race.GNOME to R.string.race_gnome,
 | 
					 | 
				
			||||||
            Race.TIEFLING to R.string.race_tiefling,
 | 
					 | 
				
			||||||
            Race.AARAKOCRA to R.string.race_aarakocra,
 | 
					 | 
				
			||||||
            Race.GENASI to R.string.race_genasi,
 | 
					 | 
				
			||||||
            Race.DEEP_GNOME to R.string.race_deep_gnome,
 | 
					 | 
				
			||||||
            Race.GOLIATH to R.string.race_goliath,
 | 
					 | 
				
			||||||
            Race.UNDETERMINED to R.string.race_undetermined,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable/im_brulkhai.jpeg
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 61 KiB  | 
| 
		 Before Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 23 KiB  | 
| 
		 Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 28 KiB  |