From 45f32018e2dc1117b879f5b995eb5a12d0ce4fae Mon Sep 17 00:00:00 2001 From: ArthurKun <16458204+ArthurKun21@users.noreply.github.com> Date: Sat, 6 Jan 2024 22:38:45 +0800 Subject: [PATCH] Added UI indicator for the current wave and turns for skill maker (#1730) --- .../github/fate_grand_automata/ui/FGATitle.kt | 7 +- .../ui/skill_maker/SkillMakerActivity.kt | 8 +- .../ui/skill_maker/SkillMakerAtk.kt | 161 +++++++++++++----- .../ui/skill_maker/SkillMakerMain.kt | 12 +- .../ui/skill_maker/SkillMakerSavedState.kt | 3 +- .../ui/skill_maker/SkillMakerViewModel.kt | 34 +++- app/src/main/res/values-b+zh+CN/localized.xml | 1 - app/src/main/res/values-b+zh+TW/localized.xml | 2 +- app/src/main/res/values-ja/localized.xml | 2 +- app/src/main/res/values-ko/localized.xml | 1 - app/src/main/res/values-vi/localized.xml | 1 - app/src/main/res/values/localized.xml | 3 +- 12 files changed, 174 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/FGATitle.kt b/app/src/main/java/io/github/fate_grand_automata/ui/FGATitle.kt index 5eda76a19..99ae89c7f 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/FGATitle.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/FGATitle.kt @@ -8,10 +8,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign @Composable -fun FGATitle(text: String) = Text( +fun FGATitle( + text: String, + modifier: Modifier = Modifier, +) = Text( text, textAlign = TextAlign.Center, color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier + modifier = modifier .fillMaxWidth() ) \ No newline at end of file diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerActivity.kt b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerActivity.kt index 4c437da58..71d25ab83 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerActivity.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerActivity.kt @@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.compose.animation.Crossfade import androidx.compose.animation.core.spring import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.res.stringResource import androidx.core.view.WindowCompat import dagger.hilt.android.AndroidEntryPoint @@ -78,6 +79,9 @@ fun SkillMakerUI( val (current, navigate) = vm.navigation + val turn by vm.turn + val wave by vm.wave + Crossfade( current, animationSpec = spring() @@ -85,7 +89,9 @@ fun SkillMakerUI( when (nav) { SkillMakerNav.Atk -> { SkillMakerAtk( - onNextWave = { vm.nextStage(it) }, + wave = wave, + turn = turn, + onNextWave = { vm.nextWave(it) }, onNextTurn = { vm.nextTurn(it) } ) } diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerAtk.kt b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerAtk.kt index f84d87eec..76dd620e6 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerAtk.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerAtk.kt @@ -1,7 +1,9 @@ package io.github.fate_grand_automata.ui.skill_maker import androidx.annotation.StringRes +import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight @@ -17,6 +19,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -36,52 +39,78 @@ import io.github.fate_grand_automata.ui.icon @Composable private fun SelectNps( + numberOfCardsSelected: Int, npSequence: String, onNpSequenceChange: (String) -> Unit, modifier: Modifier = Modifier ) { + val numberOfNPs = (1..3).count { it.toString() in npSequence } + Row( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, modifier = modifier ) { - (1..3).map { - val isSelected = it.toString() in npSequence + (1..3).map { servantNumber -> + val isSelected = servantNumber.toString() in npSequence + + val canSelect = numberOfCardsSelected + numberOfNPs + 1 <= 3 - val selectedColor = when (it) { + val selectedColor = when (servantNumber) { 1 -> R.color.colorServant1 2 -> R.color.colorServant2 3 -> R.color.colorServant3 else -> R.color.colorAccent } - val onClick = { - onNpSequenceChange( - if (isSelected) - npSequence.filter { m -> m.toString() != it.toString() } - else npSequence + it - ) - } + val animatedColorState by animateColorAsState( + targetValue = when { + isSelected -> colorResource(selectedColor) + !canSelect -> MaterialTheme.colorScheme.surfaceVariant.copy(0.3f) + else -> MaterialTheme.colorScheme.surfaceVariant + }, + label = "Add animation to the changing of color" + ) Surface( tonalElevation = 5.dp, shape = MaterialTheme.shapes.medium, - color = - if (isSelected) - colorResource(selectedColor) - else MaterialTheme.colorScheme.surfaceVariant, + color = animatedColorState, modifier = Modifier .padding(5.dp), - onClick = onClick + onClick = { + val newNpSequence = when { + canSelect -> { + if (isSelected) { + npSequence.filter { m -> m.toString() != servantNumber.toString() } + } else { + npSequence + servantNumber + } + } + + isSelected -> { + npSequence.filter { m -> m.toString() != servantNumber.toString() } + } + + else -> { + npSequence.dropLast(1) + servantNumber + } + } + onNpSequenceChange(newNpSequence) + + + } ) { Text( - stringResource(R.string.skill_maker_atk_servant_np, it), + stringResource(R.string.skill_maker_atk_servant_np, servantNumber), textAlign = TextAlign.Center, modifier = Modifier.padding(16.dp), - color = - if (isSelected) - Color.White - else Color.Unspecified + color = when { + isSelected -> Color.White + !canSelect -> Color.Unspecified.copy(alpha = 0.3f) + else -> Color.Unspecified + } + ) } } @@ -90,36 +119,54 @@ private fun SelectNps( @Composable private fun CardsBeforeNp( + modifier: Modifier = Modifier, + numberOfNpSelected: Int, cardsBeforeNp: Int, onCardsBeforeNpChange: (Int) -> Unit ) { - Column { + Column( + modifier = modifier + ) { Text(stringResource(R.string.skill_maker_atk_cards_before_np)) Row { - (0..2).map { - val isSelected = cardsBeforeNp == it + (0..2).map { cardNumber -> + val isSelected = cardsBeforeNp == cardNumber + + val canSelect = numberOfNpSelected + cardNumber <= 3 + + val animatedColorState by animateColorAsState( + targetValue = when { + isSelected -> colorResource(R.color.colorAccent) + !canSelect -> MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f) + else -> MaterialTheme.colorScheme.surfaceVariant + }, + label = "Add animation to the changing of color" + ) Surface( tonalElevation = 5.dp, shape = MaterialTheme.shapes.medium, - color = - if (isSelected) - colorResource(R.color.colorAccent) - else MaterialTheme.colorScheme.surfaceVariant, + color = animatedColorState, modifier = Modifier .padding(5.dp), - onClick = { onCardsBeforeNpChange(it) } + enabled = canSelect, + onClick = { + if (canSelect) { + onCardsBeforeNpChange(cardNumber) + } + } ) { Text( - it.toString(), + cardNumber.toString(), textAlign = TextAlign.Center, modifier = Modifier .padding(16.dp, 10.dp), - color = - if (isSelected) - Color.White - else Color.Unspecified + color = when { + isSelected -> Color.White + !canSelect -> Color.Unspecified.copy(alpha = 0.3f) + else -> Color.Unspecified + } ) } } @@ -129,6 +176,8 @@ private fun CardsBeforeNp( @Composable fun SkillMakerAtk( + wave: Int, + turn: Int, onNextWave: (AutoSkillAction.Atk) -> Unit, onNextTurn: (AutoSkillAction.Atk) -> Unit ) { @@ -137,34 +186,62 @@ fun SkillMakerAtk( .fillMaxHeight() .padding(16.dp) ) { - FGATitle( - stringResource(R.string.skill_maker_atk_header) - ) + + Box( + modifier = Modifier + .fillMaxWidth() + ) { + FGATitle( + stringResource(R.string.skill_maker_atk_header), + modifier = Modifier.align(Alignment.Center) + ) + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.align(Alignment.CenterEnd) + ) { + Text(stringResource(R.string.skill_maker_main_wave, wave)) + + Text(stringResource(R.string.skill_maker_main_turn, turn)) + } + } var npSequence by rememberSaveable { mutableStateOf("") } + var cardsBeforeNp by rememberSaveable { mutableIntStateOf(0) } + + var numberOfNPs by rememberSaveable { mutableIntStateOf(0) } SelectNps( + numberOfCardsSelected = cardsBeforeNp, npSequence = npSequence, - onNpSequenceChange = { npSequence = it }, + onNpSequenceChange = { NPs -> + npSequence = NPs + numberOfNPs = (1..3).count { it.toString() in npSequence } + }, modifier = Modifier .weight(1f) .fillMaxWidth() ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, + Box( + contentAlignment = Alignment.Center, modifier = Modifier .fillMaxWidth() ) { - var cardsBeforeNp by rememberSaveable { mutableStateOf(0) } + CardsBeforeNp( + modifier = Modifier.align(Alignment.CenterStart), + numberOfNpSelected = numberOfNPs, cardsBeforeNp = cardsBeforeNp, onCardsBeforeNpChange = { cardsBeforeNp = it } ) - Row { + + Row( + modifier = Modifier.align(Alignment.CenterEnd), + verticalAlignment = Alignment.CenterVertically + ) { Button( onClick = { onNextTurn(makeAtkAction(npSequence, cardsBeforeNp)) }, modifier = Modifier diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerMain.kt b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerMain.kt index c03a2e83d..683b18a48 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerMain.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerMain.kt @@ -70,8 +70,16 @@ fun SkillMakerMain( onSelectedChange = { vm.setEnemyTarget(it) } ) - val stage by vm.stage - Text(stringResource(R.string.skill_maker_main_battle, stage)) + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + val wave by vm.wave + Text(stringResource(R.string.skill_maker_main_wave, wave)) + + val turn by vm.turn + Text(stringResource(R.string.skill_maker_main_turn, turn)) + } } SkillHistory(vm) diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerSavedState.kt b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerSavedState.kt index 6ee1a87b0..39ae881ee 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerSavedState.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerSavedState.kt @@ -7,7 +7,8 @@ import kotlinx.parcelize.Parcelize data class SkillMakerSavedState( val skillString: String? = null, val enemyTarget: Int? = null, - val stage: Int = 1, + val wave: Int = 1, + val turn: Int = 1, val currentSkill: Char = '0', val currentIndex: Int = 0 ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerViewModel.kt b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerViewModel.kt index 16b20b9de..d93e43089 100644 --- a/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerViewModel.kt +++ b/app/src/main/java/io/github/fate_grand_automata/ui/skill_maker/SkillMakerViewModel.kt @@ -1,6 +1,7 @@ package io.github.fate_grand_automata.ui.skill_maker import androidx.compose.runtime.State +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel @@ -47,13 +48,20 @@ class SkillMakerViewModel @Inject constructor( m } - private val _stage = mutableStateOf( + private val _wave = mutableIntStateOf( if (state.skillString != null) { - state.stage + state.wave } else { model.skillCommand.count { it is SkillMakerEntry.Next.Wave } + 1 } ) + private val _turn = mutableIntStateOf( + if (state.skillString != null){ + state.turn + } else { + model.skillCommand.count { it is SkillMakerEntry.Next } + 1 + } + ) private val _currentIndex = mutableStateOf( if (state.skillString != null) { @@ -68,7 +76,8 @@ class SkillMakerViewModel @Inject constructor( val saveState = SkillMakerSavedState( skillString = model.toString(), enemyTarget = enemyTarget.value, - stage = stage.value, + wave = wave.value, + turn = turn.value, currentSkill = currentSkill, currentIndex = currentIndex.value ) @@ -144,8 +153,12 @@ class SkillMakerViewModel @Inject constructor( fun unSelectTargets() = setEnemyTarget(null) - val stage: State = _stage - private fun prevStage() = --_stage.value + val wave: State = _wave + private fun prevStage() = --_wave.value + + val turn: State = _turn + + private fun prevTurn() = --_turn.value fun initSkill(skill: Skill) { currentSkill = skill.autoSkillCode @@ -188,13 +201,16 @@ class SkillMakerViewModel @Inject constructor( } fun nextTurn(atk: AutoSkillAction.Atk) { + ++_turn.value + add(SkillMakerEntry.Next.Turn(atk)) back() } - fun nextStage(atk: AutoSkillAction.Atk) { - ++_stage.value + fun nextWave(atk: AutoSkillAction.Atk) { + ++_wave.value + ++_turn.value // Uncheck selected targets unSelectTargets() @@ -261,6 +277,10 @@ class SkillMakerViewModel @Inject constructor( // Decrement Battle/Turn count if (last is SkillMakerEntry.Next.Wave) { prevStage() + prevTurn() + } + if (last is SkillMakerEntry.Next.Turn){ + prevTurn() } // Undo the Battle/Turn change diff --git a/app/src/main/res/values-b+zh+CN/localized.xml b/app/src/main/res/values-b+zh+CN/localized.xml index 36eff47fc..086a4f5ea 100644 --- a/app/src/main/res/values-b+zh+CN/localized.xml +++ b/app/src/main/res/values-b+zh+CN/localized.xml @@ -35,7 +35,6 @@ "下一回合 (同一波敌人)" "敌人 %d" - "战斗 %d" "御主技能" "重设" "从者 %d" diff --git a/app/src/main/res/values-b+zh+TW/localized.xml b/app/src/main/res/values-b+zh+TW/localized.xml index afedb79d9..3c8e1a3b0 100644 --- a/app/src/main/res/values-b+zh+TW/localized.xml +++ b/app/src/main/res/values-b+zh+TW/localized.xml @@ -35,7 +35,7 @@ 下一回合\n(同一波敵人) 敵人 %d - BATTLE %d + BATTLE %d 御主技能 重設 從者 %d diff --git a/app/src/main/res/values-ja/localized.xml b/app/src/main/res/values-ja/localized.xml index 02effb44d..440b6bbbd 100644 --- a/app/src/main/res/values-ja/localized.xml +++ b/app/src/main/res/values-ja/localized.xml @@ -35,7 +35,7 @@ "次のターン 同じウェーブ" "敵 %d" - "Battle: %d" + "Battle: %d" "マスター スキル" "全削除" diff --git a/app/src/main/res/values-ko/localized.xml b/app/src/main/res/values-ko/localized.xml index 834699aee..a28788c85 100644 --- a/app/src/main/res/values-ko/localized.xml +++ b/app/src/main/res/values-ko/localized.xml @@ -35,7 +35,6 @@ "동일 웨이브 중 다음 턴" "적 %d" - "배틀: %d" "마스터 스킬" "초기화" diff --git a/app/src/main/res/values-vi/localized.xml b/app/src/main/res/values-vi/localized.xml index 4cfa1b4bc..09616ee03 100644 --- a/app/src/main/res/values-vi/localized.xml +++ b/app/src/main/res/values-vi/localized.xml @@ -34,7 +34,6 @@ Bảo Khí" "Lượt tiếp theo" "Lượt tiếp treo trong một lượt quái" "Quái %d" - "Trận đấu: %d" "Kĩ năng Master" "Dọn sạch" diff --git a/app/src/main/res/values/localized.xml b/app/src/main/res/values/localized.xml index a908690ed..a7bd5e6f8 100644 --- a/app/src/main/res/values/localized.xml +++ b/app/src/main/res/values/localized.xml @@ -35,7 +35,8 @@ NP" "Next Turn in same wave" "Enemy %d" - "Battle: %d" + "Wave: %d" + "Turn: %d" "Master Skills" "Delete selected"