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

Animations for the IOU flow #4070

Merged
merged 22 commits into from
Nov 17, 2021
Merged

Animations for the IOU flow #4070

merged 22 commits into from
Nov 17, 2021

Conversation

rdjuric
Copy link
Contributor

@rdjuric rdjuric commented Jul 15, 2021

Details

Wraps the components of our IOUModal steps in a Animatable.View. Pass a different animation type depending on whether we're increasing or decreasing our currentStepIndex.

Fixed Issues

$ #3921

Tests

QA Steps

  1. Request Money (LHN or Composer) or Split a bill
  2. The flow should be animated

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

web.mov

Mobile Web

mWeb.mp4

Desktop

desktop.mov

iOS

iOS.mp4

Android

android.mp4

@rdjuric rdjuric marked this pull request as ready for review July 15, 2021 15:48
@rdjuric rdjuric requested a review from a team as a code owner July 15, 2021 15:48
@MelvinBot MelvinBot requested review from chiragsalian and removed request for a team July 15, 2021 15:48
@rdjuric
Copy link
Contributor Author

rdjuric commented Jul 15, 2021

Ready for review @chiragsalian!

Copy link
Contributor

@chiragsalian chiragsalian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM and works well too. Just left some minor style change comments.

getAnimation() {
if (this.state.previousStepIndex < this.state.currentStepIndex) {
return 'slideInRight';
} if (this.state.previousStepIndex > this.state.currentStepIndex) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this if to the next line. No reason for it to be on the same line since its not an else-if

onStepComplete={props.onStepComplete}
participants={props.participants}
onAddParticipants={props.onAddParticipants}
/>
)
: (

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unnecessary line break

onStepComplete={props.onStepComplete}
onAddParticipants={props.onAddParticipants}
/>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, let's remove unnecessary line break.

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @rdjuric, the animations are looking good but I have a couple of suggestions for improvements:

  • It is noticeable that the current page disappears when moving to the next page. Could you try to animate the current page out, at the same time that we animate the new page in? This is how it would work natively, so it would be great to match this. It should look we're sliding over to the next page ideally (like this)
  • Also, it would be great to make the solution a bit more generic so that we can apply the animations to other Modal-with-steps components. Maybe we could wrap the Steps in a new Component (<ModalStep> or <AnimatedStep>?) which would help simplify further usage. It would also prevent the need for defining the animation props (duration/style) in each component which is unecessary.
IOUAnimationTransition.mov

@rdjuric
Copy link
Contributor Author

rdjuric commented Jul 20, 2021

Thanks for the feedback, @Julesssss

Could you try to animate the current page out, at the same time that we animate the new page in?

This is a bit hard to do here since we're not really changing screens, but just mounting/unmounting components. I modified our logic a bit to only unmount the previous step after we animate it "going away". This way when we click on the next button we first animate the current step out, and then the new step in.

I didn't really like the end result (there's a blank screen for a few ms while the next step renders after the previous one was animated out), but let me know what you think:

For some reason theIOUParticipantsPage is refusing to slideOutRight too, but I'll think of something if we prefer this way.

web.mov

Maybe we could wrap the Steps in a new Component (<ModalStep> or <AnimatedStep>?) which would help simplify further usage.

This was my first try, but wrapping the whole step in the Animatable.View was messing the styling and just didn't work with some components (like our TextInput that we auto-focus on mount).

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah I agree this isn't ideal with the blank screen in the middle.

Honestly, I'm not sure these changes would be a positive improvement without native-looking animations. I believe it should possible, as the react-navigation library is able to achieve it. Here's an example showing it can be achieved, I think the final step would be to find a way to hide the tabs: https://snack.expo.dev/iRsGTO-9h

Please let me know what you think of this solution. An alternative might be to look at the react-navigation code and copy their implementation.

@rdjuric
Copy link
Contributor Author

rdjuric commented Jul 22, 2021

Hey @Julesssss

Honestly, I'm not sure these changes would be a positive improvement without native-looking animations.

I understand your point! But I also think that I did exactly what was asked/what I proposed on the issue: animated our steps in one direction (slideInLeft) when going forward, and in another (slideInRight) when going backwards.

It's natural that we get a better idea of what we (don't) want when we see one implementation in action, but I feel like the changes you suggest are more related to our logic/navigation system than with the animations.

Here's an example showing it can be achieved, I think the final step would be to find a way to hide the tabs: https://snack.expo.dev/iRsGTO-9h

Please let me know what you think of this solution. An alternative might be to look at the react-navigation code and copy their implementation.

Thanks for the example! Is there any reason we aren't making our steps Screens instead of conditionally rendered components? We also do this in our SignInPage. It feels like we're trying to mimic a Navigator (header, back/close buttons, changing screens, transition animations) without using one, and I think we're hitting the limits of this implementation here.

I think we can:

  1. Change our IOUModal steps to be screens of a navigator, maybe a TabNavigator with tabBarVisibile={false}.
  2. Hack our current implementation to mimic a Navigator more closely?

For me it feels like 1. is a way better solution, and 2. just gets us deeper into the idea of "mimicking a navigator without using one" without (I suppose) any good reason.

Let me know what you think and if you agree this is a different issue.

@rdjuric rdjuric requested a review from Julesssss July 22, 2021 14:50
@Julesssss
Copy link
Contributor

I also think that I did exactly what was asked/what I proposed on the issue

Oh for sure, no matter the decision we end up with here, we'll payout for this work. I should have made the desire for native-like animations clear in the initial requirements, my bad.

Is there any reason we aren't making our steps Screens instead of conditionally rendered components?

Yeah, my original intention was to switch to Screens (once react-navigation implemented), but I believe this changed when we realized that this would let web users freely navigate between steps.

My preference would be to go back to your initial solution and to make it more generic and reusable, but let's see if @Expensify/design have a preference between:

@chiragsalian
Copy link
Contributor

Bump @Expensify/design, on the question asked by Jules.

@shawnborton
Copy link
Contributor

I'm a little behind on where this issue stands, but I thought that the whole rightDocked view (header included) would animate from step to step. Right now it feels like just the inner content (below the header) is animating.

@Julesssss
Copy link
Contributor

I'm a little behind on where this issue stands, but I thought that the whole rightDocked view (header included) would animate from step to step. Right now it feels like just the inner content (below the header) is animating.

Oh, interesting. I would have thought the opposite. To me, that gives the impression that the steps are individual tasks, rather than a collection of steps with the goal of 'Sending a IOU Request'. The architecture of the Modal also doesn't allow for that animation, because the Header is a separate component which sits above the content -- this isn't impossible, it just seems a bit odd IMO.

I can't point to a specific rule (Material Design peer transitions is the closest I can find), but I think it goes against the typical step-flow mobile UX because the Header (Toolbar/ActionBar) sits above the page hierarchically.

If we were navigating to a new Modal (to add a bank account, for example), then I would totally expect the Header to animate out too -- but because we treat the steps as part of a single Modal, I don't think it makes sense personally.

@rdjuric
Copy link
Contributor Author

rdjuric commented Jul 26, 2021

It should be possible to animate the header too.

If we were navigating to a new Modal (to add a bank account, for example), then I would totally expect the Header to animate out too -- but because we treat the steps as part of a single Modal, I don't think it makes sense personally.

I have the same impression. Animating only the content gives me the feeling of navigating through the steps of a page, if the header is also animated, I feel more like I'm navigating through pages.

@rdjuric
Copy link
Contributor Author

rdjuric commented Jul 28, 2021

Any updates here @shawnborton?

@shawnborton
Copy link
Contributor

I see your point, so for that sake, it seems like the first screen would animate out entirely as the header changes from screen 1 to screen 2. However, from screen 2 to screen 3, it seems like the header remains the same so I could see an argument to only animate the content there. Does that make sense?

@Julesssss
Copy link
Contributor

it seems like the first screen would animate out entirely as the header changes from screen 1 to screen 2. However, from screen 2 to screen 3, it seems like the header remains the same so I could see an argument to only animate the content there. Does that make sense?

I disagree with this too. The fact that the header text changes shouldn't change the steps relationship. The three steps are a group of siblings and sit at the same level hierarchically. This is what allows us to share the state between them architecturally, because the state lives at the IOUModal level (represented by the Header).

I'm pushing back against this because in my opinion, any other navigation than what was implemented here goes against typical mobile UX (because the transition does not match the app navigational hierarchy). If each of the steps was instead an individual Modal, it would totally make sense to animate the full page (and header) out, but this is problematic because this isn't how the stepped-flow was implemented.

This is the best example I can find of the stepped-flow (minus the tabs):

peer-transition.mp4

Comment on lines 225 to 227
<View style={this.props.listContainerStyles}>
<View
style={[...this.props.listContainerStyles]}
>
Copy link
Contributor

@Julesssss Julesssss Sep 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just noticed this. This change seems unnecessary too?

if (this.state.previousStepIndex > this.state.currentStepIndex) {
return 'out';
}
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should return null, the Component default is in and this would override it. Let's make in the default here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last return is only called when previousStepIndex === currentStepIndex, we don't want the default in since that would mean the first step (once we open the modal) would animate.

I think we can put this in a (this.state.previousStepIndex === this.state.currentStepIndex) conditional instead? It's the same logic but should be easier to understand.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point. Yeah, I think that would clear it up a bit. Maybe add a comment too.

@rdjuric
Copy link
Contributor Author

rdjuric commented Sep 15, 2021

PR updated @Julesssss. Thanks for all the help.

chiragsalian
chiragsalian previously approved these changes Sep 16, 2021
Copy link
Contributor

@chiragsalian chiragsalian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me and works well too. Leaving it to @Julesssss for final review.

@chiragsalian
Copy link
Contributor

The issue is labeled n6-hold so I'm going to update the title to reflect the same so that we don't accidentally merge it.

@chiragsalian chiragsalian changed the title Animations for the IOU flow [HOLD] Animations for the IOU flow Sep 16, 2021
Julesssss
Julesssss previously approved these changes Sep 17, 2021
@Julesssss Julesssss changed the title [HOLD] Animations for the IOU flow [N6-HOLD] Animations for the IOU flow Sep 17, 2021
@chiragsalian chiragsalian changed the title [N6-HOLD] Animations for the IOU flow [HOLD] Animations for the IOU flow Sep 17, 2021
@chiragsalian
Copy link
Contributor

As discussed 1:1, placed the title back to [HOLD] so that merging is blocked as GH doesn't recognize [N6-HOLD] to block merging.

@Julesssss Julesssss changed the title [HOLD] Animations for the IOU flow Animations for the IOU flow Oct 18, 2021
@Julesssss
Copy link
Contributor

Hi @rdjuric, sorry for the delay, we're now merging PR's again (there is a bonus payment for this delay btw). Would you mind updating the branch once more to resolve the conflict?

@chiragsalian
Copy link
Contributor

@rdjuric, friendly bump. Any update here?

@chiragsalian chiragsalian dismissed stale reviews from Julesssss and themself via 7ab444b November 17, 2021 00:42
@chiragsalian chiragsalian self-assigned this Nov 17, 2021
@chiragsalian
Copy link
Contributor

Looks like there hasn't been an update here in a while so i just took over to push it to the end.
Resolved conflicts, updated with main, retested and GH action tests pass. All yours @Julesssss to review/merge.

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests well on Web, iOS, Android & mWeb. The animation speed feels a bit slow to me, but we can change this later if others agree.

@Julesssss Julesssss merged commit 96ba12d into Expensify:main Nov 17, 2021
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by @Julesssss in version: 1.1.15-18 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

🚀 Deployed to production by @roryabraham in version: 1.1.16-10 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants