MVVMCross Downloadcache - ProgressView during loading - mvvmcross

I'm currently testing the downloadcache and this really looks great.
I have some questions regarding this plugin (I'm pretty new to C# and don't understand the full source code of the plugin):
1) ProgressView
I would like to show a progressview on the image until it has been loaded.
To do that, I need to be notified when the image is loaded.
In the "MvxImageViewLoader" I see there is an Action "afterImageChangeAction" (null by default).
However, I don't understand if and how I can access that Action from "MvxImageView"?
(how to set it)
2) Don't load old image
When using Tables or Cellectionviews in iOS, it's important to check if the URL has been changed before setting the image (because iOS reuses the objects). I looked at the source code of the downloadcache and I don't see this check.
However, in the "MvxDynamicImageHelper.cs" class, I see that when a new URL is set, it calls "ClearCurrentHttpImageRequest();" which removes the "update" Events.
So I assume this is enough to prevent that an image is set to the wrong UIImageView?
3) ImageCache size in (mega)bytes
The ImageCache does not have a property to define the mamiximum size (megabytes for example) of the persistent image store (on the HD). I prefer to use a maximum size in (mega)bytes instead of a maximum amount of files because the user will care more how much space an app takes instead of how many files are stored by the app.
I assume the easiest for me is to define a "TimeSpan PeriodSaveInterval" independent from the one in MvxFileDownloadCache to just check the size of the folder defined for the Image Cache or any other recommendations?
Is it dangerous for performance to scan the folder and calculate the size of all the images in a folder?
Regards,
Matt

1) ProgressView
I would like to show a progressview on the image until it has been loaded. To do that, I need to be notified when the image is loaded.
There is a DefaultImagePath which provides the path of an image that should be shown during loading.
But if you need a dynamic animation or other custom view, then afterImageChangeAction can be used
As you've seen, you can't do this in MvxImageView - the Action wasn't really a suitable candidate to be a bindable property so it wasn't exposed as a property.
However, you can:
do this by using MvxImageViewLoader directly in your View - there are several samples of using this in views in the N+1 samples - https://github.com/slodge/NPlus1DaysOfMvvmCross/search?q=MvxImageViewLoader
do this by creating your own MyImageView class - it's not a big class to write - https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxImageView.cs
As an alternative to using the Action callback, you can also inherit from MvxBaseImageViewLoader<T> and provide an override for the ImageHelperOnImageChanged method - see https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Binding/Views/MvxBaseImageViewLoader.cs#L49
2) Don't load old image
3) ImageCache size in (mega)bytes
The interface-driven and plugin structure of MvvmCross is defined to allow you to implement alternatives.
In the case of loading images from HTTP, there are many alternatives - you don't have to use the MvvmCross download cache for image loading.
The only docs available for the download cache plugin currently is https://github.com/slodge/MvvmCross/wiki/MvvmCross-plugins#downloadcache
For Android, some suggestions for alternative implementations are listed in: https://github.com/slodge/MvvmCross/issues/416
For iOS, it may be useful to read https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html including the section on <Application_Home>/Library/Caches

I know Stuart already provided an excellent answer. But what I did, when I needed the exact same feature, was to subclass MvxImageView and override the UIImageView.Image property. When the image is set I fire an event which is caught by the viewcontroller.

Related

Is it possible to customize how image is loaded while still using `img.loading` attribute?

For images in my webpage, instead of just specifying some image url, I need to load the image data from my own API as a binary data, and then set the src as data/jpeg;base64,..... i.e, I probably need a customized function to load the image content.
However I also want to do the loading lazily. So the ways I can think of are:
set src as empty initially, and listen to various mouse events myself or use Intersection Observer API to trigger my customized function to actually load and set src
find some way to override image's loading function? so that I could still use the native lazy loading provided by chrome?
Is option 2 possible? If so, how to override?
Thanks!

Security Sandbox Violation by a Bitmap in a Flex AIR desktop application?

*** Security Sandbox Violation ***
SecurityDomain 'file:///Users/Bluebird/Desktop/Demo/Project/Level_01
/Background.png' tried to access incompatible context 'app:/project.swf'
I understand that these "security" alerts are difficult to track down and even more difficult with scant information but I thought I would ask.
I have a large Flex/AIR desktop project where the user can select images off their local drive and collage them. There are also some swfs provided which they can use as "stamps". I am getting the error below when stamps are added to the app and clicked – the stamps have eventListeners attached – but the error does not reference the stamp (swf) but instead it references the background image.
The background image is a Spark Image defined in MXML:
<s:Image id="backgroundImage" x="{renderX}" y="{renderY}"
width="{renderWidth}" height="{renderHeight}"
smooth="true" smoothingQuality="high" scaleMode="stretch"
complete="backgroundImage_completeHandler(event)" />
The complete function does nothing important. The source property for the image is defined once the user has selected a local image:
backgroundImage.source = userFile.url
I don't see anywhere to provide a loaderContextfor the Image component (one solution usually suggested for "security" errors). Also, the backgroundImage component has no eventListeners – so I am completely baffled why it is throwing an error.
I've set the Flex compiler option to -use-network = false since this is just a desktop app and that is another commonly suggested "security" fix. I am also loading the "stamp" swfs through the trick of loading them as a byteArray first – another commonly suggested "security" fix.
Can someone help me hate Flash a little less?
For a quick check and probably fix, Instead the following line:-
backgroundImage.source = userFile.url
Trying giving it the relative path to the image file instead full absolute path.
like:
backgroundImage.source = "../images/bg.png";
Also, I assume you have already provided Security.allowDomain("*") in your stamp swfs.
First of all, per the Loader documentation, if you include the swf in the installed application content there won't be any security restrictions when loading it.
Otherwise, the Image component extends SWFLoader which does have a loaderContext property. Try passing in the current domain:
new LoaderContext(ApplicationDomain.currentDomain, SecurityDomain.currentDomain)

Limitations of Web Workers

Please bear in mind that I have never used Web Workers before and I'm having some trouble wrapping my head around them.
Here's an explanation of a simplified version of what I'm doing.
My page has links to various files - some are text, some are images, etc. Each file has an image showing a generic file icon.
I want the script to replace each generic icon with a preview of the file's contents.
The script will request the file from the server (thereby adding it to the cache, like a preloader), then create a canvas and draw the preview onto it (a thumbnail for images, an excerpt of text for text files, a more specific icon for media files...) and finally replace the generic icon's source with the canvas using a data URL.
I can do this quite easily. However, I would prefer to have it in the background so that it doesn't interfere with the UI while it's working.
Before I dive right in to this, I need to know: can Workers work with a canvas, and if so how would I create one? I don't think document.createElement('canvas') would work because Workers can't access the DOM, or am I misunderstanding when all the references I've found say they "can't access the DOM"?
You cannot access the DOM from web workers. You cannot load images. You cannot create canvas elements and draw to them from web workers. For now, web workers are pretty much limited to doing ajax calls and doing compute intensive things. See this related question/answer on web workers and canvas objects: Web Workers and Canvas and this article about using webworkers to speed up image manipulation: http://blogs.msdn.com/b/eternalcoding/archive/2012/09/20/using-web-workers-to-improve-performance-of-image-manipulation.aspx
Your simplest bet is to chunk your work into small chunks (without web workers) and do a chunk at a time, do a setTimeout(), then process the next chunk of work. This will allow the UI to be responsive while still getting your work done. If there is any CPU consuming computation to be done (like doing image analysis), this can be farmed out to a web worker and the result can be sent via message back to the main thread to be put into the DOM, but if not, then just do your work in smaller chunks to keep the UI alive.
Parts of the tasks like loading images, fetching data from servers, etc... can also be done asynchronously so it won't interfere with the responsiveness of the UI anyway if done properly.
Here's the general idea of chunking:
function doMyWork() {
// state variables
// initialize state
var x, y, z;
function doChunk() {
// do a chunk of work
// updating state variables to represent how much you've done or what remains
if (more work to do) {
// schedule the next chunk
setTimeout(doChunk, 1);
}
}
// start the whole process
doChunk();
}
Another (frustrating) limitation of Web Workers is that it can't access geolocation on Chrome.
Just my two cents.
So as others have stated, you cannot access the DOM, or do any manipulations on the DOM from a web worker. However, you can outsource some of the more complete calculations on the web worker. Then once you get your return message from the web worker inside of your main JS thread, you can extract the values you need and use them on the DOM there.
This may be unrelated to your question, but you mentioned canvas so i'll share this with you.
if you need to improve the performance of drawling to canvas, I highly recommend having two canvas objects. One that's rendered to the UI, the other hidden. That way you can build everything on the hidden canvas, then draw the hidden canvas on the displayed one. It may not sound like it will do much if anything, but it will increase performance significantly.
See this link for more details about improving canvas performance.

How to stack Sprites rendered inside Iterator?

I am rendering an image to a Sprite inside of an Iterator. I'd like each render (iteration) to remain on the canvas indefinitely, so that each successive render layers on top of the previous ones. How can I do this?
There are no Clears or any other layers in my composition.
In Quartz Composer, you'll almost always want to use a Clear patch — don't assume that you can rely on the prior contents of the framebuffer. So, to accomplish this, you'll need to load all of your images into a structure (probably by using JavaScript to feed an Image Loader patch and build a Queue from that), and then display all of the images each frame using an Iterator.
Check out Apple's "Image TV" sample composition, available in the OS X Developer Library in the Quartz Composer Conceptual Compositions bundle. This example demonstrates how to load a series of images into a structure and then display them.

What is eager loading?

What is eager loading? I code in PHP/JS but a more generalised answer will be just fine.
I saw a lot of questions regarding Java & Ruby, but i don't know any of these languages, and I find it hard to read code. I don't know whats supposed to do in the first place
There are three levels:
Eager loading: you do everything when asked. Classic example is when you multiply two matrices. You do all the calculations. That's eager loading;
Lazy loading: you only do a calculation when required. In the previous example, you don't do any calculations until you access an element of the result matrix; and
Over-eager loading: this is where you try and anticipate what the user will ask for and preload it.
I hope that makes sense in the context you're seeing it.
Let me give you a "Webby" example.
Imagine a page with rollover images like for menu items or navigation. There are three ways the image loading could work on this page:
Load every single image required before you render the page (eager);
Load only the displayed images on page load and load the others if/when they are required (lazy); and
Load only the displayed images on page load. After the page has loaded preload the other images in the background in case you need them (over-eager).
Make sense?
It's the opposite of lazy loading, which defers initialization of an object until the object is needed. Eager loading initializes an object upon creation.
If you imagine you have object called person who has a name, a date of birth and number of less critical details, lets say favourite colour, favourite tv program.
To lazy load this class you would initalise it reading in perhaps from a database all the core more frequently used details (say name and date of birth) and only read in the less used details when / if they are needed, eager loading is the opposite, i.e. you load in all the details at the same time.
The benifits of lazy loading are often citied as effiecency, however if objects aren't that complex or efficency isn't a concern eager loading may be used
Eager loading is also used in Angular 8. It just means that the instant the application is loaded inside the browser we automatically, instantly get all the code inside a particular module, for example, say you just created an Auth Module with a Signin and Signup component to it that gets imported into an App Module.
In contrast, there is lazy loading, which is when we tell the App Module which has the Auth Module loaded into it, to only load the Auth Module at a certain point in time such as when a user goes to a certain route.