Skip to content
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

[$250] Android - Distance - Unable to switch distance label unit when tapping on the label #56499

Open
1 of 8 tasks
mvtglobally opened this issue Feb 7, 2025 · 41 comments
Open
1 of 8 tasks
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 Engineering External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors

Comments

@mvtglobally
Copy link

mvtglobally commented Feb 7, 2025

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.0.95-0
Reproducible in staging?: Yes
Reproducible in production?: Unable to check (New feature)
If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: Yes, reproducible on both
If this was caught during regression testing, add the test name, ID and link from TestRail: #55517
Email or phone of affected tester (no customers): applausetester+sj9032@applause.expensifail.com
Issue reported by: Applause Internal Team
Device used: Samsung Galaxy Z Fold 4 / Android 14
App Component: Money Requests

Action Performed:

  1. Go to staging.new.expensify.com (web or mweb or iOS).
  2. Open FAB > Create expense > Distance.
  3. Enter start and stop waypoint.
  4. Tap on the distance label on the map.
  5. Note that the label will change from mile to kilometer or vice versa when tapped.
  6. Launch Android app.
  7. Open FAB > Create expense > Distance.
  8. Enter start and stop waypoint.
  9. Tap on the distance label on the map.

Expected Result:

The distance label will change from mile to kilometer or vice versa when tapped.

Actual Result:

The distance label does not change when tapped.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

https://utest-dl.s3-accelerate.amazonaws.com/12102/26469/491203/6735645/bugAttachment/Bug6735645_1738880567891%211738880241936_Screen_Recording_20250207_061628_Chrome.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250207T020848Z&X-Amz-SignedHeaders=host&X-Amz-Credential=AKIAJ2UIWMJ2OMC3UCQQ%2F20250207%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=86400&X-Amz-Signature=dac2a54db02eb81e8d48fdc8b2708d0e67edd5823ab77ff7be6674703f776af2

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021887689540451729884
  • Upwork Job ID: 1887689540451729884
  • Last Price Increase: 2025-03-07
Issue OwnerCurrent Issue Owner: @abdulrahuman5196
@mvtglobally mvtglobally added Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 labels Feb 7, 2025
Copy link

melvin-bot bot commented Feb 7, 2025

Triggered auto assignment to @VictoriaExpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

@mvtglobally mvtglobally added the DeployBlockerCash This issue or pull request should block deployment label Feb 7, 2025
Copy link

melvin-bot bot commented Feb 7, 2025

Triggered auto assignment to @marcochavezf (DeployBlockerCash), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.

Copy link

melvin-bot bot commented Feb 7, 2025

💬 A slack conversation has been started in #expensify-open-source

@github-actions github-actions bot added Engineering Hourly KSv2 and removed Daily KSv2 labels Feb 7, 2025
Copy link
Contributor

github-actions bot commented Feb 7, 2025

👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

  1. Identify the pull request that introduced this issue and revert it.
  2. Find someone who can quickly fix the issue.
  3. Fix the issue yourself.

@VictoriaExpensify VictoriaExpensify added the External Added to denote the issue can be worked on by a contributor label Feb 7, 2025
@melvin-bot melvin-bot bot changed the title Android - Distance - Unable to switch distance label unit when tapping on the label [$250] Android - Distance - Unable to switch distance label unit when tapping on the label Feb 7, 2025
Copy link

melvin-bot bot commented Feb 7, 2025

Job added to Upwork: https://www.upwork.com/jobs/~021887689540451729884

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Feb 7, 2025
Copy link

melvin-bot bot commented Feb 7, 2025

Triggered auto assignment to Contributor-plus team member for initial proposal review - @abdulrahuman5196 (External)

@OmarKoueifi
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

The issue occurs when attempting to toggle the distance label (miles ↔ kilometers) on Android. The tap event does not trigger correctly, preventing users from switching the unit.

What is the root cause of that problem?

The problem originates in the following code:

https://github.com/truph01/App/blob/5632ffda8f4781eed679d35c8acd159cc8295c7c/src/components/MapView/MapView.tsx#L315-L331

Checking the MarkerView code I saw

onTouchEnd={(e) => {
    e.stopPropagation();
}}
  • The MarkerView component uses onTouchEnd to stop event propagation.
  • This prevents the onPress event in the PressableWithoutFeedback component from triggering, as the event does not bubble up correctly.

Since this is a deploy blocker, I will begin preparing my PR and testing immediately.

What changes do you think we should make in order to solve the problem?

  1. Replace onPress with onTouchEnd:
    • Since onPress is being blocked, switching to onTouchEnd ensures the event fires correctly.
  2. Verify behavior across platforms:
    • I tested this fix on Web, iOS, and Android, and it works as expected on all platforms.

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

When using pressable components PressableWithoutFeedback in the map view inside MarkerView component use onTouchEnd instead of onPress

  • Ensure clicking/tapping a marker triggers the expected event.
  • Verify that touch events propagate correctly without blocking interactions.
  • Ensure the fix works on Web (Safari and Chrome), iOS and Android (App and browser)

What alternative solutions did you explore? (Optional)

N/A

@melvin-bot melvin-bot bot added the Overdue label Feb 10, 2025
@Julesssss Julesssss assigned Julesssss and unassigned marcochavezf Feb 10, 2025
@melvin-bot melvin-bot bot removed the Overdue label Feb 10, 2025
@Julesssss
Copy link
Contributor

Hi @OmarKoueifi, thanks for the proposal, it looks good to me. @abdulrahuman5196 could you give final approval when you have a moment? Thanks

Removing the blocker status as this is low impact.

@Julesssss Julesssss added Overdue Daily KSv2 and removed DeployBlockerCash This issue or pull request should block deployment Hourly KSv2 labels Feb 10, 2025
@melvin-bot melvin-bot bot removed the Overdue label Feb 17, 2025
Copy link

melvin-bot bot commented Feb 21, 2025

@Julesssss @abdulrahuman5196 @VictoriaExpensify this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

Copy link

melvin-bot bot commented Feb 21, 2025

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

Copy link

melvin-bot bot commented Feb 24, 2025

@Julesssss, @abdulrahuman5196, @VictoriaExpensify Whoops! This issue is 2 days overdue. Let's get this updated quick!

@melvin-bot melvin-bot bot added the Overdue label Feb 24, 2025
@abdulrahuman5196
Copy link
Contributor

Checking now. Will provide information before EOD

@melvin-bot melvin-bot bot removed the Overdue label Feb 24, 2025
@abdulrahuman5196
Copy link
Contributor

Checking again

@abdulrahuman5196
Copy link
Contributor

Regarding @OmarKoueifi 's proposal here #56499 (comment) and @rohit9625 's proposal here #56499 (comment), both suggest to change OnPress to onTouchEnd which seems to fix this issue. But as pointed out it causes another issue where dragging is also causing the distance label to switch.
But the solutions suggested to solve the dragging seems to be an workaround solution IMO, so I don't think we should go with that. We should check for some more solid solutions to solve this issue without causing dragging regression.

@rohit9625
Copy link
Contributor

I found a related GH issue. I hope this can help us understand why the issue happens in our case.

Copy link

melvin-bot bot commented Feb 28, 2025

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

@melvin-bot melvin-bot bot added the Overdue label Feb 28, 2025
@linhvovan29546
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

Android - Distance - Unable to switch distance label unit when tapping on the label

What is the root cause of that problem?

On Android, we use PanResponder to resolve conflicts between MapView events. The properties onStartShouldSetPanResponderCapture and onMoveShouldSetPanResponderCapture are set to true, which prevents the onPress event from firing. This is the correct RCA for why the issue only occurs on Android.

const InterceptPanResponderCapture = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderTerminationRequest: () => false,
});

{...responder.panHandlers}

What changes do you think we should make in order to solve the problem?

Removing panHandlers would resolve the issue, but doing so would introduce regressions. Instead, we should implement a platform-specific fix for Android by using a workaround with onTouchEnd, onTouchStart, and onTouchMove:

const TouchableWrapper = ({
    children,
    onPress,
    accessibilityLabel,
    accessibilityRole,
    testID,
}: TouchableWrapperProps) => {
    const touchStartTime = useRef<number | null>(null);
    const touchStartLocation = useRef<{x: number; y: number} | null>(null);
    
    const handleTouchStart = (event: GestureResponderEvent) => {
        touchStartTime.current = Date.now();
        touchStartLocation.current = {
            x: event.nativeEvent.pageX,
            y: event.nativeEvent.pageY
        };
    };
    
    const handleTouchMove = (event: GestureResponderEvent) => {
        // If the touch has moved more than a threshold, consider it a drag
        if (touchStartLocation.current) {
            const dx = Math.abs(event.nativeEvent.pageX - touchStartLocation.current.x);
            const dy = Math.abs(event.nativeEvent.pageY - touchStartLocation.current.y);
            
            // If moved more than 1 pixels in any direction, consider it a drag
            if (dx > 1 || dy > 1) {
                // Reset touch tracking to prevent onPress from firing
                touchStartTime.current = null;
                touchStartLocation.current = null;
            }
        }
    };
    
    const handleTouchEnd = () => {
        // Only trigger onPress if this was a quick tap (less than 200ms)
        // and the touch hasn't moved significantly
        if (touchStartTime.current  && Date.now() - touchStartTime.current < 200) {
            onPress?.();
        }
        touchStartTime.current = null;
        touchStartLocation.current = null;
    };
    
    return (
        <PressableWithoutFeedback
            onTouchStart={handleTouchStart}
            onTouchMove={handleTouchMove}
            onTouchEnd={handleTouchEnd}
            accessibilityLabel={accessibilityLabel}
            accessibilityRole={accessibilityRole}
        >
            {children}
        </PressableWithoutFeedback>
    );
};

Then, replace the PressableWithoutFeedback wrapper with TouchableWrapper in the map view component:

<PressableWithoutFeedback
accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel="distance-label"
onPress={toggleDistanceUnit}
>
<View style={[styles.distanceLabelWrapper]}>
<Text style={styles.distanceLabelText}> {distanceLabelText}</Text>
</View>
</PressableWithoutFeedback>

                            <TouchableWrapper
                                onPress={toggleDistanceUnit}
                                accessibilityLabel={translate('common.distance')}
                                accessibilityRole={CONST.ROLE.BUTTON}
                            >
                                 <View style={[styles.distanceLabelWrapper]}>
                                        <Text style={styles.distanceLabelText}> {distanceLabelText}</Text>
                                    </View>
                            </TouchableWrapper>

Important

Apply this change only for Android

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

We can write a unit test to cover the case:

  • Simulate a press event and verify that onPress triggered
  • Simulate a drag event and verify that onPress does not trigger.
  • Simulate a long press and verify that onPress does not trigger.

What alternative solutions did you explore? (Optional)

N/A

@Julesssss
Copy link
Contributor

Thanks for the proposal @linhvovan29546. I like the wrapper as it's a tidier solution in a similar vein. What do you think @abdulrahuman5196?

Also here's why we implemented the android specific code, so for reference we'll need to test that case.

Copy link

melvin-bot bot commented Mar 4, 2025

@abdulrahuman5196 Eep! 4 days overdue now. Issues have feelings too...

@Julesssss
Copy link
Contributor

Awaiting response to #56499 (comment)

Copy link

melvin-bot bot commented Mar 6, 2025

@abdulrahuman5196 6 days overdue. This is scarier than being forced to listen to Vogon poetry!

Copy link

melvin-bot bot commented Mar 7, 2025

@Julesssss @abdulrahuman5196 @VictoriaExpensify this issue is now 4 weeks old, please consider:

  • Finding a contributor to fix the bug
  • Closing the issue if BZ has been unable to add the issue to a VIP or Wave project
  • If you have any questions, don't hesitate to start a discussion in #expensify-open-source

Thanks!

Copy link

melvin-bot bot commented Mar 7, 2025

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

Copy link

melvin-bot bot commented Mar 10, 2025

@abdulrahuman5196 10 days overdue. Is anyone even seeing these? Hello?

@abdulrahuman5196
Copy link
Contributor

Checking now

@melvin-bot melvin-bot bot removed the Overdue label Mar 10, 2025
@abdulrahuman5196
Copy link
Contributor

Hi @linhvovan29546 , regarding this

On Android, we use PanResponder to resolve conflicts between MapView events. The properties onStartShouldSetPanResponderCapture and onMoveShouldSetPanResponderCapture are set to true, which prevents the onPress event from firing

Curious question: The same property is set for web as well, why is not causing issue there?

const SwipeInterceptPanResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderTerminationRequest: () => false,
});

@linhvovan29546
Copy link
Contributor

That's the difference—on Android, onStartShouldSetPanResponderCapture and onMoveShouldSetPanResponderCapture are set to true, which prevents the press event

@linhvovan29546
Copy link
Contributor

If you comment out these two fields, the onPress event will work as expected

@abdulrahuman5196
Copy link
Contributor

That's the difference—on Android, onStartShouldSetPanResponderCapture and onMoveShouldSetPanResponderCapture are set to true, which prevents the press event

Got it. Thank you. But still IMO, your solution is almost similar to previous suggestions where to handle onTouch events and calculate if the user pressing or move and handle accordingly. I am not sure if we should go via that path.

@abdulrahuman5196
Copy link
Contributor

Thanks for the proposal @linhvovan29546. I like the wrapper as it's a tidier solution in a similar vein. What do you think @abdulrahuman5196?

Also here's why we implemented the android specific code, so for reference we'll need to test that case.

Hi @Julesssss , Anyways the solution suggested is similar to previous proposals where the suggestion was to handle the touch events and calculate the difference between user moving and pressing. Just that the new proposal is suggesting to put it in a wrapper but almost same proposal.(Correct me if wrong) I am not sure if we should go via that path yet.
IMO, I think we should see if some other solid/straightforward solution exists before going with this path. What do you think?

@linhvovan29546
Copy link
Contributor

Agree, my solution is similar to the existing proposal, but I pointed out the correct RCA.

@Julesssss
Copy link
Contributor

Just that the new proposal is suggesting to put it in a wrapper but almost same proposal.

Yeah i agree with this but we're yet to see any 'better' solutions. I prefer this as it's a cleaner workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 Engineering External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors
Projects
Status: LOW
Development

No branches or pull requests

9 participants