8000 Fix Part of #4938: Redesign Profile login and PIN Reset(1/12) by adhiamboperes · Pull Request #5825 · oppia/oppia-android · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix Part of #4938: Redesign Profile login and PIN Reset(1/12) #5825

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

Open
wants to merge 46 commits into
base: develop
Choose a base branch
from

Conversation

adhiamboperes
Copy link
Collaborator
@adhiamboperes adhiamboperes commented May 23, 2025

Explanation

Fixes Part of #4938
This PR introduces the following changes:

  • redesigns the profile login screen
  • ensures that profiles with pin will login via this new screen when the onboardingv2 feature flag is enabled
  • handles PIN reset when the user has forgotten their PIN
  • expands support for Jetpack Compose
  • adds tests for all these changes

Detailed Explanation of the Changes

Use of Jetpack Compose

We agreed that we can use Jetpack Compose for new screens being introduced, complete with its own activity and fragment. Although there is an existing login screen, the UI and flows are a little different from the new one, so I opted to create an new screen. The legacy screen has TODOs added to earmark it for removal.

The PR introduces Compose UIs for the screen, as well as the admin pin reset dialogs, since these are alert dialogs. The non-admin pin reset dialog reuses the existing dialogs, since they are standalone dialog fragments.

The Composable functions are private because they are not being tested directly, like you would in in a purely Compose project. The two admin PIN reset dialogs are however in their own files because it made sense to isolate them at that level, being that they are independent components.

Finally, I added the "androidx.compose.runtime:runtime-livedata": "1.1.1", dependency to be able to observe livedata objects from within composables.

Test Design

Because the screen contains both Compose and non-compose components, some of the tests use both Compose nodes and Espresso Matchers and ViewInteractions. I am pleased with how well the dialogs tested.

I used createEmptyComposeRule() as the test rule because I found out previously in #5387 that it is the most appropriate rule to use when there is need to launch a new activity for every test, which in our case is useful for testing with different feature flag states.

maven_install.json

Due to conflicts with develop, I had to regenerate this file since we can't directly edit it.

Misc

There are no dark mode screenshots since the design team is still working on those(oppia/design-team#192), and we will need to include them in a cleanup PR.

Essential Checklist

  • The PR title and explanation each start with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".)
  • Any changes to scripts/assets files have their rationale included in the PR explanation.
  • The PR follows the style guide.
  • The PR does not contain any unnecessary code changes from Android Studio (reference).
  • The PR is made from a branch that's not called "develop" and is up-to-date with "develop".
  • The PR is assigned to the appropriate reviewers (reference).

For UI-specific PRs only

Admin Non-Admin
Screenshot Screenshot_2025-05-23-21-59-15-096_org oppia android Screenshot_2025-05-23-21-59-20-605_org oppia android
Happy Path https://github.com/user-attachments/assets/e5201d13-cd8f-476f-b3f8-35a830aa0074 https://github.com/user-attachments/assets/53ee4e37-f889-4bd6-9b08-0d3ef60b6c44
Wrong PIN https://github.com/user-attachments/assets/91613b98-4b67-4f89-87dd-e32a306e96e8 https://github.com/user-attachments/assets/4d705cd9-4821-443b-9ce9-47d1a8a61989
Reset PIN https://github.com/user-attachments/assets/eee181f0-4aa7-4b2d-88fa-8bd42fc39a69 https://github.com/user-attachments/assets/e061c064-8382-4afe-99ba-84e4101cf0ed

@adhiamboperes adhiamboperes self-assigned this May 23, 2025
@adhiamboperes adhiamboperes changed the title Fix Part Of #4938: Fix Part of #4938: May 23, 2025
@adhiamboperes adhiamboperes changed the title Fix Part of #4938: Fix Part of #4938: 1/10 May 23, 2025
@adhiamboperes adhiamboperes changed the title Fix Part of #4938: 1/12 Fix Part of #4938: Redesign Profile login and PIN reset(1/12) Jul 1, 2025
@adhiamboperes adhiamboperes changed the title Fix Part of #4938: Redesign Profile login and PIN reset(1/12) Fix Part of #4938: Redesign Profile login and PIN Reset(1/12) Jul 1, 2025
# Conflicts:
#	app/src/main/res/values/color_palette.xml
#	third_party/maven_install.json
@adhiamboperes
Copy link
Collaborator Author

Thanks @deonwaju! I have addressed your comments. Please resolve if you have the permissions, otherwise let me know and I will resolve them myself.

Copy link
Member
@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Thanks @adhiamboperes! I haven't looked at the bulky bits of the PR yet (the new Composables, the new fragment presenter, and the fragment test), but did look at everything else and left some comments. Besides those, could you also fix CI & look at the replies below?

Other Design Choices

Dialog State Management:

  • When opening two dialogs in sequence in compose, I chose to display the second dialog without dismissing the first one. This causes the second dialog to appear on top of the first. When the second dialog is dismissed, the first remains open and must be manually closed.
  • On the flip side, if the first dialog is configured to close when the positive button is clicked(to open the next dialog), it dismisses correctly, but then the second dialog doesn’t appear at all.

Neither approach is ideal, but keeping the first dialog open while showing the second is the more acceptable of the two.

This shouldn't be necessary, I think. In the non-Compose world you can check if the fragment has already been added to the activity's fragment manager (via its tag) and replace it with a new one (or not open a new one at all) to de-duplicate the dialogs. Shouldn't there be a way to do the same via Compose?

Misc

There are no dark mode screenshots since the design team is still working on those(oppia/design-team#192), and we will need to include them in a cleanup PR.

Is there a tracking issue for this that includes the details for updating this & any other affected flows in particular?

Essential Checklist

...

Can you please fill this out?

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
Copy link
Member

Choose a reason for hiding this comment

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

Are we ever adding anything to this layout dynamically? If not, can we just make the FrameLayout the root, instead? It helps reducing the layout nesting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not really. I have flattened the layout.

android:background="@color/component_color_shared_screen_primary_background_color"
android:gravity="center">

<androidx.compose.ui.platform.ComposeView
Copy link
Member

Choose a reason for hiding this comment

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

Similar to my comment for the profile_login_activity layout, can the ComposeView possibly be the top-level one here? I'm assuming the gravity doesn't matter since the ComposeView has a match_parent width/height, and we should be able to set the background of the ComposeView (I'm assuming).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed the top-level view to be the ComposeView

Copy link
Member

Choose a reason for hiding this comment

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

For this & the other class: we need to start thinking about naming standards for these files since they're a new type of file altogether that we haven't really had before.

https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#naming-unit-composable-functions-as-entities explains this, but it's honestly quite a bit more complicated than I was expecting. I suspect we'll need to think about this and have a lot more examples before we can settle on naming conventions that make sense to us.

I don't think there's an action item here, but I did want to get your thoughts on the matter, if you have any.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Generally, I believe that naming composable entities should follow the same conventions as the existing files in the project. We typically have FeatureNameActivity/Fragment/Dialog, and for custom views, we have CustomView. Composable entities will likely fall into 3 categories:

  1. the composable functions that represent small view units, and will be written inside a presenter(or a larger Composable class, e.g.
  2. composables that represent screens, standalone componets such as dialogs
  3. and finally, custom views, e.g e.g. AllClassroomsHeaderText.kt

The list is not exhaustive, but will form a bulk of Composables that we write.

Combining our present naming convention with the Noun imperative from the docs, it shouldn't be too complex.

  • ComingSoonTopicList.kt would be renamed to ComingSoonTopicListView.kt
  • This dialog can be renamed from ConfirmDataResetDialog.kt to DataResetConfirmationDialog,
  • and the smaller unit composables can be named explicitly after the view they represent, e.g NameErrorText()


/** Handles showing the [ResetPinDialogFragment]. */
fun handleRouteToResetPinDialog(profileId: ProfileId, profileName: String) {

Copy link
Member

Choose a reason for hiding this comment

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

Nit: please remove empty line for convention.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

as DialogFragment
resetPinDialog.dismiss()

fragmentManager.executePendingTransactions()
Copy link
Member

Choose a reason for hiding this comment

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

For here & above: why is this needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since there is a series of dialogs leading to one another, forcing all pending transactions to complete immediately helps prevent stacking and errors.

Copy link
oppiabot bot commented Jul 1, 2025

Unassigning @BenHenning since the review is done.

Copy link
oppiabot bot commented Jul 1, 2025

Hi @adhiamboperes, it looks like some changes were requested on this pull request by @BenHenning. PTAL. Thanks!

@adhiamboperes
Copy link
Collaborator Author

Other Design Choices

Dialog State Management:

This shouldn't be necessary, I think. In the non-Compose world you can check if the fragment has already been added to the activity's fragment manager (via its tag) and replace it with a new one (or not open a new one at all) to de-duplicate the dialogs. Shouldn't there be a way to do the same via Compose?

Compose Navigation replaces Fragment transactions and tags entirely, but has state. For hiding/showing Composables, we use remember { mutableStateOf(false) }, and set the value to true when we want the Composable to be added to the tree, and false when we want it to be removed. I did some refactor, and found a way to manage these dialogs correctly.

Misc

There are no dark mode screenshots since the design team is still working on those(oppia/design-team#192), and we will need to include them in a cleanup PR.

Is there a tracking issue for this that includes the details for updating this & any other affected flows in particular?

#4938 should track all the work related to this project.

Essential Checklist

...

Can you please fill this out?

Done

Copy link
github-actions bot commented Jul 3, 2025

Coverage Report

Results

Number of files assessed: 19
Overall Coverage: 77.35%
Coverage Analysis: PASS

Passing coverage

Files with passing code coverage
File Coverage Lines Hit Status Min Required
EventBundleCreator.ktutility/src/main/java/org/oppia/android/util/logging/EventBundleCreator.kt
77.35% 338 / 437 70%

Exempted coverage

Files exempted from coverage
File Exemption Reason
FragmentComponentImpl.ktapp/src/main/java/org/oppia/android/app/fragment/FragmentComponentImpl.kt
This file is exempted from having a test file; skipping coverage check.
ClassroomListFragmentPresenter.ktapp/src/main/java/org/oppia/android/app/classroom/ClassroomListFragmentPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileChooserFragmentPresenter.ktapp/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileLoginActivityPresenter.ktapp/src/main/java/org/oppia/android/app/profile/ProfileLoginActivityPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileChooserActivityPresenter.ktapp/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileLoginFragmentPresenter.ktapp/src/main/java/org/oppia/android/app/profile/ProfileLoginFragmentPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileRouteDialogInterface.ktapp/src/main/java/org/oppia/android/app/profile/ProfileRouteDialogInterface.kt
This file is exempted from having a test file; skipping coverage check.
AdminSettingsDialogFragment.ktapp/src/main/java/org/oppia/android/app/profile/AdminSettingsDialogFragment.kt
This file is exempted from having a test file; skipping coverage check.
PinPasswordActivityPresenter.ktapp/src/main/java/org/oppia/android/app/profile/PinPasswordActivityPresenter.kt
This file is exempted from having a test file; skipping coverage check.
PinPasswordViewModel.ktapp/src/main/java/org/oppia/android/app/profile/PinPasswordViewModel.kt
This file is exempted from having a test file; skipping coverage check.
DataResetConfirmationDialog.ktapp/src/main/java/org/oppia/android/app/profile/DataResetConfirmationDialog.kt
This file is exempted from having a test file; skipping coverage check.
PinPasswordActivity.ktapp/src/main/java/org/oppia/android/app/profile/PinPasswordActivity.kt
This file is incompatible with code coverage tooling; skipping coverage check.
ProfileChooserFragment.ktapp/src/main/java/org/oppia/android/app/profile/ProfileChooserFragment.kt
This file is incompatible with code coverage tooling; skipping coverage check.
AdminPinRecoveryDialog.ktapp/src/main/java/org/oppia/android/app/profile/AdminPinRecoveryDialog.kt
This file is exempted from having a test file; skipping coverage check.
ProfileLoginActivity.ktapp/src/main/java/org/oppia/android/app/profile/ProfileLoginActivity.kt
This file is incompatible with code coverage tooling; skipping coverage check.
AdminSettingsDialogFragmentPresenter.ktapp/src/main/java/org/oppia/android/app/profile/AdminSettingsDialogFragmentPresenter.kt
This file is exempted from having a test file; skipping coverage check.
ProfileLoginFragment.ktapp/src/main/java/org/oppia/android/app/profile/ProfileLoginFragment.kt
This file is incompatible with code coverage tooling; skipping coverage check.
ActivityComponentImpl.ktapp/src/main/java/org/oppia/android/app/activity/ActivityComponentImpl.kt
This file is exempted from having a test file; skipping coverage check.

Refer test_file_exemptions.textproto for the comprehensive list of file exemptions and their required coverage percentages.

To learn more, visit the Oppia Android Code Coverage wiki page

Copy link
oppiabot bot commented Jul 10, 2025

Hi @adhiamboperes, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 3 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you!

@oppiabot oppiabot bot added the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Jul 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Corresponds to items that haven't seen a recent update and may be automatically closed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0