-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Show Loader when adding Workspace Edit #4801
Show Loader when adding Workspace Edit #4801
Conversation
@roryabraham I've raised a draft PR. Need to clarify a couple of things:
|
If there's a form error or API error, we should display a user-friendly error message. A success message would be good too, maybe using Growl or some other visual indication.
I'm not sure. I'll defer to @Expensify/design here
I assume you meant item 2 of your list, not the PR linked in the comment. I would think yes 🟢, but again will defer to @Expensify/design here. Lastly, I'll warn you that what I see in this PR so far violates the Expensify/App Philosophy, specifically |
Thanks for the clarification @roryabraham.
I'll put in a message.
I'll wait for the comments from the design team.
Yes. I meant point# 2 from my list. It seems GH linked to the PR due to #.
Thanks for highlighting. I only went ahead with the approach because the same file had the following line:
So should I store these loading props to Onyx? |
For now, I believe this is the approach we'll want to take. |
Hi Team, any updates on this on the design front? |
…space-edit-loader
@mananjadhav In lieu of input from the design team, I'm going to go ahead and 🟢 both of these proposed changes:
And
|
Noted. Thanks for the response @roryabraham. Will update the PR. |
@roryabraham I've updated the PR with the following changes:
I haven't added Growl on success because immediately after the policy is saved, we redirect to workspace card with updated info. Let me know if you still feel we should add a Growl message for success. |
…space-edit-loader
@mananjadhav No growl on success sounds fine to me 👍 |
this.setState({previewAvatarURL: image.uri}); | ||
|
||
// Store the upload avatar promise so we can wait for it to finish before updating the policy | ||
this.uploadAvatarPromise = uploadAvatar(image).then(url => new Promise((resolve) => { | ||
updateLocalPolicyValues(this.props.policy.id, {isAvatarUploading: false}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can prevent repeating this line by putting in in an always()
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate this please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do a chain like
uploadAvatar(image).then(<stuff>).catch(<stuff>).always(updateLocalPolicyValues(this.props.policy.id, {isAvatarUploading: false});)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Sure. Will update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@stitesExpensify @roryabraham I've updated the PR. Additionally, I've also modified the size of the indicator to get it closed to the Avatar and adjusted the icon size. Screen.Recording.2021-09-03.at.1.23.26.AM.mov |
PR updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mananjadhav, looks good. If you wanted to update AvatarWithIndicator to use Animated.loop for consistency and a small performance boost that would be great!
Someday I hope we can switch over to using Reanimated instead of React Native's Animated. It comes with much better animation performance and in my opinion a simpler API. But that's a conversation for another day 😄
I’ll update the AvatarWithIndicator too. Yeah I’ve worked on Reanimated v1. But I’ve heard Reanimated V2 last year reduces a lot of boilerplate code too. |
… in AvatarIndicator
PR updated with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I apologize for not noticing these things earlier, but I have a few more comments:
Start both animations in parallel
I just noticed that there are two animations that are basically happening in parallel, so we should just use Animated.parallel
, something like this:
/**
* Start Animation for Indicator
*
* @memberof AvatarWithImagePicker
*/
start() {
Animated.loop(
Animated.parallel([
Animated.timing(this.rotate, {
toValue: 1,
duration: 2000,
easing: Easing.linear,
isInteraction: false,
useNativeDriver: true,
}),
Animated.spring(this.scale, {
toValue: 1.666,
tension: 1,
isInteraction: false,
useNativeDriver: true,
}),
]),
).start();
}
/**
* Stop Animation for Indicator
*
* @memberof AvatarWithImagePicker
*/
stop() {
Animated.spring(this.scale, {
toValue: 1,
tension: 1,
isInteraction: false,
useNativeDriver: true,
}).start(() => {
this.rotate.resetAnimation();
this.scale.resetAnimation();
this.rotate.setValue(0);
});
}
DRY up animation code
To do this, I think we should:
-
Create a new file at
src/styles/animations/SpinningIndicatorAnimation.js
-
That file should export a single class called
SpinningIndicatorAnimation
:import {Animated, Easing} from 'react-native'; class SpinningIndicatorAnimation { constructor() { this.rotate = new Animated.Value(0); this.scale = new Animated.Value(1); this.start = this.start.bind(this); this.stop = this.stop.bind(this); this.getSyncingStyles = this.getSyncingStyles.bind(this); } /** * Start Animation for Indicator * * @memberof AvatarWithImagePicker */ start() { Animated.loop( Animated.parallel([ Animated.timing(this.rotate, { toValue: 1, duration: 2000, easing: Easing.linear, isInteraction: false, useNativeDriver: true, }), Animated.spring(this.scale, { toValue: 1.666, tension: 1, isInteraction: false, useNativeDriver: true, }), ]), ).start(); } /** * Stop Animation for Indicator * * @memberof AvatarWithImagePicker */ stop() { Animated.spring(this.scale, { toValue: 1, tension: 1, isInteraction: false, useNativeDriver: true, }).start(() => { this.rotate.resetAnimation(); this.scale.resetAnimation(); this.rotate.setValue(0); }); } /** * Get Indicator Styles while animating * * @returns {Object} */ getSyncingStyles() { return { transform: [{ rotate: this.rotate.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '-360deg'], }), }, { scale: this.scale, }], }; } } export default SpinningIndicatorAnimation;
-
Then both
AvatarWithImagePicker
andAvatarWithIndicator
can just do:constructor(props) { super(props); this.animation = new SpinningIndicatorAnimation(); ... ... }
And then replace all uses of the animation methods with just
this.animation.start()
,this.animation.stop()
, orthis.animation.getSyncingStyles
.
Scaling issue
Lastly, I'm looking at the screenshots provided in the PR description, and it doesn't seem like the indicator is getting bigger when the animation starts. Instead, it actually looks like it's getting smaller and is outside the avatar circle.
Okay, I'll check the Animation updates and implement them.
I had updated this comment but not the PR description. Let me update it in the PR description. |
@roryabraham There's a comment in
|
@roryabraham I am updating the If I add a couple of messages in Offline mode, and then disable throttling, the Screen.Recording.2021-09-08.at.3.01.11.AM.movI am guessing it is because after and a quick, FYI, the following class (not using Animated.parallel) works fine without any issues.
|
@roryabraham Did you get a chance to look at my comments above? Meanwhile I'll resolve the conflicts. |
@mananjadhav Regarding this comment:
is there some observable problem that occurs when you use We can skip the use of |
Well, I didn't find any issue on the emulator but I haven't been able to check on a real Android device. Let me see if I can test and accordingly update the PR. |
…space-edit-loader # Conflicts: # src/libs/actions/PersonalDetails.js
@roryabraham PR updated. I checked on a real Android device and it worked fine. So I am guessing it shouldn't be a problem. I've also updated the videos with the latest testing of the indicator closer to the image with increased size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks for making all those changes, this is looking great!
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by @roryabraham in version: 1.0.95-2 🚀
|
This has been deployed to production and is now subject to a 7-day regression period. |
🚀 Deployed to production by @roryabraham in version: 1.0.96-0 🚀
|
Details
isUploading
flag to AvatarWithImagePicker with uploadIndicatorFixed Issues
$ #4487
Tests
QA Steps
Tested On
Screenshots
Web
v1
https://user-images.githubusercontent.com/3069065/131385161-e70fc702-9ef7-4515-bacd-86ac728d5c03.mp4
Updated
https://user-images.githubusercontent.com/3069065/132609914-524caa8b-ead7-4ec1-97c4-6288d6575dd7.mp4
Mobile Web
v1
https://user-images.githubusercontent.com/3069065/131384341-a5d4da09-e5e7-4807-8cf9-3724c797d2c6.mp4
Updated
https://user-images.githubusercontent.com/3069065/132610024-500c89e5-83d0-4c05-91c6-61688fd223c1.mp4
Desktop
v1
https://user-images.githubusercontent.com/3069065/131384466-c488f178-844d-471b-b9b6-9ca68fa5de65.mp4
Updated
https://user-images.githubusercontent.com/3069065/132610083-e81b6468-c976-4ec2-83cc-f7932de947f3.mp4
iOS
v1
https://user-images.githubusercontent.com/3069065/131384510-c38701d8-74ae-49c2-a116-e50e2fdc19a5.mp4
Updated
https://user-images.githubusercontent.com/3069065/132610283-1a851e62-640f-496d-86d2-83376a6e7125.mp4
Android
v1
https://user-images.githubusercontent.com/3069065/131384679-c6b796b0-f49e-4e76-8d48-3991d2cac241.mp4
Updated
https://user-images.githubusercontent.com/3069065/132610438-29e4b86c-81aa-45fc-ad41-7d77e0ba6c92.mp4