diff --git a/react/ActionMenu/index.jsx b/react/ActionMenu/index.jsx
index f77df3bd04..e414bc6750 100644
--- a/react/ActionMenu/index.jsx
+++ b/react/ActionMenu/index.jsx
@@ -11,6 +11,8 @@ import Radio from '../Radio'
import { spacingProp } from '../Stack'
import { usePopper } from 'react-popper'
import createDepreciationLogger from '../helpers/createDepreciationLogger'
+import { useSetFlagshipUI } from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
+import { useTheme } from '@material-ui/core'
const ActionMenuWrapper = ({
inline,
@@ -101,6 +103,26 @@ const ActionMenu = ({
anchorElRef,
containerElRef
}) => {
+ const theme = useTheme()
+ const sidebar = document.querySelector('[class*="sidebar"]')
+
+ useSetFlagshipUI(
+ {
+ bottomBackground: theme.palette.background.paper,
+ bottomTheme: 'dark',
+ topOverlay: getCssVariableValue('overlay'),
+ topBackground: theme.palette.background.paper,
+ topTheme: 'light'
+ },
+ {
+ bottomBackground: theme.palette.background[sidebar ? 'default' : 'paper'],
+ bottomTheme: 'dark',
+ topOverlay: 'transparent',
+ topBackground: theme.palette.background.paper,
+ topTheme: 'dark'
+ }
+ )
+
if (placement)
logDepecratedPlacement(
' is deprecated, use instead'
diff --git a/react/BarContextProvider/index.spec.jsx b/react/BarContextProvider/index.spec.jsx
index 86c7dd230b..fe5a7445d2 100644
--- a/react/BarContextProvider/index.spec.jsx
+++ b/react/BarContextProvider/index.spec.jsx
@@ -172,27 +172,4 @@ describe('BarContextProvider', () => {
expect(queryByText(mockVoidWebviewService)).toBeInTheDocument()
})
-
- it('should not try to provide a cozy-intent context if one is provided', () => {
- // Set Web context
- window.cozy.isFlagshipApp = false
-
- const client = createMockClient({})
- const mockStore = configureStore()
- const store = mockStore(x => x)
-
- const { queryByText } = render(
-
-
- locales}>
-
-
-
-
-
-
- )
-
- expect(queryByText(mockWebviewService.foo)).not.toBeInTheDocument()
- })
})
diff --git a/react/Dialog/index.jsx b/react/Dialog/index.jsx
index f6f6adbfbb..8411a8cdef 100644
--- a/react/Dialog/index.jsx
+++ b/react/Dialog/index.jsx
@@ -4,6 +4,8 @@ import { RemoveScroll } from 'react-remove-scroll'
import useBreakpoints from '../hooks/useBreakpoints'
import { useCozyTheme } from '../CozyTheme'
import themesStyles from '../../stylus/settings/palette.styl'
+import { useSetFlagshipUI } from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
+import { useTheme } from '@material-ui/core'
const Dialog = props => {
const { isMobile, isTablet } = useBreakpoints()
@@ -21,12 +23,47 @@ const Dialog = props => {
(props.open || props.opened) && shouldBlockScroll
? RemoveScroll
: React.Fragment
+ const cozyTheme = useCozyTheme()
+ const theme = useTheme()
+ const cozBar = document.querySelector('.coz-bar-wrapper')
+ const sidebar = document.getElementById('sidebar')
- const theme = useCozyTheme()
+ useSetFlagshipUI(
+ props.fullScreen
+ ? {
+ bottomBackground: theme.palette.background.paper,
+ bottomTheme: 'dark',
+ topBackground: theme.palette.background.paper,
+ topTheme: 'dark'
+ }
+ : {
+ bottomBackground: theme.palette.background.default,
+ bottomTheme: 'light',
+ bottomOverlay: 'rgba(0, 0, 0, 0.5)',
+ topOverlay: 'rgba(0, 0, 0, 0.5)',
+ topBackground: theme.palette.background.paper,
+ topTheme: 'light'
+ },
+ {
+ bottomBackground: theme.palette.background[sidebar ? 'default' : 'paper'],
+ bottomTheme: 'dark',
+ bottomOverlay: 'transparent',
+ topOverlay: 'transparent',
+ topBackground:
+ cozBar && getComputedStyle(cozBar).getPropertyValue('background-color'),
+ topTheme:
+ cozBar && cozBar.classList.contains('coz-theme-primary')
+ ? 'light'
+ : 'dark'
+ }
+ )
return (
-
+
)
}
diff --git a/react/SelectionBar/index.jsx b/react/SelectionBar/index.jsx
index 3230d0d28a..2c7c5cac4b 100644
--- a/react/SelectionBar/index.jsx
+++ b/react/SelectionBar/index.jsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
@@ -11,6 +11,8 @@ import useBreakpoints from '../hooks/useBreakpoints'
import styles from './styles.styl'
import CrossIcon from 'cozy-ui/transpiled/react/Icons/Cross'
+import { useWebviewIntent } from 'cozy-intent'
+import { useTheme } from '@material-ui/core'
/*
@@ -39,6 +41,37 @@ const SelectionBar = ({ actions, selected, hideSelectionBar }) => {
action.displayCondition === undefined || action.displayCondition(selected)
)
})
+ const webviewIntent = useWebviewIntent()
+ const theme = useTheme()
+
+ // This component is always rendered but hidden with CSS if there is no selection
+ // That is why we do not use useSetFlagship API here because that hook can not accept changing values
+ useEffect(() => {
+ if (!webviewIntent || !theme) return
+
+ selectedCount === 0 &&
+ webviewIntent &&
+ webviewIntent.call('setFlagshipUI', {
+ bottomBackground: theme.palette.background.default,
+ bottomTheme: 'dark'
+ })
+
+ selectedCount > 0 &&
+ webviewIntent &&
+ webviewIntent.call('setFlagshipUI', {
+ bottomBackground: theme.palette.grey[700],
+ bottomTheme: 'light'
+ })
+
+ return () =>
+ webviewIntent &&
+ theme &&
+ webviewIntent.call('setFlagshipUI', {
+ bottomBackground: theme.palette.background.default,
+ bottomTheme: 'dark'
+ })
+ }, [selectedCount, webviewIntent])
+
return (
(
-
-)
+const Sidebar = ({ children, className, ...restProps }) => {
+ const theme = useTheme()
+
+ useSetFlagshipUI(
+ {
+ bottomBackground: theme.palette.background.default,
+ bottomTheme: 'dark'
+ },
+ {
+ bottomBackground: theme.palette.background.paper
+ }
+ )
+
+ return (
+
+ )
+}
Sidebar.propTypes = {
children: PropTypes.node,
diff --git a/react/Viewer/index.jsx b/react/Viewer/index.jsx
index e35fbdcf91..894c350986 100644
--- a/react/Viewer/index.jsx
+++ b/react/Viewer/index.jsx
@@ -12,6 +12,8 @@ import ViewerByFile from './ViewerByFile'
import { isValidForPanel } from './helpers'
import PanelContent from './Panel/PanelContent'
import FooterContent from './Footer/FooterContent'
+import { useSetFlagshipUI } from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
+import { useTheme } from '@material-ui/core'
const KEY_CODE_LEFT = 37
const KEY_CODE_RIGHT = 39
@@ -149,6 +151,19 @@ const ViewerInformationsWrapper = ({
validForPanel,
toolbarRef
}) => {
+ const theme = useTheme()
+ const sidebar = document.querySelector('[class*="sidebar"]')
+
+ useSetFlagshipUI(
+ {
+ bottomBackground: theme.palette.background.paper,
+ bottomTheme: 'dark'
+ },
+ {
+ bottomBackground: theme.palette.background[sidebar ? 'default' : 'paper']
+ }
+ )
+
return (
<>
{!disableFooter && (
diff --git a/react/hooks/useSetFlagshipUi/useSetFlagshipUI.js b/react/hooks/useSetFlagshipUi/useSetFlagshipUI.js
new file mode 100644
index 0000000000..ab0b22c516
--- /dev/null
+++ b/react/hooks/useSetFlagshipUi/useSetFlagshipUI.js
@@ -0,0 +1,25 @@
+import { useEffect } from 'react'
+import { useWebviewIntent } from 'cozy-intent'
+import pickBy from 'lodash/pickBy'
+import identity from 'lodash/identity'
+import isEmpty from 'lodash/isEmpty'
+import isObject from 'lodash/isObject'
+
+export const useSetFlagshipUI = (onMount, onUnmount) => {
+ const webviewIntent = useWebviewIntent()
+
+ useEffect(() => {
+ const parsedOnMount = isObject(onMount) && pickBy(onMount, identity)
+ const parsedOnUnmount = isObject(onUnmount) && pickBy(onUnmount, identity)
+
+ webviewIntent &&
+ !isEmpty(parsedOnMount) &&
+ webviewIntent.call('setFlagshipUI', parsedOnMount)
+
+ return () => {
+ webviewIntent &&
+ !isEmpty(parsedOnUnmount) &&
+ webviewIntent.call('setFlagshipUI', parsedOnUnmount)
+ }
+ }, [webviewIntent])
+}
diff --git a/react/hooks/useSetFlagshipUi/useSetFlagshipUI.spec.js b/react/hooks/useSetFlagshipUi/useSetFlagshipUI.spec.js
new file mode 100644
index 0000000000..b5e681a43b
--- /dev/null
+++ b/react/hooks/useSetFlagshipUi/useSetFlagshipUI.spec.js
@@ -0,0 +1,201 @@
+import { renderHook } from '@testing-library/react-hooks'
+import { useSetFlagshipUI } from './useSetFlagshipUI'
+import { useWebviewIntent } from 'cozy-intent'
+
+jest.mock('cozy-intent')
+
+const mockCall = jest.fn()
+const mockCSSValue = '#fff'
+
+beforeEach(() => {
+ useWebviewIntent.mockImplementation(() => ({ call: mockCall }))
+})
+
+afterEach(() => {
+ mockCall.mockClear()
+})
+
+it('should call webviewIntent with the correct params, once at mount and once at unmount', () => {
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI(
+ {
+ bottomBackground: mockCSSValue,
+ bottomOverlay: 'transparent',
+ bottomTheme: 'dark',
+ topBackground: mockCSSValue,
+ topOverlay: 'transparent',
+ topTheme: 'dark'
+ },
+ {
+ bottomBackground: mockCSSValue,
+ bottomOverlay: 'transparent',
+ bottomTheme: 'light',
+ topBackground: mockCSSValue,
+ topOverlay: 'transparent',
+ topTheme: 'light'
+ }
+ )
+ )
+
+ expect(mockCall).toHaveBeenNthCalledWith(1, 'setFlagshipUI', {
+ bottomBackground: mockCSSValue,
+ bottomOverlay: 'transparent',
+ bottomTheme: 'dark',
+ topBackground: mockCSSValue,
+ topOverlay: 'transparent',
+ topTheme: 'dark'
+ })
+
+ unmount()
+
+ expect(mockCall).toHaveBeenNthCalledWith(2, 'setFlagshipUI', {
+ bottomBackground: mockCSSValue,
+ bottomOverlay: 'transparent',
+ bottomTheme: 'light',
+ topBackground: mockCSSValue,
+ topOverlay: 'transparent',
+ topTheme: 'light'
+ })
+})
+
+it('should call webviewIntent with the correct params with few args, once at mount and once at unmount', () => {
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI(
+ { bottomBackground: mockCSSValue },
+ { bottomBackground: mockCSSValue }
+ )
+ )
+
+ expect(mockCall).toHaveBeenNthCalledWith(1, 'setFlagshipUI', {
+ bottomBackground: mockCSSValue
+ })
+
+ unmount()
+
+ expect(mockCall).toHaveBeenNthCalledWith(2, 'setFlagshipUI', {
+ bottomBackground: mockCSSValue
+ })
+})
+
+it('should call nothing with no webviewIntent and not throw', () => {
+ useWebviewIntent.mockImplementation(() => undefined)
+
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI(
+ { bottomBackground: mockCSSValue },
+ { bottomBackground: mockCSSValue }
+ )
+ )
+
+ expect(mockCall).not.toHaveBeenCalled()
+
+ unmount()
+
+ expect(mockCall).not.toHaveBeenCalled()
+})
+
+it('should refuse to call bad args', () => {
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI(
+ {
+ bottomBackground: false,
+ bottomOverlay: 0,
+ bottomTheme: '',
+ topBackground: null,
+ topOverlay: undefined,
+ topTheme: NaN
+ },
+ {
+ bottomBackground: false,
+ bottomOverlay: 0,
+ bottomTheme: '',
+ topBackground: null,
+ topOverlay: undefined,
+ topTheme: NaN
+ }
+ )
+ )
+
+ expect(mockCall).not.toHaveBeenCalled()
+
+ unmount()
+
+ expect(mockCall).not.toHaveBeenCalled()
+})
+
+it('should refuse to call when no arg in second arg', () => {
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI({ bottomBackground: mockCSSValue })
+ )
+
+ expect(mockCall).toHaveBeenNthCalledWith(1, 'setFlagshipUI', {
+ bottomBackground: mockCSSValue
+ })
+
+ unmount()
+
+ expect(mockCall).toHaveBeenCalledTimes(1)
+})
+
+it('should refuse to call when no arg at all', () => {
+ const { unmount } = renderHook(() => useSetFlagshipUI())
+
+ expect(mockCall).not.toHaveBeenCalled()
+
+ unmount()
+
+ expect(mockCall).not.toHaveBeenCalled()
+})
+
+it('should refuse to call when empty arg', () => {
+ const { unmount } = renderHook(() => useSetFlagshipUI({}, {}))
+
+ expect(mockCall).not.toHaveBeenCalled()
+
+ unmount()
+
+ expect(mockCall).not.toHaveBeenCalled()
+})
+
+it('should refuse to call when invalid arg type', () => {
+ const { unmount } = renderHook(() => useSetFlagshipUI('foo', 10))
+
+ expect(mockCall).not.toHaveBeenCalled()
+
+ unmount()
+
+ expect(mockCall).not.toHaveBeenCalled()
+})
+
+it('should sanitize bad objects', () => {
+ const { unmount } = renderHook(() =>
+ useSetFlagshipUI(
+ {
+ bottomBackground: false,
+ bottomOverlay: 0,
+ bottomTheme: '',
+ topBackground: 'red',
+ topOverlay: undefined,
+ topTheme: NaN
+ },
+ {
+ bottomBackground: false,
+ bottomOverlay: 0,
+ bottomTheme: '',
+ topBackground: 'blue',
+ topOverlay: undefined,
+ topTheme: NaN
+ }
+ )
+ )
+
+ expect(mockCall).toHaveBeenNthCalledWith(1, 'setFlagshipUI', {
+ topBackground: 'red'
+ })
+
+ unmount()
+
+ expect(mockCall).toHaveBeenNthCalledWith(2, 'setFlagshipUI', {
+ topBackground: 'blue'
+ })
+})