Skip to content

Commit a85841d

Browse files
authored
Merge pull request #89238 from Expensify/cherry-pick-staging-89212-25142234194-1
🍒 Cherry pick PR #89212 to staging 🍒
2 parents 19392f2 + 1fe571f commit a85841d

9 files changed

Lines changed: 52 additions & 37 deletions

File tree

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009036422
115-
versionName "9.3.64-22"
114+
versionCode 1009036423
115+
versionName "9.3.64-23"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"

ios/NewExpensify/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
</dict>
4545
</array>
4646
<key>CFBundleVersion</key>
47-
<string>9.3.64.22</string>
47+
<string>9.3.64.23</string>
4848
<key>FullStory</key>
4949
<dict>
5050
<key>OrgId</key>

ios/NotificationServiceExtension/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.3.64</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.3.64.22</string>
16+
<string>9.3.64.23</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionPointIdentifier</key>

ios/ShareViewController/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.3.64</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.3.64.22</string>
16+
<string>9.3.64.23</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionAttributes</key>

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "new.expensify",
3-
"version": "9.3.64-22",
3+
"version": "9.3.64-23",
44
"author": "Expensify, Inc.",
55
"homepage": "https://new.expensify.com",
66
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",

src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} fr
44
import type {EmitterSubscription, GestureResponderEvent, NativeTouchEvent, View} from 'react-native';
55
import {DeviceEventEmitter, Dimensions, InteractionManager} from 'react-native';
66
import type {OnyxEntry} from 'react-native-onyx';
7+
import {cancelAnimation, useSharedValue, withTiming} from 'react-native-reanimated';
8+
import {scheduleOnRN} from 'react-native-worklets';
79
import {Actions, useActionSheetAwareScrollViewActions} from '@components/ActionSheetAwareScrollView';
810
import ConfirmModal from '@components/ConfirmModal';
911
import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
@@ -77,6 +79,8 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
7779
const {email, accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
7880

7981
const [isPopoverVisible, setIsPopoverVisible] = useState(false);
82+
// UI-thread timer driving the delayed hide. https://github.com/Expensify/App/issues/89069
83+
const hideDelayProgress = useSharedValue(0);
8084
const [isDeleteCommentConfirmModalVisible, setIsDeleteCommentConfirmModalVisible] = useState(false);
8185
const [shouldSetModalVisibilityForDeleteConfirmation, setShouldSetModalVisibilityForDeleteConfirmation] = useState(true);
8286

@@ -183,6 +187,7 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
183187
* @param isUnreadChat - Flag to check if the chat is unread in the LHN. Used for the Mark as Read/Unread action
184188
*/
185189
const showContextMenu: ReportActionContextMenu['showContextMenu'] = (showContextMenuParams) => {
190+
cancelAnimation(hideDelayProgress);
186191
const {
187192
type,
188193
event,
@@ -295,13 +300,7 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
295300
* Hide the ReportActionContextMenu modal popover.
296301
* @param onHideActionCallback Callback to be called after popover is completely hidden
297302
*/
298-
const hideContextMenu: ReportActionContextMenu['hideContextMenu'] = (hideContextMenuParams) => {
299-
const {callbacks = {}} = hideContextMenuParams ?? {};
300-
301-
if (typeof callbacks.onHide === 'function') {
302-
onPopoverHideActionCallback.current = callbacks.onHide;
303-
}
304-
303+
const performHide = () => {
305304
selectionRef.current = '';
306305
reportActionDraftMessageRef.current = undefined;
307306
setIsPopoverVisible(false);
@@ -315,6 +314,33 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
315314
});
316315
};
317316

317+
const hideContextMenu: ReportActionContextMenu['hideContextMenu'] = (hideContextMenuParams) => {
318+
const {callbacks = {}, hideDelayMs} = hideContextMenuParams ?? {};
319+
320+
if (typeof callbacks.onHide === 'function') {
321+
onPopoverHideActionCallback.current = callbacks.onHide;
322+
}
323+
324+
cancelAnimation(hideDelayProgress);
325+
326+
if (!hideDelayMs || hideDelayMs <= 0) {
327+
performHide();
328+
return;
329+
}
330+
331+
// UI-thread delayed hide. https://github.com/Expensify/App/issues/89069
332+
hideDelayProgress.set(0);
333+
hideDelayProgress.set(
334+
withTiming(1, {duration: hideDelayMs}, (finished) => {
335+
'worklet';
336+
337+
if (finished) {
338+
scheduleOnRN(performHide);
339+
}
340+
}),
341+
);
342+
};
343+
318344
const transactionIDs: string[] = [];
319345
if (isMoneyRequestAction(reportActionRef.current)) {
320346
const originalMessage = getOriginalMessage(reportActionRef.current);

src/pages/inbox/report/ContextMenu/ReportActionContextMenu.ts

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ type HideContextMenuParams = {
5252
callbacks?: {
5353
onHide?: () => void;
5454
};
55+
/** Delay before hiding (ms). Run on the UI thread via Reanimated.
56+
* https://github.com/Expensify/App/issues/89069 */
57+
hideDelayMs?: number;
5558
};
5659
type HideContextMenu = (params?: HideContextMenuParams) => void;
5760

@@ -71,9 +74,11 @@ type ReportActionContextMenu = {
7174

7275
const contextMenuRef = React.createRef<ReportActionContextMenu>();
7376

77+
// How long the success icon (Checkmark / "Copied!") stays visible before the menu hides.
78+
const SUCCESS_STATE_HIDE_DELAY_MS = 800;
79+
7480
/**
7581
* Hide the ReportActionContextMenu modal popover.
76-
* Hides the popover menu with an optional delay
7782
* @param [shouldDelay] - whether the menu should close after a delay
7883
* @param [onHideCallback] - Callback to be called after Context Menu is completely hidden
7984
*/
@@ -82,30 +87,14 @@ function hideContextMenu(shouldDelay?: boolean, onHideCallback = () => {}, param
8287
return;
8388
}
8489

85-
const paramsWithCallback = {
90+
contextMenuRef.current.hideContextMenu({
91+
...params,
8692
callbacks: {
8793
...params?.callbacks,
8894
onHide: onHideCallback,
8995
},
90-
...params,
91-
};
92-
93-
if (!shouldDelay) {
94-
contextMenuRef.current.hideContextMenu(paramsWithCallback);
95-
return;
96-
}
97-
98-
// Save the active instanceID for which hide action was called.
99-
// If menu is being closed with a delay, check that whether the same instance exists or a new was created.
100-
// If instance is not same, cancel the hide action
101-
const instanceID = contextMenuRef.current.instanceIDRef.current;
102-
setTimeout(() => {
103-
if (contextMenuRef.current?.instanceIDRef.current !== instanceID) {
104-
return;
105-
}
106-
107-
contextMenuRef.current.hideContextMenu(paramsWithCallback);
108-
}, 800);
96+
...(shouldDelay ? {hideDelayMs: SUCCESS_STATE_HIDE_DELAY_MS} : {}),
97+
});
10998
}
11099

111100
/**

0 commit comments

Comments
 (0)