33
44/* eslint-disable max-lines */
55
6+ import RNUtils from '@mattermost/rnutils' ;
67import merge from 'deepmerge' ;
7- import { Appearance , DeviceEventEmitter , StatusBar , Platform , Alert , type EmitterSubscription , Keyboard } from 'react-native' ;
8+ import { Appearance , DeviceEventEmitter , Platform , Alert , type EmitterSubscription , Keyboard , StatusBar } from 'react-native' ;
89import { type ComponentWillAppearEvent , type ImageResource , type LayoutOrientation , Navigation , type Options , OptionsModalPresentationStyle , type OptionsTopBarButton , type ScreenPoppedEvent , type EventSubscription } from 'react-native-navigation' ;
910import tinyColor from 'tinycolor2' ;
1011
@@ -36,6 +37,23 @@ let subscriptions: Array<EmitterSubscription | EventSubscription> | undefined;
3637export const allOrientations : LayoutOrientation [ ] = [ 'sensor' , 'sensorLandscape' , 'sensorPortrait' , 'landscape' , 'portrait' ] ;
3738export const portraitOrientation : LayoutOrientation [ ] = [ 'portrait' ] ;
3839
40+ const loginFlowScreens = new Set < AvailableScreens > ( [
41+ Screens . ONBOARDING ,
42+ Screens . SERVER ,
43+ Screens . LOGIN ,
44+ Screens . SSO ,
45+ Screens . MFA ,
46+ Screens . FORGOT_PASSWORD ,
47+ ] ) ;
48+
49+ function setNavigationBarColor ( screen : AvailableScreens , th ?: Theme ) {
50+ if ( Platform . OS === 'android' && Platform . Version >= 34 ) {
51+ const theme = th || getThemeFromState ( ) ;
52+ const color = loginFlowScreens . has ( screen ) ? theme . sidebarBg : theme . centerChannelBg ;
53+ RNUtils . setNavigationBarColor ( color , tinyColor ( color ) . isLight ( ) ) ;
54+ }
55+ }
56+
3957export function registerNavigationListeners ( ) {
4058 subscriptions ?. forEach ( ( v ) => v . remove ( ) ) ;
4159 subscriptions = [
@@ -88,14 +106,19 @@ function onCommandListener(name: string, params: any) {
88106 }
89107 }
90108
91- if ( NavigationStore . getVisibleScreen ( ) === Screens . HOME ) {
109+ const screen = NavigationStore . getVisibleScreen ( ) ;
110+ if ( screen === Screens . HOME ) {
92111 DeviceEventEmitter . emit ( Events . TAB_BAR_VISIBLE , true ) ;
93112 }
113+
114+ setNavigationBarColor ( screen ) ;
94115}
95116
96117function onPoppedListener ( { componentId} : ScreenPoppedEvent ) {
97118 // screen pop does not trigger registerCommandListener, but does trigger screenPoppedListener
98- NavigationStore . removeScreenFromStack ( componentId as AvailableScreens ) ;
119+ const screen = componentId as AvailableScreens ;
120+ NavigationStore . removeScreenFromStack ( screen ) ;
121+ setNavigationBarColor ( screen ) ;
99122}
100123
101124function onScreenWillAppear ( event : ComponentWillAppearEvent ) {
@@ -279,15 +302,40 @@ function isScreenRegistered(screen: AvailableScreens) {
279302 return true ;
280303}
281304
305+ function edgeToEdgeHack ( screen : AvailableScreens , theme : Theme ) {
306+ const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
307+
308+ if ( Platform . OS === 'android' ) {
309+ if ( Platform . Version >= 34 ) {
310+ const listener = Navigation . events ( ) . registerComponentDidAppearListener ( ( event ) => {
311+ if ( event . componentName === screen ) {
312+ setNavigationBarColor ( screen , theme ) ;
313+ listener . remove ( ) ;
314+ }
315+ } ) ;
316+ }
317+
318+ if ( Platform . Version >= 36 ) {
319+ return {
320+ drawBehind : true ,
321+ translucent : false ,
322+ isDark,
323+ } ;
324+ }
325+ }
326+
327+ StatusBar . setBarStyle ( isDark ? 'light-content' : 'dark-content' ) ;
328+ return { isDark} ;
329+ }
330+
282331export function openToS ( ) {
283332 NavigationStore . setToSOpen ( true ) ;
284333 return showOverlay ( Screens . TERMS_OF_SERVICE , { } , { overlay : { interceptTouchOutside : true } } ) ;
285334}
286335
287336export function resetToHome ( passProps : LaunchProps = { launchType : Launch . Normal } ) {
288337 const theme = getThemeFromState ( ) ;
289- const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
290- StatusBar . setBarStyle ( isDark ? 'light-content' : 'dark-content' ) ;
338+ const edgeToEdge = edgeToEdgeHack ( Screens . HOME , theme ) ;
291339
292340 if ( ! passProps . coldStart && ( passProps . launchType === Launch . AddServer || passProps . launchType === Launch . AddServerFromDeepLink ) ) {
293341 dismissModal ( { componentId : Screens . SERVER } ) ;
@@ -313,6 +361,7 @@ export function resetToHome(passProps: LaunchProps = {launchType: Launch.Normal}
313361 statusBar : {
314362 visible : true ,
315363 backgroundColor : theme . sidebarBg ,
364+ ...edgeToEdge ,
316365 } ,
317366 topBar : {
318367 visible : false ,
@@ -337,8 +386,7 @@ export function resetToHome(passProps: LaunchProps = {launchType: Launch.Normal}
337386
338387export function resetToSelectServer ( passProps : LaunchProps ) {
339388 const theme = getDefaultThemeByAppearance ( ) ;
340- const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
341- StatusBar . setBarStyle ( isDark ? 'light-content' : 'dark-content' ) ;
389+ const edgeToEdge = edgeToEdgeHack ( Screens . SERVER , theme ) ;
342390
343391 const children = [ {
344392 component : {
@@ -356,6 +404,7 @@ export function resetToSelectServer(passProps: LaunchProps) {
356404 statusBar : {
357405 visible : true ,
358406 backgroundColor : theme . sidebarBg ,
407+ ...edgeToEdge ,
359408 } ,
360409 topBar : {
361410 backButton : {
@@ -383,8 +432,7 @@ export function resetToSelectServer(passProps: LaunchProps) {
383432
384433export function resetToOnboarding ( passProps : LaunchProps ) {
385434 const theme = getDefaultThemeByAppearance ( ) ;
386- const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
387- StatusBar . setBarStyle ( isDark ? 'light-content' : 'dark-content' ) ;
435+ const edgeToEdge = edgeToEdgeHack ( Screens . ONBOARDING , theme ) ;
388436
389437 const children = [ {
390438 component : {
@@ -402,6 +450,7 @@ export function resetToOnboarding(passProps: LaunchProps) {
402450 statusBar : {
403451 visible : true ,
404452 backgroundColor : theme . sidebarBg ,
453+ ...edgeToEdge ,
405454 } ,
406455 topBar : {
407456 backButton : {
@@ -429,8 +478,7 @@ export function resetToOnboarding(passProps: LaunchProps) {
429478
430479export function resetToTeams ( ) {
431480 const theme = getThemeFromState ( ) ;
432- const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
433- StatusBar . setBarStyle ( isDark ? 'light-content' : 'dark-content' ) ;
481+ const edgeToEdge = edgeToEdgeHack ( Screens . SELECT_TEAM , theme ) ;
434482
435483 return Navigation . setRoot ( {
436484 root : {
@@ -446,6 +494,7 @@ export function resetToTeams() {
446494 statusBar : {
447495 visible : true ,
448496 backgroundColor : theme . sidebarBg ,
497+ ...edgeToEdge ,
449498 } ,
450499 topBar : {
451500 visible : false ,
@@ -472,7 +521,7 @@ export function goToScreen(name: AvailableScreens, title: string, passProps = {}
472521 }
473522
474523 const theme = getThemeFromState ( ) ;
475- const isDark = tinyColor ( theme . sidebarBg ) . isDark ( ) ;
524+ const edgeToEdge = edgeToEdgeHack ( name , theme ) ;
476525 const componentId = NavigationStore . getVisibleScreen ( ) ;
477526 if ( ! componentId ) {
478527 logError ( 'Trying to go to screen without any screen on the navigation store' ) ;
@@ -489,8 +538,10 @@ export function goToScreen(name: AvailableScreens, title: string, passProps = {}
489538 right : { enabled : false } ,
490539 } ,
491540 statusBar : {
492- style : isDark ? 'light' : 'dark' ,
541+ style : edgeToEdge . isDark ? 'light' : 'dark' ,
493542 backgroundColor : theme . sidebarBg ,
543+ drawBehind : edgeToEdge . drawBehind ?? false ,
544+ translucent : edgeToEdge . translucent ?? false ,
494545 } ,
495546 topBar : {
496547 animate : true ,
@@ -608,6 +659,7 @@ export function showModal(name: AvailableScreens, title: string, passProps = {},
608659 }
609660
610661 const theme = getThemeFromState ( ) ;
662+ const edgeToEdge = edgeToEdgeHack ( name , theme ) ;
611663 const modalPresentationStyle : OptionsModalPresentationStyle = Platform . OS === 'ios' ? OptionsModalPresentationStyle . pageSheet : OptionsModalPresentationStyle . none ;
612664 const defaultOptions : Options = {
613665 modalPresentationStyle,
@@ -617,6 +669,7 @@ export function showModal(name: AvailableScreens, title: string, passProps = {},
617669 statusBar : {
618670 visible : true ,
619671 backgroundColor : theme . sidebarBg ,
672+ ...edgeToEdge ,
620673 } ,
621674 topBar : {
622675 animate : true ,
0 commit comments