Skip to content

Commit

Permalink
[1.1.0/AN_FEAT] 배틀 구도 날씨 저장 (#343)
Browse files Browse the repository at this point in the history
* chore: DataStore 의존성 설정

* feat: Datastore 저장 로직 추가

* feat: 저장된 선택 데이터 UI 에 반영

* refactor: Skill 캐싱

* refactor: Test 객체 수정

* refactor: context 참조 수정

* refactor: 리팩토링 리뷰 반영

* refactor: 아이디 저장값 분리

* feat: Spinner 초기화 시 0으로 자동 선택되는거 방지하는 ItemSelectListener 구현

* feat: 날씨저장

* fix: BattleActivity  Context 수정

* refactor: xxStream postFix 붙이기, suspend 함수 제거

* ktlintFormat

* fix: weather 가 결과에 영향 안주던거 수정

* refactor : Flow 반환 함수 네이밍 (Stream) 붙이기

* refactor: hashMap -> mutableMap

* ktLintFormat

---------

Co-authored-by: JoYehyun <[email protected]>
  • Loading branch information
murjune and JoYehyun99 authored Oct 13, 2024
1 parent c26fa01 commit 61aa1a4
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package poke.rogue.helper.presentation.battle
import WeatherSpinnerAdapter
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
Expand All @@ -15,14 +13,16 @@ import poke.rogue.helper.presentation.base.toolbar.ToolbarActivity
import poke.rogue.helper.presentation.battle.model.SelectionData
import poke.rogue.helper.presentation.battle.model.WeatherUiModel
import poke.rogue.helper.presentation.battle.selection.BattleSelectionActivity
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.view.setImage
import timber.log.Timber

class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_battle) {
private val viewModel by viewModels<BattleViewModel> {
BattleViewModel.factory(DefaultBattleRepository.instance(this))
BattleViewModel.factory(DefaultBattleRepository.instance(applicationContext))
}
private val weatherAdapter by lazy {
WeatherSpinnerAdapter(this)
Expand Down Expand Up @@ -58,19 +58,8 @@ class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_
private fun initSpinner() {
binding.spinnerWeather.adapter = weatherAdapter
binding.spinnerWeather.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View?,
position: Int,
id: Long,
) {
val selectedWeather = parent.getItemAtPosition(position) as WeatherUiModel
viewModel.updateWeather(selectedWeather)
}

override fun onNothingSelected(parent: AdapterView<*>?) {
}
itemSelectListener<WeatherUiModel> {
viewModel.updateWeather(it)
}
}

Expand All @@ -80,6 +69,13 @@ class BattleActivity : ToolbarActivity<ActivityBattleBinding>(R.layout.activity_
weatherAdapter.updateWeathers(it)
}
}
repeatOnStarted {
viewModel.weatherPos
.collect {
Timber.tag("weatherPos").d("weatherPos: $it")
binding.spinnerWeather.setSelection(it)
}
}

repeatOnStarted {
viewModel.selectedState.collect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
Expand Down Expand Up @@ -37,6 +39,21 @@ class BattleViewModel(
private val _selectedState = MutableStateFlow(BattleSelectionsState.DEFAULT)
val selectedState = _selectedState.asStateFlow()

val weatherPos: StateFlow<Int> =
combine(
battleRepository.savedWeatherStream(),
weathers,
) { weather, weathers ->
if (weather == null || weathers.isEmpty()) return@combine null
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))
// return position
weathers.indexOfFirst { it.id == weather.id }
}.filterNotNull()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0)

private val _navigateToSelection = MutableSharedFlow<SelectionNavigationData>()
val navigateToSelection = _navigateToSelection.asSharedFlow()

Expand Down Expand Up @@ -91,12 +108,12 @@ class BattleViewModel(
private fun initSavedSelection() {
viewModelScope.launch {
launch {
battleRepository.savedPokemon().first()?.let {
battleRepository.savedPokemonStream().first()?.let {
updateOpponentPokemon(it.toSelectionUi())
}
}
launch {
battleRepository.savedPokemonWithSkill().first()?.let { (pokemon, skill) ->
battleRepository.savedPokemonWithSkillStream().first()?.let { (pokemon, skill) ->
updateMyPokemon(pokemon.toSelectionUi(), skill.toUi())
}
}
Expand All @@ -107,6 +124,7 @@ class BattleViewModel(
viewModelScope.launch {
val selectedWeather = BattleSelectionUiState.Selected(newWeather)
_selectedState.value = selectedState.value.copy(weather = selectedWeather)
battleRepository.saveWeather(newWeather.id)
}
}

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

import android.view.View
import android.widget.AdapterView

inline fun <reified T> itemSelectListener(crossinline onSelected: (T) -> Unit): AdapterView.OnItemSelectedListener {
var isSpinnerInitialized = false
return object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
if (isSpinnerInitialized) {
val selectedData = parent?.getItemAtPosition(position)
val castedData =
requireNotNull(selectedData as? T) { "Selected data is not a ${T::class.simpleName}" }
onSelected(castedData)
} else {
isSpinnerInitialized = true
}
}

override fun onNothingSelected(parent: AdapterView<*>?) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ class LocalBattleDataSource(private val battleDataStore: BattleDataStore) {
battleDataStore.savePokemon(pokemonId)
}

fun pokemonWithSkill(): Flow<PokemonWithSkillIds?> = battleDataStore.pokemonWithSkillId().map { it?.toData() }
suspend fun saveWeather(weatherId: String) {
battleDataStore.saveWeather(weatherId)
}

fun weatherIdStream(): Flow<String?> = battleDataStore.weatherId()

fun pokemonWithSkillStream(): Flow<PokemonWithSkillIds?> = battleDataStore.pokemonWithSkillId().map { it?.toData() }

fun pokemonId(): Flow<String?> = battleDataStore.pokemonId()
fun pokemonIdStream(): Flow<String?> = battleDataStore.pokemonId()

companion object {
private var instance: LocalBattleDataSource? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ interface BattleRepository {
skillId: String,
)

suspend fun savedPokemon(): Flow<Pokemon?>
suspend fun saveWeather(weatherId: String)

suspend fun savedPokemonWithSkill(): Flow<PokemonWithSkill?>
fun savedWeatherStream(): Flow<Weather?>

fun savedPokemonStream(): Flow<Pokemon?>

fun savedPokemonWithSkillStream(): Flow<PokemonWithSkill?>
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,37 @@ class DefaultBattleRepository(
opponentPokemonId = opponentPokemonId,
)

override suspend fun savePokemon(pokemonId: String) {
localBattleDataSource.savePokemon(pokemonId)
}
override suspend fun savePokemon(pokemonId: String) = localBattleDataSource.savePokemon(pokemonId)

override suspend fun savePokemonWithSkill(
pokemonId: String,
skillId: String,
) {
localBattleDataSource.savePokemonWithSkill(pokemonId, skillId)
}
) = localBattleDataSource.savePokemonWithSkill(pokemonId, skillId)

override suspend fun savedPokemon(): Flow<Pokemon?> =
localBattleDataSource.pokemonId().map { it?.let { pokemonRepository.pokemon(it) } }
override fun savedPokemonStream(): Flow<Pokemon?> =
localBattleDataSource.pokemonIdStream().map {
it?.let { pokemonRepository.pokemon(it) }
}

override suspend fun savedPokemonWithSkill(): Flow<PokemonWithSkill?> =
localBattleDataSource.pokemonWithSkill().map {
override fun savedPokemonWithSkillStream(): Flow<PokemonWithSkill?> =
localBattleDataSource.pokemonWithSkillStream().map {
it?.let { pokemonWithSkill ->
val pokemon = pokemonRepository.pokemon(pokemonWithSkill.pokemonId)
val skill = skill(pokemon.dexNumber, pokemonWithSkill.skillId)
PokemonWithSkill(pokemon, skill)
}
}

override suspend fun saveWeather(weatherId: String) = localBattleDataSource.saveWeather(weatherId)

override fun savedWeatherStream(): Flow<Weather?> =
localBattleDataSource.weatherIdStream().map {
if (it == null) {
return@map null
}
weathers().find { weather -> weather.id == it }
}

private suspend fun skill(
dexNumber: Long,
skillId: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

package poke.rogue.helper.local.datastore

import android.content.Context
Expand Down Expand Up @@ -31,6 +30,17 @@ class BattleDataStore(private val context: Context) {
}
}

suspend fun saveWeather(weatherId: String) {
context.dataStore.edit {
it[WEATHER_SELECTION_KEY] = weatherId
}
}

fun weatherId(): Flow<String?> =
context.dataStore.data.map { preferences ->
preferences[WEATHER_SELECTION_KEY]
}

fun pokemonWithSkillId(): Flow<SavedPokemonWithSkill?> =
context.dataStore.data.map { preference ->
val pokemonId = preference[PAIR_POKEMON_SELECTION_KEY]
Expand All @@ -49,6 +59,7 @@ class BattleDataStore(private val context: Context) {

private companion object {
const val BATTLE_PREFERENCE_NAME = "battle"
val WEATHER_SELECTION_KEY = stringPreferencesKey("weather_selection")
val PAIR_POKEMON_SELECTION_KEY = stringPreferencesKey("pair_pokemon_selection")
val PAIR_SKILL_SELECTION_KEY = stringPreferencesKey("pair_skill_selection")
val SINGLE_POKEMON_SELECTION_KEY = stringPreferencesKey("single_pokemon_selection")
Expand Down

0 comments on commit 61aa1a4

Please sign in to comment.