-
Notifications
You must be signed in to change notification settings - Fork 739
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
FTUE - Server selection #5691
FTUE - Server selection #5691
Conversation
9ed5786
to
3886c42
Compare
@@ -139,7 +140,8 @@ class OnboardingViewModel @AssistedInject constructor( | |||
is OnboardingAction.UpdateServerType -> handleUpdateServerType(action) | |||
is OnboardingAction.UpdateSignMode -> handleUpdateSignMode(action) | |||
is OnboardingAction.InitWith -> handleInitWith(action) | |||
is OnboardingAction.UpdateHomeServer -> handleUpdateHomeserver(action).also { lastAction = action } | |||
is OnboardingAction.SelectHomeServer -> run { lastAction = action }.also { handleHomeserverChange(action.homeServerUrl) } |
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.
actions are set straight away as setting them afterwards implicitly relies on asynchronous coroutines (which isn't the case for tests!)
homeServerUrlFromUser = null, | ||
homeServerUrl = null, | ||
loginMode = LoginMode.Unknown, | ||
serverType = ServerType.Unknown, |
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.
resetting the server url shouldn't also reset the server type
as the server type
is actually the user selection from the "Matrix, EMS, Other" page
@@ -70,6 +61,15 @@ enum class OnboardingFlow { | |||
SignInSignUp | |||
} | |||
|
|||
@Parcelize | |||
data class SelectedHomeserverState( |
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.
the individual homeserver state has been bundled into a single SelectedHomeserverState
, this object is created/updated when starting the authentication flow (by selecting or editing a homeserver url) through a single entry point StartAuthenticationFlowUseCase.kt
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.
Thank you! 💯
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.
Thanks for the large PR, good job for adding tests, I have some remarks!
@@ -18,3 +18,5 @@ package im.vector.app.core.extensions | |||
|
|||
inline fun <reified T> List<T>.nextOrNull(index: Int) = getOrNull(index + 1) | |||
inline fun <reified T> List<T>.prevOrNull(index: Int) = getOrNull(index - 1) | |||
|
|||
fun <T> List<T>.containsAll(vararg items: T) = this.containsAll(items.toList()) |
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 would avoid extension functions with the exact name as the original, I don't have a strong point though
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 was imagining this as an overload for containsAll
but I agree it can be tricky to discover the extension, will rename
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.
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.
Good!
@@ -139,7 +140,8 @@ class OnboardingViewModel @AssistedInject constructor( | |||
is OnboardingAction.UpdateServerType -> handleUpdateServerType(action) | |||
is OnboardingAction.UpdateSignMode -> handleUpdateSignMode(action) | |||
is OnboardingAction.InitWith -> handleInitWith(action) | |||
is OnboardingAction.UpdateHomeServer -> handleUpdateHomeserver(action).also { lastAction = action } | |||
is OnboardingAction.SelectHomeServer -> run { lastAction = action }.also { handleHomeserverChange(action.homeServerUrl) } |
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.
Maybe its worth create a function to wrap duplicate lines:
run { lastAction = action }.also { handleHomeserverChange(action.homeServerUrl) }
run { lastAction = action }.also { handleHomeserverChange(action.homeServerUrl) }
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.
great idea! I can extract the run { lastAction = action }
but the handleHomeserverChange(action.homeServerUrl)
is a bit trickier as we need to pull the server url from two different action types SelectHomeServer.homeServerUrl & EditHomeServer.homeServerUrl
could be a good case for a sealed interface with a common property, will have a play around!
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.
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.
Nice approach with the sealed interface, I like it
data.supportedLoginTypes.contains(LoginFlowTypes.PASSWORD) -> LoginMode.Password | ||
else -> LoginMode.Unsupported | ||
} | ||
runCatching { startAuthenticationFlowUseCase.execute(homeServerConnectionConfig) }.fold( |
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.
Using withContext(Dispatchers.IO)
to startAuthenticationFlowUseCase
will reduce the work on main thread. Or maybe using viewModelScope.launch(Dispatchers.IO)
and exclude state updates to run on Main dispatcher
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 wasn't sure about this, the authentication service has a bunch of internal non thread safe state, we can rely on the lower layers (retrofit/awaitTransaction) for doing the dispatcher switching for us, at least whilst the other parts aren't thread safe
but it does mean there's some thread jumping happening~
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.
Yes, I was talking mainly for the logic that is running on the main thread, except retrofit calls etc that always run on another thread. But if we have thread safety issues, there are not much we can do!
return FragmentFtueServerSelectionCombinedBinding.inflate(inflater, container, false) | ||
} | ||
|
||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
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.
Minor, I would have created some more methods instead of having all the login in onViewCreated
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.
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.
Thanks!
views.loginSignupSigninText.text = getString(R.string.login_server_matrix_org_text) | ||
} | ||
ServerType.EMS -> { | ||
views.loginSignupSigninServerIcon.setImageResource(R.drawable.ic_logo_element_matrix_services) | ||
views.loginSignupSigninServerIcon.isVisible = true | ||
views.loginSignupSigninTitle.text = getString(R.string.login_connect_to_modular) | ||
views.loginSignupSigninText.text = state.homeServerUrlFromUser.toReducedUrl() | ||
views.loginSignupSigninText.text = state.selectedHomeserver.userFacingUrl.toReducedUrl() | ||
} | ||
ServerType.Other -> { | ||
views.loginSignupSigninServerIcon.isVisible = false | ||
views.loginSignupSigninTitle.text = getString(R.string.login_server_other_title) |
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.
We don't need setting the icon in ServerType.Other
case?
views.loginSignupSigninServerIcon.setImageResource(R.drawable.ic_logo_element_matrix_services)
or maybe set it to null?
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.
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.
Thanks, for explaining
@@ -60,27 +60,27 @@ class FtueAuthSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOF | |||
ServerType.MatrixOrg -> { |
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.
Extremely minor, maybe its worth creating a function like:
private fun update(@DrawableRes drawableId: Int,
isServerIconVisible: Boolean,
signInTitle: String,
signInText: String
){
views.loginSignupSigninServerIcon.setImageResource(drawableId)
views.loginSignupSigninServerIcon.isVisible = isServerIconVisible
views.loginSignupSigninTitle.text = signInTitle
views.loginSignupSigninText.text = signInText
}
to reduce code duplication
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.
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.
Nice!
<string name="ftue_auth_choose_server_entry_footer">You can only connect to a server that has already been set up</string> | ||
<string name="ftue_auth_choose_server_ems_title">Want to host your own server?</string> | ||
|
||
<string name="ftue_ems_url">https://element.io/ems</string> |
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.
Maybe we should add this to vector-config urls.xml ?
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.
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.
Thanks
@@ -58,6 +62,9 @@ private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canChangeDisplay | |||
private val AN_IGNORED_FLOW_RESULT = FlowResult(missingStages = emptyList(), completedStages = emptyList()) | |||
private val ANY_CONTINUING_REGISTRATION_RESULT = RegistrationResult.FlowResponse(AN_IGNORED_FLOW_RESULT) | |||
private val A_LOGIN_OR_REGISTER_ACTION = OnboardingAction.LoginOrRegister("@a-user:id.org", "a-password", "a-device-name") | |||
private const val A_HOMESERVER_URL = "https://edited-homeserver.org" | |||
private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance) | |||
private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password) | |||
|
|||
class OnboardingViewModelTest { |
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.
+1 for adding Tests!
- replaces previous separately url strings with state usage - makes use of the state for updating the sign up and server selection fields
- helps to highlight a non secture connection, for https we strip the prefix
- moves some of the homeserver specific state to the selectServer model
- should better reflect this steps mvoes the onboarding process forwards
…e the cases differently
…count, fixes flaky initial value setting
…void duplication in the model
follows other ftue fragment conventions
…e duplication and better enforce consistency
05bc538
to
5f9d3e1
Compare
Type of change
Content
Fixes #2396 - Is behind the combined registration feature flag #5648
http://
do not have their prefix removed when editing the server url (as a way to remind the user they're insecure)Motivation and context
Introduces a new server selection screen where the user can enter a homeserver url, the aim is to centralise the flow avoiding branching paths (simplifying the overall experience)
Screenshots / GIFs
Note - some screenshots are missing the EMS hyperlink
Interactions
Theming
Devices
Tests
edit
in the register screenTested devices