-
Notifications
You must be signed in to change notification settings - Fork 0
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
Added VersionCheck class and support for verifying data and showing a default dialog (#5, #6, #7) #13
Conversation
* Moved Version into models package
…t; added more unit tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My biggest concern with using a viewModel is that I think it means we lose the ability to validate the version from the App class, and to replicate it we'd need to make sure that every activity in the app is calling runVersionCheck
in the onResume via the ViewModel. I think we could get around that and keep most of this functionality if we refactored out the runVersionCheck
into a separate Repository which could be used at the app level directly, but keep the VersionCheckViewModel, and have it monitor the repository instead.
So it might looks something like:
VersionCheckRepository
- Contains a shared flow of Status
- has
runVersionCheck
VersionCheckViewModel
- monitors the VersionCheckRepository's flow, converts it to LiveData for observers
Activity/Fragment can monitor VersionCheckViewModel (essentially the same)
App can call runVersionCheck
via the VersionCheckRepository if necessary
} | ||
|
||
class DefaultUpgradeDialog( | ||
private val activity: Activity): UpgradeDialog, LifecycleObserver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this leak activity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm, good question. I didn't run leak canary, but this felt like the only way to get access to the activity to get context to show the dialog. Maybe I could extract this out by having a delegate/interface that the Activity or App implements to give context or create the dialog. I'll ponder that a little more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should no longer be an issue.
requiresUpdate: Boolean, | ||
canDismiss: Boolean) { | ||
|
||
val builder = AlertDialog.Builder(activity).apply { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check if activity is still active here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should no longer be an issue
...eckkotlin/src/main/java/com/steamclock/versioncheckkotlin/interfaces/VersionDataConverter.kt
Show resolved
Hide resolved
Yeah, I agree with you on these points for sure. I went this route for a few reasons:
|
@jacobminer Ok ready for another round of review! Big refactor here - I have moved the bulk of the logic into the Let me know if this is closer to what you were thinking! Edit: This broke some of my unit tests, but once we have accepted a final implementation I will update them to use the repositories instead. |
// Looking at documentation we may be able to trigger the update with each collection so | ||
// we do not actually have to call this manually? <-- todo | ||
applicationScope.launch(Dispatchers.IO) { | ||
// Delay to show that we do get the initial state value before we call the update |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to remove this before committing this is mostly for testing right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer an issue
// repeatOnLifecycle(Lifecycle.State.STARTED) as our collection scope. | ||
versionRepository.displayStateFlow.collect { | ||
upgradeDialog.show(activity, it) | ||
Toast.makeText(activity, it.toString(), Toast.LENGTH_LONG).show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: Remove toast before releasing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer an issue
…ects flow and reacts to activity lifecycle changes
@jacobminer Ok, 3rd time's the charm? Hopefully my changes reflect what you were suggesting in our talk. I have
|
@@ -0,0 +1,55 @@ | |||
package com.steamclock.versioncheckkotlin.utils | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can probably remove this file now that we are no longer using LiveData; when I update the test scripts I will look into this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@@ -0,0 +1,96 @@ | |||
//import androidx.arch.core.executor.testing.InstantTaskExecutorRule | |||
//import com.steamclock.versioncheckkotlin.utils.TestConstants | |||
//import com.steamclock.versioncheckkotlin.VersionCheckViewModel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will update this to test VersionCheck once we have finalized implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated with new unit test
) | ||
val upgradeDialog = DefaultUpgradeDialog(versionChecker.displayStateFlow) | ||
|
||
ProcessLifecycleOwner.get().lifecycle.addObserver(versionChecker) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went back and looked at the Swift library and I now see what you mean about how they are listening for the application events.
I'm totally fine with pulling out the lifecycle listener code out of VersionCheck and simply making the app itself handle the lifecycle observation manually. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way works for me! From an app standpoint, it's pretty convenient to use it this way, but the runVersionCheck
function is also exposed, so it could be used either way. Maybe leave it as is, then note in the docs that you can choose to observe the lifecycle in the app and call runVersionCheck
or call ProcessLifecycleOwner.get().lifecycle.addObserver(versionChecker)
depending on what behaviour best fits the project?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! 🚀
versioncheckkotlin/src/main/java/com/steamclock/versioncheckkotlin/VersionCheckViewModel.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/steamclock/versioncheckkotlinsample/MainActivity.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/steamclock/versioncheckkotlinsample/MainActivity.kt
Outdated
Show resolved
Hide resolved
) | ||
val upgradeDialog = DefaultUpgradeDialog(versionChecker.displayStateFlow) | ||
|
||
ProcessLifecycleOwner.get().lifecycle.addObserver(versionChecker) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way works for me! From an app standpoint, it's pretty convenient to use it this way, but the runVersionCheck
function is also exposed, so it could be used either way. Maybe leave it as is, then note in the docs that you can choose to observe the lifecycle in the app and call runVersionCheck
or call ProcessLifecycleOwner.get().lifecycle.addObserver(versionChecker)
depending on what behaviour best fits the project?
Sorry, it looks like my comments from the previous version got included in this PR review. Disregard those! |
Summary of Problem:
Android project had some initial work done on it, but didn't end up getting fully flushed out.
Sorry, there's a few issues being addressed here all at the same time, I should have broken them up but just kept going down rabbit holes and they were somewhat intertwined.
Proposed Solution:
This PR addresses the following tickets:
This PR adds:
PlatformVersionData
,VersionData
,Status
andDisplayState
data models; named to match iOS as close as possibleURLFetcher
interface and a default implementation that pulls down a string from a given URLVersionCheck
contains flows for exposing both the display and status states; it can also be setup as a lifecycle listener to automatically run checks "on start"DefaultUpgradeDialog
collects display flow from VersionCheck and handles creation of a default alert dialog; it should be setup as an activity lifecycle listener to automatically handle the show/dismiss of the dialog.VersionDataConverter
interface and a default implementation to parse JSON into aVersionData
object; to avoid having to import specific parsing libraries, this is done with basic JSONObject and JSONArray manual parsing.Setup and Usage
Currently, to add version checking at the application level, setup is as follows (the MainActivity is still playing around with using the ViewModel as a proof of concept, but in practice I am guessing we'd be applying this at the application level)
Testing Steps:
Still todo: