-
Notifications
You must be signed in to change notification settings - Fork 58
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
Issue/715 request cancel image upload #736
Conversation
Release v1.1.0
…to listen to in-progress image upload blocks being deleted
…a upload to be cancelled
Hey @mzorz, thanks for the explanation. I am sharing your thoughts that this approach could be better. Not sure if that it's a good approach ( from architecture side ) that Maybe cleaner way would be to provide (pass delete/remove action) event from Probably it would be good to hear from @Tug if he has something on his mind about this specific problem ? |
Agreed! Maybe we can use the filter to only plant the flag that it was the
Great idea, thank you for proposing it! I'd also love to hear any hints from @Tug :) |
… and returns true, the upload cancellation will be requested
@marecar3 I moved the bridge-specific code to the
This kept me wondering, I think passing a prop down to the Component will make it re-render and ideally that's something we would want to avoid (especially since we are going to the redux store to remove it right after); I think the change suggested in the commit above makes the logic sligthly better (or easier to understand / separating responsibilities) - still open to suggestions as to how it'd be best 👍 |
Filters in WordPress eco-system are functions used to modify and pass data through. (Passing data through filters allows developers to modify the default behavior of a specific function.) I guess in this case we need to use an Action instead, and add the mediaID to the payload of the action. WordPress actions are used to execute a specific code at a specific event. |
🙇 thank you @daniloercoli ! Will go that way 👍 |
Implemented the |
Sorry for the delay, I had a quick look and I must admit I'm not a fan of having this logic in BlockHolder, but I don't think we have much choice at the moment. I guess a better alternative would be to design a better bridge that can handle setting/removing hooks from the native code, this way we could have the hook set when the upload starts until it finishes and be notified from gb when the component is unmounted. |
Thanks for chiming in @Tug ! Yes I agree this is not ideal but does the job for now.
Definitely that'd be closer to ideal! One problem posed by having callback references in both worlds is that these reside in memory, so it would be best to be able to be able to recover callbacks / hooks on state change, for example in Aztec we can recover media items by marking them in content itself. We don't have such "metadata" in Gutenberg (or do we?). Anyway, certainly matter of lengthier discussion 👍 So, ready for another round @marecar3 🙇 |
onRemoveBlockCheckUpload = ( mediaId: number ) => { | ||
if ( hasAction( 'blocks.onRemoveBlockCheckUpload' ) ) { | ||
// now remove the action as it's a one-shot use and won't be needed anymore | ||
removeAction( 'blocks.onRemoveBlockCheckUpload', 'gutenberg-mobile/blocks' ); |
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.
Maybe it would be a good option to put those two arguments in some constants so that we can reuse them in other parts of the code?
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.
I was looking into the Gutenberg code for other addAction
/ removeAction
calls elsewhere and they seem to have the text right there so, followed that. Does that make sense?
Adding a note here as well - I also considered using an instance ID as seen in that piece of code before to make sure to have different actions for each of the blocks, but given it all happens in a brief amount of time (from the time the user presses the trash icon making the action be added, and then when the component gets unmounted where the action gets removed), it didn't make sense to add the complexity of having to add a props to pass down to the component (which essentially would make it re-render and then again, make the bridge change unnecessary at the block holder level).
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.
Well if someone tries to change action name, he would need to change it on 3 different places. I think that it's a good practice to have one constant which will hold the name of the action?
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.
I think that it's a good practice
sure thing - don't get me wrong, I totally understand what you're saying in terms of how having a constant is useful to avoid having the text modified and introduce bugs this way 😅 👍.
The thing (I left a comment about it in the other PR) is we would need to define it in gutenberg-mobile
(where block holder lives) and import it in the gutenberg repo (where the Image component lives) making the block holder even aware of the Image component, which seems off. If we do it the other way around then we make the Image component aware of something defined in gutenberg-mobile block-holder. Both ways seem strange to me 🤔 .
Perhaps I'm missing something, can you explain how would you do it? thanks in advance for your time and patience 🙇
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.
Ah ok thanks for the explanation, I thought that we are not on the same page regarding what should be done. Ok in that case :)
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.
Excellent! Glad it's sorted out 😄 - do you think this is good to be approved then @marecar3?
@mzorz I'm implementing the behaviour in iOS using this PR/branch. |
@Tug one question, the component being umounted it doesn't mean the block is deleted right? I was thinking couldn't we send an onDelete event from the block holder when the delete button is pressed? the onDelete event will have the block Id , and the image block could listen to it, so if they receive the event and it belongs to them they send cancelUpload message to the bridge? or the event will arrive too late to them? |
Yeah, I am sharing @SergioEstevao thoughts as it could be a cleaner solution to send an event from |
hi @SergioEstevao @marecar3 !
Unfortunately AFAIU the Block does not have the And then this other problem:
I think that's the case, as we are first removing the block and then we wuold be sending the event. We could try otherwise but AFAIU there's no guarantee both events will be serialized (we can't assume order will be respected) |
Forgot to add this @SergioEstevao :
That's correct, and that's the purpose of adding the Not a fan of deriving this fact from that flag, but... |
Yeah I don't think it would improve the code in this case, you'd have the Image block listen for an event that's defined outside of gutenberg. The way it's designed at the moment, Image emits its own event and it can be caught (or ignored) from anywhere, pretty neat. In the future, I'd like to see the hook system hard wired to the native app, so you could do something like: uploadImageFile( mediaFile );
GutenbergEditorFragment.setGutenbergActionListener('blocks.onRemoveBlockCheckUpload', 'gutenberg-mobile/blocks', new GutenbergActionListener() {
@Override
public boolean onAction(Object data) {
int mediaId = (int) data;
mOnMediaLibraryButtonListener.onCancelUploadForMediaDueToDeletedBlock(mediaId);
}
}); |
That'd be great! Opening up for extensibility sounds good 👍 |
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.
LGTM!
Fixes #715
Gutenberg PR WordPress/gutenberg#14391
WPAndroid PR wordpress-mobile/WordPress-Android#9402
Until now, when the user started uploading an image in an image block, the image will continue to upload until finished doing so regardless of the block containing such image being deleted.
This PR adds a new method to the bridge interface to request the host app to handle an in-progress upload cancellation.
The bridge methods added are self-explained as they follow the same structure of what we already have in place, but the way we detect a block being deleted might use some further explanation:
when the user taps on the trash icon, we detect that event without ambiguity in the Toolbar handler. It is at this point that we
add a filteradd an action that will be called later. Thefilteraction is added here to handle the situation, but is needed to be invoked from the component that has knowledge of themediaId
corresponding to the in-progress upload.when the Image component that is part of this
ImageBlock
is about to be unmounted, we make use of the action. If thefilteraction exists, it will be executed and is passed the needed information (mediaid
and whether it's an in progress upload or not).the
filteraction then checks that the mediaId exists and is an in-progress upload and signals the host app to cancel this upload by means of the bridge.Finally, the
filteraction is removed as it no longer serves a purpose. You can see thisfilteraction is added and removed in a brief amount of time.I'm not 100% sold on this approach so open to suggestions, but I couldn't find a better way to:
Note: The iOS side of the bridge still needs to be implemented
To test: