Implement view model provider, local database
This commit is contained in:
		@@ -4,6 +4,7 @@
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:name=".PokeSearch"
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
        android:enableOnBackInvokedCallback="true"
 | 
			
		||||
        android:dataExtractionRules="@xml/data_extraction_rules"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/src/main/java/com/ti/mobpo/AppViewModelProvider.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
object AppViewModelProvider {
 | 
			
		||||
    val Factory = viewModelFactory {
 | 
			
		||||
        initializer {
 | 
			
		||||
            PokeSearchViewModel(
 | 
			
		||||
                pokesearchApplication().appContainer.favouritesRepository
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun CreationExtras.pokesearchApplication(): PokeSearch =
 | 
			
		||||
    (this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as PokeSearch)
 | 
			
		||||
							
								
								
									
										19
									
								
								app/src/main/java/com/ti/mobpo/PokeSearch.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/src/main/java/com/ti/mobpo/PokeSearch.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package com.ti.mobpo
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import com.ti.mobpo.data.AppContainer
 | 
			
		||||
import com.ti.mobpo.data.AppDataContainer
 | 
			
		||||
 | 
			
		||||
class PokeSearch : Application() {
 | 
			
		||||
    lateinit var appContainer: AppContainer
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        super.onCreate()
 | 
			
		||||
        appContainer = createAppContainer()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createAppContainer(): AppContainer {
 | 
			
		||||
        return AppDataContainer(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,4 +17,7 @@ interface FavouriteDao {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT id FROM favourites")
 | 
			
		||||
    fun getAllFavoriteIds(): Flow<List<Int>>
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT EXISTS(SELECT 1 FROM favourites WHERE id = :id LIMIT 1)")
 | 
			
		||||
    suspend fun isFavourite(id: Int): Boolean
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,4 +20,10 @@ interface FavouritesRepository {
 | 
			
		||||
     * Delete item from the data source
 | 
			
		||||
     */
 | 
			
		||||
    suspend fun deleteItem(item: Favourite)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the item is a favourite
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    suspend fun isFavourite(id: Int): Boolean
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,8 @@ class OfflineFavouritesRepository(private val favouriteDao: FavouriteDao) : Favo
 | 
			
		||||
    override suspend fun deleteItem(item: Favourite) {
 | 
			
		||||
        favouriteDao.delete(item)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun isFavourite(id: Int): Boolean {
 | 
			
		||||
        return favouriteDao.isFavourite(id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ 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
 | 
			
		||||
@@ -30,7 +31,6 @@ 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.pokesearch.PokeSearchViewModel
 | 
			
		||||
import com.ti.mobpo.ui.screens.Favourites
 | 
			
		||||
import com.ti.mobpo.ui.screens.PokeSearchScreen
 | 
			
		||||
 | 
			
		||||
@@ -61,8 +61,6 @@ fun Navigation() {
 | 
			
		||||
    val updatedSelectedIndex = items.indexOfFirst { it.route == currentRoute }
 | 
			
		||||
    selectedItemIndex = rememberUpdatedState(updatedSelectedIndex).value
 | 
			
		||||
 | 
			
		||||
    val pokeSearchViewModel: PokeSearchViewModel = viewModel()
 | 
			
		||||
 | 
			
		||||
    Scaffold (
 | 
			
		||||
        bottomBar = {
 | 
			
		||||
            NavigationBar {
 | 
			
		||||
@@ -106,7 +104,7 @@ fun Navigation() {
 | 
			
		||||
                            ExitTransition.None
 | 
			
		||||
                        }) {
 | 
			
		||||
                        composable(route = Screen.PokeSearch.route) {
 | 
			
		||||
                            PokeSearchScreen(pokeSearchViewModel)
 | 
			
		||||
                            PokeSearchScreen()
 | 
			
		||||
                        }
 | 
			
		||||
                        composable(
 | 
			
		||||
                            route = Screen.Favourites.route) {
 | 
			
		||||
@@ -124,7 +122,6 @@ fun Navigation() {
 | 
			
		||||
@Composable
 | 
			
		||||
fun NavigationPreview() {
 | 
			
		||||
    Surface {
 | 
			
		||||
        val pokeSearchViewModel: PokeSearchViewModel = viewModel()
 | 
			
		||||
        PokeSearchScreen(pokeSearchViewModel)
 | 
			
		||||
        PokeSearchScreen()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,8 @@ package com.ti.mobpo.ui.pokesearch
 | 
			
		||||
 | 
			
		||||
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 kotlinx.coroutines.flow.MutableStateFlow
 | 
			
		||||
@@ -12,7 +14,7 @@ import java.io.IOException
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PokeSearchViewModel : ViewModel() {
 | 
			
		||||
class PokeSearchViewModel(private val favouritesRepository: FavouritesRepository) : ViewModel() {
 | 
			
		||||
    private val service = PokeApi.retrofitService;
 | 
			
		||||
 | 
			
		||||
    private val _pokemonDetails = MutableStateFlow<List<PokemonDetails>?>(null)
 | 
			
		||||
@@ -26,7 +28,8 @@ class PokeSearchViewModel : ViewModel() {
 | 
			
		||||
                val detailsList = mutableListOf<PokemonDetails>()
 | 
			
		||||
                for (pokemonSpecies in filteredList) {
 | 
			
		||||
                    val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url))
 | 
			
		||||
                    detailsList.add(details)
 | 
			
		||||
                    val isFavorite = favouritesRepository.isFavourite(details.id)
 | 
			
		||||
                    detailsList.add(details.copy(isFavorite = isFavorite))
 | 
			
		||||
                }
 | 
			
		||||
                _pokemonDetails.value = detailsList
 | 
			
		||||
            } catch (e: IOException) {
 | 
			
		||||
@@ -48,5 +51,17 @@ class PokeSearchViewModel : ViewModel() {
 | 
			
		||||
                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))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,13 @@ 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
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun PokeSearchScreen(pokeSearchViewModel: PokeSearchViewModel) {
 | 
			
		||||
    PokeSearch(pokeSearchViewModel)
 | 
			
		||||
fun PokeSearchScreen(viewModel: PokeSearchViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
 | 
			
		||||
    PokeSearch(viewModel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user