-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Chrome mWeb - scan button provides no feedback #30094
Changes from 12 commits
04476a3
c09a37c
e8664c0
7307db8
710cee1
9e87798
b3f0a85
ab6ad33
afc709c
e846414
6788075
6f76928
0b23ac2
f21f204
1349a1e
96f76c5
6080787
5da6f16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import {useTabAnimation} from '@react-navigation/material-top-tabs'; | ||
import {useIsFocused} from '@react-navigation/native'; | ||
import {useEffect, useState} from 'react'; | ||
|
||
/** | ||
* Custom React hook to determine the focus status of a tab in a Material Top Tab Navigator. | ||
* It evaluates whether the current tab is focused based on the tab's animation position and | ||
* the screen's focus status within a React Navigation environment. | ||
* | ||
* This hook is designed for use with the Material Top Tabs provided by '@react-navigation/material-top-tabs'. | ||
* It leverages the `useTabAnimation` hook from the same package to track the animated position of tabs | ||
* and the `useIsFocused` hook from '@react-navigation/native' to ascertain if the current screen is in focus. | ||
* | ||
* Note: This hook contains a conditional invocation of another hook (`useTabAnimation`), | ||
* which is typically an anti-pattern in React. This is done to account for scenarios where the hook | ||
* might not be used within a Material Top Tabs Navigator context. Proper usage should ensure that | ||
* this hook is only used where appropriate. | ||
* | ||
* Note: This hook is almost identical to native implementation, except for the `selectedTab` parameter | ||
* and the fact that it uses requestAnimationFrame to mitigate issues when updating the isTabFocused state. | ||
* | ||
* @param {Object} params - The parameters object. | ||
* @param {number} params.tabIndex - The index of the tab for which focus status is being determined. | ||
* @returns {boolean} Returns `true` if the tab is both animation-focused and screen-focused, otherwise `false`. | ||
* | ||
* @example | ||
* const isTabFocused = useTabNavigatorFocus({ tabIndex: 1 }); | ||
*/ | ||
function useTabNavigatorFocus({tabIndex}) { | ||
let tabPositionAnimation = null; | ||
try { | ||
// Retrieve the animation value from the tab navigator, which ranges from 0 to the total number of pages displayed. | ||
// Even a minimal scroll towards the camera page (e.g., a value of 0.001 at start) should activate the camera for immediate responsiveness. | ||
// STOP!!!!!!! This is not a pattern to be followed! We are conditionally rendering this hook becase when used in the edit flow we'll never be inside a tab navigator. | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
tabPositionAnimation = useTabAnimation(); | ||
} catch (error) { | ||
tabPositionAnimation = null; | ||
} | ||
const isPageFocused = useIsFocused(); | ||
// set to true if the hook is not used within the MaterialTopTabs context | ||
// the hook will then return true if the screen is focused | ||
const [isTabFocused, setIsTabFocused] = useState(!tabPositionAnimation); | ||
|
||
useEffect(() => { | ||
if (!tabPositionAnimation) { | ||
return; | ||
} | ||
const index = Number(tabIndex); | ||
|
||
const listenerId = tabPositionAnimation.addListener(({value}) => { | ||
// Activate camera as soon the index is animating towards the `tabIndex` | ||
requestAnimationFrame(() => { | ||
setIsTabFocused(value > index - 1 && value < index + 1); | ||
}); | ||
}); | ||
|
||
// We need to get the position animation value on component initialization to determine | ||
// if the tab is focused or not. Since it's an Animated.Value the only synchronous way | ||
// to retrieve the value is to use a private method. | ||
// eslint-disable-next-line no-underscore-dangle | ||
const initialTabPositionValue = tabPositionAnimation.__getValue(); | ||
|
||
if (typeof initialTabPositionValue === 'number') { | ||
requestAnimationFrame(() => { | ||
setIsTabFocused(initialTabPositionValue > index - 1 && initialTabPositionValue < index + 1); | ||
}); | ||
} | ||
|
||
return () => { | ||
if (!tabPositionAnimation) { | ||
return; | ||
} | ||
tabPositionAnimation.removeListener(listenerId); | ||
}; | ||
}, [tabIndex, tabPositionAnimation]); | ||
|
||
return isTabFocused && isPageFocused; | ||
} | ||
|
||
export default useTabNavigatorFocus; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,75 @@ | ||||||||||||||||||
import {useTabAnimation} from '@react-navigation/material-top-tabs'; | ||||||||||||||||||
import {useIsFocused} from '@react-navigation/native'; | ||||||||||||||||||
import {useEffect, useState} from 'react'; | ||||||||||||||||||
import CONST from '@src/CONST'; | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Custom React hook to determine the focus status of a specific tab in a Material Top Tab Navigator, with additional | ||||||||||||||||||
* conditions based on a selected tab state. It evaluates whether the specified tab is focused by combining the tab's | ||||||||||||||||||
* animation position and the screen's focus status within a React Navigation environment. | ||||||||||||||||||
* | ||||||||||||||||||
* The hook is primarily intended for use with Material Top Tabs provided by '@react-navigation/material-top-tabs'. | ||||||||||||||||||
* It utilizes the `useTabAnimation` hook from this package to track the animated position of the tabs and the | ||||||||||||||||||
* `useIsFocused` hook from '@react-navigation/native' to determine if the current screen is focused. Additionally, | ||||||||||||||||||
* it uses a `selectedTab` parameter to apply custom logic based on the currently selected tab. | ||||||||||||||||||
* | ||||||||||||||||||
* Note: This hook employs a conditional invocation of the `useTabAnimation` hook, which is generally against React's | ||||||||||||||||||
* rules of hooks. This pattern is used here to handle scenarios where the hook might not be employed within a | ||||||||||||||||||
* Material Top Tabs Navigator context. Ensure this hook is only used in appropriate scenarios to avoid potential issues. | ||||||||||||||||||
* | ||||||||||||||||||
* @param {Object} params - The parameters object. | ||||||||||||||||||
* @param {number} params.tabIndex - The index of the tab for which focus status is being determined. | ||||||||||||||||||
* @param {string} params.selectedTab - The tab identifier passed by <TopTab.Screen /> to the component. Used only on native platform | ||||||||||||||||||
* | ||||||||||||||||||
* @returns {boolean} Returns `true` if the specified tab is both animation-focused and screen-focused, otherwise `false`. | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
* | ||||||||||||||||||
* @example | ||||||||||||||||||
* const isTabFocused = useTabNavigatorFocus({ tabIndex: 1, selectedTab: 'home' }); | ||||||||||||||||||
*/ | ||||||||||||||||||
function useTabNavigatorFocus({tabIndex, selectedTab}) { | ||||||||||||||||||
let tabPositionAnimation = null; | ||||||||||||||||||
try { | ||||||||||||||||||
// Retrieve the animation value from the tab navigator, which ranges from 0 to the total number of pages displayed. | ||||||||||||||||||
// Even a minimal scroll towards the camera page (e.g., a value of 0.001 at start) should activate the camera for immediate responsiveness. | ||||||||||||||||||
// STOP!!!!!!! This is not a pattern to be followed! We are conditionally rendering this hook becase when used in the edit flow we'll never be inside a tab navigator. | ||||||||||||||||||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||||||||||||||||||
tabPositionAnimation = useTabAnimation(); | ||||||||||||||||||
} catch (error) { | ||||||||||||||||||
tabPositionAnimation = null; | ||||||||||||||||||
} | ||||||||||||||||||
const isPageFocused = useIsFocused(); | ||||||||||||||||||
// set to true if the hook is not used within the MaterialTopTabs context | ||||||||||||||||||
// the hook will then return true if the screen is focused | ||||||||||||||||||
const [isTabFocused, setIsTabFocused] = useState(!tabPositionAnimation); | ||||||||||||||||||
|
||||||||||||||||||
// Retrieve the animation value from the tab navigator, which ranges from 0 to the total number of pages displayed. | ||||||||||||||||||
// Even a minimal scroll towards the camera page (e.g., a value of 0.001 at start) should activate the camera for immediate responsiveness. | ||||||||||||||||||
|
||||||||||||||||||
// STOP!!!!!!! This is not a pattern to be followed! We are conditionally rendering this hook becase when used in the edit flow we'll never be inside a tab navigator. | ||||||||||||||||||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||||||||||||||||||
|
||||||||||||||||||
useEffect(() => { | ||||||||||||||||||
if (!tabPositionAnimation) { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
const listenerId = tabPositionAnimation.addListener(({value}) => { | ||||||||||||||||||
if (selectedTab !== CONST.TAB.SCAN) { | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the only difference between this file and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not only, also requestanimation frame is meant for web while it can't be used on native. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see. Can you please comment at the top of both of these files to explain the differences? Neither of those was very obvious to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added descriptions |
||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
// Activate camera as soon the index is animating towards the `cameraTabIndex` | ||||||||||||||||||
setIsTabFocused(value > tabIndex - 1 && value < tabIndex + 1); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
return () => { | ||||||||||||||||||
if (!tabPositionAnimation) { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
tabPositionAnimation.removeListener(listenerId); | ||||||||||||||||||
}; | ||||||||||||||||||
}, [tabIndex, tabPositionAnimation, selectedTab]); | ||||||||||||||||||
|
||||||||||||||||||
return isTabFocused && isPageFocused; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
export default useTabNavigatorFocus; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind applying this change, then I think it should be all ready to merge.