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 8d7c96ef..60657ca4 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 @@ -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 @@ -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(R.layout.activity_battle) { private val viewModel by viewModels { - BattleViewModel.factory(DefaultBattleRepository.instance(this)) + BattleViewModel.factory(DefaultBattleRepository.instance(applicationContext)) } private val weatherAdapter by lazy { WeatherSpinnerAdapter(this) @@ -58,19 +58,8 @@ class BattleActivity : ToolbarActivity(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 { + viewModel.updateWeather(it) } } @@ -80,6 +69,13 @@ class BattleActivity : ToolbarActivity(R.layout.activity_ weatherAdapter.updateWeathers(it) } } + repeatOnStarted { + viewModel.weatherPos + .collect { + Timber.tag("weatherPos").d("weatherPos: $it") + binding.spinnerWeather.setSelection(it) + } + } repeatOnStarted { viewModel.selectedState.collect { diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleViewModel.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleViewModel.kt index 529c5d32..29f47811 100644 --- a/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleViewModel.kt +++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/BattleViewModel.kt @@ -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 @@ -37,6 +39,21 @@ class BattleViewModel( private val _selectedState = MutableStateFlow(BattleSelectionsState.DEFAULT) val selectedState = _selectedState.asStateFlow() + val weatherPos: StateFlow = + 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() val navigateToSelection = _navigateToSelection.asSharedFlow() @@ -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()) } } @@ -107,6 +124,7 @@ class BattleViewModel( viewModelScope.launch { val selectedWeather = BattleSelectionUiState.Selected(newWeather) _selectedState.value = selectedState.value.copy(weather = selectedWeather) + battleRepository.saveWeather(newWeather.id) } } diff --git a/android/app/src/main/java/poke/rogue/helper/presentation/battle/view/WeatherItemSelectedListener.kt b/android/app/src/main/java/poke/rogue/helper/presentation/battle/view/WeatherItemSelectedListener.kt new file mode 100644 index 00000000..84aad3d6 --- /dev/null +++ b/android/app/src/main/java/poke/rogue/helper/presentation/battle/view/WeatherItemSelectedListener.kt @@ -0,0 +1,27 @@ +package poke.rogue.helper.presentation.battle.view + +import android.view.View +import android.widget.AdapterView + +inline fun 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<*>?) {} + } +} diff --git a/android/data/src/main/java/poke/rogue/helper/data/datasource/LocalBattleDataSource.kt b/android/data/src/main/java/poke/rogue/helper/data/datasource/LocalBattleDataSource.kt index 957eeb4e..a2fbb6c8 100644 --- a/android/data/src/main/java/poke/rogue/helper/data/datasource/LocalBattleDataSource.kt +++ b/android/data/src/main/java/poke/rogue/helper/data/datasource/LocalBattleDataSource.kt @@ -19,9 +19,15 @@ class LocalBattleDataSource(private val battleDataStore: BattleDataStore) { battleDataStore.savePokemon(pokemonId) } - fun pokemonWithSkill(): Flow = battleDataStore.pokemonWithSkillId().map { it?.toData() } + suspend fun saveWeather(weatherId: String) { + battleDataStore.saveWeather(weatherId) + } + + fun weatherIdStream(): Flow = battleDataStore.weatherId() + + fun pokemonWithSkillStream(): Flow = battleDataStore.pokemonWithSkillId().map { it?.toData() } - fun pokemonId(): Flow = battleDataStore.pokemonId() + fun pokemonIdStream(): Flow = battleDataStore.pokemonId() companion object { private var instance: LocalBattleDataSource? = null diff --git a/android/data/src/main/java/poke/rogue/helper/data/repository/BattleRepository.kt b/android/data/src/main/java/poke/rogue/helper/data/repository/BattleRepository.kt index b96a0824..5dff8a36 100644 --- a/android/data/src/main/java/poke/rogue/helper/data/repository/BattleRepository.kt +++ b/android/data/src/main/java/poke/rogue/helper/data/repository/BattleRepository.kt @@ -26,7 +26,11 @@ interface BattleRepository { skillId: String, ) - suspend fun savedPokemon(): Flow + suspend fun saveWeather(weatherId: String) - suspend fun savedPokemonWithSkill(): Flow + fun savedWeatherStream(): Flow + + fun savedPokemonStream(): Flow + + fun savedPokemonWithSkillStream(): Flow } diff --git a/android/data/src/main/java/poke/rogue/helper/data/repository/DefaultBattleRepository.kt b/android/data/src/main/java/poke/rogue/helper/data/repository/DefaultBattleRepository.kt index 90be93c0..5cfb30b3 100644 --- a/android/data/src/main/java/poke/rogue/helper/data/repository/DefaultBattleRepository.kt +++ b/android/data/src/main/java/poke/rogue/helper/data/repository/DefaultBattleRepository.kt @@ -40,22 +40,20 @@ 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 = - localBattleDataSource.pokemonId().map { it?.let { pokemonRepository.pokemon(it) } } + override fun savedPokemonStream(): Flow = + localBattleDataSource.pokemonIdStream().map { + it?.let { pokemonRepository.pokemon(it) } + } - override suspend fun savedPokemonWithSkill(): Flow = - localBattleDataSource.pokemonWithSkill().map { + override fun savedPokemonWithSkillStream(): Flow = + localBattleDataSource.pokemonWithSkillStream().map { it?.let { pokemonWithSkill -> val pokemon = pokemonRepository.pokemon(pokemonWithSkill.pokemonId) val skill = skill(pokemon.dexNumber, pokemonWithSkill.skillId) @@ -63,6 +61,16 @@ class DefaultBattleRepository( } } + override suspend fun saveWeather(weatherId: String) = localBattleDataSource.saveWeather(weatherId) + + override fun savedWeatherStream(): Flow = + localBattleDataSource.weatherIdStream().map { + if (it == null) { + return@map null + } + weathers().find { weather -> weather.id == it } + } + private suspend fun skill( dexNumber: Long, skillId: String, diff --git a/android/local/src/main/java/poke/rogue/helper/local/datastore/BattleDataStore.kt b/android/local/src/main/java/poke/rogue/helper/local/datastore/BattleDataStore.kt index 8d4b6e17..fc3f9a70 100644 --- a/android/local/src/main/java/poke/rogue/helper/local/datastore/BattleDataStore.kt +++ b/android/local/src/main/java/poke/rogue/helper/local/datastore/BattleDataStore.kt @@ -1,4 +1,3 @@ - package poke.rogue.helper.local.datastore import android.content.Context @@ -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 = + context.dataStore.data.map { preferences -> + preferences[WEATHER_SELECTION_KEY] + } + fun pokemonWithSkillId(): Flow = context.dataStore.data.map { preference -> val pokemonId = preference[PAIR_POKEMON_SELECTION_KEY] @@ -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")