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

Fix statusBar color changes on modal pages #2413

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

pictos
Copy link
Member

@pictos pictos commented Dec 26, 2024

Description of Change

Created and register new service for handle the DialogFragment (Modal pages on Android).

Linked Issues

PR Checklist

  • Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • Has tests (if omitted, state reason in description)
  • Has samples (if omitted, state reason in description)
  • Rebased on top of main at time of PR
  • Changes adhere to coding standard
  • Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

@pictos pictos requested a review from a team December 26, 2024 02:27
@pictos pictos added the pending documentation This feature requires documentation label Dec 26, 2024
@brminnick brminnick requested a review from Copilot December 26, 2024 05:51
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs:73

  • The use of Debug.Assert might not be appropriate for production code. Consider using explicit error handling instead.
Debug.Assert(dialog is not null);

src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs:136

  • The method IsDialogFragment could be more explicit in its error handling. Consider adding more descriptive error messages.
static bool IsDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment)

@brminnick
Copy link
Collaborator

Thanks Pedro! Is there any reason to keep the previous implementation?

I saw that you implemented it under a feature flag to give devs the option to opt-out. Would it be cool if we just ripped out the old code? Or is there a known-issue where devs would want to fall back to the previous implementation?

@pictos
Copy link
Member Author

pictos commented Dec 26, 2024

@brminnick, we should keep both implementations, this PR adds support for Modal pages in Android maui apps.
In the short the reason is:

Our code for status bar looks for Activity.Window and change the color and style. DialogFragment has its own Window and that Window doesn't inherit anything from the Activity.Window so we need to handle that manually. Also, Android doesn't provide a way to know which DialogFragment is presented (imagine a scenario where you do 3 modal navigations, you will end up with 3 ModalPages and 3 DialogFragment, which one is on top and should change?)

Let me give the full context, so it will be clear why this is needed

For .NET 9 Shane and I worked to migrate all modal navigations to use DialogFragment to improve the general code and will be more aligned with android provides today, but it has some details that, at least for me, were unknown. So far, the way to intercept all the DialogFragments is using the Fragment.LifecycleCallback.

MCT wasn't the only package that has problem with this change, I saw that Mpopups and a bottomSheet lib also faced issues due to this change in .NET Maui, and I believe we can face other issues in the future, like for our Popup implementation.

So, we land on this PR, where I choose to create a proxy for the Fragment.LifecycleCallback, making easy for devs to extend it and centralize it, if it works really well, I'll try to promote it to Maui for .NET 10.

Now answering your questions:

Is there any reason to keep the previous implementation?

Yes, because the old code handles all scenarios but Modal navigation. Sadly, there's not out of the box way to know if there's a DialogFragment in the live-tree and which one (can be more than one) is being presented to change its StatusBarColor. Maybe Android improve it in the near future.

I saw that you implemented it under a feature flag to give devs the option to opt-out. Would it be cool if we just ripped out the old code? Or is there a known issue where devs would want to fall back to the previous implementation?

The idea of having it as a feature flag, is to give more power to devs. Right now, our implementation just handles StatusBarColor, but in their apps they want to work around/fix issues on other packages, so they can implement the interface and have full control over all Android Modal Navigation aspects.

Let me know if you've any question or consideration

@brminnick
Copy link
Collaborator

Thanks Pedro!! Yup - that makes perfect sense.

FYI - I tweaked some of the naming and moved all of the code to CommunityToolkit.Maui.Core because it doesn't use Microsoft.Maui.Controls and our existing StatusBar code (eg CommunityToolkit.Maui.Core.Platform.Statusbar) also lives in CommunityToolkit.Maui.Core.

Could you open a Docs PR documenting this new option and include an example for devs who are interested in expanding upon our implementation?

@brminnick brminnick requested a review from Copilot December 27, 2024 20:49

Choose a reason for hiding this comment

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

Copilot reviewed 6 out of 8 changed files in this pull request and generated no comments.

Files not reviewed (2)
  • src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs: Evaluated as low risk
  • src/CommunityToolkit.Maui.Core/Interfaces/IDialogFragmentService.android.cs: Evaluated as low risk
Comments suppressed due to low confidence (1)

src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs:70

  • [nitpick] The error message 'Dialog window cannot be null' could be more descriptive. Consider changing it to 'Dialog window cannot be null. Ensure that the dialog fragment is properly initialized and attached to a window.'
throw new InvalidOperationException("Dialog window cannot be null");
var window = dialog.Window;
if (dialogFragment.Dialog?.Window is not Window dialogWindow)
{
throw new InvalidOperationException("Dialog window cannot be null");
Copy link
Member Author

Choose a reason for hiding this comment

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

@brminnick we shouldn't throw here, since there's no way for devs to catch this exception. I used Debug.Assert because it's what the runtime/sdk uses to safe check for null . But here you're checking against a type which can be false and throw this exception.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Using Debug.Assert() is a bit of an anti-pattern because it only works when building in Debug configuration:

Debug.Assert method works only in debug builds.

This means that when users consume our library and the value of dialog.Window is null, the following code in Release builds is guaranteed to throw an unhelpful NullReferenceException:

Debug.Assert(dialog is not null);
Debug.Assert(dialog.Window is not null);

var window = dialog.Window;

In what scenario would this code be executed called and dialog.Window also be null? If this scenario exists, I agree that we should implement a solution.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think just returning is enough, the only scenario I can imagine that will happening is when the app is backgrounded or is moving into background.

@pictos
Copy link
Member Author

pictos commented Dec 27, 2024

@brminnick I added the implementation outside Core in order to make it not public, the Core project is meant to not have all members public so other toolkit implementors can access everything.

@brminnick
Copy link
Collaborator

the Core project is meant to not have all members public so other toolkit implementors can access everything

Is this documented? I don't recall setting this rule when I created CommunityToolkit.Maui.Core.

CONTRIBUTING.md only includes one rule, that new code belongs in CommunityToolkit.Maui.Core if it does not use Microsoft.Maui.Controls

I'll add the needs-discussion label to ask the the team in our January Standup. If you're able to join too, we'll bump this discussion to the top of the meeting!

@brminnick brminnick added the needs discussion Discuss it on the next Monthly standup label Dec 28, 2024
@pictos
Copy link
Member Author

pictos commented Dec 30, 2024

@brminnick , I would love to join, let me see here and I'll confirm with you and team on discord

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion Discuss it on the next Monthly standup pending documentation This feature requires documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Net 9 Android - StatusBar Color overriden on modal pages
3 participants