-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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: messages content overlap when bottom sheet is shown #38232
fix: messages content overlap when bottom sheet is shown #38232
Conversation
@Santhosh-Sellavel 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] |
@kirillzyusko Please tag reviewers to continue review here as this seems to be follow-up! |
@cubuspl42 @shubham1206agra tagging you to continue your review here cc @roryabraham |
I remind about a few minor comments from the old PR |
Done 🙌 Would you mind to have a look again? 👀 |
Recently, we had a similar situation where the code changes were supposed not to affect other platforms, but actually broke one of them. Will this be different here? We don't know yet. I know the checklist can be a pain, but let's try to actually follow it when it could be in the right. |
Can you mark #37203 in the description? |
@roryabraham Can you generate ad-hoc build here? |
Minor thing: also please change "PROPOSAL: GH_LINK_ISSUE(COMMENT)" to "PROPOSAL: N/A" or something like that |
Yeah, it's very good point - let me record and attach videos from other platforms 👍 |
@cubuspl42 done, I've uploaded all videos! |
@kirillzyusko Can you reproduce this? fix-message-content-overlap-ios-compressed.mp4 |
Yes, I can. Thank you for catching this - I'll try to fix it 🙌 |
@cubuspl42 I think I fixed the problem (thank you again for reporting it 🙌 ). I patched a dependency - would you mind to pull latest changes, re-install |
Conflicts 🙁 |
cc75058
to
080eb7c
Compare
@cubuspl42 resolved 🙂 |
Sorry to be picky, but I found something else. I put actual effort to build fix-message-content-overlap-bug-2-ios-compressed.mp4 |
As I understand it, the general goal is to ensure that we don't cover the element which has the user's attention with an input panel (like a keyboard or custom keyboard-alike component). In this aspect, I find this a regression, as on On the feature branch, the keyboard can nearly cover the edited message. It can be worked around by manually scrolling after the fact, but I don't think it's enough. |
For reference, the behavior on fix-message-content-overlap-bug-2-main-ios-compressed.mp4Please note that, in this case, I also start to edit a message on the bottom of the screen (partially obscured by the composer), but it ends up being cleanly pushed up over the keyboard. |
Will wait for a conflict-free branch before running an AdHoc build here |
080eb7c
to
3796426
Compare
@roryabraham I resolved merge conflicts - may I kindly ask you to review these changes? @cubuspl42 I think I fixed the problem 🤞 May I kindly ask you to check again? |
Sometimes this can be waited out. |
@kirillzyusko Would you solve conflicts and merge |
@shubham1206agra Do you remember that you are co-assigned? This is non-trivial change, so maybe don't wait for each other, this doesn't need to be sequential 🙂 |
3796426
to
f9a1338
Compare
@cubuspl42 Done 🙌 |
@kirillzyusko Can you check https://github.com/kirillzyusko/react-native-keyboard-controller/releases/tag/1.11.5 and maybe bump the version? |
@shubham1206agra done 🙌
Can you provide a little bit more info? How did you open this screen (i. e. you tried to search for people to start a new conversation)? Would be awesome if you could add an expected result/reference how it looks now. |
No I just opened the search page. Expected should be no gap (very less gap) at all. |
@kirillzyusko Sorry for the confusion. Same problem exists for |
Screen.Recording.2024-03-27.at.6.19.39.PM.movBUG: The keyboard freezes on left swipe. It is much smoother on main right now. |
Screen.Recording.2024-03-27.at.6.31.39.PM.movBUG: The edit composer goes out of view on adding emojis with keyboard open. Might want to try 2-3 times to repro the issue. |
Screen.Recording.2024-03-27.at.6.34.19.PM.movBUG: The edit composer goes out of view when I try to edit message twice. |
@kirillzyusko Bump on these. |
@shubham1206agra thank you for bumping it. I've seen bugs that you reported but didn't have a time to look into them yet (was busy with e2e tests). Also I think it's wort to mention that starting from tomorrow I'll go to vacation, so realistically I can return to this task only after 2 weeks 😔 |
Kiryl will be OOO until 19.04 - Expect to continue on this PR the week after returning! |
eefe880
to
ac3a8c3
Compare
I resolved merge conflicts, but the animation performance is really bad after new architecture get enabled. I'll investigate what causes it and will try to reproduce problems that were reported before 👍 |
Some checks are failing, just saying 👇 |
@rojiphil Can you familiarise yourself with this code in the meanwhile? |
Yeah, I know, thanks ❤️ We've temporarily postponed a work on this PR, because since the new architecture was enabled - the animation on chat screen (resizing the content along with the keyboard) became unsynchronized with the keyboard (and animations are junky in this PR as well). So the best solution would be to fix animation in a current codebase and then proceed with this PR, but we'll see how it goes 👀 |
f5c2f05
to
21e69b3
Compare
A little bit context: I've noticed that I started to use both I did it (git didn't show up any conflicts) and I pushed this branch. GitHub immediately closed the PR and showed +0/-0 changes) because branch got corrupted. With help of @shubham1206agra I restored my changes prior to final rebase, but the problem now is that GH doesn't allow to re-open this PR (even if I push new commits and there is an actual diff): I had to open a new PR: #42143 Sorry for inconvenience 😔 If you have some ideas on how to restore this PR I'll be happy to hear 🙌 |
Details
A successor of #16356
The first step of react-native-keyboard-controller migration plan
Important
This PR relies on
react-native-keyboard-controller
(useKeyboardHandler
) hook andKeyboardAvoidingView
component).How it works 🤔
This PR is iOS only for now. Other platforms are not affected. Also, in this explanation, we are talking about iOS only since on Android, iOS web and Android Web keyboard handling works differently.
Note
We're talking about default platform behavior. If we start to use
react-native-keyboard-controller
on Android - it'll disable all default keyboard handling by OS and will delegate the keyboard handling to us - so we will have identical behavior across both iOS/Android platforms.But it may introduce additional issues (because we need to enter edge-to-edge mode - that would be good to do on entire app level, but it may bring some issues with
StatusBar
paddings, so everything has to be verified very carefully). That's why I think it would be better to handle in separate PR.When we long press on a message, we want to be able to see it. It's easy when we have the keyboard closed. But gets tricky when the keyboard is open.
But first of all let's focus on the case when the keyboard is closed. User long press on the message, we render the bottom sheet (action sheet) with some options. If the message is higher than the height of bottom sheet - the message is visible. When the message is the last one (first from the bottom), it can be fully or partially covered by the bottom sheet.
Press to see videos
300481023-9dc8be61-799d-470b-997f-ee5c5995fe19.mp4
300481277-0d0570cd-a85f-4cf5-8a91-6a3d5ad72c58.mp4
Also everything is tricky when we have keyboard open 😓
Press to see videos with keyboard
300482884-cbe3b610-fa85-4071-a3dd-bbc1a9d56e05.mp4
300483006-2e5ba833-c0fa-4fad-b383-b3854e5fa112.mp4
To achieve this goal we had to:
FlatList
ofReportListView
(it uses reanimated to move the view by the offset)KeyboardAvoiding
so we're in sync with keyboard-avoiding style updatesActionSheetAwareScrollViewContext
to pass the transition function, so we can transition from one state to another by action triggered from different parts of the applicationBelow you can find more use cases that involves keyboard and other UI elements interactions:
Interactions with other UI elements
300483536-04991f52-a41b-4d3e-abaf-12712b94f1aa.mp4
300483723-91b076a9-4c7a-4fbb-bc50-1e8194763e9d.mp4
Note
Call popover, bottom sheet and emoji picker are implemented as Modal windows and on iOS keyboard instantly gets hidden when modal window is shown. But "Attachment" popup is implemented not as modal, so for this type of transition we are using
progress
-based animations. When we press on plus -> popup is already shown under keyboard and we dismiss the keyboard. Overall the mechanism is similar to what we've used in the past, except the moment where we substitutetranslationY
value - in case when keyboard disappear/appears we interpolate it byprogress
variable to achieve smooth transitions.Technical details ⚒️
So in order to calculate the offset for the message, we:
ref.current.measureInWindow
, so we can haveheight
andy
coordinate of the imageonLayout
callbackDimensions
safeArea.top
sincey
coordinate doesn't get into account safe areaelementOffset = (y + safeArea.top + itemHeight) - (windowHeight - popoverHeight)
In order to animate item when they keyboard was open, we need to also know its height which is provided by useAnimatedKeyboard hook from react-native-reanimated, but we should always subtract safeArea.bottom from it since it's not part of the calculation for the offset, but only keyboardHeight.
Overall, the keyboard is the tricky part. On iOS, the keyboard doesn't resize the viewport. So for the content to not be covered by the keyboard,
KeyboardAvoidingView
is used. In React Native,KeyboardAvoidingView
is implemented as a view that changes its height or resizes the children's view by the keyboard height. It's done using RN's Layout Animations. This results in the animation for the keyboard being applied using the native event emitter callback which uses the bridge. So open/close events of the keyboard will always be delayed that resulting in the delayed keyboard avoiding animation and, which is more important, scheduling layout animations.In order to be consistent 100% of the time with animation and timings, we had to:
KeyboardAvoidingView
fromreact-native-keyboard-controller
for iOS. It reacts on keyboard height/state change on UI thread in the same frame, so we can schedule an update for styles in the next frameuseDerivedValue
for all the logic, since introducinguseAnimatedReaction
or having multiple shared values will delay updates for 1 frame, but we want to be 100% in sync with keyboard updatespaddingTop: translateY
(becauseScrollView
is inverted).Another important aspect of the implementation is the usage of the state machine for the animation. State machine allows us to specify the chain of events and how to handle them, and more importantly what actions to ignore, for example:
KEYBOARD_OPEN
actionEMOJI_PICKER_OPEN
actionEMOJI_PICKER_CLOSE
action which again does nothingKEYBOARD_OPEN
action. idle can react to this action by transitioning into keyboardOpen stateKEYBOARD_CLOSE
,EMOJI_PICKER_OPEN
actionsEMOJI_PICKER_OPEN
action which transitions our state intoemojiPickerOpen
state. now we react only toEMOJI_PICKER_CLOSE
actionKEYBOARD_CLOSE
action. but we ignore it since ouremojiPickerOpen
state can only handleEMOJI_PICKER_CLOSE
action. so we write the logic for handling 9. hiding the keyboard but maintaining the offset based on the keyboard state shared valueEMOJI_PICKER_CLOSE
action which transitions us back intokeyboardOpen
state.Fixed Issues
$ #10632
PROPOSAL: N/A
Tests
These steps were performed on all the platforms. The new behavior is iOS only for now.
Before each next we make sure the keyboard is open:
Offline tests
Should not affect the offline state.
QA Steps
Same as Tests
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodSTYLE.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)Design
label and/or tagged@Expensify/design
so the design team can review the changes.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
telegram-cloud-document-2-5460627828225625066.mp4
Android: mWeb Chrome
telegram-cloud-document-2-5460627828225625138.mp4
iOS: Native
1104ff6c-6eba-4295-a905-6caaaf3edf28.mp4
iOS: mWeb Safari
6eff007f-3c61-4f19-a60e-43f46d2f0e61.mp4
MacOS: Chrome / Safari
e5e28bd8-529f-4da3-8ae7-bff03bd14499.mp4
MacOS: Desktop
2c813bc9-6988-4fbc-8f36-3282c9cecd82.mp4