Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
2.99k stars 2.5k forks source link

adding carousel to attachment modal #9279

Closed JediWattson closed 1 year ago

JediWattson commented 1 year ago

Details

add a carousel to the attachment modal that navigates through a chat's attachments

Fixed Issues

https://github.com/Expensify/App/issues/7862
PROPOSAL: https://github.com/Expensify/App/issues/7862#issuecomment-1128202430

Tests

iOS / android

  1. tap on an image in chat and an attachment modal presents
  2. swipe left or right to change the attachment to the next or previous one
  3. tap on the modal to make the arrows on the sides appear or disappear
  4. tap on an arrow to change the attachment to the next or previous one
  5. verify attachment's name are displayed correctly in modal header

web / desktop

  1. click an image
  2. clicking an arrow will change the attachment to the next or previous one
  3. verify that moving the cursor outside the modal will make the arrows disappear
  4. verify moving the cursor back into the modal will make the arrows appear
  5. verify modal header matches file name, and correct attachment is downloaded

Offline tests

QA Steps

iOS / android

  1. tap on an image in chat and an attachment modal presents
  2. swipe left or right to change the attachment to the next or previous one
  3. tap on the modal to make the arrows on the sides appear or disappear
  4. tap on an arrow to change the attachment to the next or previous one
  5. verify attachment's name are displayed correctly in modal header

web / desktop

  1. click an image
  2. clicking an arrow will change the attachment to the next or previous one
  3. verify that moving the cursor outside the modal will make the arrows disappear
  4. verify moving the cursor back into the modal will make the arrows appear
  5. verify modal header matches file name, and correct attachment is downloaded

PR Author Checklist

Screenshots/Videos

Web https://user-images.githubusercontent.com/6119181/209240380-e1d0d2c8-6d9b-40a9-a13f-d73cd30bf659.mov
Mobile Web - Chrome https://user-images.githubusercontent.com/6119181/209581657-961beb4a-41c9-40f1-9435-491643434669.mov
Mobile Web - Safari https://user-images.githubusercontent.com/6119181/209581646-c0f64f3b-81fb-497e-9976-0a6e603a92e9.mov
Desktop https://user-images.githubusercontent.com/6119181/209240439-beb8e0c8-a46f-418b-acb4-d56e82bf65e4.mov
iOS https://user-images.githubusercontent.com/6119181/209240861-68fc6624-4096-4186-936b-4291fcfca9b4.mov
Android https://user-images.githubusercontent.com/6119181/210114328-cbd4e055-382f-4710-92fd-3fb50e3831e7.MOV
JediWattson commented 1 year ago

I set this branch up to get a signed commit in. I'll be looking this comment first and then I'll need to update the videos I made for the updated buttons. Also I think there's about 2 comments that I've responded to that I left unresolved, but the rest I either went with the suggested code or unchanged the code.

chiragsalian commented 1 year ago

Review paused until santhosh get's back from OOO. Adding him as reviewer so that he sees the PR once he's back.

Santhosh-Sellavel commented 1 year ago

@JediWattson From issue description https://github.com/Expensify/App/issues/7862#issue-1146471345

Expected Result:

  1. When the member is viewing the most recent attachment in the chat, there's only a left arrow icon on the attachment preview screen to navigate further back. Similarly, when the member is viewing the oldest attachment in the chat, there's only a right arrow to navigate forward.
  2. If the member is previewing an attachment that isn't the oldest or latest in the chat history, there will be both left/right arrow icon to navigate "forward" or "back" to the next attachment preview.
  3. On desktop/Web: The arrow can be clicked to navigate to the next attachment preview, or the left/right arrow keys on the keyboard can be used
  4. On mobile/mWeb: The arrow can be tapped or the member can swipe left/right on the preview to navigate to the next attachment preview depending on the direction
  5. On desktop/Web, the arrows are visible on hover. On mobile/mWeb, a single tap on the image hides/shows the arrows.

I believe PR covers only 1 & 2 what above 3, 4, 5.

JediWattson commented 1 year ago

@JediWattson From issue description #7862 (comment)

Expected Result:

  1. When the member is viewing the most recent attachment in the chat, there's only a left arrow icon on the attachment preview screen to navigate further back. Similarly, when the member is viewing the oldest attachment in the chat, there's only a right arrow to navigate forward.
  2. If the member is previewing an attachment that isn't the oldest or latest in the chat history, there will be both left/right arrow icon to navigate "forward" or "back" to the next attachment preview.
  3. On desktop/Web: The arrow can be clicked to navigate to the next attachment preview, or the left/right arrow keys on the keyboard can be used
  4. On mobile/mWeb: The arrow can be tapped or the member can swipe left/right on the preview to navigate to the next attachment preview depending on the direction
  5. On desktop/Web, the arrows are visible on hover. On mobile/mWeb, a single tap on the image hides/shows the arrows.

I believe PR covers only 1 & 2 what above 3, 4, 5.

for 3 I would propose to add a listener to handle the arrow press. It would be added when the component is mounted:

   componentDidMount() {
        document.addEventListener('keydown', this.handleArrowPress)
    }

    componentWillUnmount() {
        document.removeEventListener('keydown', this.handleArrowPress)
    }

handleArrowPress will check the e.key and call cycleThroughAttachments

    /**
     * Listens for keyboard shortcuts and applies the action
     *
     * @param {Object} e
     */
    handleArrowPress(e) {
        if(e.key === "ArrowLeft" && !this.state.isBackDisabled) {
            this.cycleThroughAttachments(-1);
        }
        if(e.key === "ArrowRight" && !this.state.isForwardDisabled) {
            this.cycleThroughAttachments(1);
        }
    }
  1. I see a SwipeableView but I'm unsure how I want to handle the data change because I feel it's best like this:
  <SwipeableView>
    <AttachmentView sourceURL={sourceURL} file={this.state.file} />
  </SwipeableView>
  // ... <AttachmentCarousel 
  1. On mobile you want the arrows to initially appear then disappear onPress right? For desktop they would be visible onMouseOver?
Santhosh-Sellavel commented 1 year ago

On mobile you want the arrows to initially appear then disappear onPress right?

  1. On desktop/Web, the arrows are visible on hover. On mobile/mWeb, a single tap on the image hides/shows the arrows.

From 5 we can get the answer, we should toggle arrow visibility when tapping on the image.

But I'm not sure whether we should show or hide the arrows initially. @Expensify/design team please help us here.

cc: @shawnborton

Santhosh-Sellavel commented 1 year ago

@JediWattson Sounds good! Please make the suggested changes, let me know when changes are done.

shawnborton commented 1 year ago

For mobile, I think it's okay if they are visible by default and then tapping the image hides them.

JediWattson commented 1 year ago

I just got most of the changes here up. I just need to add the functionality for the arrows to show and not show

Santhosh-Sellavel commented 1 year ago

@JediWattson Any update on this?

JediWattson commented 1 year ago

I'm finishing up the arrows today, and then possibly get into the swiping too. I can add new videos showing this this weekend too.

Santhosh-Sellavel commented 1 year ago

@JediWattson Further update on this?

github-actions[bot] commented 1 year ago

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

Santhosh-Sellavel commented 1 year ago

@JediWattson You should use only one git account. Do not use multiple accounts. Can you revert & commit changes properly thanks!

JediWattson commented 1 year ago

Will do, I think I've completed the requirements now too. Now it seems I just need to clean that up, and add some videos for swiping and toggling arrows

JediWattson commented 1 year ago

I believe all I have left now is to make some videos showing the arrows show and not showing along with swiping and update the qa instructions

Santhosh-Sellavel commented 1 year ago

Good then,

And let us know when PR is ready for review.

Santhosh-Sellavel commented 1 year ago

@JediWattson Bump!

JediWattson commented 1 year ago

@Santhosh-Sellavel I got some new videos up to show the swiping in native apps. A couple things I really can't figure out are: in mobile browsers I'm unable to capture an event to toggle showing the arrows, and in a pdf I couldn't get a similar event so I left the arrows on there

Santhosh-Sellavel commented 1 year ago

A couple things I really can't figure out are: in mobile browsers I'm unable to capture an event to toggle showing the arrows, and in a pdf I couldn't get a similar event so I left the arrows on there

Sorry for the delay, are these both specific to mobile web alone?

Santhosh-Sellavel commented 1 year ago

@JediWattson bump!

JediWattson commented 1 year ago

the arrows not toggling is specific to mobile browsers, but the pdf seems to be an issue for both mobile browsers and native

JediWattson commented 1 year ago

I believe I got this 100% now! @Santhosh-Sellavel

Santhosh-Sellavel commented 1 year ago

Good @JediWattson KIndly update your PR Description along with all other necessary info and updated screen recordings too thanks!

Santhosh-Sellavel commented 1 year ago

@JediWattson Bump!

JediWattson commented 1 year ago

@Santhosh-Sellavel apologies, I just need to update the mobile web videos to show the arrows showing/disappearing and it should be good. I'll try to finish that up in the next couple days

Santhosh-Sellavel commented 1 year ago

@JediWattson bump!

JediWattson commented 1 year ago

@Santhosh-Sellavel I have updated the mobile web videos to reflect the new changes. I should 100% hopefully!

Santhosh-Sellavel commented 1 year ago

Please resolve conflicts & let us know when it is ready for review again thanks!

@JediWattson

JediWattson commented 1 year ago

@Santhosh-Sellavel conflicts are resolved!

Santhosh-Sellavel commented 1 year ago

What about the Other changes I requested in the review, please address that too..

JediWattson commented 1 year ago

@Santhosh-Sellavel do you mean the attachments not working? That should be fixed now

Santhosh-Sellavel commented 1 year ago

Can you check other review comments

Santhosh-Sellavel commented 1 year ago

@JediWattson Sorry for the delay here, I'm not sure why you end up modifying the Swipeable View for onPress. Adding more swipe-related functionality is fine but not okay with adding irrelevant interaction here.

Before moving forward we need to know,

What other options did you explore i.e without modifying this Swipeable component? What's the problem with that method? Why did you think this is the best way to address this?

If you summarise this with enough info, we will get to know more context on this to help us decide on it. We can also take this to slack to get other help on problems you are facing.

Thanks!

cc: @chiragsalian

JediWattson commented 1 year ago

What other options did you explore i.e without modifying this Swipeable component?

I tried to putting Pressable in a place that would take the onTap gesture but not capture any other gestures that make swiping possible. For native mobile I couldn't find a place where that was possible so I added that in Swipeable.

What's the problem with that method?

It doesn't work for mobile browsers and moving Pressable out of there obstructs using Swipeable in native mobile

Why did you think this is the best way to address this?

because it's a use case for mobile web where I can't handle onClick or something that's distinct from mobile and not have it hinder the functionality of mobile.

Santhosh-Sellavel commented 1 year ago

@JediWattson Can you elaborate bit more in details, please include the snippets/commits which we can use to play around with.

mobile browsers and moving Pressable out of there obstructs using Swipeable in native mobile

How did you do that?

JediWattson commented 1 year ago

If I did something like in the below code I'm unable to capture the gestures in Swipable because pressable takes the events now, however it works in mobile web.

<Pressable>
  <Swipable />
</Pressable>

so I used Swipable to handle the tap gesture on native mobile, and then with mobile web the Swipable/index.js containing Pressable now works for web as well

Santhosh-Sellavel commented 1 year ago

It's better we leave Swipeable View untouched. Write a new component Just to handle interactions for AttachmentCarousel, let's separate specific interactions there.

JediWattson commented 1 year ago

I don't get the point of splitting up Swipable if the web based component isn't used to mirror the events found in the native component? I mean why have the index.native.js when that's what it seems to be there for?

Santhosh-Sellavel commented 1 year ago

I don't get the point of splitting up Swipable if the web based component isn't used to mirror the events found in the native component? I mean why have the index.native.js when that's what it seems to be there for?

I'm not getting it, can you ask in other words?

JediWattson commented 1 year ago

why is this component split into two variants for native and web if not to be modified so as to mirror interactions amongst the platforms?

Santhosh-Sellavel commented 1 year ago

why is this component split into two variants for native and web

There is a comment there already, we are supporting swipe only for native apps it seems!

https://github.com/Expensify/App/blob/cc31727073a1f6dfdec49af47689064b598d20bd/src/components/SwipeableView/index.js#L1-L3

JediWattson commented 1 year ago

but now that I needed to add a tap gesture in the SwipeableView that's used for both mobile native and web platforms then it makes sense to modify that to reduce code reuse

Santhosh-Sellavel commented 1 year ago

Swipeable is intended for swipe only actions.

Pressable is intended for tap actions

I don't get it why we want to add a press to Swipeable.

If we need to combine both swipe and tap we should form a new component.

Example take a look at PressableWithSecondaryInteraction which combines longpress & click

JediWattson commented 1 year ago

can I rename Swipable to SwipableWithPressable then? That makes sense, and that comment explains why swiping is only available for iOS/Android

Santhosh-Sellavel commented 1 year ago

@JediWattson

Let's leave Swipeable untouched.

SwipeableWithPressable is not need to be defined we might not use it for other

Sometimes it's okay to reuse code.

Actually, as I said it's better to write a new component Attachment Carousel Action Listener. to define touch/pan/tap listeners split platform-specific only if required.

Props of the component be toggleArrows, nextAttachment or previousAttachment etc.

JediWattson commented 1 year ago

is there an example of this somewhere else in the app so I can understand better what the ask is here?

also SwipeableWithPressable is just the renaming of Swipeable and would solve what you're saying here because it's identifying this component is now pressable too. I mean currently Swipeable is technically incorrect with that pressable gesture being handled now.

trjExpensify commented 1 year ago

@chiragsalian or @marcaaron do either of you have an opinion on this https://github.com/Expensify/App/pull/9279#issuecomment-1257185660 so we can help keep this moving and get across the finish line?

marcaaron commented 1 year ago

I'm not really up to speed on this conversation. Can someone provided a quick summary of what they need help with?

chiragsalian commented 1 year ago

Discussing some of the pending points,

  1. also SwipeableWithPressable is just the renaming of Swipeable and would solve what you're saying here because it's identifying this component is now pressable too.

and,

  1. can I rename Swipable to SwipableWithPressable then? That makes sense, and that comment explains why swiping is only available for iOS/Android

At this point I think it's better to write multiple Attachment Carousel Action Listener, each having platform specific code. This way one can use swipeable for mobile and another can use pressable for web. I think this is what Santhosh was suggesting too, correct me if I'm wrong. Plus I still don't get why pressable is in swipeable. I don't quite understand why using panresponder means we have to have pressable in swipeable. Maybe if you can explain this more?

  1. is there an example of this somewhere else in the app so I can understand better what the ask is here?

Sure does this help, basically, if you look at any of our index.native.js files you can see how we write platform-specific codes. Eg: web, mobile.

Santhosh-Sellavel commented 1 year ago

@marcaaron

PR is not reviewed completely yet this discussion occurred from the initial review itself.

The interaction requirements for this issue,

On desktop/Web: The arrow can be clicked to navigate to the next attachment preview, or the left/right arrow keys on the keyboard can be used On mobile/mWeb: The arrow can be tapped or the member can swipe left/right on the preview to navigate to the next attachment preview depending on the direction On desktop/Web, the arrows are visible on hover. On mobile/mWeb, a single tap on the image hides/shows the arrows.

To achieve this we need to listen,

Now what @JediWattson had done is modified the SwipeableView, to add more swipe functionalities currently, we have only swipeDown action there, also for SwibeableView is available only for native platforms.

So I requested changes to modify it in a way, that keeps swipe-related & pressable interactions separate.

@JediWattson says they have a problem keeping it separate as some interactions don't work. Didn't get a clear idea on why even after follow-ups.

So I suggested two options,

But so far @JediWattson suggesting is renaming SwipeableView to SwipeableWithPressable or modifying SwipeableView

cc: @chiragsalian