Advertisement

Responsive Advertisement

DataStore Preferences instead of sharepreference in jetpack compose in android studio

  • Step1 :-  First of all add dependency

    androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
    
    datastorePreferences = "1.1.1"
    
    // For hilt dependency
    
    
    hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
    hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" } // In plugins
    hiltPlugin={id="com.google.dagger.hilt.android",version.ref="hiltAndroid"}
    //also add aboove line in project level
    import android.content.Context
    import androidx.datastore.core.DataStore
    import androidx.datastore.core.IOException
    import androidx.datastore.preferences.core.Preferences
    import androidx.datastore.preferences.core.booleanPreferencesKey
    import androidx.datastore.preferences.core.edit
    import androidx.datastore.preferences.core.emptyPreferences
    import androidx.datastore.preferences.preferencesDataStore
    import kotlinx.coroutines.flow.Flow
    import kotlinx.coroutines.flow.catch
    import kotlinx.coroutines.flow.map


    val Context.datastore: DataStore<Preferences> by preferencesDataStore(name = "on_boarding_pref")

    class DataStoreRepository(context: Context) {
    private object PreferencesKey {
    val onBoardingKey = booleanPreferencesKey(name = "on_boarding_completed")
    }

    private val dataStore = context.datastore

    suspend fun saveOnBoardingState(completed: Boolean) {
    dataStore.edit { preferences ->
    preferences[PreferencesKey.onBoardingKey] = completed
    }
    }

    fun readOnBoardingState(): Flow<Boolean> {
    return dataStore.data
    .catch { exception ->
    if (exception is IOException) {
    emit(emptyPreferences())
    } else {
    throw exception
    }
    }
    .map { preferences ->
    val onBoardingState = preferences[PreferencesKey.onBoardingKey] ?: false
    onBoardingState
    }
    }

    }

  • Step2 :-  If you're using DI use this

    @Module
    @InstallIn(SingletonComponent::class)
    object MainModule {

    @Provides
    @Singleton
    fun provideDataStoreRepository(
    @ApplicationContext context: Context
    ) = DataStoreRepository(context = context)

    }
  • Step3 :-  I have created two viewmodel 1 is SplashViewmodel  and 2 is WelcomeViewModel

    @HiltViewModel
    class SplashViewModel @Inject constructor(private val respository: DataStoreRepository) :
    ViewModel() {

    private val _isLoading: MutableState<Boolean> = mutableStateOf(true)
    val isLoading: State<Boolean> = _isLoading

    private val _startDestinaton: MutableState<String> = mutableStateOf(Screen.Welcome.route)
    val startDestination: State<String> = _startDestinaton


    init {
    viewModelScope.launch {
    delay(2000) // Introduce a 2-second delay for splash screen
    respository.readOnBoardingState().collect { completed ->
    _startDestinaton.value = if (completed) Screen.Home.route else Screen.Welcome.route
    }
    _isLoading.value = false
    }
    }
    }
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import com.example.jetpacktutorials.ui.theme.data.DataStoreRepository
    import dagger.hilt.android.lifecycle.HiltViewModel
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.launch
    import javax.inject.Inject


    @HiltViewModel
    class WelcomeViewModel @Inject constructor(private val repository: DataStoreRepository) :
    ViewModel() {

    fun saveOnBoardingState(completed: Boolean) {
    viewModelScope.launch(Dispatchers.IO) {
    repository.saveOnBoardingState(completed = completed)
    }
    }
    }
    Also create for hilt 

    @HiltAndroidApp
    class MyApplication:Application() {
    }

  • Step4 :-  I have 3 screens
    @Composable
    fun HomeScreen() {
    Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center
    ) {
    Text(
    modifier = Modifier.padding(20.dp),
    text = "Welcome to Home Screen",
    fontSize = MaterialTheme.typography.titleLarge.fontSize
    )
    }
    }

    @Composable
    @Preview(showBackground = true)
    fun PreviewHomeScreen() {
    HomeScreen()
    }
    @Composable
    fun WelcomeScreen(
    navController: NavController,
    welcomeViewModel: WelcomeViewModel = hiltViewModel()
    ) {
    val pages = listOf(OnBoardingPage.First, OnBoardingPage.Second, OnBoardingPage.Third)
    val pagerState = rememberPagerState(
    initialPage = 0,
    initialPageOffsetFraction = 0f,
    pageCount = { pages.size }
    )
    Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
    modifier = Modifier.weight(10f), state = pagerState, beyondViewportPageCount = 3
    ) { position ->
    PagerScreen(onBoardingPage = pages[position])
    }
    HorizontalPagerIndicator(
    pagerState = pagerState,
    pageCount = pages.size,
    indicatorShape = CircleShape,
    activeColor = Color.Black,
    inactiveColor = Color.Gray, // Use Gray for better contrast
    indicatorWidth = 10.dp, // Adjust the size of the indicators
    indicatorHeight = 10.dp,
    spacing = 8.dp, // Add spacing between indicators
    modifier = Modifier
    .padding(top = 16.dp)
    .align(Alignment.CenterHorizontally)
    .weight(1f)
    // Fill width for centering
    )
    FinishButton(modifier = Modifier.weight(1f), pagerState = pagerState) {
    welcomeViewModel.saveOnBoardingState(completed = true)
    navController.popBackStack()
    navController.navigate(Screen.Home.route)
    }
    }

    }

    @Composable
    fun PagerScreen(onBoardingPage: OnBoardingPage) {
    Column(
    modifier = Modifier
    .fillMaxWidth(),
    horizontalAlignment = Alignment.CenterHorizontally,
    verticalArrangement = Arrangement.Top
    ) {
    Image(
    modifier = Modifier
    .fillMaxWidth(0.5f)
    .fillMaxHeight(0.6f),
    painter = painterResource(id = onBoardingPage.image),
    contentDescription = "Pager Page"
    )
    Text(
    modifier = Modifier.fillMaxWidth(),
    text = onBoardingPage.title,
    fontSize = MaterialTheme.typography.headlineMedium.fontSize,
    fontWeight = FontWeight.Bold,
    textAlign = TextAlign.Center
    )
    Text(
    modifier = Modifier
    .fillMaxWidth()
    .padding(horizontal = 40.dp)
    .padding(top = 20.dp),
    text = onBoardingPage.description,
    fontSize = MaterialTheme.typography.bodyMedium.fontSize,
    fontWeight = FontWeight.Medium,
    textAlign = TextAlign.Center
    )


    }
    }


    // Finish button for when slider ends..
    @Composable
    fun FinishButton(
    modifier: Modifier,
    pagerState: PagerState,
    onclick: () -> Unit
    ) {
    Row(
    modifier = Modifier
    .padding(horizontal = 40.dp)
    .padding(top = 14.dp),
    verticalAlignment = Alignment.Top,
    horizontalArrangement = Arrangement.Center
    ) {

    AnimatedVisibility(
    modifier = Modifier.fillMaxWidth(),
    visible = pagerState.currentPage == 2
    ) {

    Button(
    onClick = onclick,
    colors = ButtonDefaults.buttonColors(
    contentColor = Color.White
    )
    ) {
    Text("Finish")
    }

    }


    }

    }

    @Composable
    @Preview(showBackground = true)
    fun FirstScreenPreview() {
    Column(modifier = Modifier.fillMaxSize()) {
    PagerScreen(onBoardingPage = OnBoardingPage.First)
    }
    }

    @Composable
    @Preview(showBackground = true)
    fun SecondScreenPreview() {
    Column(modifier = Modifier.fillMaxSize()) {
    PagerScreen(onBoardingPage = OnBoardingPage.Second)
    }
    }

    @Composable
    @Preview(showBackground = true)
    fun ThirdScreenPreview() {
    Column(modifier = Modifier.fillMaxSize()) {
    PagerScreen(onBoardingPage = OnBoardingPage.Third)
    }
    }
    @Composable
    fun AnimatedSplashScreen(navController: NavHostController, splashViewModel: SplashViewModel = hiltViewModel()) {
    val isLoading by splashViewModel.isLoading
    val startDestination by splashViewModel.startDestination
    var startAnimation by remember { mutableStateOf(false) }

    val alphaAnim = animateFloatAsState(
    targetValue = if (startAnimation) 1f else 0f,
    animationSpec = tween(
    durationMillis = 3000
    ), label = "alphaAnimation"
    )

    // Display the splash screen with the animation
    Splash(alpha = alphaAnim.value)

    // Start the animation and navigation effect
    LaunchedEffect(key1 = true) {
    if (isLoading) {
    // Start animation once loading is finished
    startAnimation = true
    // After the animation duration, navigate to the next screen
    delay(3000) // wait for animation to finish
    navController.popBackStack()
    navController.navigate(startDestination)
    }
    }
    }


    @Composable
    fun Splash(alpha: Float) {
    Box(
    modifier = Modifier
    .background(if (isSystemInDarkTheme()) Color.Black else Color.DarkGray)
    .fillMaxSize(),
    contentAlignment = Alignment.Center
    ) {
    Icon(
    modifier = Modifier
    .size(120.dp)
    .alpha(alpha = alpha),
    imageVector = Icons.Default.Email,
    contentDescription = "Logo Icon",
    tint = Color.White
    )
    //For drawable image

    /* Image(
    painter = painterResource(id = R.drawable.ic_launcher_background), // Replace with your drawable
    contentDescription = "Email Icon",
    modifier = Modifier
    .size(120.dp)
    .alpha(alpha = alpha),
    contentScale = ContentScale.Fit, // Optional: adjust the scaling of the image
    colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(Color.White) // Apply tint if needed
    )*/
    }
    }
  • Step5 :- For onboarding i have created fix data with using sealed class


    import androidx.annotation.DrawableRes
    import com.example.jetpacktutorials.R

    sealed class OnBoardingPage(
    @DrawableRes
    val image: Int,
    val title: String,
    val description: String
    ) {

    data object First :
    OnBoardingPage(image = R.drawable.img1, "First Slider", "Hii, This is first Slider , Welcome In this App")

    data object Second :
    OnBoardingPage(image = R.drawable.img2, "Second Slider", "Hii, This is Second Slider, Welcome In this App")

    data object Third :
    OnBoardingPage(image = R.drawable.img3, "Third Slider", "Hii, This is Third Slider,Welcome In this App")

    }

  • Step6 :- For Screen Routing

    sealed class Screen(val route: String) {
    data object Welcome:Screen("welcome")
    data object Splash : Screen("splash_screen")
    data object Home : Screen("home_screen")
    }
  • Step7 :-  For this i have this navgraph

    import androidx.compose.runtime.Composable
    import androidx.navigation.NavHostController
    import androidx.navigation.compose.NavHost
    import androidx.navigation.compose.composable
    import com.example.jetpacktutorials.ui.theme.ui.home.HomeScreen
    import com.example.jetpacktutorials.ui.theme.ui.welcome.WelcomeScreen
    import com.example.jetpacktutorials.ui.theme.utils.AnimatedSplashScreen

    @Composable
    fun SetupNavGraph(navController: NavHostController,startDestination:String) {
    NavHost(
    navController = navController,
    startDestination =startDestination
    ) {
    composable(route = Screen.Welcome.route) {
    WelcomeScreen(navController = navController)
    }
    composable(route = Screen.Home.route) {
    HomeScreen()
    }
    composable(route = Screen.Splash.route) {
    AnimatedSplashScreen(navController = navController)
    }
    }
    }



Post a Comment

0 Comments