Skip to content

Commit

Permalink
[0.2.0.alpha/AN-UI] 배틀 도우미 선택 화면 구현 (#239)
Browse files Browse the repository at this point in the history
* ui: 배틀 선택 activity 정의

* ui: 포켓몬, 기술 선택 fragment 정의

* ui: 선택 UI 모델 정의

* ui: 포켓몬, 기술 선택 어댑터 정의

* chore: 패키지 분리

* ui: 아이템 선택 시 선택된 효과 표시

* ui: 선택된 포켓몬 정보 연결

* feat: 화면 이동 버튼 기능 구현

* chore: UiState 패키지 이동

- 배틀 선택 페이지 내에 있던 UiState를 배틀 패키지 내로 이동

---------

Co-authored-by: JoYehyun <[email protected]>
  • Loading branch information
murjune and JoYehyun99 committed Aug 19, 2024
1 parent 33c0cea commit bc3e8a1
Show file tree
Hide file tree
Showing 31 changed files with 1,041 additions and 3 deletions.
3 changes: 3 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.PokeRogueHelper"
tools:targetApi="31">
<activity
android:name=".presentation.battle.selection.BattleSelectionActivity"
android:exported="false" />
<activity
android:name=".presentation.battle.BattleActivity"
android:exported="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import poke.rogue.helper.R
import poke.rogue.helper.databinding.ActivityBattleBinding
import poke.rogue.helper.presentation.base.toolbar.ToolbarActivity
import poke.rogue.helper.presentation.battle.model.WeatherUiModel
import poke.rogue.helper.presentation.battle.selection.BattleSelectionActivity
import poke.rogue.helper.presentation.util.context.startActivity
import poke.rogue.helper.presentation.util.repeatOnStarted

class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_battle) {
Expand All @@ -30,6 +32,10 @@ class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_
private fun initView() {
binding.vm = viewModel
binding.lifecycleOwner = this

binding.ivMinePokemon.setOnClickListener {
startActivity<BattleSelectionActivity> { }
}
}

private fun initSpinner() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package poke.rogue.helper.presentation.battle

sealed interface BattleSelectionUiState<out T : Any> {
data class Selected<T : Any>(val selected: T) : BattleSelectionUiState<T>

data object Empty : BattleSelectionUiState<Nothing>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package poke.rogue.helper.presentation.battle.model

import poke.rogue.helper.presentation.type.model.TypeUiModel

data class PokemonSelectionUiModel(
val id: String,
val dexNumber: Long,
val name: String,
val frontImageUrl: String,
val backImageUrl: String,
val types: List<TypeUiModel>,
) {
companion object {
val DUMMY =
listOf(
PokemonSelectionUiModel(
id = "Bulbasaur",
dexNumber = 1,
name = "이상해씨",
frontImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png",
backImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png",
types =
listOf(
TypeUiModel.GRASS,
TypeUiModel.POISON,
),
),
PokemonSelectionUiModel(
id = "Charmander",
dexNumber = 4,
name = "파이리",
frontImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png",
backImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/4.png",
types = listOf(TypeUiModel.FIRE),
),
PokemonSelectionUiModel(
id = "Squirtle",
dexNumber = 7,
name = "꼬북이",
frontImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png",
backImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/7.png",
types = listOf(TypeUiModel.WATER),
),
PokemonSelectionUiModel(
id = "Pikachu",
dexNumber = 25,
name = "피카츄",
frontImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png",
backImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/25.png",
types = listOf(TypeUiModel.ELECTRIC),
),
PokemonSelectionUiModel(
id = "Charizard",
dexNumber = 6,
name = "리자몽",
frontImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png",
backImageUrl = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/6.png",
types = listOf(TypeUiModel.FIRE, TypeUiModel.FLYING),
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package poke.rogue.helper.presentation.battle.model

import poke.rogue.helper.presentation.type.model.TypeUiModel

data class SkillSelectionUiModel(
val id: String,
val name: String,
val type: TypeUiModel,
val category: String,
) {
companion object {
val DUMMY =
listOf(
SkillSelectionUiModel(
id = "1",
name = "몸통박치기",
type = TypeUiModel.NORMAL,
category = "Physical Attack",
),
SkillSelectionUiModel(
id = "2",
name = "울음소리",
type = TypeUiModel.NORMAL,
category = "Status Change",
),
SkillSelectionUiModel(
id = "3",
name = "덩굴채찍",
type = TypeUiModel.GRASS,
category = "Physical Attack",
),
SkillSelectionUiModel(
id = "4",
name = "성장",
type = TypeUiModel.NORMAL,
category = "Status Change",
),
SkillSelectionUiModel(
id = "5",
name = "씨뿌리기",
type = TypeUiModel.GRASS,
category = "Status Change",
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package poke.rogue.helper.presentation.battle.selection

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
import poke.rogue.helper.R
import poke.rogue.helper.databinding.ActivityBattleSelectionBinding
import poke.rogue.helper.presentation.base.error.ErrorHandleActivity
import poke.rogue.helper.presentation.base.error.ErrorHandleViewModel
import poke.rogue.helper.presentation.battle.BattleSelectionUiState
import poke.rogue.helper.presentation.util.repeatOnStarted
import poke.rogue.helper.presentation.util.view.setImage

class BattleSelectionActivity :
ErrorHandleActivity<ActivityBattleSelectionBinding>(R.layout.activity_battle_selection) {
private val viewModel by viewModels<BattleSelectionViewModel>()
private val selectionPagerAdapter: BattleSelectionPagerAdapter by lazy {
BattleSelectionPagerAdapter(this)
}

override val errorViewModel: ErrorHandleViewModel
get() = viewModel

override val toolbar: Toolbar
get() = binding.toolbarBattleSelection

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initViews()
initObserver()
}

private fun initViews() {
binding.lifecycleOwner = this
binding.vm = viewModel
binding.pagerBattleSelection.adapter = selectionPagerAdapter
binding.pagerBattleSelection.isUserInputEnabled = false
}

private fun initObserver() {
repeatOnStarted {
viewModel.selectedPokemon.collect { selectionState ->
if (selectionState is BattleSelectionUiState.Selected) {
val selected = selectionState.selected
binding.ivPokemon.setImage(selected.frontImageUrl)
binding.toolbarBattleSelection.title = selected.name
}
}
}

repeatOnStarted {
viewModel.currentStep.collect {
binding.pagerBattleSelection.currentItem = it.ordinal
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package poke.rogue.helper.presentation.battle.selection

import poke.rogue.helper.presentation.battle.model.PokemonSelectionUiModel
import poke.rogue.helper.presentation.battle.model.SkillSelectionUiModel

interface BattleSelectionHandler {
fun selectPokemon(pokemon: PokemonSelectionUiModel)

fun selectSkill(skill: SkillSelectionUiModel)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package poke.rogue.helper.presentation.battle.selection

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import poke.rogue.helper.presentation.battle.selection.pokemon.PokemonSelectionFragment
import poke.rogue.helper.presentation.battle.selection.skill.SkillSelectionFragment

class BattleSelectionPagerAdapter(fragmentActivity: FragmentActivity) :
FragmentStateAdapter(fragmentActivity) {
private val pages = SelectionStep.entries

override fun getItemCount(): Int = pages.size

override fun createFragment(position: Int): Fragment =
when (pages[position]) {
SelectionStep.POKEMON_SELECTION -> PokemonSelectionFragment()
SelectionStep.SKILL_SELECTION -> SkillSelectionFragment()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package poke.rogue.helper.presentation.battle.selection

import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import poke.rogue.helper.analytics.AnalyticsLogger
import poke.rogue.helper.analytics.analyticsLogger
import poke.rogue.helper.presentation.base.error.ErrorHandleViewModel
import poke.rogue.helper.presentation.battle.BattleSelectionUiState
import poke.rogue.helper.presentation.battle.model.PokemonSelectionUiModel
import poke.rogue.helper.presentation.battle.model.SkillSelectionUiModel

class BattleSelectionViewModel(
logger: AnalyticsLogger = analyticsLogger(),
) : ErrorHandleViewModel(logger), BattleSelectionHandler, NavigationHandler {
private val _pokemons = MutableStateFlow(PokemonSelectionUiModel.DUMMY)
val pokemons = _pokemons.asStateFlow()

private val _selectedPokemon =
MutableStateFlow<BattleSelectionUiState<PokemonSelectionUiModel>>(BattleSelectionUiState.Empty)
val selectedPokemon = _selectedPokemon.asStateFlow()

private val _skills = MutableStateFlow(SkillSelectionUiModel.DUMMY)
val skills = _skills.asStateFlow()

private val _selectedSkill =
MutableStateFlow<BattleSelectionUiState<SkillSelectionUiModel>>(BattleSelectionUiState.Empty)
val selectedSkill = _selectedSkill.asStateFlow()

private val _currentStep = MutableStateFlow(SelectionStep.POKEMON_SELECTION)
val currentStep: StateFlow<SelectionStep> = _currentStep.asStateFlow()

override fun selectPokemon(pokemon: PokemonSelectionUiModel) {
_selectedPokemon.value = BattleSelectionUiState.Selected(pokemon)
}

override fun selectSkill(skill: SkillSelectionUiModel) {
_selectedSkill.value = BattleSelectionUiState.Selected(skill)
}

override fun navigateToNextPage() {
val nextPage =
when (currentStep.value) {
SelectionStep.POKEMON_SELECTION -> SelectionStep.SKILL_SELECTION
SelectionStep.SKILL_SELECTION -> return // TODO : Complete Selection
}
_currentStep.value = nextPage
}

override fun navigateToPrevPage() {
val prevPage =
when (currentStep.value) {
SelectionStep.POKEMON_SELECTION -> return
SelectionStep.SKILL_SELECTION -> SelectionStep.POKEMON_SELECTION
}
_currentStep.value = prevPage
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package poke.rogue.helper.presentation.battle.selection

interface NavigationHandler {
fun navigateToNextPage()

fun navigateToPrevPage()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package poke.rogue.helper.presentation.battle.selection

import android.view.View
import androidx.databinding.BindingAdapter
import poke.rogue.helper.R

@BindingAdapter("invisible")
fun View.setInvisible(invisible: Boolean) {
visibility = if (invisible) View.INVISIBLE else View.VISIBLE
}

@BindingAdapter("selectedBackground")
fun View.setBackground(isSelected: Boolean) {
if (isSelected) {
setBackgroundResource(R.drawable.bg_battle_selected_border)
} else {
setBackgroundResource(R.drawable.bg_battle_default)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package poke.rogue.helper.presentation.battle.selection

enum class SelectionStep(val buttonText: String) {
POKEMON_SELECTION("다음"),
SKILL_SELECTION("선택 완료"),
;

fun isLastStep(hasSkillSelection: Boolean): Boolean {
return if (hasSkillSelection) {
this == SKILL_SELECTION
} else {
this == POKEMON_SELECTION
}
}
}
Loading

0 comments on commit bc3e8a1

Please sign in to comment.