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

IImageSourceHandler impl #70

Closed
wants to merge 2 commits into from
Closed

IImageSourceHandler impl #70

wants to merge 2 commits into from

Conversation

ysmoradi
Copy link
Contributor

@ysmoradi ysmoradi commented Aug 4, 2020

This closes #69
To test it simply add followings to MainPage.xaml

NavigationPage.TitleIconImageSource="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"

This uses Glidex.forms image handler's method which accepts ImageSource only for UriImageSources

We need another issue in XF, because it calls our handler's method for UriImageSources but it doesn't call the same method for FileImageSources and StreamImageSources )-:

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 4, 2020

Please accept this PR because of followings:

1- I know this works for UriImageSources and it's not working for other image source types, but UriImageSource is more important because it needs authentication in some scenarios and if we pass custom IGlideHandler which adds required request headers, at least everything works (Image and ImageView and UriImageSource will gets handled by Glide and StreamImageSource and FileImageSource will gets handled by XF which is not high performant, but at least works!)

2- After XF fixes issues described here, our ImageSourceHandler will handle all ImageSource types without releasing new version of glidex.forms which improves xf apps performance even more!

@jonathanpeppers
Copy link
Owner

@ysmoradi Why can't Xamarin.Forms just always call IImageViewHandler.LoadImageAsync? If it can, let's change Xamarin.Forms instead?

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 4, 2020

@ysmoradi Why can't Xamarin.Forms just always call IImageViewHandler.LoadImageAsync? If it can, let's change Xamarin.Forms instead?

From this perspective, IImageSourceHandler interface is useless.
They've introduced two interfaces for two different reasons

IImageViewHandler => For Image & ImageButtons
IImageSourceHandlers => For ImageSources of background, icons, toolbar item etc.

But, as I'm not completly in and have no idea for all historical descicions, I'm happy to ask them about this.
I just took a look at FFImageLoading handler which is implementing IImageSourceHandler only and I think it's fine to implement IImageSourceHandler.

I'll open an issue in xamarin forms tomorrow

Thanks for paying attention

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 6, 2020

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 7, 2020

@roubachof Do you have any idea about this?
It seems you've implemented IImageSourceHandler only
Thanks in advance

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 10, 2020

@daniel-luberda Do you have any idea about this?
It seems you've implemented both IImageSourceHandler and IImageViewHandler
Thanks in advance

@ysmoradi
Copy link
Contributor Author

@jonathanpeppers I've submitted an issue to XF
I've also tried to contact with FFImageLoading & Nuke maintainers
No luck!
Could you please merge this PR, so we can make UriImageSources work?
As I said, whenever XF team supports IImageSourceHandler completely for non Image/ImageButton images (such as Page's icon etc), our code will remain unchanged.
I'd rather the idea to only have IImageViewHandler, but this needs efforts from XF team, and it seems they've other priorities )":
Thanks in advance

@jonathanpeppers
Copy link
Owner

@ysmoradi did you send a PR to Xamarin.Forms to fix it?

@ysmoradi
Copy link
Contributor Author

ysmoradi commented Aug 12, 2020

@jonathanpeppers I've submitted an issue. I'm fine with PR too, but first of all, someone should give me basic understanding on XF image handling structure!

It's totally unclear! Look at GlideX.Forms | Nuke | FFImageLoading:
One has implemented IImageViewHandler only!
Another one has implemented IImageSourceHandler only!
Another one has implemented both!

I'm an active person on GitHub as you can see on my profile, and I've submitted lots of PRs to several repositories. But I can't reverse engineering entire codes to submit a PR, and at the end someone says "hey! your assumptions were wrong!"

A good PR comes with an good issue first!

@ysmoradi
Copy link
Contributor Author

I see a few details are provided in my issue, I try to submit a PR, but can't give my word

jonathanpeppers added a commit that referenced this pull request Sep 25, 2020
Context: #70

Multiple things are cleaned up in #70, I'm pulling over the parts that make sense.

* Use `MemoryStream.CopyToAsync()`

Co-authored-by: Yaser Moradi <ysmoradi@outlook.com>
jonathanpeppers added a commit that referenced this pull request Sep 25, 2020
if (builder is null) {
return null;
} else {
var result = await builder.Submit ().GetAsync ();
Copy link
Owner

Choose a reason for hiding this comment

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

This isn't the proper way to await an IFuture with cancellation. This should be something like:

Suggested change
var result = await builder.Submit ().GetAsync ();
var future = builder.Submit ();
var result = await Task.Run (() => future.Get (), token);

return null;
} else {
var result = await builder.Submit ().GetAsync ();
return (Bitmap) result;
Copy link
Owner

Choose a reason for hiding this comment

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

This code throws InvalidCastException because result is BitmapDrawable!

Suggested change
return (Bitmap) result;
if (result is BitmapDrawable drawable)
return drawable.Bitmap;

Comment on lines +106 to +138
switch (source) {
case FileImageSource fileSource:
var fileName = fileSource.File;
var drawable = ResourceManager.GetDrawableByName (fileName);
if (drawable != 0) {
Forms.Debug ("Loading `{0}` as an Android resource", fileName);
builder = request.AsBitmap ().Load (drawable);
} else {
Forms.Debug ("Loading `{0}` from disk", fileName);
builder = request.AsBitmap ().Load (fileName);
}
break;

case UriImageSource uriSource:
var url = uriSource.Uri.OriginalString;
Forms.Debug ("Loading `{0}` as a web URL", url);
builder = request.AsBitmap ().Load (url);
break;

case StreamImageSource streamSource:
Forms.Debug ("Loading `{0}` as a byte[]. Consider using `AndroidResource` instead, as it would be more performant", nameof (StreamImageSource));
using (var memoryStream = new MemoryStream ())
using (var stream = await streamSource.Stream (token)) {
if (token.IsCancellationRequested || stream == null)
return null;
if (!IsActivityAlive (context, source)) {
return null;
}
await stream.CopyToAsync (memoryStream, token);
builder = request.AsBitmap ().Load (memoryStream.ToArray ());
}
break;
}
Copy link
Owner

Choose a reason for hiding this comment

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

This long switch statement is a lot of copy-paste. This should be refactored out into smaller methods that the other LoadViaGlide() method can share.

@@ -19,5 +19,6 @@ public interface IGlideHandler
/// <param name="token">The CancellationToken if you need it</param>
/// <returns>True if the image was handled. Return false if you need the image to be cleared for you.</returns>
bool Build (ImageView imageView, ImageSource source, RequestBuilder builder, CancellationToken token);
void Build (ImageSource source, RequestBuilder builder, CancellationToken token);
Copy link
Owner

Choose a reason for hiding this comment

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

This should be a C# 8 default interface method, so that existing IGlideHandler implementations won't get a compilation error.

This should also use ref RequestBuilder builder so that IGlideHandler's can set the builder to null if desired.


public async Task<Bitmap> LoadImageAsync (ImageSource source, Context context, CancellationToken token = default)
{
Forms.Debug ("IImageViewHandler of type `{0}`, `{1}` called.", GetType (), nameof (LoadImageAsync));
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
Forms.Debug ("IImageViewHandler of type `{0}`, `{1}` called.", GetType (), nameof (LoadImageAsync));
Forms.Debug ("IImageSourceHandler of type `{0}`, `{1}` called.", GetType (), nameof (LoadImageAsync));

@jonathanpeppers
Copy link
Owner

Closing in favor of #77, let me know if those changes will work for you.

@ysmoradi
Copy link
Contributor Author

Thanks so much
We've switched from TabbedPage's icon to custom views, but I can test it for sure
Is there any pre-release for this or I've to build it manually? (I can do that anyway)

@jonathanpeppers
Copy link
Owner

There are .nupkg files on CI here: https://jopepper.visualstudio.com/Jon%20Peppers%20OSS/_build/results?buildId=502&view=artifacts&type=publishedArtifacts

I think I want to have a fix for #71 and VisualStateManager before doing another release.

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.

TabbedPage.ToolbarItems IconImageSource with Uri stop working after installing glidex.forms nuget package!
2 participants