Working on an android app (personal project) with Kotlin and Jetpack.
Using Proto datastore to store application settings/configurations. Using Hilt for D.I.
My code was just working fine with intended outcomes, I thought to take "suggestions" from ChatGPT for optimizing my code, and ChatGPT presented me with the refactored version of the code.
** First let me share my code:**
@HiltViewModel
class ApplicationEntryViewModel @Inject constructor(
private val protoData: DataStore<GeneralApplicationPreferences>
) : ViewModel() {
private val _applicationStates = MutableStateFlow(GeneralPreferences())
val applicationStates
get() = _applicationStates.asStateFlow()
init {
viewModelScope.launch {
protoData.data.collectLatest { preferences: GeneralApplicationPreferences ->
GLOBAL_DATA_PRECISION = protoDataPrecisionToDataPrecision(preferences.dataPrecision)
_applicationStates.update { currentValue ->
currentValue.copy(
currentDestination = preferences.currentDestination.ifEmpty {
NavigationDestinations.SAMCompanion.screen_route
},
showTrailingZero = preferences.showTrailingZero,
isHCVisible = preferences.isHcVisible,
isWFHClassificationEnabled = preferences.isWfhClassificationVisible,
isBMIVisible = preferences.isBmiVisible,
isGradeVisible = preferences.isGradeVisible,
isICDSDataSamplerEnabled = preferences.isIcdsDataSamplerEnabled,
isSchoolDataSamplerEnabled = preferences.isSchoolDataSamplerEnabled
)
}
}
SHOW_TRAILING_ZERO = _applicationStates.value.showTrailingZero
}
}
private suspend fun toggleShowICDSDataSampler (isEnabled: Boolean) {
_applicationStates.update { value ->
value.copy(
isICDSDataSamplerEnabled = isEnabled
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isIcdsDataSamplerEnabled = _applicationStates.value.isICDSDataSamplerEnabled
}
}
}
}
private suspend fun toggleShowSchoolDataSampler (isEnabled: Boolean) {
_applicationStates.update { value ->
value.copy(
isSchoolDataSamplerEnabled = isEnabled
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isSchoolDataSamplerEnabled = _applicationStates.value.isSchoolDataSamplerEnabled
}
}
}
}
private suspend fun updateCurrentDestination (destinationRoute: String?) {
_applicationStates.update { currentValue ->
currentValue.copy(
currentDestination = destinationRoute ?: NavigationDestinations.SAMCompanion.screen_route
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.currentDestination = _applicationStates.value.currentDestination
}
}
}
}
private suspend fun icdsToggleHCVisibility (isVisible: Boolean) {
_applicationStates.update { currentValue ->
currentValue.copy(
isHCVisible = isVisible
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isHcVisible = _applicationStates.value.isHCVisible
}
}
}
}
private suspend fun icdsToggleWFHClassificationVisibility (isVisible: Boolean) {
_applicationStates.update { currentValue ->
currentValue.copy(
isWFHClassificationEnabled = isVisible
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isWfhClassificationVisible = _applicationStates.value.isWFHClassificationEnabled
}
}
}
}
private suspend fun schoolToggleBMIVisibility (isVisible: Boolean) {
_applicationStates.update { currentValue ->
currentValue.copy(
isBMIVisible = isVisible
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isBmiVisible = _applicationStates.value.isBMIVisible
}
}
}
}
private suspend fun schoolToggleGradeVisibility (isVisible: Boolean) {
_applicationStates.update { currentValue ->
currentValue.copy(
isGradeVisible = isVisible
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.isGradeVisible = _applicationStates.value.isGradeVisible
}
}
}
}
private suspend fun updateDataPrecision (newPrecision: DataPrecision) {
GLOBAL_DATA_PRECISION = newPrecision
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.dataPrecision = GLOBAL_DATA_PRECISION.toProtoDataPrecision()
}
}
}
}
private suspend fun toggleShowSchoolHeightInFPS (inFPS: Boolean) {
_applicationStates.update { value ->
value.copy(
showSchoolHeightInFPS = inFPS
)
}
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.showSchoolHeightInFps = _applicationStates.value.showSchoolHeightInFPS
}
}
}
}
private suspend fun toggleShowTrailingZeroAfterDecimal (showTrailingZero: Boolean) {
_applicationStates.update { value ->
value.copy(
showTrailingZero = showTrailingZero
)
}
SHOW_TRAILING_ZERO = showTrailingZero
viewModelScope.launch {
protoData.updateData { preferences: GeneralApplicationPreferences ->
preferences.copy {
this.showTrailingZero = _applicationStates.value.showTrailingZero
}
}
}
}
suspend fun handleEventsFor (event: PreferenceEvents) {
when (event) {
is PreferenceEvents.DestinationChanged -> updateCurrentDestination(event.destination)
is PreferenceEvents.ToggleBMI -> schoolToggleBMIVisibility(event.isBMIVisible)
is PreferenceEvents.ToggleGrade -> schoolToggleGradeVisibility(event.isGradeVisible)
is PreferenceEvents.ToggleHC -> icdsToggleHCVisibility(event.isHCVisible)
is PreferenceEvents.ToggleWFHClassification -> icdsToggleWFHClassificationVisibility(event.isWFHClassificationEnabled)
is PreferenceEvents.ToggleShowHeightInFPS -> toggleShowSchoolHeightInFPS(event.showHeightInFPS)
is PreferenceEvents.ToggleTrailingZero -> toggleShowTrailingZeroAfterDecimal(event.showTrailingZero)
is PreferenceEvents.ToggleGlobalDataPrecision -> updateDataPrecision(event.precision)
is PreferenceEvents.ToggleICDSDataSampler -> toggleShowICDSDataSampler(event.isDataSamplerEnabled)
is PreferenceEvents.ToggleSchoolDataSampler -> toggleShowSchoolDataSampler(event.isDataSamplerEnabled)
}
}
}
data class GeneralPreferences (
val currentDestination: String = NavigationDestinations.School.screen_route,
val isICDSDataSamplerEnabled: Boolean = false,
val isHCVisible: Boolean = false,
val isWFHClassificationEnabled: Boolean = false,
val isSchoolDataSamplerEnabled: Boolean = false,
val isBMIVisible: Boolean = false,
val isGradeVisible: Boolean = false,
val showSchoolHeightInFPS: Boolean = false,
val showTrailingZero: Boolean = false,
)
GLOBAL_DATA_PRECISION and SHOW_TRAILING_ZERO - these two are global variables
ChatGPT's refactored code:
@HiltViewModel
class ApplicationEntryViewModel @Inject constructor(
private val protoData: DataStore<GeneralApplicationPreferences>
) : ViewModel() {
private val _applicationStates = MutableStateFlow(GeneralPreferences())
val applicationStates
get() = _applicationStates.asStateFlow()
init {
viewModelScope.launch {
protoData.data.collectLatest { preferences ->
handleDataStoreUpdate(preferences)
}
}
}
private fun handleDataStoreUpdate(preferences: GeneralApplicationPreferences) {
GLOBAL_DATA_PRECISION = protoDataPrecisionToDataPrecision(preferences.dataPrecision)
_applicationStates.value = preferences.toGeneralPreferences()
SHOW_TRAILING_ZERO = _applicationStates.value.showTrailingZero
}
private suspend fun updatePreference(
updater: suspend (GeneralPreferences) -> GeneralPreferences,
updaterProto: suspend (GeneralApplicationPreferences) -> GeneralApplicationPreferences
) {
_applicationStates.value = updater(_applicationStates.value)
viewModelScope.launch {
protoData.updateData { preferences ->
updaterProto(preferences)
}
}
}
private fun GeneralApplicationPreferences.toGeneralPreferences(): GeneralPreferences {
return GeneralPreferences(
currentDestination = currentDestination.ifEmpty { NavigationDestinations.SAMCompanion.screen_route },
isICDSDataSamplerEnabled = isIcdsDataSamplerEnabled,
isHCVisible = isHcVisible,
isWFHClassificationEnabled = isWfhClassificationVisible,
isSchoolDataSamplerEnabled = isSchoolDataSamplerEnabled,
isBMIVisible = isBmiVisible,
isGradeVisible = isGradeVisible,
showSchoolHeightInFPS = showSchoolHeightInFps,
showTrailingZero = showTrailingZero
)
}
suspend fun handleEventsFor(event: PreferenceEvents) {
when (event) {
is PreferenceEvents.DestinationChanged -> updatePreference(
{ it.copy (currentDestination = event.destination) },
{ it.copy { currentDestination = event.destination } }
)
is PreferenceEvents.ToggleBMI -> updatePreference(
{ it.copy (isBMIVisible = event.isBMIVisible) },
{ it.copy { isBmiVisible = event.isBMIVisible} }
)
is PreferenceEvents.ToggleGrade -> updatePreference(
{ it.copy (isGradeVisible = event.isGradeVisible) },
{ it.copy { isGradeVisible = event.isGradeVisible} }
)
is PreferenceEvents.ToggleHC -> updatePreference(
{ it.copy (isHCVisible = event.isHCVisible) },
{ it.copy { isHcVisible = event.isHCVisible} }
)
is PreferenceEvents.ToggleWFHClassification -> updatePreference(
{ it.copy (isWFHClassificationEnabled = event.isWFHClassificationEnabled) },
{ it.copy { isWfhClassificationVisible = event.isWFHClassificationEnabled} }
)
is PreferenceEvents.ToggleShowHeightInFPS -> updatePreference(
{ it.copy (showSchoolHeightInFPS = event.showHeightInFPS) },
{ it.copy { showSchoolHeightInFps = event.showHeightInFPS} }
)
is PreferenceEvents.ToggleTrailingZero -> updatePreference(
{ it.copy (showTrailingZero = event.showTrailingZero) },
{ it.copy { showTrailingZero = event.showTrailingZero} }
)
is PreferenceEvents.ToggleGlobalDataPrecision -> updatePreference(
{ it } ,
{ it.copy { dataPrecision = event.precision.toProtoDataPrecision()} }
)
is PreferenceEvents.ToggleICDSDataSampler -> updatePreference(
{ it.copy (isICDSDataSamplerEnabled = event.isDataSamplerEnabled) },
{ it.copy { isIcdsDataSamplerEnabled = event.isDataSamplerEnabled} }
)
is PreferenceEvents.ToggleSchoolDataSampler -> updatePreference(
{ it.copy (isSchoolDataSamplerEnabled = event.isDataSamplerEnabled) },
{ it.copy { isSchoolDataSamplerEnabled = event.isDataSamplerEnabled} }
)
}
}
}
data class GeneralPreferences (
val currentDestination: String = NavigationDestinations.School.screen_route,
val isICDSDataSamplerEnabled: Boolean = false,
val isHCVisible: Boolean = false,
val isWFHClassificationEnabled: Boolean = false,
val isSchoolDataSamplerEnabled: Boolean = false,
val isBMIVisible: Boolean = false,
val isGradeVisible: Boolean = false,
val showSchoolHeightInFPS: Boolean = false,
val showTrailingZero: Boolean = false,
)
Both the versions are working as intended.
What I observed in the following line (of ChaGPT's code):
is PreferenceEvents.ToggleGlobalDataPrecision -> updatePreference( { it } , { it.copy { dataPrecision = event.precision.toProtoDataPrecision()} } )
At this point I am unable to understand how come the GLOBAL_DATA_PRECISION is getting updated in the ChatGPT's code. Which led me to believe that if ProtoDataStore is updated the rest of the state variables are also automatically updated. Am I right? Or I got the whole thing wrong?