diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6ac73280..64197610 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -17,6 +17,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.PokeRogueHelper"
tools:targetApi="31">
+
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleActivity.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleActivity.kt
index 59b55320..ced0411f 100644
--- a/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleActivity.kt
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleActivity.kt
@@ -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(R.layout.activity_battle) {
@@ -30,6 +32,10 @@ class BattleActivity : ToolbarActivity(R.layout.activity_
private fun initView() {
binding.vm = viewModel
binding.lifecycleOwner = this
+
+ binding.ivMinePokemon.setOnClickListener {
+ startActivity { }
+ }
}
private fun initSpinner() {
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleSelectionUiState.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleSelectionUiState.kt
new file mode 100644
index 00000000..2c8ccca3
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleSelectionUiState.kt
@@ -0,0 +1,7 @@
+package poke.rogue.helper.presentation.battle
+
+sealed interface BattleSelectionUiState {
+ data class Selected(val selected: T) : BattleSelectionUiState
+
+ data object Empty : BattleSelectionUiState
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/PokemonSelectionUiModel.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/PokemonSelectionUiModel.kt
new file mode 100644
index 00000000..9acda68a
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/PokemonSelectionUiModel.kt
@@ -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,
+) {
+ 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),
+ ),
+ )
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/SkillSelectionUiModel.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/SkillSelectionUiModel.kt
new file mode 100644
index 00000000..88dcccf2
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/model/SkillSelectionUiModel.kt
@@ -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",
+ ),
+ )
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionActivity.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionActivity.kt
new file mode 100644
index 00000000..0db0c6f4
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionActivity.kt
@@ -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(R.layout.activity_battle_selection) {
+ private val viewModel by viewModels()
+ 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
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionHandler.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionHandler.kt
new file mode 100644
index 00000000..7cb1f879
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionHandler.kt
@@ -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)
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionPagerAdapter.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionPagerAdapter.kt
new file mode 100644
index 00000000..a3ade56d
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionPagerAdapter.kt
@@ -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()
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionViewModel.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionViewModel.kt
new file mode 100644
index 00000000..4bea52eb
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/BattleSelectionViewModel.kt
@@ -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.Empty)
+ val selectedPokemon = _selectedPokemon.asStateFlow()
+
+ private val _skills = MutableStateFlow(SkillSelectionUiModel.DUMMY)
+ val skills = _skills.asStateFlow()
+
+ private val _selectedSkill =
+ MutableStateFlow>(BattleSelectionUiState.Empty)
+ val selectedSkill = _selectedSkill.asStateFlow()
+
+ private val _currentStep = MutableStateFlow(SelectionStep.POKEMON_SELECTION)
+ val currentStep: StateFlow = _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
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/NavigationHandler.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/NavigationHandler.kt
new file mode 100644
index 00000000..94e19706
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/NavigationHandler.kt
@@ -0,0 +1,7 @@
+package poke.rogue.helper.presentation.battle.selection
+
+interface NavigationHandler {
+ fun navigateToNextPage()
+
+ fun navigateToPrevPage()
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionBindingAdapter.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionBindingAdapter.kt
new file mode 100644
index 00000000..19c55d79
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionBindingAdapter.kt
@@ -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)
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionStep.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionStep.kt
new file mode 100644
index 00000000..821bf185
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/SelectionStep.kt
@@ -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
+ }
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionAdapter.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionAdapter.kt
new file mode 100644
index 00000000..d59ef184
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionAdapter.kt
@@ -0,0 +1,66 @@
+package poke.rogue.helper.presentation.battle.selection.pokemon
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import poke.rogue.helper.databinding.ItemBattlePokemonSelectionBinding
+import poke.rogue.helper.presentation.battle.model.PokemonSelectionUiModel
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionHandler
+import poke.rogue.helper.presentation.util.view.ItemDiffCallback
+
+class PokemonSelectionAdapter(
+ private val selectionHandler: BattleSelectionHandler,
+) : ListAdapter(pokemonComparator) {
+ private var selectedPokemonId: String? = null
+
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int,
+ ): PokemonSelectionViewHolder =
+ PokemonSelectionViewHolder(
+ ItemBattlePokemonSelectionBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false,
+ ),
+ selectionHandler,
+ )
+
+ override fun onBindViewHolder(
+ viewHolder: PokemonSelectionViewHolder,
+ position: Int,
+ ) {
+ val pokemon = getItem(position)
+ val isSelected = pokemon.id == selectedPokemonId
+ viewHolder.bind(pokemon, isSelected)
+ }
+
+ fun updateSelectedPokemon(selectedId: String) {
+ var previousSelectedPosition: Int? = null
+ var newSelectedPosition: Int? = null
+
+ currentList.forEachIndexed { index, pokemon ->
+ if (pokemon.id == selectedPokemonId) {
+ previousSelectedPosition = index
+ }
+ if (pokemon.id == selectedId) {
+ newSelectedPosition = index
+ }
+ if (previousSelectedPosition != null && newSelectedPosition != null) {
+ return@forEachIndexed
+ }
+ }
+
+ selectedPokemonId = selectedId
+ previousSelectedPosition?.let { notifyItemChanged(it) }
+ newSelectedPosition?.let { notifyItemChanged(it) }
+ }
+
+ companion object {
+ private val pokemonComparator =
+ ItemDiffCallback(
+ onItemsTheSame = { oldItem, newItem -> oldItem.id == newItem.id },
+ onContentsTheSame = { oldItem, newItem -> oldItem == newItem },
+ )
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionFragment.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionFragment.kt
new file mode 100644
index 00000000..47a88cb9
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionFragment.kt
@@ -0,0 +1,64 @@
+package poke.rogue.helper.presentation.battle.selection.pokemon
+
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.widget.Toolbar
+import androidx.fragment.app.activityViewModels
+import poke.rogue.helper.R
+import poke.rogue.helper.databinding.FragmentPokemonSelectionBinding
+import poke.rogue.helper.presentation.base.error.ErrorHandleFragment
+import poke.rogue.helper.presentation.base.error.ErrorHandleViewModel
+import poke.rogue.helper.presentation.battle.BattleSelectionUiState
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionViewModel
+import poke.rogue.helper.presentation.util.repeatOnStarted
+import poke.rogue.helper.presentation.util.view.LinearSpacingItemDecoration
+import poke.rogue.helper.presentation.util.view.dp
+
+class PokemonSelectionFragment :
+ ErrorHandleFragment(R.layout.fragment_pokemon_selection) {
+ private val sharedViewModel: BattleSelectionViewModel by activityViewModels()
+ private val pokemonAdapter: PokemonSelectionAdapter by lazy {
+ PokemonSelectionAdapter(sharedViewModel)
+ }
+
+ override val errorViewModel: ErrorHandleViewModel
+ get() = sharedViewModel
+ override val toolbar: Toolbar?
+ get() = null
+
+ override fun onViewCreated(
+ view: View,
+ savedInstanceState: Bundle?,
+ ) {
+ super.onViewCreated(view, savedInstanceState)
+ initViews()
+ initObserver()
+ binding.lifecycleOwner = viewLifecycleOwner
+ }
+
+ private fun initViews() {
+ with(binding.rvPokemons) {
+ adapter = pokemonAdapter
+ addItemDecoration(
+ LinearSpacingItemDecoration(spacing = 4.dp, false),
+ )
+ }
+ }
+
+ private fun initObserver() {
+ repeatOnStarted {
+ sharedViewModel.pokemons.collect {
+ pokemonAdapter.submitList(it)
+ }
+ }
+
+ repeatOnStarted {
+ sharedViewModel.selectedPokemon.collect { selectionState ->
+ if (selectionState is BattleSelectionUiState.Selected) {
+ val selected = selectionState.selected
+ pokemonAdapter.updateSelectedPokemon(selected.id)
+ }
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionViewHolder.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionViewHolder.kt
new file mode 100644
index 00000000..7b399eb5
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/pokemon/PokemonSelectionViewHolder.kt
@@ -0,0 +1,29 @@
+package poke.rogue.helper.presentation.battle.selection.pokemon
+
+import androidx.recyclerview.widget.RecyclerView
+import poke.rogue.helper.databinding.ItemBattlePokemonSelectionBinding
+import poke.rogue.helper.presentation.battle.model.PokemonSelectionUiModel
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionHandler
+import poke.rogue.helper.presentation.biome.BiomeTypesAdapter
+import poke.rogue.helper.presentation.util.view.dp
+
+class PokemonSelectionViewHolder(
+ private val binding: ItemBattlePokemonSelectionBinding,
+ private val selectionHandler: BattleSelectionHandler,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(
+ pokemonSelectionUiModel: PokemonSelectionUiModel,
+ isSelected: Boolean,
+ ) {
+ binding.pokemon = pokemonSelectionUiModel
+ binding.isSelected = isSelected
+ binding.selectionHandler = selectionHandler
+
+ val typeAdapter = BiomeTypesAdapter(context = binding.root.context, binding.flexboxTypes)
+ typeAdapter.addTypes(
+ types = pokemonSelectionUiModel.types,
+ spacingBetweenTypes = 8.dp,
+ iconSize = 18.dp,
+ )
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionAdapter.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionAdapter.kt
new file mode 100644
index 00000000..56262071
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionAdapter.kt
@@ -0,0 +1,65 @@
+package poke.rogue.helper.presentation.battle.selection.skill
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import poke.rogue.helper.databinding.ItemBattleSkillSelectionBinding
+import poke.rogue.helper.presentation.battle.model.SkillSelectionUiModel
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionHandler
+import poke.rogue.helper.presentation.util.view.ItemDiffCallback
+
+class SkillSelectionAdapter(private val selectionHandler: BattleSelectionHandler) :
+ ListAdapter(skillComparator) {
+ private var selectedSkillId: String? = null
+
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int,
+ ): SkillSelectionViewHolder =
+ SkillSelectionViewHolder(
+ ItemBattleSkillSelectionBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false,
+ ),
+ selectionHandler,
+ )
+
+ override fun onBindViewHolder(
+ viewHolder: SkillSelectionViewHolder,
+ position: Int,
+ ) {
+ val skill = getItem(position)
+ val isSelected = skill.id == selectedSkillId
+ viewHolder.bind(skill, isSelected)
+ }
+
+ fun updateSelectedSkill(selectedId: String) {
+ var previousSelectedPosition: Int? = null
+ var newSelectedPosition: Int? = null
+
+ currentList.forEachIndexed { index, skill ->
+ if (skill.id == selectedSkillId) {
+ previousSelectedPosition = index
+ }
+ if (skill.id == selectedId) {
+ newSelectedPosition = index
+ }
+ if (previousSelectedPosition != null && newSelectedPosition != null) {
+ return@forEachIndexed
+ }
+ }
+
+ selectedSkillId = selectedId
+ previousSelectedPosition?.let { notifyItemChanged(it) }
+ newSelectedPosition?.let { notifyItemChanged(it) }
+ }
+
+ companion object {
+ private val skillComparator =
+ ItemDiffCallback(
+ onItemsTheSame = { oldItem, newItem -> oldItem.id == newItem.id },
+ onContentsTheSame = { oldItem, newItem -> oldItem == newItem },
+ )
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionFragment.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionFragment.kt
new file mode 100644
index 00000000..3591f1a5
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionFragment.kt
@@ -0,0 +1,65 @@
+package poke.rogue.helper.presentation.battle.selection.skill
+
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.widget.Toolbar
+import androidx.fragment.app.activityViewModels
+import poke.rogue.helper.R
+import poke.rogue.helper.databinding.FragmentSkillSelectionBinding
+import poke.rogue.helper.presentation.base.error.ErrorHandleFragment
+import poke.rogue.helper.presentation.base.error.ErrorHandleViewModel
+import poke.rogue.helper.presentation.battle.BattleSelectionUiState
+import poke.rogue.helper.presentation.battle.model.SkillSelectionUiModel
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionViewModel
+import poke.rogue.helper.presentation.util.repeatOnStarted
+import poke.rogue.helper.presentation.util.view.LinearSpacingItemDecoration
+import poke.rogue.helper.presentation.util.view.dp
+
+class SkillSelectionFragment :
+ ErrorHandleFragment(R.layout.fragment_skill_selection) {
+ private val sharedViewModel: BattleSelectionViewModel by activityViewModels()
+ private val skillAdapter: SkillSelectionAdapter by lazy {
+ SkillSelectionAdapter(sharedViewModel)
+ }
+
+ override val errorViewModel: ErrorHandleViewModel
+ get() = sharedViewModel
+ override val toolbar: Toolbar?
+ get() = null
+
+ override fun onViewCreated(
+ view: View,
+ savedInstanceState: Bundle?,
+ ) {
+ super.onViewCreated(view, savedInstanceState)
+ initViews()
+ initObserver()
+ skillAdapter.submitList(SkillSelectionUiModel.DUMMY)
+ }
+
+ private fun initViews() {
+ with(binding.rvSkills) {
+ adapter = skillAdapter
+ addItemDecoration(
+ LinearSpacingItemDecoration(spacing = 4.dp, false),
+ )
+ }
+ }
+
+ private fun initObserver() {
+ repeatOnStarted {
+ sharedViewModel.skills.collect {
+ skillAdapter.submitList(it)
+ }
+ }
+
+ repeatOnStarted {
+ sharedViewModel.selectedSkill.collect { selectionState ->
+ if (selectionState is BattleSelectionUiState.Selected) {
+ val selected = selectionState.selected
+ skillAdapter.updateSelectedSkill(selected.id)
+ }
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionViewHolder.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionViewHolder.kt
new file mode 100644
index 00000000..87635ad4
--- /dev/null
+++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/selection/skill/SkillSelectionViewHolder.kt
@@ -0,0 +1,20 @@
+package poke.rogue.helper.presentation.battle.selection.skill
+
+import androidx.recyclerview.widget.RecyclerView
+import poke.rogue.helper.databinding.ItemBattleSkillSelectionBinding
+import poke.rogue.helper.presentation.battle.model.SkillSelectionUiModel
+import poke.rogue.helper.presentation.battle.selection.BattleSelectionHandler
+
+class SkillSelectionViewHolder(
+ private val binding: ItemBattleSkillSelectionBinding,
+ private val selectionHandler: BattleSelectionHandler,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(
+ skillSelectionUiModel: SkillSelectionUiModel,
+ isSelected: Boolean,
+ ) {
+ binding.skill = skillSelectionUiModel
+ binding.isSelected = isSelected
+ binding.selectionHandler = selectionHandler
+ }
+}
diff --git a/android/app/src/main/res/drawable/bg_battle_selection.xml b/android/app/src/main/res/drawable/bg_battle_default.xml
similarity index 100%
rename from android/app/src/main/res/drawable/bg_battle_selection.xml
rename to android/app/src/main/res/drawable/bg_battle_default.xml
diff --git a/android/app/src/main/res/drawable/bg_battle_selected_border.xml b/android/app/src/main/res/drawable/bg_battle_selected_border.xml
new file mode 100644
index 00000000..f8be55a2
--- /dev/null
+++ b/android/app/src/main/res/drawable/bg_battle_selected_border.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/bg_before_button.xml b/android/app/src/main/res/drawable/bg_before_button.xml
new file mode 100644
index 00000000..67c5e19c
--- /dev/null
+++ b/android/app/src/main/res/drawable/bg_before_button.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/bg_button_enabled_selector.xml b/android/app/src/main/res/drawable/bg_button_enabled_selector.xml
new file mode 100644
index 00000000..93a5bcc0
--- /dev/null
+++ b/android/app/src/main/res/drawable/bg_button_enabled_selector.xml
@@ -0,0 +1,15 @@
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/bg_search_view.xml b/android/app/src/main/res/drawable/bg_search_view.xml
index f6a1cfdb..46889101 100644
--- a/android/app/src/main/res/drawable/bg_search_view.xml
+++ b/android/app/src/main/res/drawable/bg_search_view.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/android/app/src/main/res/drawable/icon_arrow_right_pixel.png b/android/app/src/main/res/drawable/icon_arrow_right_pixel.png
new file mode 100644
index 00000000..940fa98c
Binary files /dev/null and b/android/app/src/main/res/drawable/icon_arrow_right_pixel.png differ
diff --git a/android/app/src/main/res/layout/activity_battle.xml b/android/app/src/main/res/layout/activity_battle.xml
index d98ab243..0ccd83e1 100644
--- a/android/app/src/main/res/layout/activity_battle.xml
+++ b/android/app/src/main/res/layout/activity_battle.xml
@@ -157,7 +157,7 @@
style="@style/TextAppearance.Poke.TitleBold"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:background="@drawable/bg_battle_selection"
+ android:background="@drawable/bg_battle_default"
android:paddingHorizontal="4dp"
android:paddingVertical="8dp"
android:text="@string/battle_move_selection"
@@ -183,7 +183,7 @@
android:layout_width="2dp"
android:layout_height="0dp"
android:layout_margin="24dp"
- android:background="@drawable/bg_battle_selection"
+ android:background="@drawable/bg_battle_default"
app:layout_constraintBottom_toBottomOf="@id/gl_bottom"
app:layout_constraintEnd_toEndOf="@id/gl_end"
app:layout_constraintStart_toStartOf="@id/gl_start"
diff --git a/android/app/src/main/res/layout/activity_battle_selection.xml b/android/app/src/main/res/layout/activity_battle_selection.xml
new file mode 100644
index 00000000..23babf3d
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_battle_selection.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/fragment_pokemon_selection.xml b/android/app/src/main/res/layout/fragment_pokemon_selection.xml
new file mode 100644
index 00000000..86c2fc40
--- /dev/null
+++ b/android/app/src/main/res/layout/fragment_pokemon_selection.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/fragment_skill_selection.xml b/android/app/src/main/res/layout/fragment_skill_selection.xml
new file mode 100644
index 00000000..7ac09d40
--- /dev/null
+++ b/android/app/src/main/res/layout/fragment_skill_selection.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/item_battle_pokemon_selection.xml b/android/app/src/main/res/layout/item_battle_pokemon_selection.xml
new file mode 100644
index 00000000..57c08717
--- /dev/null
+++ b/android/app/src/main/res/layout/item_battle_pokemon_selection.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/item_battle_skill_selection.xml b/android/app/src/main/res/layout/item_battle_skill_selection.xml
new file mode 100644
index 00000000..8ff2db60
--- /dev/null
+++ b/android/app/src/main/res/layout/item_battle_skill_selection.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index cee8c27c..c16cb314 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -78,6 +78,10 @@
내 포켓몬을 선택해주세요!
상대 포켓몬을 선택해주세요!
기술을 선택해주세요!
+ 선택 완료
+ 기술을 검색하세요
+ 포켓몬을 검색하세요
+ 포켓몬을 선택하세요
알수없는 문제가 발생했습니다..