From 93b4d04587166db13d1ae4ccaafb652e3f38d48d Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 00:05:02 +0200 Subject: [PATCH 01/11] Change names of database methods --- .../java/com/ti/mobpo/data/FavouriteDao.kt | 5 +- .../com/ti/mobpo/data/FavouritesRepository.kt | 2 +- .../mobpo/data/OfflineFavouritesRepository.kt | 4 +- .../com/ti/mobpo/ui/screens/Favourites.kt | 56 ++++++++++++++++++- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/data/FavouriteDao.kt b/app/src/main/java/com/ti/mobpo/data/FavouriteDao.kt index c409f3a..6669a1c 100644 --- a/app/src/main/java/com/ti/mobpo/data/FavouriteDao.kt +++ b/app/src/main/java/com/ti/mobpo/data/FavouriteDao.kt @@ -14,9 +14,8 @@ interface FavouriteDao { @Delete suspend fun delete(favourite: Favourite) - - @Query("SELECT id FROM favourites") - fun getAllFavoriteIds(): Flow> + @Query("SELECT * from favourites ORDER BY id ASC") + fun getAllItems(): Flow> @Query("SELECT EXISTS(SELECT 1 FROM favourites WHERE id = :id LIMIT 1)") suspend fun isFavourite(id: Int): Boolean diff --git a/app/src/main/java/com/ti/mobpo/data/FavouritesRepository.kt b/app/src/main/java/com/ti/mobpo/data/FavouritesRepository.kt index 4083c1b..b701947 100644 --- a/app/src/main/java/com/ti/mobpo/data/FavouritesRepository.kt +++ b/app/src/main/java/com/ti/mobpo/data/FavouritesRepository.kt @@ -9,7 +9,7 @@ interface FavouritesRepository { /** * Retrieve all the items from the the given data source. */ - fun getAllFavoriteIds(): Flow> + fun getAllItems(): Flow> /** * Insert item in the data source diff --git a/app/src/main/java/com/ti/mobpo/data/OfflineFavouritesRepository.kt b/app/src/main/java/com/ti/mobpo/data/OfflineFavouritesRepository.kt index 6f4b000..12443cf 100644 --- a/app/src/main/java/com/ti/mobpo/data/OfflineFavouritesRepository.kt +++ b/app/src/main/java/com/ti/mobpo/data/OfflineFavouritesRepository.kt @@ -3,8 +3,8 @@ package com.ti.mobpo.data import kotlinx.coroutines.flow.Flow class OfflineFavouritesRepository(private val favouriteDao: FavouriteDao) : FavouritesRepository { - override fun getAllFavoriteIds(): Flow> { - return favouriteDao.getAllFavoriteIds() + override fun getAllItems(): Flow> { + return favouriteDao.getAllItems() } override suspend fun insertItem(item: Favourite) { favouriteDao.insert(item) diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt index 2fe3bd6..dae1083 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt @@ -1,10 +1,60 @@ package com.ti.mobpo.ui.screens +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.ti.mobpo.AppViewModelProvider +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.ui.Modifier @Composable -fun Favourites() { - println("Favourites") - Text("Favourites Page") +fun FavoritesScreen(viewModel: FavouritesViewModel = viewModel(factory = AppViewModelProvider.Factory)) { + Favorites(viewModel) +} + +@Composable +fun Favorites(favoritesViewModel: FavouritesViewModel) { + val favorites by favoritesViewModel.pokemonDetails.collectAsState() + favoritesViewModel.loadFavourites() + + Column( + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxSize() + .padding(20.dp) + ) { + Spacer(modifier = Modifier.height(16.dp)) + + favorites?.let { favoritesList -> + if (favoritesList.isNotEmpty()) { + LazyVerticalGrid( + columns = GridCells.Adaptive(150.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(items = favoritesList, key = { pokemon -> pokemon.id }) { pokemon -> + PokemonCard(pokemon, toggleFavorite = { pokemonId -> + favoritesViewModel.toggleFavorite(pokemonId) + }) + } + } + } else { + Text("No favorites found") + } + } + } } From e0a40a548eb6182b3790ef16ef4c805c52bb3745 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:04:22 +0200 Subject: [PATCH 02/11] Some ugly code..., it works --- .../java/com/ti/mobpo/AppViewModelProvider.kt | 14 +++- app/src/main/java/com/ti/mobpo/PokeSearch.kt | 9 +++ .../main/java/com/ti/mobpo/ui/Navigation.kt | 6 +- .../mobpo/ui/pokesearch/PokeSearchUiState.kt | 3 - .../com/ti/mobpo/ui/screens/Favourites.kt | 7 +- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 6 +- .../com/ti/mobpo/ui/util/FeatureManager.kt | 18 +++++ .../ui/viewmodels/FavouritesViewModel.kt | 76 +++++++++++++++++++ .../PokeSearchViewModel.kt | 2 +- 9 files changed, 124 insertions(+), 17 deletions(-) delete mode 100644 app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchUiState.kt create mode 100644 app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt create mode 100644 app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt rename app/src/main/java/com/ti/mobpo/ui/{pokesearch => viewmodels}/PokeSearchViewModel.kt (98%) diff --git a/app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt b/app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt index 84a07fc..81f6270 100644 --- a/app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt +++ b/app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt @@ -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) \ No newline at end of file + (this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as PokeSearch) + diff --git a/app/src/main/java/com/ti/mobpo/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/PokeSearch.kt index 3d45059..953cb2a 100644 --- a/app/src/main/java/com/ti/mobpo/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/PokeSearch.kt @@ -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) + } } diff --git a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt index e09a3c7..3fb9343 100644 --- a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt +++ b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt @@ -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() } } } diff --git a/app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchUiState.kt b/app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchUiState.kt deleted file mode 100644 index 5012bf5..0000000 --- a/app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchUiState.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.ti.mobpo.ui.pokesearch - -data class PokeSearchUiState(val searchQuery: String = "") diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt index dae1083..fe9d851 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt @@ -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) { + LaunchedEffect(Unit) { + favoritesViewModel.loadFavourites() + } + val favorites by favoritesViewModel.pokemonDetails.collectAsState() - favoritesViewModel.loadFavourites() Column( verticalArrangement = Arrangement.Top, diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index a2aa2a7..cc238cb 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -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), diff --git a/app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt b/app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt new file mode 100644 index 0000000..df3bf9e --- /dev/null +++ b/app/src/main/java/com/ti/mobpo/ui/util/FeatureManager.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt new file mode 100644 index 0000000..b829db6 --- /dev/null +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt @@ -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?>(null) + val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() + + fun loadFavourites() { + // Ugly workaround to make sure all the favourites are loaded before displaying them + viewModelScope.launch { + try { + val favouritesList: StateFlow = + favouritesRepository.getAllItems().map { FavouriteUiState(it) } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = FavouriteUiState() + ) + favouritesList.collect { state -> + val detailsList = mutableListOf() + 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 = listOf()) diff --git a/app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt similarity index 98% rename from app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchViewModel.kt rename to app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 5bdc5a6..cd1888a 100644 --- a/app/src/main/java/com/ti/mobpo/ui/pokesearch/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -1,4 +1,4 @@ -package com.ti.mobpo.ui.pokesearch +package com.ti.mobpo.ui.viewmodels import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope From 2f1c6604ba44f97d8c0e9495c6686ecc4e0cdeaa Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:40:33 +0200 Subject: [PATCH 03/11] Make sure code doesnt get fetched multiple times, share the same vm over the whole session --- .../com/ti/mobpo/model/FavouriteUiState.kt | 5 +++ .../main/java/com/ti/mobpo/ui/Navigation.kt | 14 ++++++-- .../com/ti/mobpo/ui/screens/Favourites.kt | 2 +- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 2 +- .../ui/viewmodels/FavouritesViewModel.kt | 6 +--- .../ui/viewmodels/PokeSearchViewModel.kt | 33 +++++++++++++++---- 6 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt diff --git a/app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt b/app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt new file mode 100644 index 0000000..69f5cd1 --- /dev/null +++ b/app/src/main/java/com/ti/mobpo/model/FavouriteUiState.kt @@ -0,0 +1,5 @@ +package com.ti.mobpo.model + +import com.ti.mobpo.data.Favourite + +data class FavouriteUiState(val favourites: List = listOf()) \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt index 3fb9343..e763f24 100644 --- a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt +++ b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt @@ -20,17 +20,22 @@ 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.AppViewModelProvider import com.ti.mobpo.ui.screens.FavoritesScreen import com.ti.mobpo.ui.screens.PokeSearchScreen +import com.ti.mobpo.ui.viewmodels.FavouritesViewModel +import com.ti.mobpo.ui.viewmodels.PokeSearchViewModel @Composable fun Navigation() { @@ -59,6 +64,9 @@ fun Navigation() { val updatedSelectedIndex = items.indexOfFirst { it.route == currentRoute } selectedItemIndex = rememberUpdatedState(updatedSelectedIndex).value + val pokeSearchVM = viewModel(factory = AppViewModelProvider.Factory) + val favoritesVM = viewModel(factory = AppViewModelProvider.Factory) + Scaffold ( bottomBar = { NavigationBar { @@ -102,11 +110,11 @@ fun Navigation() { ExitTransition.None }) { composable(route = Screen.PokeSearch.route) { - PokeSearchScreen() + PokeSearchScreen(pokeSearchVM) } composable( route = Screen.Favourites.route) { - FavoritesScreen() + FavoritesScreen(favoritesVM) } } } @@ -120,6 +128,6 @@ fun Navigation() { @Composable fun NavigationPreview() { Surface { - PokeSearchScreen() + PokeSearchScreen(viewModel(factory = AppViewModelProvider.Factory)) } } \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt index fe9d851..bbee671 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt @@ -23,7 +23,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier @Composable -fun FavoritesScreen(viewModel: FavouritesViewModel = viewModel(factory = AppViewModelProvider.Factory)) { +fun FavoritesScreen(viewModel: FavouritesViewModel) { Favorites(viewModel) } diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index cc238cb..27c0a1a 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -47,7 +47,7 @@ import com.ti.mobpo.capitalizeFirstLetterAfterHyphens import com.ti.mobpo.ui.theme.MobileSecurityTheme @Composable -fun PokeSearchScreen(viewModel: PokeSearchViewModel = viewModel(factory = AppViewModelProvider.Factory)) { +fun PokeSearchScreen(viewModel: PokeSearchViewModel) { PokeSearch(viewModel) } diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt index b829db6..a318f12 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt @@ -4,6 +4,7 @@ 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.FavouriteUiState import com.ti.mobpo.model.PokemonDetails import com.ti.mobpo.network.PokeApi import com.ti.mobpo.ui.util.FeatureManager @@ -47,9 +48,6 @@ class FavouritesViewModel(private val favouritesRepository: FavouritesRepository } } - - - fun toggleFavorite(pokemonId: Int) { _pokemonDetails.value = _pokemonDetails.value?.map { pokemon -> if (pokemon.id == pokemonId) { @@ -72,5 +70,3 @@ class FavouritesViewModel(private val favouritesRepository: FavouritesRepository } } } - -data class FavouriteUiState(val favourites: List = listOf()) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index cd1888a..8146c7f 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -5,6 +5,7 @@ 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.model.PokemonSpecies import com.ti.mobpo.network.PokeApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -13,23 +14,41 @@ import kotlinx.coroutines.launch import java.io.IOException - +private const val SHOW_LIMIT = 20; class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository) : ViewModel() { private val service = PokeApi.retrofitService; private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() + private val _initialPokemonList = MutableStateFlow?>(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) { viewModelScope.launch { try { - val response = service.getPokemon() - val filteredList = response.results.filter { it.name.contains(query, ignoreCase = true) } + val filteredList = _initialPokemonList.value?.filter { it.name.contains(query, ignoreCase = true) } val detailsList = mutableListOf() - for (pokemonSpecies in filteredList) { - val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) - val isFavorite = favouritesRepository.isFavourite(details.id) - detailsList.add(details.copy(isFavorite = isFavorite)) + if (filteredList != null) { + for (pokemonSpecies in filteredList.take(SHOW_LIMIT)) { + val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) + val isFavorite = favouritesRepository.isFavourite(details.id) + detailsList.add(details.copy(isFavorite = isFavorite)) + } } _pokemonDetails.value = detailsList } catch (e: IOException) { From ba724006c2deb4f20ae6f815833702c8165e228e Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:42:28 +0200 Subject: [PATCH 04/11] Remove unused imports --- app/src/main/java/com/ti/mobpo/data/Favourite.kt | 2 -- app/src/main/java/com/ti/mobpo/ui/Navigation.kt | 1 - app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt | 3 --- app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt | 1 - 4 files changed, 7 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/data/Favourite.kt b/app/src/main/java/com/ti/mobpo/data/Favourite.kt index eec9166..c4c9cbf 100644 --- a/app/src/main/java/com/ti/mobpo/data/Favourite.kt +++ b/app/src/main/java/com/ti/mobpo/data/Favourite.kt @@ -2,8 +2,6 @@ package com.ti.mobpo.data import androidx.room.Entity import androidx.room.PrimaryKey -import com.ti.mobpo.model.Sprites -import com.ti.mobpo.model.Type @Entity(tableName = "favourites") data class Favourite( diff --git a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt index e763f24..de389ca 100644 --- a/app/src/main/java/com/ti/mobpo/ui/Navigation.kt +++ b/app/src/main/java/com/ti/mobpo/ui/Navigation.kt @@ -20,7 +20,6 @@ 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 diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt index bbee671..69fa014 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt @@ -12,13 +12,10 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel -import com.ti.mobpo.AppViewModelProvider 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 diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index 27c0a1a..bdc531e 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -42,7 +42,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.ti.mobpo.model.PokemonDetails import coil.compose.AsyncImage import coil.request.ImageRequest -import com.ti.mobpo.AppViewModelProvider import com.ti.mobpo.capitalizeFirstLetterAfterHyphens import com.ti.mobpo.ui.theme.MobileSecurityTheme From 3085f958bd6ecf54360e46ae23c64f13a86c3fa9 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:49:14 +0200 Subject: [PATCH 05/11] When display limit is reached, stop filter --- .../java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt | 2 +- .../java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt index a318f12..db27440 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt @@ -18,7 +18,7 @@ import kotlinx.coroutines.launch import java.io.IOException class FavouritesViewModel(private val favouritesRepository: FavouritesRepository, featureManager: FeatureManager) : ViewModel() { - private val service = PokeApi.retrofitService; + private val service = PokeApi.retrofitService private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 8146c7f..231cbcf 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -44,7 +44,10 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository val filteredList = _initialPokemonList.value?.filter { it.name.contains(query, ignoreCase = true) } val detailsList = mutableListOf() if (filteredList != null) { - for (pokemonSpecies in filteredList.take(SHOW_LIMIT)) { + for (pokemonSpecies in filteredList) { + if (detailsList.size >= SHOW_LIMIT) { + break + } val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) val isFavorite = favouritesRepository.isFavourite(details.id) detailsList.add(details.copy(isFavorite = isFavorite)) From 0ebf26c457e9c5e257aef68d993d5f2c674aafc4 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:51:20 +0200 Subject: [PATCH 06/11] Instaid of searching is a string contains, start from the beginning... makes more sense --- .../com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 231cbcf..cef183d 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -36,18 +36,13 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository } } - - fun search(query: String) { viewModelScope.launch { try { - val filteredList = _initialPokemonList.value?.filter { it.name.contains(query, ignoreCase = true) } + val filteredList = _initialPokemonList.value?.filter { it.name.startsWith(query, ignoreCase = true) } val detailsList = mutableListOf() if (filteredList != null) { - for (pokemonSpecies in filteredList) { - if (detailsList.size >= SHOW_LIMIT) { - break - } + for (pokemonSpecies in filteredList.take(SHOW_LIMIT)) { val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) val isFavorite = favouritesRepository.isFavourite(details.id) detailsList.add(details.copy(isFavorite = isFavorite)) From fd122ec3761d37a99ea43aedcb439d51b2d51872 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 01:52:35 +0200 Subject: [PATCH 07/11] Sort the list alphabetticaly for bin search --- .../main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index cef183d..4d12068 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -29,7 +29,7 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository viewModelScope.launch { try { val response = service.getPokemon() - _initialPokemonList.value = response.results + _initialPokemonList.value = response.results.sortedBy { it.name.lowercase() } } catch (e: IOException) { /*TODO*/ } From 84e801ed016b6abc0558270ed2ef4b3074b4256b Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 02:02:39 +0200 Subject: [PATCH 08/11] Add bin search --- .../ui/viewmodels/PokeSearchViewModel.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 4d12068..148d586 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -39,10 +39,11 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository fun search(query: String) { viewModelScope.launch { try { - val filteredList = _initialPokemonList.value?.filter { it.name.startsWith(query, ignoreCase = true) } + val filteredList = _initialPokemonList.value?.binarySearch(query) val detailsList = mutableListOf() if (filteredList != null) { - for (pokemonSpecies in filteredList.take(SHOW_LIMIT)) { + for (index in filteredList until minOf(_initialPokemonList.value?.size ?: 0, filteredList + SHOW_LIMIT)) { + val pokemonSpecies = _initialPokemonList.value!![index] val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) val isFavorite = favouritesRepository.isFavourite(details.id) detailsList.add(details.copy(isFavorite = isFavorite)) @@ -55,6 +56,21 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository } } + private fun List.binarySearch(query: String): Int { + var low = 0 + var high = this.size - 1 + while (low <= high) { + val mid = (low + high) ushr 1 + val comparison = this[mid].name.compareTo(query, ignoreCase = true) + when { + comparison == 0 -> return mid + comparison < 0 -> low = mid + 1 + else -> high = mid - 1 + } + } + return low + } + private fun extractPokemonId(url: String): Int { val parts = url.split("/") return parts[parts.size - 2].toInt() From 7b36f08a26702950371a28a64e06a9173ce21d20 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 02:06:14 +0200 Subject: [PATCH 09/11] Add loading indicator --- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 35 +++++++++++-------- .../ui/viewmodels/PokeSearchViewModel.kt | 6 ++++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index bdc531e..869b4f0 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -19,6 +19,7 @@ import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.outlined.FavoriteBorder import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -53,6 +54,7 @@ fun PokeSearchScreen(viewModel: PokeSearchViewModel) { @Composable fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { val searchResults by pokeSearchViewModel.pokemonDetails.collectAsState() + val isLoading by pokeSearchViewModel.isLoading.collectAsState() Column( verticalArrangement = Arrangement.Top, @@ -67,21 +69,25 @@ fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { Spacer(modifier = Modifier.height(16.dp)) - searchResults?.let { results -> - if (results.isNotEmpty()) { - LazyVerticalGrid( - columns = GridCells.Adaptive(150.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(items = results, key = { pokemon -> pokemon.id }) { pokemon -> - PokemonCard(pokemon, toggleFavorite = { pokemonId -> - pokeSearchViewModel.toggleFavorite(pokemonId) - }) + if(isLoading) { + CircularProgressIndicator() + } else { + searchResults?.let { results -> + if (results.isNotEmpty()) { + LazyVerticalGrid( + columns = GridCells.Adaptive(150.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(items = results, key = { pokemon -> pokemon.id }) { pokemon -> + PokemonCard(pokemon, toggleFavorite = { pokemonId -> + pokeSearchViewModel.toggleFavorite(pokemonId) + }) + } } + } else { + Text("No results found") } - } else { - Text("No results found") } } } @@ -125,7 +131,8 @@ fun PokemonCard(pokemon: PokemonDetails, toggleFavorite: (Int) -> Unit) { ) IconButton( onClick = { toggleFavorite(pokemon.id) }, - modifier = Modifier.wrapContentSize() + modifier = Modifier + .wrapContentSize() .layout { measurable, constraints -> if (constraints.maxHeight == Constraints.Infinity) { layout(0, 0) {} diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 148d586..404c5a7 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -21,6 +21,9 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() private val _initialPokemonList = MutableStateFlow?>(null) + + private val _isLoading = MutableStateFlow(false) + val isLoading: StateFlow = _isLoading.asStateFlow() init { fetchPokemonSpecies() } @@ -37,6 +40,7 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository } fun search(query: String) { + _isLoading.value = true viewModelScope.launch { try { val filteredList = _initialPokemonList.value?.binarySearch(query) @@ -52,6 +56,8 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository _pokemonDetails.value = detailsList } catch (e: IOException) { /* Handle error */ + } finally { + _isLoading.value = false } } } From 8c69116171117f3ad90f727b4bbdc6a5099feb88 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 03:11:29 +0200 Subject: [PATCH 10/11] use buildin functions instaid --- .../ui/viewmodels/PokeSearchViewModel.kt | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt index 404c5a7..f85849e 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/PokeSearchViewModel.kt @@ -14,9 +14,9 @@ import kotlinx.coroutines.launch import java.io.IOException -private const val SHOW_LIMIT = 20; +private const val SHOW_LIMIT = 20 class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository) : ViewModel() { - private val service = PokeApi.retrofitService; + private val service = PokeApi.retrofitService private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() @@ -43,10 +43,16 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository _isLoading.value = true viewModelScope.launch { try { - val filteredList = _initialPokemonList.value?.binarySearch(query) + val firstIndex = _initialPokemonList.value?.indexOfFirst { it.name.startsWith(query, ignoreCase = true) } + val lastIndex = _initialPokemonList.value?.indexOfLast { it.name.startsWith(query, ignoreCase = true) } + val detailsList = mutableListOf() - if (filteredList != null) { - for (index in filteredList until minOf(_initialPokemonList.value?.size ?: 0, filteredList + SHOW_LIMIT)) { + + if (firstIndex != null && lastIndex != null) { + val endIndex = minOf(firstIndex + SHOW_LIMIT, lastIndex + 1) + val startIndex = maxOf(firstIndex, endIndex - SHOW_LIMIT) + + for (index in startIndex until endIndex) { val pokemonSpecies = _initialPokemonList.value!![index] val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) val isFavorite = favouritesRepository.isFavourite(details.id) @@ -62,21 +68,6 @@ class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository } } - private fun List.binarySearch(query: String): Int { - var low = 0 - var high = this.size - 1 - while (low <= high) { - val mid = (low + high) ushr 1 - val comparison = this[mid].name.compareTo(query, ignoreCase = true) - when { - comparison == 0 -> return mid - comparison < 0 -> low = mid + 1 - else -> high = mid - 1 - } - } - return low - } - private fun extractPokemonId(url: String): Int { val parts = url.split("/") return parts[parts.size - 2].toInt() From 8690ed006e12a9bd1cf4005f2eb54f7541a1d541 Mon Sep 17 00:00:00 2001 From: Joren Date: Tue, 30 Apr 2024 11:59:20 +0200 Subject: [PATCH 11/11] Add a toggle for access --- .../com/ti/mobpo/ui/screens/Favourites.kt | 29 ++++++++++++++++++- .../ui/viewmodels/FavouritesViewModel.kt | 14 +++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt index 69fa014..022b788 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/Favourites.kt @@ -16,6 +16,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.AlertDialog +import androidx.compose.material3.Button import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier @@ -41,6 +43,31 @@ fun Favorites(favoritesViewModel: FavouritesViewModel) { ) { Spacer(modifier = Modifier.height(16.dp)) + // Show AlertDialog if access check failed + if (favoritesViewModel.accessCheckFailed.value) { + AlertDialog( + onDismissRequest = { + // Dismiss the dialog + favoritesViewModel.accessCheckFailed.value = false + }, + title = { + Text("Access Denied") + }, + text = { + Text("You do not have access to this feature.") + }, + confirmButton = { + Button( + onClick = { + favoritesViewModel.accessCheckFailed.value = false + } + ) { + Text("OK") + } + } + ) + } + favorites?.let { favoritesList -> if (favoritesList.isNotEmpty()) { LazyVerticalGrid( @@ -59,4 +86,4 @@ fun Favorites(favoritesViewModel: FavouritesViewModel) { } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt index db27440..09108a4 100644 --- a/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/viewmodels/FavouritesViewModel.kt @@ -1,5 +1,7 @@ package com.ti.mobpo.ui.viewmodels +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ti.mobpo.data.Favourite @@ -17,15 +19,23 @@ 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 +class FavouritesViewModel(private val favouritesRepository: FavouritesRepository, + private val featureManager: FeatureManager +) : ViewModel() { + private val service = PokeApi.retrofitService private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() + val accessCheckFailed: MutableState = mutableStateOf(false) fun loadFavourites() { + // featureManager.setPaidFeatureEnabled(false) enable and disable acccess // Ugly workaround to make sure all the favourites are loaded before displaying them viewModelScope.launch { + if(!featureManager.hasAccessToPaidFeature()) { + accessCheckFailed.value = true + return@launch + } try { val favouritesList: StateFlow = favouritesRepository.getAllItems().map { FavouriteUiState(it) }