Create Onboarding with Data Store and Clean Architecture in Jetpack Compose

HariAgusWidakdo
2 min readMay 23, 2023

--

https://github.com/HariAgus/GroceriesApp-Compose/blob/master/assets/on_boarding_page.png

Bismillah, hello everyone in this article I will created Onboarding Page with Data Store and implement clean architecture and also of course using Jetpack Compose, the sample is as the picture above.

https://fti.ars.ac.id/portfolio/2010300919151

The codings will be made as above, but I won’t go into detail. If you want to read more details about clean architecture, you can visit this link : https://developer.android.com/topic/architecture.

Of course, the first thing we need is the Data Source library

implementation "androidx.datastore:datastore-preferences:1.0.0"

Next, create class OnBoardingOperations (Domain Layer) and OnBoardingOperationImpl(Data Layer) :

interface OnBoardingOperations {

suspend fun saveOnBoardingState(isCompleted: Boolean)
fun readOnBoardingState(): Flow<Boolean>

}
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = ON_BOARDING_NAME)

class OnBoardingOperationImpl(context: Context) : OnBoardingOperations {

private object PreferencesKey {
val onBoardingKey = booleanPreferencesKey(name = ON_BOARDING_KEY)
}

private val dataStore = context.dataStore

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

override 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
}
}
}

Next, we create data class UseCase Class for interaction with ViewModel

data class UseCases(
val saveOnBoardingUseCase: SaveOnBoardingUseCase,
val insertProductsUseCase: InsertProductsUseCase,
)

and next in class viewModel reads data from the UseCase, why do we use MutableStateFlow here? because MutableStateFlow is a mutable flow that can generate state data and can change its value. Yep, this is highly recommended for jetpack compose.

@HiltViewModel
class SplashViewModel @Inject constructor(
private val useCases: UseCases
) : ViewModel() {

private val _onBoardingIsCompleted = MutableStateFlow(false)
val onBoardingIsCompleted: StateFlow<Boolean> = _onBoardingIsCompleted

init {
viewModelScope.launch {
useCases.insertProductsUseCase.invoke(DataDummy.generateDummyProduct())
}

viewModelScope.launch(Dispatchers.IO) {
_onBoardingIsCompleted.value =
useCases.readOnBoardingUseCase().stateIn(viewModelScope).value
}
}

}

And finally we reads the onBoardingIsCompleted value in the viewModel, and don’t forget to convert the data into collectAsState(), because so that the value can be used in the view(UI), as below :

@Composable
fun SplashScreen(
navController: NavHostController,
splashViewModel: SplashViewModel = hiltViewModel()
) {
val onBoardingIsCompleted by splashViewModel.onBoardingIsCompleted.collectAsState()
val scale = remember { Animatable(0f) }

LaunchedEffect(key1 = true) {
scale.animateTo(
targetValue = 0.8f,
animationSpec = tween(
durationMillis = 800,
easing = {
OvershootInterpolator(4f).getInterpolation(it)
}
)
)
delay(1200L)
navController.popBackStack()

if (onBoardingIsCompleted) navController.navigate(Graph.MAIN)
else navController.navigate(Screen.OnBoarding.route)
}

Splash(scale = scale.value)
}

Finish… maybe that’s all, if you need the full code please check link in below and I would like to thank you for reading this article, which still has many flaws.

https://github.com/HariAgus/GroceriesApp-Compose

--

--

HariAgusWidakdo

Mobile Developer | Kotlin | SwiftUI 📱. Sometimes write my story 📚