fix: sync playback speed between parent and thread video players#85195
Conversation
| if (currentVideoPlayerRef.current.playbackRate === currentPlaybackSpeed) { | ||
| return; | ||
| } | ||
| currentVideoPlayerRef.current.playbackRate = currentPlaybackSpeed; |
There was a problem hiding this comment.
core fix, same pattern as VolumeContext (line 41-46) which re-applies stored volume when originalParent changes. when user navigates to thread, originalParent updates and this applies stored playback speed to the new player.
| @@ -225,10 +224,9 @@ function BaseVideoPlayer({ | |||
|
|
|||
| const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { | |||
| updateVideoPopoverMenuPlayerRef(videoPlayerRef.current); | |||
There was a problem hiding this comment.
removed the reverse-sync that was overwriting global playback speed from the local player. previously opening the popover menu on a thread player (still at 1x default) would write 1x back to global state, wiping out the 2x the user selected. the useEffect in VideoPopoverMenuContext now handles keeping players in sync.
|
@ZhenjaHorbach 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] |
JmillsExpensify
left a comment
There was a problem hiding this comment.
Product review isn't required on this one.
| if (currentVideoPlayerRef.current.playbackRate === currentPlaybackSpeed) { | ||
| return; |
There was a problem hiding this comment.
I think this condition is a bit redundant
There was a problem hiding this comment.
And we don't need ref in dependencies
So let's use something like this
useEffect(() => {
if (!originalParent || !currentVideoPlayerRef.current) {
return;
}
if (currentVideoPlayerRef.current.playbackRate !== currentPlaybackSpeed) {
currentVideoPlayerRef.current.playbackRate = currentPlaybackSpeed;
}
}, [originalParent, currentPlaybackSpeed]);
|
@ZhenjaHorbach addressed both, removed the ref from deps and the redundant condition. ready for another look |
0d87aa8 to
9c80207
Compare
9c80207 to
505dece
Compare
Reviewer Checklist
Screenshots/VideosAndroid: HybridApp2026-03-16.16.44.26.movAndroid: mWeb Chrome2026-03-16.16.41.30.moviOS: HybridApp2026-03-16.16.44.26.moviOS: mWeb Safari2026-03-16.16.41.30.movMacOS: Chrome / Safari2026-03-16.16.36.36.mov |
|
LGTM! |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
🚧 @AndrewGable has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/AndrewGable in version: 9.3.39-0 🚀
|
|
🚀 Deployed to production by https://github.com/cristipaval in version: 9.3.39-3 🚀
|
Explanation of Change
when you change playback speed on a video in a parent chat and navigate to the thread, the thread player plays at 1x and the speed menu shows 1x instead of your selection.
two things were wrong:
new player instances never got the stored playback speed applied on mount.
VolumeContextalready solved the exact same problem for volume by watchingoriginalParentfromPlaybackContextand re-applying the stored value when the active player changes. added the same pattern toVideoPopoverMenuContext.showPopoverMenuinBaseVideoPlayerwas reading the local player'splaybackRateand writing it back to global state viaupdatePlaybackSpeed. so opening the menu on a thread player (still at 1x) would overwrite the user's 2x selection. removed this reverse-sync.Fixed Issues
$ #84443
PROPOSAL: #84443 (comment)
Tests
Offline tests
N/A - playback speed is stored in memory, not persisted
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari