Some ugly code..., it works
This commit is contained in:
		@@ -1,11 +1,11 @@
 | 
			
		||||
package com.ti.mobpo
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider
 | 
			
		||||
import androidx.lifecycle.createSavedStateHandle
 | 
			
		||||
import androidx.lifecycle.viewmodel.CreationExtras
 | 
			
		||||
import androidx.lifecycle.viewmodel.initializer
 | 
			
		||||
import androidx.lifecycle.viewmodel.viewModelFactory
 | 
			
		||||
import com.ti.mobpo.ui.pokesearch.PokeSearchViewModel
 | 
			
		||||
import com.ti.mobpo.ui.viewmodels.FavouritesViewModel
 | 
			
		||||
import com.ti.mobpo.ui.viewmodels.PokeSearchViewModel
 | 
			
		||||
 | 
			
		||||
object AppViewModelProvider {
 | 
			
		||||
    val Factory = viewModelFactory {
 | 
			
		||||
@@ -13,9 +13,17 @@ object AppViewModelProvider {
 | 
			
		||||
            PokeSearchViewModel(
 | 
			
		||||
                pokesearchApplication().appContainer.favouritesRepository
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        initializer {
 | 
			
		||||
            FavouritesViewModel(
 | 
			
		||||
                pokesearchApplication().appContainer.favouritesRepository, pokesearchApplication().featureManager
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun CreationExtras.pokesearchApplication(): PokeSearch =
 | 
			
		||||
    (this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as PokeSearch)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,26 @@ package com.ti.mobpo
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import com.ti.mobpo.data.AppContainer
 | 
			
		||||
import com.ti.mobpo.data.AppDataContainer
 | 
			
		||||
import com.ti.mobpo.ui.util.FeatureManager
 | 
			
		||||
 | 
			
		||||
class PokeSearch : Application() {
 | 
			
		||||
    lateinit var appContainer: AppContainer
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    lateinit var featureManager: FeatureManager
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        super.onCreate()
 | 
			
		||||
        appContainer = createAppContainer()
 | 
			
		||||
        featureManager = createFeatrureManager()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createAppContainer(): AppContainer {
 | 
			
		||||
        return AppDataContainer(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createFeatrureManager(): FeatureManager {
 | 
			
		||||
        return FeatureManager(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,18 +20,16 @@ import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.rememberUpdatedState
 | 
			
		||||
import androidx.compose.runtime.saveable.rememberSaveable
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.lifecycle.viewmodel.compose.viewModel
 | 
			
		||||
import androidx.navigation.compose.NavHost
 | 
			
		||||
import androidx.navigation.compose.composable
 | 
			
		||||
import androidx.navigation.compose.currentBackStackEntryAsState
 | 
			
		||||
import androidx.navigation.compose.rememberNavController
 | 
			
		||||
import com.ti.mobpo.ui.screens.Favourites
 | 
			
		||||
import com.ti.mobpo.ui.screens.FavoritesScreen
 | 
			
		||||
import com.ti.mobpo.ui.screens.PokeSearchScreen
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
@@ -108,7 +106,7 @@ fun Navigation() {
 | 
			
		||||
                        }
 | 
			
		||||
                        composable(
 | 
			
		||||
                            route = Screen.Favourites.route) {
 | 
			
		||||
                            Favourites()
 | 
			
		||||
                            FavoritesScreen()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
package com.ti.mobpo.ui.pokesearch
 | 
			
		||||
 | 
			
		||||
data class PokeSearchUiState(val searchQuery: String = "")
 | 
			
		||||
@@ -18,6 +18,8 @@ import com.ti.mobpo.ui.viewmodels.FavouritesViewModel
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.grid.items
 | 
			
		||||
import androidx.compose.material3.CircularProgressIndicator
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
@@ -27,8 +29,11 @@ fun FavoritesScreen(viewModel: FavouritesViewModel = viewModel(factory = AppView
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun Favorites(favoritesViewModel: FavouritesViewModel) {
 | 
			
		||||
    val favorites by favoritesViewModel.pokemonDetails.collectAsState()
 | 
			
		||||
    LaunchedEffect(Unit) {
 | 
			
		||||
        favoritesViewModel.loadFavourites()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val favorites by favoritesViewModel.pokemonDetails.collectAsState()
 | 
			
		||||
 | 
			
		||||
    Column(
 | 
			
		||||
        verticalArrangement = Arrangement.Top,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package com.ti.mobpo.ui.screens
 | 
			
		||||
 | 
			
		||||
import com.ti.mobpo.ui.pokesearch.PokeSearchViewModel
 | 
			
		||||
import com.ti.mobpo.ui.viewmodels.PokeSearchViewModel
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
@@ -26,9 +26,6 @@ import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.layout.ContentScale
 | 
			
		||||
@@ -94,7 +91,6 @@ fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) {
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun PokemonCard(pokemon: PokemonDetails, toggleFavorite: (Int) -> Unit) {
 | 
			
		||||
    var isFavourite by remember { mutableStateOf(false) }
 | 
			
		||||
    Card(
 | 
			
		||||
        shape = MaterialTheme.shapes.medium,
 | 
			
		||||
        elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
package com.ti.mobpo.ui.util
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
class FeatureManager(private val context: Context) {
 | 
			
		||||
    private val PREFS_NAME = "FeaturePrefs"
 | 
			
		||||
    private val KEY_PAID_FEATURE_ENABLED = "paid_feature_enabled"
 | 
			
		||||
 | 
			
		||||
    fun hasAccessToPaidFeature(): Boolean {
 | 
			
		||||
        val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
 | 
			
		||||
        return prefs.getBoolean(KEY_PAID_FEATURE_ENABLED, false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setPaidFeatureEnabled(enabled: Boolean) {
 | 
			
		||||
        val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
 | 
			
		||||
        prefs.edit().putBoolean(KEY_PAID_FEATURE_ENABLED, enabled).apply()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,76 @@
 | 
			
		||||
package com.ti.mobpo.ui.viewmodels
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import com.ti.mobpo.data.Favourite
 | 
			
		||||
import com.ti.mobpo.data.FavouritesRepository
 | 
			
		||||
import com.ti.mobpo.model.PokemonDetails
 | 
			
		||||
import com.ti.mobpo.network.PokeApi
 | 
			
		||||
import com.ti.mobpo.ui.util.FeatureManager
 | 
			
		||||
import kotlinx.coroutines.flow.MutableStateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.SharingStarted
 | 
			
		||||
import kotlinx.coroutines.flow.StateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.asStateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.map
 | 
			
		||||
import kotlinx.coroutines.flow.stateIn
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
 | 
			
		||||
class FavouritesViewModel(private val favouritesRepository: FavouritesRepository, featureManager: FeatureManager) : ViewModel() {
 | 
			
		||||
    private val service = PokeApi.retrofitService;
 | 
			
		||||
 | 
			
		||||
    private val _pokemonDetails = MutableStateFlow<List<PokemonDetails>?>(null)
 | 
			
		||||
    val pokemonDetails: StateFlow<List<PokemonDetails>?> = _pokemonDetails.asStateFlow()
 | 
			
		||||
 | 
			
		||||
    fun loadFavourites() {
 | 
			
		||||
        // Ugly workaround to make sure all the favourites are loaded before displaying them
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            try {
 | 
			
		||||
                val favouritesList: StateFlow<FavouriteUiState> =
 | 
			
		||||
                    favouritesRepository.getAllItems().map { FavouriteUiState(it) }
 | 
			
		||||
                        .stateIn(
 | 
			
		||||
                            scope = viewModelScope,
 | 
			
		||||
                            started = SharingStarted.WhileSubscribed(5_000L),
 | 
			
		||||
                            initialValue = FavouriteUiState()
 | 
			
		||||
                        )
 | 
			
		||||
                favouritesList.collect { state ->
 | 
			
		||||
                    val detailsList = mutableListOf<PokemonDetails>()
 | 
			
		||||
                    for (favourite in state.favourites) {
 | 
			
		||||
                        val details = service.getPokemonDetails(favourite.id)
 | 
			
		||||
                        detailsList.add(details.copy(isFavorite = true))
 | 
			
		||||
                    }
 | 
			
		||||
                    _pokemonDetails.value = detailsList
 | 
			
		||||
                }
 | 
			
		||||
            } catch (e: IOException) {
 | 
			
		||||
                /* Handle error */
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun toggleFavorite(pokemonId: Int) {
 | 
			
		||||
        _pokemonDetails.value = _pokemonDetails.value?.map { pokemon ->
 | 
			
		||||
            if (pokemon.id == pokemonId) {
 | 
			
		||||
                pokemon.copy(isFavorite = !pokemon.isFavorite)
 | 
			
		||||
            } else {
 | 
			
		||||
                pokemon
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            if (_pokemonDetails.value != null) {
 | 
			
		||||
                val pokemon = _pokemonDetails.value!!.find { it.id == pokemonId }
 | 
			
		||||
                pokemon?.let {
 | 
			
		||||
                    if (it.isFavorite) {
 | 
			
		||||
                        favouritesRepository.insertItem(Favourite(it.id, it.name))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        favouritesRepository.deleteItem(Favourite(it.id, it.name))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
data class FavouriteUiState(val favourites: List<Favourite> = listOf())
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.ti.mobpo.ui.pokesearch
 | 
			
		||||
package com.ti.mobpo.ui.viewmodels
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
		Reference in New Issue
	
	Block a user