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.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.composable.stringResource
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
@Stable
|
||||
data class DropDownFieldUio<T>(
|
||||
@StringRes val label: Int,
|
||||
val values: List<Pair<T, Int>>,
|
||||
val value: State<Pair<T?, String>>,
|
||||
val onValueChange: (T?, String) -> Unit,
|
||||
val values: List<T>,
|
||||
val value: State<T?>,
|
||||
val valueLabel: @Composable (T) -> String,
|
||||
val onValueChange: (T?) -> Unit,
|
||||
) {
|
||||
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,
|
||||
values = emptyList(),
|
||||
value = mutableStateOf(id to value),
|
||||
onValueChange = { _, _ -> },
|
||||
value = mutableStateOf(id),
|
||||
valueLabel = valueLabel,
|
||||
onValueChange = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -70,7 +78,7 @@ fun <T> DropDownField(
|
|||
ExposedDropdownMenuBox(
|
||||
modifier = modifier,
|
||||
expanded = expended,
|
||||
onExpandedChange = { expended = !expended && field.value.value.first == null },
|
||||
onExpandedChange = { expended = !expended && field.value.value == null },
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.menuAnchor(),
|
||||
|
|
@ -85,13 +93,13 @@ fun <T> DropDownField(
|
|||
trailingIcon = {
|
||||
AnimatedContent(
|
||||
modifier = Modifier.size(size = 48.dp),
|
||||
targetState = field.value.value.first != null,
|
||||
targetState = field.value.value != null,
|
||||
transitionSpec = { fadeIn() with fadeOut() },
|
||||
label = "DropDownFieldTrailingIconAnimation",
|
||||
) {
|
||||
when (it) {
|
||||
true -> IconButton(
|
||||
onClick = { field.onValueChange(null, "") },
|
||||
onClick = { field.onValueChange(null) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 18.dp),
|
||||
|
|
@ -116,7 +124,7 @@ fun <T> DropDownField(
|
|||
focusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
),
|
||||
value = field.value.value.second,
|
||||
value = field.value.value?.let { field.valueLabel(it) } ?: "",
|
||||
onValueChange = {},
|
||||
)
|
||||
|
||||
|
|
@ -125,14 +133,13 @@ fun <T> DropDownField(
|
|||
onDismissRequest = { expended = false },
|
||||
) {
|
||||
field.values.forEach {
|
||||
val label = stringResource(id = it.second)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
expended = false
|
||||
field.onValueChange(it.first, label)
|
||||
field.onValueChange(it)
|
||||
},
|
||||
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_YES)
|
||||
private fun DropDownFieldPreview(
|
||||
@PreviewParameter(DropDownFieldPreviewProvider::class) preview: Pair<String?, String>,
|
||||
@PreviewParameter(DropDownFieldPreviewProvider::class) preview: Lexicon.Race?,
|
||||
) {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
|
|
@ -153,16 +160,17 @@ private fun DropDownFieldPreview(
|
|||
.fillMaxWidth()
|
||||
.padding(all = 8.dp),
|
||||
field = DropDownFieldUio(
|
||||
label = R.string.lexicon_search,
|
||||
label = R.string.search_field_race,
|
||||
values = emptyList(),
|
||||
value = remember { mutableStateOf(preview) },
|
||||
onValueChange = { _, _ -> },
|
||||
valueLabel = { stringResource(id = it) },
|
||||
onValueChange = { },
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DropDownFieldPreviewProvider : PreviewParameterProvider<Pair<String?, String>> {
|
||||
override val values: Sequence<Pair<String?, String>> = sequenceOf(null to "", "" to "preview")
|
||||
private class DropDownFieldPreviewProvider : PreviewParameterProvider<Lexicon.Race?> {
|
||||
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.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
|
|
@ -145,7 +146,7 @@ private fun PartyBackground(
|
|||
Gyroscope {
|
||||
val balance = remember {
|
||||
derivedStateOf {
|
||||
max(-1f, min(1f, this.gyroscope.value.roll))
|
||||
max(-1f, min(1f, this.gyroscope.value.roll * 2.5f))
|
||||
}
|
||||
}
|
||||
val colorFilter = remember {
|
||||
|
|
@ -263,13 +264,13 @@ private fun PartyBackground(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberPortrait(): List<Int> = remember {
|
||||
private fun rememberPortrait(): List<Int> = rememberSaveable {
|
||||
listOf(
|
||||
R.drawable.im_tigrane,
|
||||
R.drawable.im_unathana,
|
||||
R.drawable.im_brulkhai,
|
||||
R.drawable.im_nelia,
|
||||
R.drawable.im_leandre,
|
||||
R.drawable.im_nelia,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -279,14 +280,14 @@ private fun animatedWeight(
|
|||
amplitude: Float = E.toFloat(),
|
||||
divergence: Float = 0.95f,
|
||||
position: Float,
|
||||
step: Float = .16f,
|
||||
step: Float = .10f,
|
||||
): Float {
|
||||
val animatedWeight = animateFloatAsState(
|
||||
targetValue = divergence * amplitude.pow(-(position - progress.value).pow(2f) / step) + (1f - divergence),
|
||||
label = "AnimatedBackgroundWeight",
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioNoBouncy,
|
||||
stiffness = Spring.StiffnessLow,
|
||||
stiffness = (Spring.StiffnessLow + Spring.StiffnessVeryLow) / 2f,
|
||||
)
|
||||
)
|
||||
return animatedWeight.value
|
||||
|
|
@ -378,6 +379,8 @@ private fun rememeberGoogleStringResource(): AnnotatedString {
|
|||
private fun AuthenticationScreenContentPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
PartyBackground()
|
||||
|
||||
AuthenticationScreenContent(
|
||||
modifier = Modifier
|
||||
.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_YES
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -34,7 +33,6 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.screens.navigateToCharacterDetail
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.composable.stringResource
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
@Stable
|
||||
|
|
@ -81,8 +80,8 @@ fun SearchScreen(
|
|||
screen.navigateToCharacterDetail(
|
||||
id = item.id,
|
||||
highlight = form.search.value.value.takeIf { it.isNotEmpty() },
|
||||
race = form.race.value.value.first,
|
||||
gender = form.gender.value.value.first,
|
||||
race = form.race.value.value,
|
||||
gender = form.gender.value.value,
|
||||
)
|
||||
},
|
||||
onBack = {
|
||||
|
|
@ -95,7 +94,7 @@ fun SearchScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun SearchScreenContent(
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -178,21 +177,20 @@ private fun SearchScreenContent(
|
|||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun SearchScreenContentPreview() {
|
||||
LexiconTheme {
|
||||
val context = LocalContext.current
|
||||
Surface {
|
||||
SearchScreenContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
form = SearchFormUio(
|
||||
search = TextFieldUio.preview(R.string.search_field_search),
|
||||
gender = DropDownFieldUio.preview(
|
||||
label = R.string.search_field_gender,
|
||||
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(
|
||||
label = R.string.search_field_race,
|
||||
id = null,
|
||||
value = "",
|
||||
label = R.string.search_field_race,
|
||||
valueLabel = { stringResource(id = Lexicon.Race.HALF_ORC) },
|
||||
),
|
||||
),
|
||||
items = remember {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.pixelized.rplexicon.model.Lexicon.Race
|
|||
import com.pixelized.rplexicon.repository.LexiconRepository
|
||||
import com.pixelized.rplexicon.ui.composable.form.DropDownFieldUio
|
||||
import com.pixelized.rplexicon.ui.composable.form.TextFieldUio
|
||||
import com.pixelized.rplexicon.utilitary.composable.stringResource
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -18,8 +19,8 @@ class SearchViewModel @Inject constructor(
|
|||
repository: LexiconRepository,
|
||||
) : ViewModel() {
|
||||
private val _search = mutableStateOf("")
|
||||
private val _gender = mutableStateOf<Pair<Gender?, String>>(null to "")
|
||||
private val _race = mutableStateOf<Pair<Race?, String>>(null to "")
|
||||
private val _gender = mutableStateOf<Gender?>(null)
|
||||
private val _race = mutableStateOf<Race?>(null)
|
||||
|
||||
val form = SearchFormUio(
|
||||
search = TextFieldUio(
|
||||
|
|
@ -31,15 +32,17 @@ class SearchViewModel @Inject constructor(
|
|||
),
|
||||
gender = DropDownFieldUio(
|
||||
label = R.string.search_field_gender,
|
||||
values = genders(),
|
||||
values = Lexicon.Gender.values().toList(),
|
||||
value = _gender,
|
||||
onValueChange = { id, value -> _gender.value = id to value },
|
||||
valueLabel = { stringResource(id = it) },
|
||||
onValueChange = { id -> _gender.value = id },
|
||||
),
|
||||
race = DropDownFieldUio(
|
||||
label = R.string.search_field_race,
|
||||
values = races(),
|
||||
values = Lexicon.Race.values().toList(),
|
||||
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 {
|
||||
data.filter { item ->
|
||||
val gender = _gender.value.first?.let { it == item.gender }
|
||||
val race = _race.value.first?.let { it == item.race }
|
||||
val gender = _gender.value?.let { it == item.gender }
|
||||
val race = _race.value?.let { it == item.race }
|
||||
val search = _search.value.takeIf { it.isNotEmpty() }?.let {
|
||||
val name = item.name.contains(_search.value, true)
|
||||
val diminutive = item.diminutive?.contains(_search.value, true) == true
|
||||
|
|
@ -66,8 +69,8 @@ class SearchViewModel @Inject constructor(
|
|||
|
||||
private fun Lexicon.toSearchUio(
|
||||
search: String = _search.value,
|
||||
highlightGender: Boolean = this.gender == _gender.value.first,
|
||||
highlightRace: Boolean = this.race == _race.value.first,
|
||||
highlightGender: Boolean = this.gender == _gender.value,
|
||||
highlightRace: Boolean = this.race == _race.value,
|
||||
) = SearchItemUio(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
|
|
@ -80,29 +83,4 @@ class SearchViewModel @Inject constructor(
|
|||
highlightGender = highlightGender,
|
||||
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 |