-
Notifications
You must be signed in to change notification settings - Fork 745
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 - Choose a display name #5211
Changes from 11 commits
0759d52
c11fa24
1fd4011
97862ff
bb98e2e
7d6b9af
83f2f72
af5e932
b2e4020
ccd3626
4a01193
8dec4fd
16424f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright (c) 2021 New Vector Ltd | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package im.vector.app.features.onboarding.ftueauth | ||
|
||
import android.os.Bundle | ||
import android.text.Editable | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import com.google.android.material.textfield.TextInputLayout | ||
import im.vector.app.core.platform.SimpleTextWatcher | ||
import im.vector.app.databinding.FragmentFtueDisplayNameBinding | ||
import im.vector.app.features.onboarding.OnboardingAction | ||
import im.vector.app.features.onboarding.OnboardingViewEvents | ||
import javax.inject.Inject | ||
|
||
class FtueAuthChooseDisplayNameFragment @Inject constructor() : AbstractFtueAuthFragment<FragmentFtueDisplayNameBinding>() { | ||
|
||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueDisplayNameBinding { | ||
return FragmentFtueDisplayNameBinding.inflate(inflater, container, false) | ||
} | ||
|
||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
super.onViewCreated(view, savedInstanceState) | ||
setupViews() | ||
} | ||
|
||
private fun setupViews() { | ||
views.displayNameSubmit.isEnabled = views.displayNameInput.hasContentEmpty() | ||
views.displayNameInput.editText?.addTextChangedListener(object : SimpleTextWatcher() { | ||
override fun afterTextChanged(s: Editable) { | ||
val newContent = s.toString() | ||
views.displayNameSubmit.isEnabled = newContent.isNotEmpty() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be nice to reset the error here. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. I mixed between display name and userId, my bad. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still it could be nice to display the error in the TextInputLayout. You can do it easily by overidding For network error (in airplane mode for instance), it's maybe better if the error is displayed in a dialog (so just call Long display name can be rejected by the homeserver, and other rules may apply, that's why it could be nice to inline the error in such case IMO, instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for the screenshot and explanation! I've checked in with product/design, we'd like to do a pass of all the onboarding errors and their copy I'll create another subtask in #5200 to revisit the error handling here in case there's other types of errors we'd like to capture within the text field instead of dialog and I'll need to track down all the possible error types (and their copy) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack |
||
} | ||
}) | ||
|
||
views.displayNameSubmit.debouncedClicks { | ||
val newDisplayName = views.displayNameInput.editText?.text.toString() | ||
viewModel.handle(OnboardingAction.UpdateDisplayName(newDisplayName)) | ||
} | ||
|
||
views.displayNameSkip.debouncedClicks { viewModel.handle(OnboardingAction.UpdateDisplayNameSkipped) } | ||
} | ||
|
||
override fun resetViewModel() { | ||
// Nothing to do | ||
} | ||
|
||
override fun onBackPressed(toolbarButton: Boolean): Boolean { | ||
viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnTakeMeHome)) | ||
return false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return true? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah 🤦 thought I'd included updates from the previous PR comments, will fix! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated 8dec4fd |
||
} | ||
} | ||
|
||
private fun TextInputLayout.hasContentEmpty() = !editText?.text.isNullOrEmpty() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -223,8 +223,10 @@ class FtueAuthVariant( | |
} | ||
OnboardingViewEvents.OnAccountCreated -> onAccountCreated() | ||
OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn() | ||
OnboardingViewEvents.OnPersonalizeProfile -> TODO() | ||
OnboardingViewEvents.OnPersonalizeProfile -> onPersonalizeProfile() | ||
OnboardingViewEvents.OnTakeMeHome -> navigateToHome(createdAccount = true) | ||
OnboardingViewEvents.OnDisplayNameUpdated -> onDisplayNameUpdated() | ||
OnboardingViewEvents.OnDisplayNameSkipped -> onDisplayNameUpdated() | ||
}.exhaustive | ||
} | ||
|
||
|
@@ -389,4 +391,16 @@ class FtueAuthVariant( | |
activity.startActivity(intent) | ||
activity.finish() | ||
} | ||
|
||
private fun onPersonalizeProfile() { | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthChooseDisplayNameFragment::class.java, | ||
option = commonOption | ||
) | ||
} | ||
|
||
private fun onDisplayNameUpdated() { | ||
// TODO go to the real profile picture fragment | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this will be the next PR |
||
navigateToHome(createdAccount = true) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:app="http://schemas.android.com/apk/res-auto" | ||
style="@style/LoginFormScrollView" | ||
android:layout_height="match_parent" | ||
android:background="?android:colorBackground" | ||
android:fillViewport="true" | ||
android:paddingTop="0dp" | ||
android:paddingBottom="0dp"> | ||
|
||
<androidx.constraintlayout.widget.ConstraintLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content"> | ||
|
||
<androidx.constraintlayout.widget.Guideline | ||
android:id="@+id/displayNameGutterStart" | ||
android:layout_width="wrap_content" | ||
android:layout_height="match_parent" | ||
android:orientation="vertical" | ||
app:layout_constraintGuide_percent="@dimen/ftue_auth_gutter_start_percent" /> | ||
|
||
<androidx.constraintlayout.widget.Guideline | ||
android:id="@+id/displayNameGutterEnd" | ||
android:layout_width="wrap_content" | ||
android:layout_height="match_parent" | ||
android:orientation="vertical" | ||
app:layout_constraintGuide_percent="@dimen/ftue_auth_gutter_end_percent" /> | ||
|
||
<Space | ||
android:id="@+id/headerSpacing" | ||
android:layout_width="match_parent" | ||
android:layout_height="52dp" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameHeaderIcon" | ||
app:layout_constraintTop_toTopOf="parent" /> | ||
|
||
<ImageView | ||
android:id="@+id/displayNameHeaderIcon" | ||
android:layout_width="wrap_content" | ||
android:layout_height="0dp" | ||
android:adjustViewBounds="true" | ||
android:contentDescription="@null" | ||
android:src="@drawable/ic_user_round" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameHeaderTitle" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintHeight_percent="0.15" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toTopOf="parent" | ||
app:tint="?colorSecondary" /> | ||
|
||
<TextView | ||
android:id="@+id/displayNameHeaderTitle" | ||
style="@style/Widget.Vector.TextView.Title.Medium" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:layout_marginTop="16dp" | ||
android:gravity="center" | ||
android:text="@string/ftue_display_name_title" | ||
android:textColor="?vctr_content_primary" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameHeaderSubtitle" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameHeaderIcon" /> | ||
|
||
<TextView | ||
android:id="@+id/displayNameHeaderSubtitle" | ||
style="@style/Widget.Vector.TextView.Subtitle" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:layout_marginTop="8dp" | ||
android:gravity="center" | ||
android:text="@string/ftue_display_name_subtitle" | ||
android:textColor="?vctr_content_secondary" | ||
app:layout_constraintBottom_toTopOf="@id/titleContentSpacing" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameHeaderTitle" /> | ||
|
||
<Space | ||
android:id="@+id/titleContentSpacing" | ||
android:layout_width="match_parent" | ||
android:layout_height="0dp" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameInput" | ||
app:layout_constraintHeight_percent="0.03" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameHeaderSubtitle" /> | ||
|
||
<com.google.android.material.textfield.TextInputLayout | ||
android:id="@+id/displayNameInput" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:hint="@string/ftue_display_name_entry_title" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/titleContentSpacing"> | ||
|
||
<com.google.android.material.textfield.TextInputEditText | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:maxLines="1" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be nice to set an inputType and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great idea, will do 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added 6fb5d05 |
||
|
||
</com.google.android.material.textfield.TextInputLayout> | ||
|
||
<TextView | ||
android:id="@+id/displayNameEntryFooter" | ||
style="@style/Widget.Vector.TextView.Micro" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:layout_marginTop="4dp" | ||
android:text="@string/ftue_display_name_entry_footer" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameInput" /> | ||
|
||
<Space | ||
android:id="@+id/actionsSpacing" | ||
android:layout_width="match_parent" | ||
android:layout_height="0dp" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameSubmit" | ||
app:layout_constraintHeight_percent="0.03" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameEntryFooter" | ||
app:layout_constraintVertical_bias="0" | ||
app:layout_constraintVertical_chainStyle="packed" /> | ||
|
||
<Button | ||
android:id="@+id/displayNameSubmit" | ||
style="@style/Widget.Vector.Button.Login" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:text="@string/ftue_personalize_submit" | ||
android:textAllCaps="true" | ||
app:layout_constraintBottom_toTopOf="@id/displayNameSkip" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/actionsSpacing" /> | ||
|
||
<Button | ||
android:id="@+id/displayNameSkip" | ||
style="@style/Widget.Vector.Button.Text.Login" | ||
android:layout_width="0dp" | ||
android:layout_height="wrap_content" | ||
android:text="@string/ftue_personalize_skip_this_step" | ||
android:textAllCaps="true" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintEnd_toEndOf="@id/displayNameGutterEnd" | ||
app:layout_constraintStart_toStartOf="@id/displayNameGutterStart" | ||
app:layout_constraintTop_toBottomOf="@id/displayNameSubmit" /> | ||
|
||
</androidx.constraintlayout.widget.ConstraintLayout> | ||
|
||
</androidx.core.widget.NestedScrollView> | ||
|
||
|
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 uses the same async state mechanism as the other parts of the onboarding state (sign in/register), the login V2 converts this to a simple
isLoading: boolean
but I've avoided doing the same change here to keep the diff smaller