Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.1.1/AN-FEAT] 페이지 이동 로직 개선 #379

Open
wants to merge 11 commits into
base: an/develop
Choose a base branch
from
22 changes: 18 additions & 4 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ val properties =

android {
namespace = libs.versions.applicationId.get()
compileSdk = libs.versions.compileSdk.get().toInt()
compileSdk =
libs.versions.compileSdk
.get()
.toInt()
signingConfigs {
getByName("debug") {
keyAlias = "androiddebugkey"
Expand All @@ -35,10 +38,19 @@ android {
}
defaultConfig {
applicationId = libs.versions.applicationId.get()
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
minSdk =
libs.versions.minSdk
.get()
.toInt()
targetSdk =
libs.versions.targetSdk
.get()
.toInt()
versionName = libs.versions.appVersion.get()
versionCode = libs.versions.versionCode.get().toInt()
versionCode =
libs.versions.versionCode
.get()
.toInt()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["runnerBuilder"] =
"de.mannodermaus.junit5.AndroidJUnit5Builder"
Expand Down Expand Up @@ -174,4 +186,6 @@ dependencies {
androidTestImplementation(libs.bundles.android.test)
testRuntimeOnly(libs.junit.vintage.engine)
androidTestRuntimeOnly(libs.junit5.android.test.runner)

implementation(libs.balloon)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package poke.rogue.helper.presentation.battle

import WeatherSpinnerAdapter
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
Expand All @@ -17,13 +19,19 @@ import poke.rogue.helper.presentation.battle.view.itemSelectListener
import poke.rogue.helper.presentation.util.context.colorOf
import poke.rogue.helper.presentation.util.parcelable
import poke.rogue.helper.presentation.util.repeatOnStarted
import poke.rogue.helper.presentation.util.serializable
import poke.rogue.helper.presentation.util.view.setImage
import timber.log.Timber

class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_battle) {
private val viewModel by viewModels<BattleViewModel> {
BattleViewModel.factory(DefaultBattleRepository.instance(applicationContext))
BattleViewModel.factory(
intent.getStringExtra(POKEMON_ID),
intent.serializable(SELECTION_TYPE),
DefaultBattleRepository.instance(applicationContext),
)
}

private val weatherAdapter by lazy {
WeatherSpinnerAdapter(this)
}
Expand Down Expand Up @@ -128,4 +136,20 @@ class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_
}
}
}

companion object {
private const val POKEMON_ID = "pokemonId"
private const val SELECTION_TYPE = "selectionType"

fun intent(
context: Context,
pokemonId: String,
isMine: Boolean,
): Intent =
Intent(context, BattleActivity::class.java).apply {
putExtra(POKEMON_ID, pokemonId)
val selectionType = if (isMine) SelectionType.MINE else SelectionType.OPPONENT
putExtra(SELECTION_TYPE, selectionType)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ import poke.rogue.helper.presentation.battle.model.toUi
class BattleViewModel(
private val battleRepository: BattleRepository,
private val logger: AnalyticsLogger = analyticsLogger(),
) : ErrorHandleViewModel(logger), BattleNavigationHandler {
pokemonId: String? = null,
selectionType: SelectionType? = null,
) : ErrorHandleViewModel(logger),
BattleNavigationHandler {
private val _weathers = MutableStateFlow(emptyList<WeatherUiModel>())
val weathers = _weathers.asStateFlow()

Expand All @@ -48,7 +51,8 @@ class BattleViewModel(
if (weathers.any { it.id == weather.id }.not()) return@combine null
val selectedWeather = weathers.first { it.id == weather.id }
// update selected weather
_selectedState.value = selectedState.value.copy(weather = BattleSelectionUiState.Selected(selectedWeather))
_selectedState.value =
selectedState.value.copy(weather = BattleSelectionUiState.Selected(selectedWeather))
// return position
weathers.indexOfFirst { it.id == weather.id }
}.filterNotNull()
Expand All @@ -58,26 +62,28 @@ class BattleViewModel(
val navigateToSelection = _navigateToSelection.asSharedFlow()

val battleResult: StateFlow<BattleResultUiState> =
selectedState.map {
if (it.allSelected) {
val result = fetchBattlePredictionResult()
BattleResultUiState.Success(result)
} else {
BattleResultUiState.Idle
}
}.stateIn(
viewModelScope + errorHandler,
SharingStarted.WhileSubscribed(5000),
BattleResultUiState.Idle,
)
selectedState
.map {
if (it.allSelected) {
val result = fetchBattlePredictionResult()
BattleResultUiState.Success(result)
} else {
BattleResultUiState.Idle
}
}.stateIn(
viewModelScope + errorHandler,
SharingStarted.WhileSubscribed(5000),
BattleResultUiState.Idle,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바뀐 코드가 개행 밖에 없는데 왜 이런 일이 생기는 거죠.. ?
이게 생각보다 코드 리뷰할 때 귀찮게 하긴 하네요 😲

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러게요,,,? 다시 확인 해볼께용


val isBattleFetchSuccessful =
battleResult.map { it.isSuccess() }
battleResult
.map { it.isSuccess() }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)

init {
initWeathers()
initSavedSelection()
handlePokemonSelection(pokemonId, selectionType)
}

private suspend fun fetchBattlePredictionResult(): BattlePredictionUiModel {
Expand All @@ -89,12 +95,13 @@ class BattleViewModel(
val opponentPokemonId =
requireNotNull(opponentPokemon.selectedData()?.id) { "상대 포켓몬은 null일 수 없습니다." }

return battleRepository.calculatedBattlePrediction(
weatherId = weatherId,
myPokemonId = myPokemonId,
mySkillId = mySkillId,
opponentPokemonId = opponentPokemonId,
).toUi()
return battleRepository
.calculatedBattlePrediction(
weatherId = weatherId,
myPokemonId = myPokemonId,
mySkillId = mySkillId,
opponentPokemonId = opponentPokemonId,
).toUi()
}
}

Expand All @@ -105,21 +112,62 @@ class BattleViewModel(
}
}

private fun initSavedSelection() {
private fun handlePokemonSelection(
pokemonId: String?,
selectionType: SelectionType?,
) {
when {
pokemonId == null -> {
fetchSavedMyPokemon()
fetchSavedOpponentPokemon()
}

selectionType == SelectionType.MINE -> {
selectMyPokemon(pokemonId)
fetchSavedOpponentPokemon()
}

selectionType == SelectionType.OPPONENT -> {
fetchSavedMyPokemon()
selectOpponentPokemon(pokemonId)
}

else -> error("선택 타입 정보를 알 수 없습니다.")
}
}

private fun fetchSavedMyPokemon() {
viewModelScope.launch {
launch {
battleRepository.savedPokemonStream().first()?.let {
updateOpponentPokemon(it.toSelectionUi())
}
battleRepository.savedPokemonWithSkillStream().first()?.let { (pokemon, skill) ->
updateMyPokemon(pokemon.toSelectionUi(), skill.toUi())
}
launch {
battleRepository.savedPokemonWithSkillStream().first()?.let { (pokemon, skill) ->
updateMyPokemon(pokemon.toSelectionUi(), skill.toUi())
}
}
}

private fun fetchSavedOpponentPokemon() {
viewModelScope.launch {
battleRepository.savedPokemonStream().first()?.let {
updateOpponentPokemon(it.toSelectionUi())
}
}
}

private fun selectMyPokemon(pokemonId: String) {
viewModelScope.launch {
val (pokemon, skill) = battleRepository.pokemonWithRandomSkill(pokemonId)
val selectionData = SelectionData.WithSkill(pokemon.toSelectionUi(), skill.toUi())
updatePokemonSelection(selectionData)
}
}

private fun selectOpponentPokemon(pokemonId: String) {
viewModelScope.launch {
val pokemon = battleRepository.pokemon(pokemonId)
val selectionData = SelectionData.WithoutSkill(pokemon.toSelectionUi())
updatePokemonSelection(selectionData)
}
}

fun updateWeather(newWeather: WeatherUiModel) {
viewModelScope.launch {
val selectedWeather = BattleSelectionUiState.Selected(newWeather)
Expand Down Expand Up @@ -191,19 +239,28 @@ class BattleViewModel(
private fun previousSelection(
hasSkillSelection: Boolean,
previousPokemonSelection: PokemonSelectionUiModel,
): SelectionData {
return if (hasSkillSelection) {
): SelectionData =
if (hasSkillSelection) {
val skill =
requireNotNull(selectedState.value.skill.selectedData()) { "스킬이 선택되어야 합니다." }
SelectionData.WithSkill(previousPokemonSelection, skill)
} else {
SelectionData.WithoutSkill(previousPokemonSelection)
}
}

companion object {
fun factory(battleRepository: BattleRepository): ViewModelProvider.Factory =
BaseViewModelFactory { BattleViewModel(battleRepository) }
fun factory(
pokemonId: String?,
selectionType: SelectionType?,
battleRepository: BattleRepository,
): ViewModelProvider.Factory =
BaseViewModelFactory {
BattleViewModel(
battleRepository = battleRepository,
pokemonId = pokemonId,
selectionType = selectionType,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package poke.rogue.helper.presentation.battle

enum class SelectionType {
MINE,
OPPONENT,
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import poke.rogue.helper.presentation.util.view.dp
class BiomeActivity : ErrorHandleActivity<ActivityBiomeBinding>(R.layout.activity_biome) {
private val viewModel by viewModels<BiomeViewModel> {
BiomeViewModel.factory(
DefaultBiomeRepository.instance(),
DefaultBiomeRepository.instance(applicationContext),
)
}
override val errorViewModel: ErrorHandleViewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,52 @@ import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
import com.google.android.material.tabs.TabLayoutMediator
import com.skydoves.balloon.ArrowPositionRules
import com.skydoves.balloon.BalloonAnimation
import com.skydoves.balloon.BalloonSizeSpec
import com.skydoves.balloon.createBalloon
import poke.rogue.helper.R
import poke.rogue.helper.analytics.analyticsLogger
import poke.rogue.helper.data.repository.DefaultBiomeRepository
import poke.rogue.helper.databinding.ActivityBiomeDetailBinding
import poke.rogue.helper.presentation.base.error.ErrorHandleActivity
import poke.rogue.helper.presentation.base.error.ErrorHandleViewModel
import poke.rogue.helper.presentation.battle.BattleActivity
import poke.rogue.helper.presentation.dex.detail.PokemonDetailActivity
import poke.rogue.helper.presentation.util.context.startActivity
import poke.rogue.helper.presentation.util.context.stringOf
import poke.rogue.helper.presentation.util.logClickEvent
import poke.rogue.helper.presentation.util.repeatOnStarted

class BiomeDetailActivity :
ErrorHandleActivity<ActivityBiomeDetailBinding>(R.layout.activity_biome_detail) {
class BiomeDetailActivity : ErrorHandleActivity<ActivityBiomeDetailBinding>(R.layout.activity_biome_detail) {
private lateinit var pagerAdapter: BiomeDetailPagerAdapter
private val viewModel: BiomeDetailViewModel by viewModels {
BiomeDetailViewModel.factory(
DefaultBiomeRepository.instance(),
DefaultBiomeRepository.instance(applicationContext),
analyticsLogger(),
)
}
override val errorViewModel: ErrorHandleViewModel
get() = viewModel
override val toolbar: Toolbar
get() = binding.toolbarBiomeDetail
private val tooltip by lazy {
createBalloon(this) {
setWidth(BalloonSizeSpec.WRAP)
setHeight(BalloonSizeSpec.WRAP)
setText(stringOf(R.string.biome_navigation_mode_info))
setTextColorResource(R.color.poke_white)
setTextSize(11f)
setArrowPositionRules(ArrowPositionRules.ALIGN_ANCHOR)
setArrowSize(10)
setArrowPosition(0.0f)
setPadding(12)
setCornerRadius(8f)
setBackgroundColorResource(R.color.poke_red_20)
setBalloonAnimation(BalloonAnimation.ELASTIC)
build()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -41,6 +63,7 @@ class BiomeDetailActivity :
binding.lifecycleOwner = this
initAdapter()
initObservers()
initTooltip()
}

private fun initAdapter() {
Expand All @@ -62,7 +85,7 @@ class BiomeDetailActivity :
is BiomeDetailUiEvent.NavigateToNextBiomeDetail -> {
val biomeId = event.biomeId
startActivity<BiomeDetailActivity> {
putExtras(BiomeDetailActivity.intent(this@BiomeDetailActivity, biomeId))
putExtras(intent(this@BiomeDetailActivity, biomeId))
analyticsLogger().logClickEvent(NAVIGATE_TO_NEXT_BIOME_DETAIL)
}
}
Expand All @@ -72,11 +95,24 @@ class BiomeDetailActivity :
putExtras(PokemonDetailActivity.intent(this@BiomeDetailActivity, pokemonId))
}
}

is BiomeDetailUiEvent.NavigateToBattle -> {
val pokemonId = event.pokemonId
startActivity<BattleActivity> {
putExtras(BattleActivity.intent(this@BiomeDetailActivity, pokemonId, isMine = false))
}
}
}
}
}
}

private fun initTooltip() {
binding.tvNavigationMode.setOnClickListener {
tooltip.showAlignTop(it)
}
}

companion object {
private const val BIOME_ID = "biomeId"
private const val NAVIGATE_TO_NEXT_BIOME_DETAIL = "Nav_Next_Biome_Detail"
Expand Down
Loading
Loading