Make sure code doesnt get fetched multiple times, share the same vm over the whole session
This commit is contained in:
		
							
								
								
									
										5
									
								
								app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package com.ti.mobpo.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.ti.mobpo.data.Favourite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class FavouriteUiState(val favourites: List<Favourite> = listOf())
 | 
				
			||||||
@@ -20,17 +20,22 @@ import androidx.compose.material3.Text
 | 
				
			|||||||
import androidx.compose.runtime.Composable
 | 
					import androidx.compose.runtime.Composable
 | 
				
			||||||
import androidx.compose.runtime.getValue
 | 
					import androidx.compose.runtime.getValue
 | 
				
			||||||
import androidx.compose.runtime.mutableStateOf
 | 
					import androidx.compose.runtime.mutableStateOf
 | 
				
			||||||
 | 
					import androidx.compose.runtime.remember
 | 
				
			||||||
import androidx.compose.runtime.rememberUpdatedState
 | 
					import androidx.compose.runtime.rememberUpdatedState
 | 
				
			||||||
import androidx.compose.runtime.saveable.rememberSaveable
 | 
					import androidx.compose.runtime.saveable.rememberSaveable
 | 
				
			||||||
import androidx.compose.runtime.setValue
 | 
					import androidx.compose.runtime.setValue
 | 
				
			||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
import androidx.compose.ui.tooling.preview.Preview
 | 
					import androidx.compose.ui.tooling.preview.Preview
 | 
				
			||||||
 | 
					import androidx.lifecycle.viewmodel.compose.viewModel
 | 
				
			||||||
import androidx.navigation.compose.NavHost
 | 
					import androidx.navigation.compose.NavHost
 | 
				
			||||||
import androidx.navigation.compose.composable
 | 
					import androidx.navigation.compose.composable
 | 
				
			||||||
import androidx.navigation.compose.currentBackStackEntryAsState
 | 
					import androidx.navigation.compose.currentBackStackEntryAsState
 | 
				
			||||||
import androidx.navigation.compose.rememberNavController
 | 
					import androidx.navigation.compose.rememberNavController
 | 
				
			||||||
 | 
					import com.ti.mobpo.AppViewModelProvider
 | 
				
			||||||
import com.ti.mobpo.ui.screens.FavoritesScreen
 | 
					import com.ti.mobpo.ui.screens.FavoritesScreen
 | 
				
			||||||
import com.ti.mobpo.ui.screens.PokeSearchScreen
 | 
					import com.ti.mobpo.ui.screens.PokeSearchScreen
 | 
				
			||||||
 | 
					import com.ti.mobpo.ui.viewmodels.FavouritesViewModel
 | 
				
			||||||
 | 
					import com.ti.mobpo.ui.viewmodels.PokeSearchViewModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun Navigation() {
 | 
					fun Navigation() {
 | 
				
			||||||
@@ -59,6 +64,9 @@ fun Navigation() {
 | 
				
			|||||||
    val updatedSelectedIndex = items.indexOfFirst { it.route == currentRoute }
 | 
					    val updatedSelectedIndex = items.indexOfFirst { it.route == currentRoute }
 | 
				
			||||||
    selectedItemIndex = rememberUpdatedState(updatedSelectedIndex).value
 | 
					    selectedItemIndex = rememberUpdatedState(updatedSelectedIndex).value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val pokeSearchVM = viewModel<PokeSearchViewModel>(factory = AppViewModelProvider.Factory)
 | 
				
			||||||
 | 
					    val favoritesVM = viewModel<FavouritesViewModel>(factory = AppViewModelProvider.Factory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scaffold (
 | 
					    Scaffold (
 | 
				
			||||||
        bottomBar = {
 | 
					        bottomBar = {
 | 
				
			||||||
            NavigationBar {
 | 
					            NavigationBar {
 | 
				
			||||||
@@ -102,11 +110,11 @@ fun Navigation() {
 | 
				
			|||||||
                            ExitTransition.None
 | 
					                            ExitTransition.None
 | 
				
			||||||
                        }) {
 | 
					                        }) {
 | 
				
			||||||
                        composable(route = Screen.PokeSearch.route) {
 | 
					                        composable(route = Screen.PokeSearch.route) {
 | 
				
			||||||
                            PokeSearchScreen()
 | 
					                            PokeSearchScreen(pokeSearchVM)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        composable(
 | 
					                        composable(
 | 
				
			||||||
                            route = Screen.Favourites.route) {
 | 
					                            route = Screen.Favourites.route) {
 | 
				
			||||||
                            FavoritesScreen()
 | 
					                            FavoritesScreen(favoritesVM)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -120,6 +128,6 @@ fun Navigation() {
 | 
				
			|||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun NavigationPreview() {
 | 
					fun NavigationPreview() {
 | 
				
			||||||
    Surface {
 | 
					    Surface {
 | 
				
			||||||
        PokeSearchScreen()
 | 
					        PokeSearchScreen(viewModel(factory = AppViewModelProvider.Factory))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -23,7 +23,7 @@ import androidx.compose.runtime.LaunchedEffect
 | 
				
			|||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun FavoritesScreen(viewModel: FavouritesViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
 | 
					fun FavoritesScreen(viewModel: FavouritesViewModel) {
 | 
				
			||||||
    Favorites(viewModel)
 | 
					    Favorites(viewModel)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ import com.ti.mobpo.capitalizeFirstLetterAfterHyphens
 | 
				
			|||||||
import com.ti.mobpo.ui.theme.MobileSecurityTheme
 | 
					import com.ti.mobpo.ui.theme.MobileSecurityTheme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun PokeSearchScreen(viewModel: PokeSearchViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
 | 
					fun PokeSearchScreen(viewModel: PokeSearchViewModel) {
 | 
				
			||||||
    PokeSearch(viewModel)
 | 
					    PokeSearch(viewModel)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
 | 
				
			|||||||
import androidx.lifecycle.viewModelScope
 | 
					import androidx.lifecycle.viewModelScope
 | 
				
			||||||
import com.ti.mobpo.data.Favourite
 | 
					import com.ti.mobpo.data.Favourite
 | 
				
			||||||
import com.ti.mobpo.data.FavouritesRepository
 | 
					import com.ti.mobpo.data.FavouritesRepository
 | 
				
			||||||
 | 
					import com.ti.mobpo.model.FavouriteUiState
 | 
				
			||||||
import com.ti.mobpo.model.PokemonDetails
 | 
					import com.ti.mobpo.model.PokemonDetails
 | 
				
			||||||
import com.ti.mobpo.network.PokeApi
 | 
					import com.ti.mobpo.network.PokeApi
 | 
				
			||||||
import com.ti.mobpo.ui.util.FeatureManager
 | 
					import com.ti.mobpo.ui.util.FeatureManager
 | 
				
			||||||
@@ -47,9 +48,6 @@ class FavouritesViewModel(private val favouritesRepository: FavouritesRepository
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun toggleFavorite(pokemonId: Int) {
 | 
					    fun toggleFavorite(pokemonId: Int) {
 | 
				
			||||||
        _pokemonDetails.value = _pokemonDetails.value?.map { pokemon ->
 | 
					        _pokemonDetails.value = _pokemonDetails.value?.map { pokemon ->
 | 
				
			||||||
            if (pokemon.id == pokemonId) {
 | 
					            if (pokemon.id == pokemonId) {
 | 
				
			||||||
@@ -72,5 +70,3 @@ class FavouritesViewModel(private val favouritesRepository: FavouritesRepository
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
data class FavouriteUiState(val favourites: List<Favourite> = listOf())
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
 | 
				
			|||||||
import com.ti.mobpo.data.Favourite
 | 
					import com.ti.mobpo.data.Favourite
 | 
				
			||||||
import com.ti.mobpo.data.FavouritesRepository
 | 
					import com.ti.mobpo.data.FavouritesRepository
 | 
				
			||||||
import com.ti.mobpo.model.PokemonDetails
 | 
					import com.ti.mobpo.model.PokemonDetails
 | 
				
			||||||
 | 
					import com.ti.mobpo.model.PokemonSpecies
 | 
				
			||||||
import com.ti.mobpo.network.PokeApi
 | 
					import com.ti.mobpo.network.PokeApi
 | 
				
			||||||
import kotlinx.coroutines.flow.MutableStateFlow
 | 
					import kotlinx.coroutines.flow.MutableStateFlow
 | 
				
			||||||
import kotlinx.coroutines.flow.StateFlow
 | 
					import kotlinx.coroutines.flow.StateFlow
 | 
				
			||||||
@@ -13,24 +14,42 @@ import kotlinx.coroutines.launch
 | 
				
			|||||||
import java.io.IOException
 | 
					import java.io.IOException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private const val SHOW_LIMIT = 20;
 | 
				
			||||||
class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository) : ViewModel() {
 | 
					class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository) : ViewModel() {
 | 
				
			||||||
    private val service = PokeApi.retrofitService;
 | 
					    private val service = PokeApi.retrofitService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val _pokemonDetails = MutableStateFlow<List<PokemonDetails>?>(null)
 | 
					    private val _pokemonDetails = MutableStateFlow<List<PokemonDetails>?>(null)
 | 
				
			||||||
    val pokemonDetails: StateFlow<List<PokemonDetails>?> = _pokemonDetails.asStateFlow()
 | 
					    val pokemonDetails: StateFlow<List<PokemonDetails>?> = _pokemonDetails.asStateFlow()
 | 
				
			||||||
 | 
					    private val _initialPokemonList = MutableStateFlow<List<PokemonSpecies>?>(null)
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        fetchPokemonSpecies()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun fetchPokemonSpecies() {
 | 
				
			||||||
 | 
					        viewModelScope.launch {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                val response = service.getPokemon()
 | 
				
			||||||
 | 
					                _initialPokemonList.value = response.results
 | 
				
			||||||
 | 
					            } catch (e: IOException) {
 | 
				
			||||||
 | 
					                /*TODO*/
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun search(query: String) {
 | 
					    fun search(query: String) {
 | 
				
			||||||
        viewModelScope.launch {
 | 
					        viewModelScope.launch {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                val response = service.getPokemon()
 | 
					                val filteredList = _initialPokemonList.value?.filter { it.name.contains(query, ignoreCase = true) }
 | 
				
			||||||
                val filteredList = response.results.filter { it.name.contains(query, ignoreCase = true) }
 | 
					 | 
				
			||||||
                val detailsList = mutableListOf<PokemonDetails>()
 | 
					                val detailsList = mutableListOf<PokemonDetails>()
 | 
				
			||||||
                for (pokemonSpecies in filteredList) {
 | 
					                if (filteredList != null) {
 | 
				
			||||||
 | 
					                    for (pokemonSpecies in filteredList.take(SHOW_LIMIT)) {
 | 
				
			||||||
                        val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url))
 | 
					                        val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url))
 | 
				
			||||||
                        val isFavorite = favouritesRepository.isFavourite(details.id)
 | 
					                        val isFavorite = favouritesRepository.isFavourite(details.id)
 | 
				
			||||||
                        detailsList.add(details.copy(isFavorite = isFavorite))
 | 
					                        detailsList.add(details.copy(isFavorite = isFavorite))
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                _pokemonDetails.value = detailsList
 | 
					                _pokemonDetails.value = detailsList
 | 
				
			||||||
            } catch (e: IOException) {
 | 
					            } catch (e: IOException) {
 | 
				
			||||||
                /* Handle error */
 | 
					                /* Handle error */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user