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

[VIO-103] feat: Implement new FlagshipUI API #1082

Merged
merged 19 commits into from
Jan 5, 2024

Conversation

Ldoppea
Copy link
Member

@Ldoppea Ldoppea commented Dec 18, 2023

The FlagshipUI is responsible to apply the correct theme to status and navigation bars base on the displayed screen or cozy-app

Previous setFlagshipUI API had numerous caveats:

  • It was difficult to keep track of which component was rendered on top
  • It was difficult to handle components unmounting as we had to know which theme to apply by guessing which view would be shown after unmounting the components
  • Previous point implied the creation of many hacks in order to have enough context to make a choice (i.e. hideSplashscreen, leaving LockScreen, handle cozy-home theme, keep track of home's konnector state, leaving OsReceiveScreen etc)

This new implementation is an attempt to simplify the API and to reduce the need of hacks and side effects

It is based on new out-of-react service (FlagshipUIService) that keeps track of all components that use the useFlagshipUI() hook

When a component registers, unregister or change its color, then the FlagshipUIService updates its reference array and recompute the new FlagshipUI to be applied

To ease the rendering order calculation, we hardcoded array of ZIndex that every component should use when calling the useFlagshipUI() hook

This can be done because the application UI is simple enough so we know which screen should be on top of others

This seems to be the only reliable way to predict screens order. We tried to guess components positions based on React tree using different
hooks (i.e. useMemo, useEffect, useLayoutEffect, useFocus), but none of them would allows us to keep track of screens order

We chose to put this mechanism out of React so changing the status and navigation bars would not produce any re-rendering

Related PR: cozy/cozy-libs#2360

What can be done next

Some improvements can be done for this API

First one is that this API wouldn't be usable on generic components (i.e. modals). To allow this, we can create a React Provider that would allow any component to retrieve its ZIndex from the corresponding Context. This provider would have to be put in a parent component like we do for the useFlagshipUI() hook

Second one it that current implementation only handle react-native side, but we keep the old architecture on cozy-apps. If this new API is proven to be stable and useful, then we can port it on cozy-intent so cozy-apps would be able to use it

Some parts of the code can still be cleaned. This is the case of setFlagshipUI.ts and themeManager.ts that still have some complex code. It is a bit early to clean them as it is unclear how much we need them with the new API. But we should keep in mind to recheck this part in a few weeks


TODO:

@Ldoppea Ldoppea force-pushed the feat/rework_set_flagship_ui branch 2 times, most recently from ca14804 to ecd9dcf Compare December 19, 2023 11:25
@Ldoppea Ldoppea changed the title Feat/rework set flagship UI feat: Implement new FlagshipUI API Dec 19, 2023
@Ldoppea Ldoppea force-pushed the feat/rework_set_flagship_ui branch 11 times, most recently from 81fd6c5 to 6b73311 Compare December 20, 2023 14:49
@Ldoppea Ldoppea changed the title feat: Implement new FlagshipUI API [VIO-129] feat: Implement new FlagshipUI API Dec 27, 2023
@Ldoppea Ldoppea changed the title [VIO-129] feat: Implement new FlagshipUI API [VIO-103] feat: Implement new FlagshipUI API Dec 27, 2023
* This array should be used everytime we call useFlagshipUI to apply a ZIndex to the component
* All ZIndexes are grouped here to ensure no screen overlap
*/
export const ScreenIndexes = {
Copy link
Contributor

Choose a reason for hiding this comment

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

For me all this is declarative config and shouldn't really be in the same place

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean this should be in another existing file? Or do you want it in a new file?

Copy link
Contributor

Choose a reason for hiding this comment

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

yes a new file as I don't see an existing one filling that role. but maybe it can be handled later as it's non critical

Copy link
Member Author

Choose a reason for hiding this comment

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

Done here : 7b2a6c9

@acezard acezard self-requested a review January 3, 2024 10:02
Copy link
Contributor

@acezard acezard left a comment

Choose a reason for hiding this comment

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

As we said I would have preferred to use react-navigation as a backbone, I'm not too sold on the complexity of FlagshipUIService, but anyway the current system is an issue so I'm ok to move forward

@Ldoppea Ldoppea marked this pull request as ready for review January 4, 2024 15:50
@Ldoppea Ldoppea requested a review from zatteo as a code owner January 4, 2024 15:50
The FlagshipUI is responsible to apply the correct theme to status and
navigation bars base on the displayed screen or cozy-app

Previous `setFlagshipUI` API had numerous caveats:
- It was difficult to keep track of which component was rendered on top
- It was difficult to handle components unmounting as we had to know
  which theme to apply by guessing which view would be shown after
  unmounting the components
- Previous point implied the creation of many hacks in order to have
  enough context to make a choice (i.e. hideSplashscreen, leaving
  LockScreen, handle cozy-home theme, keep track of home's konnector
  state, leaving OsReceiveScreen etc)

This new implementation is an attempt to simplify the API and to reduce
the need of hacks and side effects

It is based on new out-of-react service (`FlagshipUIService`) that
keeps track of all components that use the `useFlagshipUI()` hook

When a component registers, unregister or change its color, then the
`FlagshipUIService` updates its reference array and recompute the new
FlagshipUI to be applied

To ease the rendering order calculation, we hardcoded array of ZIndex
that every component should use when calling the `useFlagshipUI()` hook

This can be done because the application UI is simple enough so we know
which screen should be on top of others

This seems to be the only reliable way to predict screens order. We
tried to guess components positions based on React tree using different
hooks (i.e. useMemo, useEffect, useLayoutEffect, useFocus), but none of
them would allows us to keep track of screens order

We chose to put this mechanism out of React so changing the status and
navigation bars would not produce any re-rendering
The comment describes that iOS does not have any navigation bar
(BottomBar), which is true

But the code did try to apply a `bottomTheme` and would ignore any
`topTheme` set without a `bottomTheme` which is the reverse of what we
want
This is the first implementation of the new `seFlagshipUI()` hook

We need to call `useFlagshipUI()` with 3 parameters:
- The component's name -> used only for debuging purpose
- The component's ZIndex -> should be based on a ZIndex from
  `ScreenIndexes` object (this is done this way to ease keep tracking
  or all screens relating positions)
- The default FlagshipUI -> applied when the component is mount. This
  can be changed later in the component lifecycle using
  `setFlagshipColors` (not used here)

We do this for both the base view (ClouderyOffer) and the overlay that
is displayed on top of the WebView until it is fully loaded

Then we need to ensure that any component using this hook is not
mounted when not displayed because `useFlagshipUI()` is heavily based
on the components lifecycles

This is why we extracted the LoadingOverlay in its own conditionally
mounted component, so it's hook won't be called before needed

Also note that the initial values for FlagshipUI are declared outside
of the component in order to be stable and not trigger the hook on
every rerender
The HomeView component does not directly call the FlagshipUI API. This
is done by the cozy-app embedded in the CozyWebView

We need those calls to include the HomeView's `componentId` so the
`FlagshipUiService`` can keep track of them

The embedded cozy-app uses `cozy-intent` to call `localMethods` and we
don't  have direct control on the calls parameters

Also we don't want to update the cozy-apps as this would imply to
handle 2 API versions (as old cozy-apps can still exist on the user's
device)

Instead we intercept those calls in the `cozy-intent` native part and
we inject the `componentId` as a parameter of `tryEmit()`

Related PR: cozy/cozy-libs#2360
With the new FlagshipUI API, the HomeScreen doesn't need to keep track
of the home's UI anymore

The FlagshipUIService already keeps track of the application state and
receive UI update from the embedded cozy-home
The HomeView keeps track of the cozy-home theme

This is done by calling `setTheme` from the cozy-home webapp

This code seems to exist only to support the old FlagshipUI API, but
it's hard to see the implications of removing everything

So instead we want to plug the new API on the `setHomeTheme` hook

Then in the future we should investigate if all this file can be
simplified or removed

Related PR: cozy/cozy-libs#2360
This is the same principle as we did for the HomeView

The difference here is that we have the loading animation that should
be migrated too

With the new API, the Animation view is responsible to handle its own
FlagshipUI, so we don't need to keep track of its state inside of the
CozyAppScreen

This part will be removed in the following commit
CozyAppScreen needs to listen for FlagshipUI changes in order to know
which color to display on top and bottom bars (as the cozy-apps are not
displayed in an immersive way)

We want to use the new API event listener instead of the old one

Also not that the new event listener allows to filter on the
component's own events by comparing its `componentId`, so we ensure it
won't react to changes from the HomeView or any other components
As said in the previous commits: with the new API, the Animation view
is responsible to handle its own FlagshipUI, so we don't need to keep
track of its state inside of the CozyAppScreen
Ldoppea added 10 commits January 4, 2024 17:37
The SplashScreenService is not a React component, so we use
`flagshipUIEventHandler.emit` to handle the new FlagshipUI API

As it is not a React component, it doesn't have the same lifecycle and
it won't be unmounted

Instead of simulating registering/unregistering it from the
FlagshipUIService, we make it live "forever" in the FlagshipUIService
and we just "hide" it by setting an `undefined` UI when
`hideSplashScreen` is called

This would avoid having to handle initial SplashScreen that already
exists when the app is started
Now that OsReceive uses the new FlagshipUI API, then this hack is not
needed anymore

Related PR: #1043
This hack was created to set the correct FlagshipUI when leaving the
OsReceive screen

With the new API the HomeView's FlagshipUI is automatically restored
when OsReceiveScreen is unmounted

Related commit: b5b6dd1
The LockScreenBars seemed to be here to handle a non-immersive screen
and would suggest that Biometry screens are not immersive

But after a few tests it seems like every part of this screens and so
there is no need to top and bottom bars. Even more, this seems to fix
a bug as in a test device this would produce darken status and
navigation bars as those would overlap with the OS's Biometric prompt
backdrop
`cozy-intent` has been upgraded to `2.19.0` to retrieve `tryEmit`
improvements for new FlagshipUI API

Related PR: cozy/cozy-libs#2360
@Ldoppea Ldoppea force-pushed the feat/rework_set_flagship_ui branch from 4bb373b to 7b2a6c9 Compare January 4, 2024 16:37
@Ldoppea Ldoppea merged commit a2e1ab0 into master Jan 5, 2024
1 check passed
@Ldoppea Ldoppea deleted the feat/rework_set_flagship_ui branch January 5, 2024 10:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants