Displaying a progress dialog before calling URLLoader.load in flex? - actionscript-3

I'm developing a flex application (run in web browser), that lets the user load a number of files and then sends them all to a server in one single multipart/form-data request.
My problem is this:
For security reasons, flash requires that the user initiates the URLLoader.load action by clicking on a button. That's ok, the user clicks the save button in the application and off we go.
Unfortunately, the uploading part of the request doesn't seem to be asynchronous, but only the downloading part. The data can be any size since the user can add an arbitrary number of files, so the upload can take a while to complete.
In an ideal world I would do something like this in the click handler of the save button:
PopupManager.createPopup(this, ProgressDialog, true);
doUpload();
Unfortunately this will result in the progressdialog being shown after the upload finishes.
So, can I defer the upload start until the popup has been shown, like this?
PopupManager.createPopup(this, ProgressDialog, true);
setTimeout(doUpload, 100);
Turns out I can't do this either, because of the security reasons mentioned above. This will throw a SecurityError: Error #2176.
Basically the problem is
A popup won't be visible until the code in the current frame has completed
URLLoader.load blocks until the upload part of the request is completed
The popup arrives too late, since the time consuming part is already over.
I can't wait for the popup, since the load action has to be initiated by the user click.
Is there any way whatsoever to work around this limitation?
Here is a small application that illustrates the problem. Button two and three will throw the SecurityError.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="419" height="250">
<fx:Script>
<![CDATA[
import mx.core.IFlexDisplayObject;
import mx.managers.PopUpManager;
private var urlLoader:URLLoader;
private var popup:IFlexDisplayObject;
protected function sendNowButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendNowButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
doLoad();
trace("<< URLLoaderSendTest.sendNowButton_clickHandler(event)");
}
protected function sendWithSetTimeoutButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendLaterButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
setTimeout(doLoad, 200);
trace("<< URLLoaderSendTest.sendLaterButton_clickHandler(event)");
}
protected function sendWithCallLaterButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendWithCallLaterButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
callLater(doLoad);
trace("<< URLLoaderSendTest.sendWithCallLaterButton_clickHandler(event)");
}
private function doLoad():void {
trace(">> URLLoaderSendTest.doLoad()");
var bytes:ByteArray = new ByteArray();
bytes.writeInt(1);
var request:URLRequest = new URLRequest("http://localhost/test/");
request.method = URLRequestMethod.POST;
request.contentType = "multipart/form-data";
request.data = bytes;
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, loaderComplete);
urlLoader.load(request);
trace("<< URLLoaderSendTest.doLoad()");
}
protected function loaderComplete(event:Event):void {
trace(">> URLLoaderSendTest.loaderComplete(event)");
PopUpManager.removePopUp(popup);
}
]]>
</fx:Script>
<s:Button id="sendNowButton" x="10" y="10"
label="Send now"
click="sendNowButton_clickHandler(event)"/>
<s:Button id="sendWithsetTimeoutButton" x="10" y="40"
label="Send with setTimeout"
click="sendWithSetTimeoutButton_clickHandler(event)"/>
<s:Button id="sendWithCallLaterButton" x="10" y="70"
label="Send with callLater"
click="sendWithCallLaterButton_clickHandler(event)"/>
</s:Application>

Related

Playing a video with flex, AS3

I am currently trying to make a game on flex and one of the problems I ran in to is how to play a short animation at the beginning. This is what I have so far:
Game.mxml
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
name="Game"
backgroundColor="#000000"
horizontalAlign="center"
creationComplete="Init();"
enterFrame="UpdateFrame();"
paddingLeft="0"
paddingTop="0"
paddingBottom="0"
paddingRight="0"
width="800" height="600">
<mx:Script>
<![CDATA[
include "Game.as";
]]>
</mx:Script>
<mx:Canvas id="gamePanel" x="0" y="0" width="100%" height="100%" mouseDown="MouseDown(event)" mouseUp="MouseUp(event)" mouseMove="MouseMoved(event)"/>
</mx:Application>
and Game.as
import flash.display.*;
import flash.events.*;
import flash.external.ExternalInterface;
import mx.events.*;
import mx.controls.*;
[Embed(source="MyVideoClip.flv")] private var MyVideoClip:Class;
public function Init():void
{
var MyVideo:Video = new Video(800, 600);
addChild(MyVideo);
var qNetConnection:NetConnection = new NetConnection();
qNetConnection.connect(null);
var qNetStream:NetStream = new NetStream(qNetConnection);
MyVideo.attachNetStream(qNetStream);
qNetStream.client = new Object();
qNetStream.play(MyVideoClip);
}
private function UpdateFrame():void
{
}
private function MouseDown(event:MouseEvent):void
{
}
private function MouseUp(event:MouseEvent):void
{
}
private function MouseMoved(event:MouseEvent):void
{
}
I am rather new to Flex and AS3 so most of this code was ripped off web tutorials. Whenever I try to compile it I get: 'Error: 'MyVideoClip.flv' does no have a recongnized extention, and a mimeType was not provided. Error: unable to transcode 'MyVideoClip.flv''
If I remove the 'embed' line and replace MyVideoClip with "MyVideoClip.flv" in the play() function, the code compiles with no errors, but when I open the SWF all I get is a black screen. What am I doing terribly wrong?
Thanks in advance!!
Try setting the mime-type, e.g.:
[Embed(source = "MyVideoClip.flv", mimeType = "application/octet-stream")]
You embedded the video file (its bytes) into the output SWF. So now NetStream must play from a bytes source. Just set a byteArray as equal to new MyVideoClip(); and append to NetStream.
Try this...
[Embed(source="MyVideoClip.flv", mimeType="application/octet-stream")] private var MyVideoClip:Class; //# embed the FLV's bytes
public var VideoClipBytes : ByteArray;
public var MyVideo:Video;
public var qNetConnection:NetConnection;
public var qNetStream:NetStream;
public function Init():void
{
VideoClipBytes = new MyVideoClip() as ByteArray; //# fill a byte Array with embedded bytes
qNetConnection = new NetConnection(); qNetConnection.connect(null);
qNetStream = new NetStream(qNetConnection);
qNetStream.client = new Object();
MyVideo = new Video(800, 600);
MyVideo.attachNetStream(qNetStream);
addChild(MyVideo);
qNetStream.play(null); //# play mode is now bytes
qNetStream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN); //# ready for new audio/video data
qNetStream.appendBytes( VideoClipBytes ); //# add bytes to decoder queue (playback)
}
PS : I made some of your variables as public so later you can access & control them from any other functions. Remember if you make var inside a public function it stays valid only in that one function and doesn't exist to other functions. Best make such vars as publicly available to all functions.

How do i delete text line from a txt file? ActionScript

Good morning! So here is basic code, which i get from the "Mobile Development with Adobe Flash Professional CS5.5 and Flash Builder 4.5" tutorial. Pretty much basic code, but those bastards didnt gave any information about DELETE function. THis is my first time application for this, so help is needed!
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
height="494" creationComplete="readFile()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] public var todo_items:ArrayCollection;
private function readFile():void
{
var todoFile:File =File.applicationStorageDirectory.resolvePath("todo.txt");
if (todoFile.exists)
{
var fs:FileStream = new FileStream();
fs.open(todoFile, FileMode.READ);
var result:String = fs.readUTFBytes(fs.bytesAvailable);
var items:Array = result.split("\n");
items.pop();
todo_items = new ArrayCollection(items);
fs.close();
}
else { trace("Aplication cant find the file");
}
}
private function writeFile():void
{
var todoFile:File = File.applicationStorageDirectory.resolvePath("todo.txt");
var fs:FileStream = new FileStream();
fs.open(todoFile, FileMode.APPEND);
fs.writeUTFBytes(task_txt.text + "\n");
fs.close();
readFile();
}
private function deleteFile():void
{
//????????????? HEEEEELP !!!!!!!!!!
}
]]>
</fx:Script>
<s:List id="todo_list" left="10" right="10" top="146" bottom="87" dataProvider="{todo_items}"/>
<s:Button left="11" right="10" top="69" height="65" label="Save task" click="writeFile()"
enabled="{task_txt.text.length > 0}"/>
<s:TextInput id="task_txt" left="10" right="10" top="10" height="51" prompt="Specify a task"/>
<s:Button left="10" right="10" bottom="14" label="Delete"
click="todo_items.removeItemAt(todo_list.selectedIndex); deleteFile()"
enabled="{todo_list.selectedIndex != -1}"/>
What you want to do is
read in all of the data from the file, just like readFile is doing.
delete from that data whatever lines you want to delete.
write the data back to the file - like writeFile is doing - in FileMode.WRITE mode, as you want it to overwrite, not append.
If you can't quite figure this out and need code instead of a guide, feel free to comment on here and I'll give you more than just pointers.
The code in readFile (all of it) reads in the data from the file into an ArrayCollection called todo_items.
If you want to remove an item from the file, you want to remove it from that ArrayCollection (something like todo_items.removeItemAt(index)).
Now, you have an ArrayCollection containing the data you want to be in the file. At this point, you need to imitate what writeFile() is doing, but with FileMode.WRITE, and you want to write out every item in your list, instead of the one item in the textbox you want to add.
private function deleteFile():void
{
var todoFile:File = File.applicationStorageDirectory.resolvePath("todo.txt");
var fs:FileStream = new FileStream();
fs.open(todoFile, FileMode.WRITE);
for(var item:String in todo_items)
{
fs.writeUTFBytes(item + "\n")
}
fs.close();
readFile();
}
On a somewhat related note - I don't think 'deleteFile' is a good name for what you are doing here. You might want a deleteItem() method that deletes the selected item, and then a saveFile() method that contains the code above.
I presume the deleteFile method is intended to delete the file? If so, Adobe's Reference documents the File class and deletion this is normally a good place to start when exploring classes.
private function deleteFile():void
{
var todoFile:File = File.applicationStorageDirectory.resolvePath("todo.txt");
todoFile.deleteFile()
}

EFFECT_REPEAT not firing on every iteration of Animate instance when losing focus

I'm not sure if that title is descriptive enough, but here is the basic issue. I have a spark.effects.Animate instance repeating n times with a listener on the EFFECT_REPEAT event. In that event's listener, I'm incrementing a variable. Logic would dictate that if the variable started at 0 and the animation was played with a repeatCount of 3, the variable would be 2 when finished. This works fine, until I focus a different tab. When doing this, on occasion, the repeat event isn't fired/handled (or the animation is just not actually doing the animation) and my count isn't correct when finished.
This is a fully functioning example built against Flex 4.5. To duplicate just click the GO button and maintain focus on the TAB. Then click it again and switch tabs and switch back. The counts don't match.
How can I fix this so that the repeat event is called consistently?
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="600" height="400" applicationComplete="application1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Image;
import mx.events.EffectEvent;
import mx.events.FlexEvent;
import spark.effects.Animate;
import spark.effects.animation.MotionPath;
import spark.effects.animation.SimpleMotionPath;
private var animate:Animate;
private var someCounter:int = 0;
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
// Create the graphic
var img:Image = new Image();
img.source = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
// Add the graphic
addElement( img );
// Create the motion path
var smp:SimpleMotionPath = new SimpleMotionPath();
smp.property = "x";
smp.valueFrom = 0;
smp.valueTo = this.width - 275;
// Add the motion path to a Vector
var paths:Vector.<MotionPath> = new Vector.<MotionPath>();
paths.push( smp );
// Create the animation
animate = new Animate();
animate.easer = null;
animate.target = img;
animate.duration = 150;
animate.repeatCount = 15;
animate.motionPaths = paths;
animate.addEventListener( EffectEvent.EFFECT_REPEAT, animate_effectRepeatHandler );
animate.addEventListener( EffectEvent.EFFECT_END, animate_effectEndHandler );
}
private function animate_effectRepeatHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString();
someCounter++;
}
private function animate_effectEndHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString(); // Sometimes doesn't equal animate.repeatCount - 1
}
protected function button1_clickHandler(event:MouseEvent):void
{
if( !animate.isPlaying )
{
someCounter = 0;
animate.play();
}
}
]]>
</fx:Script>
<mx:Label id="lblCounter" horizontalCenter="0" bottom="50" width="150" height="50" textAlign="center" />
<mx:Button horizontalCenter="0" bottom="0" label="GO" width="150" height="50" click="button1_clickHandler(event)" />
</s:Application>

Recording video from camera, overlaying bitmaps, adding audio, saving to the device all in as3/AIR mobile

I am tasked with recording a live video stream from the camera on a mobile device, then overlaying bitmaps that change over time, and adding an audio mp3 track to the video file, and then saving it to somewhere on the device like the Camera roll.
I saw a few posts that were helpful, mostly this one: AS3 Flash/AIR recording video with webcam and save it
But apparently, some have experienced app freezes on desktops. I can only imagine that on a mobile device it would be worse...
Also, how can I add the video info together with a separate audio mp3 into one file?
Has anyone accomplished something like this?
Update, I got the video working. Kinda. I still get this error sometimes. Even with short videos.
Error #2030: End of file was encountered.
Sometimes it works fine. But at least I'm able to record FLVs from components. I haven't done the audio addition yet.
To run this code, you'll need the FLVRecorder found here: http://www.joristimmerman.be/wordpress/2008/12/18/flvrecorder-record-to-flv-using-air/
<?xml version="1.0" encoding="utf-8"?>
import mx.core.UIComponent;
import mx.events.FlexEvent;
private var file:File;
private var recorder:FLVRecorder=FLVRecorder.getInstance()
private var fps:uint = 10;
private var timer:Timer;
protected function viewnavigator1_creationCompleteHandler(event:FlexEvent):void
{
// 2. Define the target FLV-file’s properties, the file instance to your flv-file, width & height, framerate and the systemManager instance, that’s a Flash internal declared variable and the optional duration in seconds:
file=File.desktopDirectory.resolvePath("recording.flv");
recorder.setTarget(file,320,320,fps,systemManager)
var camera : Camera = Camera.getCamera();
if (camera)
{
var ui : UIComponent = new UIComponent();
var video : Video = new Video(320, 320);
camera.setMode(320, 320, 24.);
video.attachCamera(camera);
ui.addChild(video);
cameraGroup.addElement(ui);
}
timer = new Timer(1000/fps);
timer.addEventListener(TimerEvent.TIMER, captureScreen);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, stopRecording);
}
protected function stopRecording(event:Event):void
{
timer.stop();
//when saving is done
recorder.addEventListener(FLVRecorderEvent.FLV_CREATED, fileMade)
//when saving starts
recorder.addEventListener(FLVRecorderEvent.FLV_START_CREATION, startCreatingFLV)
// TODO Auto-generated method stub
recorder.stopRecording()
}
private function startCreatingFLV(e:FLVRecorderEvent):void{
recorder.addEventListener(FLVRecorderEvent.PROGRESS,onFLVCreationProgress)
}
private function onFLVCreationProgress(e:FLVRecorderEvent):void{
//e.progress: percent complete (0 to 1)
//pbSaving: ProgressBar component in Flex
trace("saving progress ", e.progress,1);
}
protected function captureScreen(event:TimerEvent):void
{
trace("captured screen");
recorder.captureComponent(movieGroup) //DisplayObject, takes a screenshot from that component
}
protected function startRecording(event:MouseEvent):void
{
// TODO Auto-generated method stub
timer.start();
}
protected function fileMade(event:Event):void
{
trace("file made");
}
]]>
</fx:Script>
<s:VGroup>
<s:HGroup>
<s:Button label="start" click="startRecording(event)"/>
<s:Button label="stop" click="stopRecording(event)"/>
<s:Label id="progress" text="waiting..."/>
</s:HGroup>
<s:Group id="movieGroup" width="50%" height="50%">
<s:Group id="cameraGroup" width="100%" height="100%"/>
<s:Image source="image.png" width="25%" height="25%"/>
</s:Group>
</s:VGroup>

Action Script 3 - Events between Spark and Custom Components

We are building an interface for a game.
The interface has a tabbed menu at the bottom of the screen, with each tab displaying different aspects of an object (called a node).
When you click on one of these parts, it becomes the focus, and we download it's details in XML, including all it's sub-nodes and parent nodes and then update the tab display accordingly, or at least that's what we'd like to happen.
What we have:
MainInterface.mxml
<s:Application...
<fx:Script>
<![CDATA[
public var currentNode:Node = new Node();
protected function selectNodeHandler(event:Event):void
{
loader = new URLLoader(new URLRequest(ourWebSite + event.target.id + ".xml"))
//the xmlDownloaded function below is what changes the contents of currentNode
loader.addEventListener(Event.COMPLETE, xmlDownloaded);
...
<s:SkinnableContainer id="dashBoard"..
<mx:TabNavigator...
<s:NavigatorContent...
<s:SkinnableDataContainer ...
dataProvider="{currentNode.children}"
itemRenderer="renderers.NodeRenderer">
Node.as (valueObjects.Node)
...
[Bindable] public var id:String;
[Bindable] public var name:String;
[Bindable] public var children:ArrayCollection = new ArrayCollection();
[Bindable] public var parents:ArrayCollection = new ArrayCollection();
...
NodeRenderer.mxml (renderers.NodeRenderer)
<s:ItemRenderer ... click="nodeRenderer_clickHandler(event)">
<fx:Script>
<![CDATA[
protected function nodeRenderer_clickHandler(event:MouseEvent):void
{
var eventObject:Event = new Event ("nodeSelected");
dispatchEvent(eventObject);
}
...
<s:Label text = "{data.name}"/>
We tried adding an event listener for "selectNode" to the dashBoard:SkinnableContainer you see see above, but it didn't seem to want to take. We suspect this is because dashBoard is from a spark component and the dispatcher for "selectNode" is on of our own custom components, but we weren't sure... in any case that's what the code assist seemed to indicate as we had to write it in by hand.
We're not sure how to pick up the Events in FlashBuilder 4's debugger, so we're having trouble working out where it's going wrong. Basically, when someone clicks on the label of a child or parent node (that is displayed by the itemRenderer), we want a URLRequest sent to our website, with the url specific to the node clicked on. We then want a URLLoader listening for the return which will update public variable 'currentNode' when xmlDownloaded is called by the loader.
If you could clarify how the click event should be dispatched, what should be listening for it then sending the URLRequest and where the URLLoader that is listening for the xml data to return should be that would solve our problems. Alternatively, if there is a better (more conventional) way to be doing what we're trying to do that would also help, as we're relatively new to actionscript and flex.
protected function selectNodeHandler(url:String):void
{
loader = new URLLoader(new URLRequest(url));
//consider identifying the loader, for instance
loader.name = url; // you could also pass a second parameter
//to the function and assign it to the name property of the loader.
//the xmlDownloaded function below is what changes the contents of currentNode
loader.addEventListener(Event.COMPLETE, xmlDownloaded);
}
protected function nodeRenderer_clickHandler(event:MouseEvent):void
{
var url:String = ourWebSite + event.currentTarget.id + ".xml";
selectNodeHandler( url );
}
protected function xmlDownloaded( event:Event ):void
{
//identify the target here with the name property
var id:String = event.target.name;
}