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

Updated StatusBarBehavior to support defining which lifecycle event to use in applying the changes #1471

Merged
merged 7 commits into from
Feb 25, 2024

Conversation

Cybrosys
Copy link
Contributor

@Cybrosys Cybrosys commented Oct 24, 2023

Description of Change

  • Updated the StatusBarBehavior to use the Page's NavigatedTo event to set the desired color and style.
  • Sample was updated to showcase that back navigation now sets the desired color and style.
  • Unit test/fact was added to confirm expected exception on NavigatedTo.
    • Had to use reflection to invoke OnAttachedTo so the behavior would subscribe to the Page's NavigatedTo event.

Linked Issues

PR Checklist

Additional information

There was a mix of tabs and spaces in the StatusBarBehaviorPage.xaml file. Looking at the majority of the other xaml files they were using spaces instead of tabs, so I merely updated the xaml file to match the others and only have spaces.

@Cybrosys
Copy link
Contributor Author

@dotnet-policy-service agree

@Cybrosys
Copy link
Contributor Author

Is the toolkit build failing due to the unit tests failing? I saw that there were several failing Color-unit tests due to bad string comparison, for example:

Expected: CMYKA(100%,100%,0%,0%,1)
Actual:   CMYKA(100 %,100 %,0 %,0 %,1)

I don't know the policy in this case, if I should fix the unit tests or ignore them as they are out of scope for this PR?

pictos
pictos previously requested changes Oct 24, 2023
Copy link
Member

@pictos pictos left a comment

Choose a reason for hiding this comment

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

@Cybrosys Thanks for your contribution, but this doesn't feel right. At first glance, it matches the behavior that you expect, but it breaks the API for PlatformBehavior, by design isn't intended to run every time you navigate in an implicit way. So we need to think of another fix here, maybe adding a boolean for the user to choose when he wants to trigger the Color change during navigation.

Not sure if you followed all the discussion on #1194 or just referenced it as a fixed issue, but there're implementation details and guidelines, for example, do Apple and Google recommend an app to change the status bar color very often? As a framework we don't want to lead devs to the not recommended path, if you need it for your project you should implement it on your project.

About the Tabbar navigation on Shell triggering the PlatformBehavior, that's because an implementation detail on Shell that came from XF, where the Tabs are recreated every time you navigate to it, so that means the page will be created and behavior will be attached triggering the OnAttached method, in other words, there's not to do with the behavior itself and something that, AFAIK, the team wants to fix in future releases

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Oct 24, 2023

@pictos I understand. I merely created this PR as I saw that @bijington had requested that one be created back in June during the discussions on #1194. I was directed to that issue by @cat0363 from my own reported issue #1466.

The changes are based on what @cat0363 suggested.

From my point of view, if I have a page that is configured with a specific status bar color and style, I would expect that to be respected regardless of which navigational pattern was involved in the user getting there. Changing the colors and styles might deviate from Apple's or Google's recommendations, but in the end is that not a choice left up to the developer?

Adding a boolean or enumeration/flags to control when the color and style should change sounds good to me. Any suggestions?

@bijington
Copy link
Contributor

If it is a recommendation to not keep changing the status bar colour then I would argue that we already make it possible to go against this recommendation given the nature of the StatusBarBehavior - developers can set it at the page level rather than an application level.

The above is why I think it makes sense for the default behavior to set the status bar color to match whatever the current page is set to.

I am all for the idea of the change :)

@pictos
Copy link
Member

pictos commented Oct 24, 2023

About the recommendation of not changing the status bar a lot, I'm not sure since has been a long time since the last app that I released to the stores, but I remember that it should be something stable for the most part of the app. But we can't protect devs from themself all the time but is good to not provide an easy way for them to hurt themself.

@Cybrosys I hope my message didn't sound rude, English isn't my primary language, and I just want to have as much information as possible about the concerns around this change.

If the team thinks it's fine to add the flag, I would say it should be enough to have a boolean property for that. But we would need to document the Shell behavior since they will be generated every time devs should handle that by themself

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Oct 24, 2023

@pictos No, not at all. And the same for me and how I replied.

If we look at styling the status bar. I have never seen that as something separate from the current view. When I build native Android apps each Activity has a Theme, each theme can override how the status bar looks. The Theme will be applied regardless of how an Activity was presented or navigated back to,

Maui does not expose any styling options for the status bar, which is why the StatusBarBehavior was created; please correct me if I'm wrong. In one sense I would wish that it was supported in Maui, but since it is not I would expect the StatusBarBehavior to give me the expected behavior as if it was supported in Maui.

I can understand that StatusBarBehavior breaks the API for PlatformBehavior, but I do not fully understand the hesitancy of changing the status bar color and style as it is supported natively on Android per Theme and Activity. iOS is a slightly different matter as the status bar is transparent so the navigation bar color becomes the status bar color. So I can understand how overly manipulating the status bar on iOS might be frowned upon by Apple.

If the concern is the amount of calls to alter the status bar, perhaps the existing status bar color and style could be checked before making the call? When an instance of StatusBarBehavior is created, the current color and style is not retrieved from the current platform. On Android the current status bar color could be retrieved using getStatusBarColor method on Window.

So, if the StatusBarBehavior was a bit smarter and actually checked the current color and style, it would remove unnecessary calls to alter the status bar.

Or?

@pictos
Copy link
Member

pictos commented Oct 24, 2023

My concern is not about the number of times the method will be called, but how many times the statusBar color will change. If we can confirm that isn't something that Apple is against, we can implement it.

In any case, the best implementation is using the boolean flag, that way it's not a breaking change, and users can opt-in to that behavior.

@Cybrosys
Copy link
Contributor Author

Any suggestion to what the flag/property should be called and if it should be a bindable property?

  • SetColorAndStyleWhenNavigatedTo
  • SetColorAndStyleOnAppearing
  • ActivateWhenNavigatedTo
  • ActivateOnAppearing
  • ...

Or should it be an enum property Mode(?) where the enum would have two values?

  • Default/Once
  • Always/OnAppearing

@KSemenenko
Copy link
Member

I did something like this for XF, there is no way except update status bar color each time you perform navigation

@cat0363
Copy link
Contributor

cat0363 commented Oct 25, 2023

@Cybrosys , I remember that the discussion on Issue #1194 was inconclusive.
For this reason, I did not create a PR. This is because it is desirable to deal with things as they should be.
I agree with this suggestion.

Rather than making destructive changes, I think it's better to leave the timing of changes up to the users.
I think a compromise solution is to set up a flag as @pictos says. The code I showed in Issue #1194 was missing that.

Maybe we need to think about what it means to change the color of the status bar. I believe that by doing so,
we will be able to see what it really should be.

@cat0363
Copy link
Contributor

cat0363 commented Oct 25, 2023

@Cybrosys , I forgot to mention it, but it sounds like it's a device-specific issue.
Is this really the solution?

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Oct 25, 2023

I can think of a couple of normal scenarios where you might want to change the status bar color and style, one would be showing an onboarding view without a navigation bar or some view where you might want the contents to extend in under the status bar. Once the user navigates back from those views you'd want the status bar restored to its default state for the app.

Since the current implementation of the StatusBarBehavior does not restore the state or reapply it, I would have to implement this myself in the code-behind, which defeats the purpose of the StatusBarBehavior a bit. I might also be expecting too much of the behavior.

If my app was never going to change the status bar color I could update the Android style or use the static methods on the StatusBar once, which the StatusBarBehavior solves today. But if I want anything more than that we get into these scenarios where some expectations are not met, resulting in the developer thinking that there's a bug with the behavior.

@bijington
Copy link
Contributor

It sounds like something non breaking is a good way to go. Rather than a Boolean property to drive this what does everyone think to an enum that allows a developer to define which lifecycle event this behavior gets applied? e.g. OnNavigatedTo, OnAppearing, etc.

@brminnick
Copy link
Collaborator

Rather than a Boolean property to drive this what does everyone think to an enum that allows a developer to define which lifecycle event this behavior gets applied? e.g. OnNavigatedTo, OnAppearing, etc.

Enum makes sense, since it'll give us the opportunity to add additional lifecycle states in the future. Someday, maybe (hopefully!) the MAUI team will give us us OnLoaded or WillAppear.

@pictos
Copy link
Member

pictos commented Oct 30, 2023

@brminnick just to confirm and move forward with this implementation, are we going with enum instead of a boolean?

@brminnick
Copy link
Collaborator

Yup! I vote for an enum.

It's a bit overkill today, but it'll allow us the flexibility to add additional overloads/implementations in the future without breaking changes.

@pictos
Copy link
Member

pictos commented Oct 31, 2023

@Cybrosys do you have time to implement this feature? Let me know if you would like to discuss the API design or something before doing some code.

public enum NameThatYouChoose
{
    None,
    PageNavigation
}

For now, we should have two values, one for the default (actual) behavior and the new one. You can use other names since I'm terrible at naming things.

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Oct 31, 2023

@pictos yes I have the time to implement the feature.

Naming things is also hard for me, and doubly so for MAUI as I am not familiar with the current naming strategy of classes or enums. With that said, I would greatly appreciate suggestions with regards to naming. As I see it there are three areas:

  • The name of the property on StatusBarBehavior.
  • The name of the enum (will be easier to come up with once we decide on the property name).
  • The enum values (will be easier to come up with once we decide on the property name).

An initial idea regarding to the property name was Behavior, as it is the behavior of the behavior... but, since the name of the class already contains that word it does not feel correct:
StatusBarBehavior.Behavior = ...;

Other property name ideas are:

  • Mode
  • Reapply(On/When)
  • Trigger(On/When)

There is also the question of what to do with the unit test that I added (that is using reflection). Should I remove it or is there some way that I could trigger the OnAttachedTo to achieve the same result?

@bijington
Copy link
Contributor

bijington commented Oct 31, 2023

What if we use the following:

  • property name: ApplyOn
  • enum name: LifecycleEvent
  • value name: OnNavigatedTo

Then the code would read:

<toolkit:StatusBarBehavior Color="Orange" ApplyOn="LifecycleEvent.OnNavigatedTo"

Or

StatusBarBehavior behavior = new();

behavior.Color = Colors.Orange;
behavior.ApplyOn = LifecycleEvent.OnNavigatedTo;

Thoughts?

And I would default the value to be whatever lifecycle event we currently base it off.

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Oct 31, 2023

@bijington I like those names.

The enum LifecycleEvent sounds like something that could exist in the core MAUI project and that makes me wonder where we would put it in the CommunityToolkit that would make sense and hopefully not cause any naming conflicts, perhaps a different name more related to the StatusBarBehavior would be something to consider?

Another thought is also if OnAttachedTo and OnNavigatedTo are lifecycle events? If I think of lifecycle events I think of created, paused, resumed and destroyed; OnAttachedTo could be treated as related to the created-lifecycle event.

What about StatusBarEvent?

@bijington
Copy link
Contributor

You make a good point. I was hoping we could go for a general set of lifecycle events but I was only focussed on Page related ones.

I'll try and have a think today

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Nov 3, 2023

How about naming it based on the property name ApplyOn:

public enum StatusBarApplyOn
{
    OnAttachedTo,
    OnNavigatedTo
}

If you see that it might be used for other behaviors then maybe:

public enum BehaviorApplication
{
    OnAttachedTo,
    OnNavigatedTo
}

@bijington
Copy link
Contributor

How about naming it based on the property name ApplyOn:


public enum StatusBarApplyOn

{

    OnAttachedTo,

    OnNavigatedTo

}

If you see that it might be used for other behaviors then maybe:


public enum BehaviorApplication

{

    OnAttachedTo,

    OnNavigatedTo

}

I'm happy with the more specific name for now. I don't think the generic would work for all scenarios because OnNavigatedTo is a page event whereas OnAttachedTo is a behavior event. On that note should we include that detail in the name? So it would be something like;

public enum StatusBarApplyOn
{
    OnBehaviorAttachedTo, 
    OnPageNavigatedTo
}

@Cybrosys Cybrosys requested a review from pictos November 3, 2023 22:59
@pictos
Copy link
Member

pictos commented Nov 6, 2023

From my point of view, the OnAttachedTo will lead devs to a pitfall. Every behavior will be triggered when it's attached, but with your enum, I can see devs thinking they can trigger the behavior only on OnPageNavigatedTo and that will not be true... Also, we need to think in a scenario where devs can opt-in for more than one value on that enum. I would rename the OnAttachedTo (or any variation of that) to Default

@bijington
Copy link
Contributor

You make a good point re: OnAttachedTo. And also with the multiple values - we could mark the enum with Flags and handle it that way. Not sure how easy it is set in XAML that way.

I prefer naming the default value to represent the lifecycle event it relates to and we just make that the default value of the property. The name Default won't mean anything to a developer unless they look it up which feels wrong.

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Nov 6, 2023

It is possible to use flags in XAML:
ApplyOn="OnBehaviorAttachedTo,OnPageNavigatedTo"

...and we can have Default and OnBehaviorAttachedTo:

[Flags]
public enum StatusBarApplyOn
{
	/// <summary>
	/// Apply color and style when the behavior has been attached to the page.
	/// </summary>
	Default = OnBehaviorAttachedTo,

	/// <summary>
	/// Apply color and style when the behavior has been attached to the page.
	/// </summary>
	OnBehaviorAttachedTo = 0,

	/// <summary>
	/// Apply color and style when the page has been navigated to.
	/// </summary>
	OnPageNavigatedTo = 1,
}

@pictos
Copy link
Member

pictos commented Nov 6, 2023

Actually, the thing is, that the Default/AttachedTo will always happen, so I believe we can omit it.

@bijington
Copy link
Contributor

Do we want to include OnPageSizeChanged as a possible option also? Although I realise we only use this by default for iOS.

Although just to circle back to the original question we had discussed as part of this issue, if we don't need the default behavior can we just fix the behavior to apply the status bar behavior in OnNavigatedTo and not bother with the extra enum property?

@Cybrosys
Copy link
Contributor Author

Cybrosys commented Nov 7, 2023

Actually, the thing is, that the Default/AttachedTo will always happen, so I believe we can omit it.

I added the below check in OnAttachedTo, so unless I misunderstand the statement, it will only happen if you specify it:

if (ApplyOn == StatusBarApplyOn.OnBehaviorAttachedTo)
{
	StatusBar.SetColor(StatusBarColor);
	StatusBar.SetStyle(StatusBarStyle);
}

I do not understand how we can omit Default/AttachedTo from the enum as that would make it a single value enum. If we were to support that then it would have to be a nullable enum? If we're talking about a nullable single value enum then that almost sounds like what was suggested earlier of adding a boolean property:
ApplyOnNavigatedTo

@bijington
Copy link
Contributor

I can't speak for @pictos here but I think he means we don't see a need for using that event in general and therefore could remove the enum value and also the current code to apply the logic then.

If the above is the case then I would return to my earlier question around whether your original fix was the right one (I think it is) and we forget about the enum.

In the other hand I do quite like the idea of introducing an enum like this in future to make the behaviors more configurable.

@pictos
Copy link
Member

pictos commented Nov 9, 2023

Friends, just to give feedback, I'll take a look at this in more detail this weekend/next week. I'm very focused on my .net conf talk right now (:

But I've some ideas on how we can approach this, just need to do a PoC and share with you

Mikael Nensén and others added 6 commits November 10, 2023 09:00
@bijington
Copy link
Contributor

Where did we get with this? @pictos did you manage to play with that PoC?

@pictos
Copy link
Member

pictos commented Dec 4, 2023

@bijington not yet... There's a lot of stuff on my plate and not too much time. But I'll work on this in order to have something right after the holidays. I'll update you all asap

@ghost ghost added stale The author has not responded in over 30 days help wanted This proposal has been approved and is ready to be implemented labels Jan 4, 2024
@bijington
Copy link
Contributor

I am really sorry we have taken so long on this PR. I would like to try and get it over the line now, I think we have two options:

  1. Use the original idea of applying this behaviour always when the page is navigated to.
  2. Continue with the enum and apply it based on what the user has defined.

I think I like option 2 as it makes it more configurable although I would question when we really need the OnAttachedTo logic. Thoughts anyone?

@Cybrosys
Copy link
Contributor Author

@bijington the only argument would be to not break the current and/or expected behavior.

@pictos mentioned he had an idea of how to approach it, so maybe he has or will have some spare time to pursue those ideas?

@bijington
Copy link
Contributor

Ok that's fair. I think I'd be happy to move forward with the current approach. I know how busy Pedro is and I don't want to add to his list of things to do.

Copy link
Contributor

@bijington bijington left a comment

Choose a reason for hiding this comment

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

I'm happy to go ahead with this

@bijington bijington dismissed pictos’s stale review February 25, 2024 13:47

We have address this with the ApplyOn property

@bijington bijington enabled auto-merge (squash) February 25, 2024 13:48
@bijington bijington changed the title Updated StatusBarBehavior to use the NavigatedTo event Updated StatusBarBehavior to support defining which lifecycle event to use in applying the changes Feb 25, 2024
@bijington bijington merged commit 9d3e2fb into CommunityToolkit:main Feb 25, 2024
7 checks passed
@bijington
Copy link
Contributor

@Cybrosys thank you for making the effort to provide this improvement! It is greatly appreciated

@Cybrosys Cybrosys deleted the bug/1194-statusbarbehavior branch February 25, 2024 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted This proposal has been approved and is ready to be implemented stale The author has not responded in over 30 days
Projects
None yet
6 participants