Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#159][Part1] [Compose] Support datastore replacing shared preference #389

Conversation

lydiasama
Copy link
Contributor

@lydiasama lydiasama commented Jan 11, 2023

#159

What happened 👀

Part 1: Integrate for sample-compose
Part 2: Integrate for sample-xml
Part 3: Integrate for both template-xml & template-compose

Insight 📝

  • Add the DataStore Preferences dependencies to the Sample-Compose project.
  • Add use cases for GetFirstTimeLaunchPreferencesUseCase and UpdateFirstTimeLaunchPreferencesUseCase.
  • At first, I attempt to call the use cases by the following approach:
init {
        execute {
            showLoading()
            getModelsUseCase()
                .catch {
                    _error.emit(it)
                }
                .collect { result ->
                    val uiModels = result.toUiModels()
                    _uiModels.emit(uiModels)
                }
            getFirstTimeLaunchUseCase()
                .catch {
                    _error.emit(it)
                }
                .collect { firstTimeLaunch ->
                    Timber.d("firstTimeLaunch: $firstTimeLaunch")
                    _firstTimeLaunch.emit(firstTimeLaunch)
                    if (firstTimeLaunch) {
                        updateFirstTimeLaunchUseCase(false)
                    }
                    Timber.d("firstTimeLaunch: after if")
                }
            hideLoading()
        }
    }

But it has never come to do the hideLoading() function. It seems it never ends the collect() function. So I changed the approach to be:

init {
        execute {
            showLoading()
            val getModelsFlow = getModelsUseCase()
            val getFirstTimeLaunchPreferencesFlow = getFirstTimeLaunchPreferencesUseCase()

            getModelsFlow.combine(getFirstTimeLaunchPreferencesFlow) { uiModels, firstTimeLaunch ->
                _uiModels.emit(uiModels.toUiModels())

                _firstTimeLaunch.emit(firstTimeLaunch)
                if (firstTimeLaunch) {
                    updateFirstTimeLaunchPreferencesUseCase(false)
                }
            }.catch {
                _error.emit(it)
                hideLoading()
            }.collect {
                hideLoading()
            }
        }
    }

And what's interesting is, when I tried the .onCompletion, it will do the onCompletion block when gets error, but not execute it when it succeeds. So in success case, it will not hide loading if we do the following code:

init {
        execute {
            val getModelsFlow = getModelsUseCase()
            val getFirstTimeLaunchPreferencesFlow = getFirstTimeLaunchPreferencesUseCase()
           ...
            }.onStart {
                showLoading()
            }.onCompletion {
                hideLoading()                
            }.catch {
                _error.emit(it)
            }.collect()
        }
    }

After discussing with @Wadeewee, we can wrap the appPreferencesDataStore.data with flow, so that we can use .first() to get only the first emit from the DataStore preferences and it can finish the collect() function.

💡 Here is the solution:

init {
        execute {
            val getModelsFlow = getModelsUseCase()
            val getFirstTimeLaunchPreferencesFlow = getFirstTimeLaunchPreferencesUseCase()
           ...
            }.onStart {
                showLoading()
            }.onCompletion {
                hideLoading()
            }.catch {
                _error.emit(it)
            }.collect()
        }
    }
  • 💡 I have an idea to combine the _uiModels, _firstTimeLaunch, and showLoading flow in HomeViewState. So we can get rid of their public variables. Moreover, we can just observe only
val homeViewState: HomeViewState by viewModel.homeViewState.collectAsState()

in HomeScreen. BTW, I'm not sure if we could reduce the recomposition by doing this because when the HomeViewState's properties are changed, it might trigger to recompose anyway. So I'll keep the codebase as the same.

  • I added these attributes to AndroidManifest because when I test uninstall and reinstall the app, sometimes the preferences does not remove entirely. But instead, it keep some caches. So it's better to not allow caching.
    Ref: https://stackoverflow.com/a/33176898
        android:allowBackup="false"
        android:fullBackupContent="false"

Proof Of Work 📹

Success case:

device-2023-01-11-181454.mp4

Error case:

device-2023-01-12-172134.mp4

How does it look like in the device's storage:

Screenshot 2566-01-11 at 6 18 42 PM

@github-actions
Copy link

github-actions bot commented Jan 11, 2023

4 Warnings
⚠️ Uh oh! BaseViewModel.kt is under 95% coverage!
⚠️ Uh oh! HomeViewModel.kt is under 95% coverage!
⚠️ Uh oh! Your project is under 80% coverage!
⚠️ Uh oh! HomeScreen.kt is under 95% coverage!

Kover report for template-xml:

🧛 Template - XML Unit Tests Code Coverage: 29.95%

Coverage of Modified Files:

File Coverage
BaseViewModel.kt 0.00%
HomeViewModel.kt 0.00%
UseCase.kt 100.00%

Modified Files Not Found In Coverage Report:

AndroidManifest.xml
AppPreferencesRepository.kt
AppPreferencesRepositoryImpl.kt
HomeScreen.kt
IsFirstTimeLaunchPreferencesUseCase.kt
IsFirstTimeLaunchPreferencesUseCaseTest.kt
PreferencesModule.kt
StorageModule.kt
UpdateFirstTimeLaunchPreferencesUseCase.kt
UpdateFirstTimeLaunchPreferencesUseCaseTest.kt
UseCaseTest.kt
Versions.kt
build.gradle.kts
build.gradle.kts

Codebase cunningly covered by count Shroud 🧛

Kover report for template-compose:

🧛 Template - Compose Unit Tests Code Coverage: 24.28%

Coverage of Modified Files:

File Coverage
BaseViewModel.kt 97.62%
HomeScreen.kt 0.00%
HomeViewModel.kt 100.00%
UseCase.kt 100.00%

Modified Files Not Found In Coverage Report:

AndroidManifest.xml
AppPreferencesRepository.kt
AppPreferencesRepositoryImpl.kt
IsFirstTimeLaunchPreferencesUseCase.kt
IsFirstTimeLaunchPreferencesUseCaseTest.kt
PreferencesModule.kt
StorageModule.kt
UpdateFirstTimeLaunchPreferencesUseCase.kt
UpdateFirstTimeLaunchPreferencesUseCaseTest.kt
UseCaseTest.kt
Versions.kt
build.gradle.kts
build.gradle.kts

Codebase cunningly covered by count Shroud 🧛

Generated by 🚫 Danger

@luongvo luongvo force-pushed the feature/353-set-up-app-resources-and-theme-management branch from 33274a5 to cc91780 Compare January 11, 2023 18:06
@toby-thanathip
Copy link
Contributor

@lydiasama Will your issue be split up like this? 🙏

  • Part 1: Integrate for sample-compose
  • Part 2: Integrate for sample-xml
  • Part 3: Integrate for both template-xml & template-compose

Also, please rebase 🚀

@lydiasama lydiasama force-pushed the feature/159-part2-support-datastore-replacing-shared-preference branch from 48d57de to 2a7f79d Compare January 13, 2023 09:26
@lydiasama lydiasama changed the title [#159][Part2] [Compose] Support datastore replacing shared preference [#159][Part1] [Compose] Support datastore replacing shared preference Jan 13, 2023
@lydiasama
Copy link
Contributor Author

@Tuubz Updated. 🚀

Base automatically changed from feature/353-set-up-app-resources-and-theme-management to develop January 19, 2023 04:50
@luongvo luongvo linked an issue Feb 9, 2023 that may be closed by this pull request
Copy link
Contributor

@kaungkhantsoe kaungkhantsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

@lydiasama lydiasama force-pushed the feature/159-part2-support-datastore-replacing-shared-preference branch from 4fe2a05 to 6dbe671 Compare February 9, 2023 05:41
@lydiasama
Copy link
Contributor Author

lydiasama commented Feb 9, 2023

@luongvo @thiennguyen0196 Resolved all. Plus, unit tests are added.

Copy link
Contributor

@thiennguyen0196 thiennguyen0196 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now

Copy link
Member

@luongvo luongvo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest lgtm, 1 last issue 👋

@lydiasama lydiasama requested a review from luongvo February 9, 2023 10:21
Copy link
Member

@luongvo luongvo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

Copy link
Member

@chornerman chornerman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comment 🚀

@lydiasama lydiasama requested a review from chornerman February 10, 2023 03:22
Copy link
Member

@chornerman chornerman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👏🏼 👏🏼

Copy link
Member

@luongvo luongvo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@kaungkhantsoe
Copy link
Contributor

@lydiasama Conflict 🦀

@lydiasama
Copy link
Contributor Author

@kaungkhantsoe Thanks ❤️ Resolved!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support DataStore in a replacement for SharedPreference
9 participants