-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Fix tapping on new messages after marking a message unread leads to a blank page #32630
base: main
Are you sure you want to change the base?
Conversation
@parasharrajat Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
onScroll(event); | ||
|
||
if (isNative) { |
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.
We only call the handleUnreadFloatingButton
for Native devices because the native InvertedFlatList doesn't have the implementation to handle the scroll events to call the onScrollEnd
handler.
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.
Looks like the issue we faced is present on mWeb then this check will prevent that fix. Right? Also, the scrollend implementation is done on web file(index.js) not on native (index.native.js) of InvertedFlatList.
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.
This check is only used to have the same behavior (shows the "New message" button on scroll) for Native devices because there is no scroll implementation for the index.native.js
file for InvetedFlatList.
I'll improve the index.native.js
to use the scrolls mechanism instead of this isNative
check.
c17eb26
to
ab90916
Compare
}; | ||
|
||
const scrollToBottomAndMarkReportAsRead = () => { | ||
reportScrollManager.scrollToBottom(); | ||
const scrollToUnreadMessageAndMarkReportAsRead = () => { |
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.
Let's make sure that the unread message is fully visible on the window.
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.
Using the méthod reportScrollManager.scrollToIndex
the behavior is to put on the bottom the unread message and the user can see all the message content.
I don't know if your suggestion is to scroll and show this unread message in a particular place on the screen, for example in the middle of the screen. If so, we need to improve the method reportScrollManager.scrollToIndex
to receive the viewPosition
(scrolltoindex) with a number that indicates the place we want to show this message.
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.
I don't know if your suggestion is to scroll and show this unread message in a particular place on the screen, for example in the middle of the screen. If so, we need to improve the method reportScrollManager.scrollToIndex to receive the viewPosition (scrolltoindex) with a number that indicates the place we want to show this message.
This is a good suggestion when there are multiple unread messages. so I would say let's leave that part for now. No added complexity.
const platform = getPlatform(); | ||
const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID; |
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.
We don't allow direct use of Platform API. Instead, use platform files (index.js or index.native.js etc).
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.
I understood, I saw another component using this approach and I thought I could use the same approach.
I'll change the behavior for native using the index.native.js
file.
5cf0e42
to
e74926d
Compare
e74926d
to
3a7aafd
Compare
Testing... |
useEffect( | ||
() => () => { | ||
if (!scrollEndTimeout.current) { | ||
return; | ||
} | ||
|
||
clearTimeout(scrollEndTimeout.current); | ||
}, | ||
[props.innerRef], | ||
); | ||
|
||
/** | ||
* Emits when the scrolling is in progress. Also, | ||
* invokes the onScroll callback function from props. | ||
* | ||
* @param {Event} event - The onScroll event from the FlatList | ||
*/ | ||
const onScroll = (event) => { | ||
props.onScroll(event); | ||
}; | ||
|
||
/** | ||
* Emits when the scrolling has ended. Also, | ||
* invokes the onScrollEnd callback function from props. | ||
*/ | ||
const onScrollEnd = () => { | ||
props.onScrollEnd(); | ||
}; | ||
|
||
/** | ||
* Decides whether the scrolling has ended or not. If it has ended, | ||
* then it calls the onScrollEnd function. Otherwise, it calls the | ||
* onScroll function and pass the event to it. | ||
* | ||
* @param {Event} event - The onScroll event from the FlatList | ||
*/ | ||
const handleScroll = (event) => { | ||
onScroll(event); | ||
|
||
const timestamp = Date.now(); | ||
|
||
// console.log('=> handleScroll', {timestamp, 'lastScrollEvent.current': lastScrollEvent.current}) | ||
|
||
if (scrollEndTimeout.current) { | ||
clearTimeout(scrollEndTimeout.current); | ||
} | ||
|
||
scrollEndTimeout.current = setTimeout(() => { | ||
if (lastScrollEvent.current !== timestamp) { | ||
return; | ||
} | ||
// Scroll has ended | ||
lastScrollEvent.current = null; | ||
onScrollEnd(); | ||
}, 250); | ||
|
||
lastScrollEvent.current = timestamp; | ||
}; |
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.
Most of this logic same on both native and web file so we should move this to BaseInvertedFlatList
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.
Could you please review this commit 590666a please?
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.
Hi @parasharrajat if you have any questions or suggestions, please let me know.
const scrollToUnreadMessageAndMarkReportAsRead = () => { | ||
const scrollIndex = getScrollIndex(); | ||
|
||
isUnreadMessageFocused.current = true; |
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.
can you explain the purpose of this flag?
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.
This flag is used to avoid showing the "New Message" button when the scroll ends after the user clicks the "New Message" button.
When the user clicks on the "New Message" button the scroll occurs and we don't need to show again the "New Message" button because this current scroll was triggered by the "New Message" button action.
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.
Ok. I think you tried you mimic Slack behaviour but it is still different from slack. On Slack, when an unread message is visible on the screen marker remains hidden.
@wlegolas Can you please merge main? |
… in Native devices
…atList component for Native devices
…behavior after user clicks on the New message button
…mentation to the BaseInvertedFlatList component
a095842
to
5ddfe37
Compare
Sure, I updated my branch with the |
Please use merge commit instead of force push. For now, we are fine on this PR. |
Hi @parasharrajat I resolved a conflict in the If you have any questions, please let me know. |
|
||
const AUTOSCROLL_TO_TOP_THRESHOLD = 128; | ||
const WINDOW_SIZE = 15; | ||
|
||
function BaseInvertedFlatList<T>(props: FlatListProps<T>, ref: ForwardedRef<FlatList>) { | ||
function BaseInvertedFlatList<T>({onScroll: onScrollProp = () => {}, onScrollEnd: onScrollEndProp = () => {}, ...props}: InvertedFlatListProps<T>, ref: ForwardedRef<FlatList>) { |
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.
No need to give inline type when have already defined that.
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.
Sorry to ask @parasharrajat I didn't understand. Do you mean to not give inline type onScrollProp
?
* onScroll function and pass the event to it. | ||
* | ||
* This is a temporary work around, since react-native-web doesn't | ||
* support onScrollBeginDrag and onScrollEndDrag props for FlatList. |
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.
I think native has this method so we should use those instead for the native part.
function InvertedFlatList<T>( | ||
{onScroll: onScrollProp = () => {}, onScrollEnd: onScrollEndProp = () => {}, contentContainerStyle, ...props}: InvertedFlatListProps<T>, | ||
ref: ForwardedRef<FlatList>, | ||
) { |
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.
Same as the previous comment.
const scrollToUnreadMessageAndMarkReportAsRead = () => { | ||
const scrollIndex = getScrollIndex(); | ||
|
||
isUnreadMessageFocused.current = true; |
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.
Ok. I think you tried you mimic Slack behaviour but it is still different from slack. On Slack, when an unread message is visible on the screen marker remains hidden.
I am not sure if we want to mimic Slack behavior. Also, this is a big decision to make. If we find this idle then we will have to propose this on Slack first. I tested your branch and there are a few issues. I will post them here after I am done. |
I'm not trying to mimic Slack behavior, just trying to bring the behavior to the "New message" button closes that the behavior we know from Slack, but you're right, we need to propose to the Expensify team. In my opinion, for this issue, we only need to know which is the expected result when there is a new message, I just putting this behavior because for me makes sense to show the "New message" button when there is a new message and the scroll ends. But I'm totally open to hearing your suggestion |
Reviewing... |
Hi @parasharrajat do you have updates about your review process? |
@wlegolas Please merge the main when you get time. Thanks for waiting. |
Hi @parasharrajat I merged the main into my branch, I did some tests and the implementation is working as expected. If you need anything else, please let me know. |
Hi @parasharrajat did you have time to review my PR? |
I have been OOO since 10 days. I was about to grt back but something came up. I will try to get this tomorrow. I started the analysis before going OOO. |
Details
This PR will fix the issue related to the displayed blank page when the user clicks on the "New messages" button before the scroll action ends.
Fixed Issues
$ #31591
PROPOSAL: #31591 (comment)
Tests
Offline tests
QA Steps
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
evidence-Android-Native.mp4
Android: mWeb Chrome
evidence-Android-mWeb-Chrome.mp4
iOS: Native
evidence-iOS-Native.mp4
iOS: mWeb Safari
evidence-iOS-mWeb-Safari.mp4
MacOS: Chrome / Safari
Chrome
evidence-MacOS-Chrome.mp4
Safari
evidence-MacOS-Safari.mp4
MacOS: Desktop
evidence-MacOS-Desktop.mp4