AIR Application - actionscript-3

I have my AIR application i.e MyAIRApplication ready. I am trying to make a splash screen for it.
Here's my code so far ..
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="showSplash()"
visible="false"
layout="absolute"
showFlexChrome="false">
<mx:Script>
<![CDATA[
import components.Splash;
import mx.core.Window;
import mx.controls.Alert;
import mx.events.AIREvent;
private var splash:Window;
private var splashTimer:Timer;
private function showSplash():void {
splash = new Splash();
splash.systemChrome = "none";
splash.transparent = true;
splash.type = NativeWindowType.LIGHTWEIGHT;
splash.addEventListener(AIREvent.WINDOW_COMPLETE, boot);
splash.open();
}
private function boot(event:AIREvent):void {
splashTimer = new Timer(3000, 2);
splashTimer.addEventListener(TimerEvent.TIMER_COMPLETE, showApp);
splashTimer.start();
this.removeEventListener(AIREvent.WINDOW_COMPLETE, boot);
}
private function showApp(event:Event):void {
splash.close();
splash = null;
splashTimer.stop();
splashTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, showApp);
splashTimer = null;
// My Application .. where I wrote all components
var mainWin:WindowedApplication = new MyAIRApplication();
mainWin.activate();
mainWin.visible = true;
}
]]>
</mx:Script>
</mx:WindowedApplication>
Splash.mxml :
<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300"
showFlexChrome="false" >
<mx:Image x="0" y="0" width="600" height="400" source="#Embed('../images/splash-bg.png')" scaleContent="false"/>
</mx:Window>
But I am facing 2 problems :
My AIR application ( i.e MyAIRApplication ) is not showing up, on completing the splash screen.
My Splash Screen is getting shown on top left corner always
Can anyone please provide me with a solution ?

var mainWin:WindowedApplication = new MyAIRApplication();
WindowedApplication isn't created like this. You already have one when your app start, use it. Just make its contents hidden to be shown after the splash.
Also I'm not sure that closing splash window with splash.close() will fire WINDOW_COMPLETE event, check this too with trace (rewrite to Event.CLOSE if needed.)
Windows aren't centered by default. Get screen size with Capabilities.screenResolutionX/Y, calculate x/y for centered window and call splash.move(x, y).

It also might have something to do with you casting your splash var as type Window,
private var splash:Window;
But then instantiating it as a new Splash
private function showSplash():void {
splash = new Splash();
They should both be either Window or Splash.

Related

Item Renderer not Working correctly in Spark List

I used flex sdk 4.5 for creating Adobe Air application. My application download files one by one. I show the currently downloading, pending and completed files in spark list. I used item Renderer that show the progress of the file and other states.
It works fine if selected files fit in current view. But as number of downloads increase, the Spark list shows vertical scroll. here I have the problem. Here file downloading functionality works fine, but if I try to scroll the list, File titles mix up or displayed out of order.
item renderer code:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="onInit()"
>
<fx:Script><![CDATA[
import com.streamingnetworks.hdvrwin.vo.DownloadInfo;
import mx.events.CloseEvent;
[Bindable]private var downloadInfo:DownloadInfo;
private var url:String = "";
private var fileName:String = "";
private function onInit():void
{
downloadInfo = data as DownloadInfo;
downloadInfo.addEventListener("Progress", onProgress);
downloadInfo.addEventListener("DownloadComplete", onComplete);
prog.label = "Downloading %3%%";
lblPath.text = " - " + downloadInfo.getPathIp();
trace("Downloading: " + downloadInfo.name);
}
private function onProgress(e:Event):void
{
prog.setProgress(downloadInfo.downloadedBytes, downloadInfo.totalBytes);
lblState.text = downloadInfo.getDownState();
}
private function onComplete(e:Event):void
{
prog.label = "Download Complete";
}
protected function onClose(event:CloseEvent):void
{
downloadInfo.state = "deleted"
}
]]></fx:Script>
<s:TitleWindow top="0" left="0" right="0" bottom="0" dropShadowVisible="false"
title="{'Downloading ' + downloadInfo.name}" close="onClose(event)">
<mx:ProgressBar id="prog" label="" mode="manual"
trackHeight="20" labelPlacement="center" width="100%"/>
<s:HGroup top="25">
<s:Label id="lblState" text="Downloading 0 Bytes of 0 Bytes."/>
<s:Label id="lblPath"/>
</s:HGroup>
</s:TitleWindow>
</s:ItemRenderer>
here the list control where I am using that renderer
<s:List id="lstControls" dataProvider="{urlArr}"
itemRenderer="ItemRenderer"
left="5" right="5" bottom="5" top="40"/>
urlArr is an arrayList that contains only url in string form.
How can I solve this problem? Any Help will be appreciated. Thanks
Your renderers are not updating correctly because you are setting your data when the renderer is created - but you should be overriding the set data method, eg:
override public function set data(value:Object):void
{
super.data = value;
downloadInfo = data as DownloadInfo;
downloadInfo.addEventListener("Progress", onProgress);
downloadInfo.addEventListener("DownloadComplete", onComplete);
prog.label = "Downloading %3%%";
lblPath.text = " - " + downloadInfo.getPathIp();
trace("Downloading: " + downloadInfo.name);
}
And remove the creationComplete listener.
As a better practice. Have all the data your progress bars will need all ready in the data provider and have them react ONLY to changes in the data. Adding and removing listeners and binding internally will only cause you grief. Renderers do not live forever and are re-used inside of list components. Manage everything through overriding set data().
In this example I would create a model object with a name like FileDownloadInfo and properties such as .downloadProgress .fileName and .ipAddress then have the renderer update on property change events of .downloadProgress

as3 / flex interface incompatibility when loading external swf

I have a main project, and i want to load another project's swf into it:
//loader code in Main class of main project
var url:URLRequest = new URLRequest("../src/components/TextTool.swf");
var ttWrapper:UIComponent = new UIComponent();
var ldr:SWFLoader = new SWFLoader();
var context:LoaderContext = new LoaderContext();
if (Security.sandboxType == Security.LOCAL_TRUSTED) {
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
} ldr.source = "../src/components/TextTool.swf";
ldr.loaderContext = context;
ldr.addEventListener(Event.COMPLETE, onLoadComplete);
ldr.load();
can.addElement(ldr);
Here's the code of the Main class of the second project:
<?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:stark="stark.*" name="textModule" >
<stark:TextTool name="myTF" id="myTF"></stark:TextTool>
</s:Application>
Now both of the projects contain an interface file : IModule, with the same code, and an element of the second project (the one that's being loaded) which is an instance of my custom class "TextTool", which extends s:Group and implements IModule:
<s:Group 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="400"
xmlns:com="src"
height="130" creationComplete = "initText()" implements="IModule"></s:Group>
Now as soon as i've loaded the swf, i want to access that TextTool instance which has and id of "myTF" :
//Code in the main class of the main project
trace(getQualifiedClassName(mySwf.getChildByName('textModule')['myTF']));
trace(mySwf.getChildByName('textModule')['myTF'] is IModule);
//output:
//stark::TextTool
//false
As i've mentioned above, i have the interface in both projects, same code, it has the same path relative to main classes, and myTF does extend IModule. After the swf is loaded, i get the right element, but i still get false when verifying if it implements IModule.
Why?
You're testing Application for implementation
trace(mySwf.getChildByName('textModule') is IModule);
I think you forgot to add ['myTF']
trace(mySwf.getChildByName('textModule')['myTF'] is IModule);
You're loading both into different ApplicationDomains, so whichever loads first wins. Try loading them into the same ApplicationDomain.

Weird crash in AIR application

I have a crash that only happens with the installed application I can't make it cvrash in the IDE(Flash Builder debug or run option)
After a long time of commenting and uncomenting code I found the problem and I am posting the code below
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:ns="generic_components.*"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
//import core.Logger;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.events.TextOperationEvent;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
//Logger.init();
}
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
//Logger.write("camel case for "+txt);
for (var i:int=1;i<txt.length;i++)
{
// Logger.write("camel iter "+i);
var c:String=txt.charAt(i);
//Logger.write("camel char is "+c);
if(c==c.toUpperCase())
{
res=res+" "+c;
}
else
res=res+c;
}
return res;
}
protected function test_clickHandler(event:Event):void
{
Alert.show(humanFromCamelCase("CompanyId"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button id="test" label="TEST" click="test_clickHandler(event)"/>
</s:WindowedApplication>
Also see a web sample here http://ploscariu.com/crash/TestWeb.html (may be not there in the future)
What is weird about this crash:
1 I have no idea what happens
2 The usual crash handler in the player does not show up
3 is not crashing in the development enviroment IDE
4 if i uncomment those Logger.write then the code works on my machine fine(it could not work on all machines), the Logger.write writes the sting in a file and is placed in another project swf (I did not included the logger code)
I a, assuming that the call to Logger.write can cause a delay or something similar
It is something wrong in my code or the player is buggy? or the compiler??
Any ideas?
Edit:
-is not the logger i use since the error happens when I am not using it like in the sample code or page, no logger the app it crashes
-i get no dialog from Flash with a crash report
This is so incredibly odd!!!! I have NO idea why this happening (yet)... but I have a workaround:
Instead of res=res+c, use res+=c:
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
for (var i:int=1;i<txt.length;i++)
{
var c:String=txt.charAt(i);
if(c === c.toUpperCase())
{
res += " " + c;
}
else
res += c;
}
return res;
}
I have no idea why you're having an error, however, I would replace the function with this instead:
public static function humanFromCamelCase(txt:String):String{
return txt.replace(/([A-Z])/g, ' $1').replace(/^ /, "");
}
Haven't tested it, but you get the idea. This is a much simpler and faster approach.
I also thought of another way:
public static function humanFromCamelCase(txt:String):String{
return txt.split(/(?=[A-Z])/).join(' ');
}

How to run a function after the canvas has changed in ActionScript 3.0?

Please understand: I am a total beginner at Actionscript and anything like Actionscript, and though I generally have some idea of what I'm doing as a programmer, I'm having some setbacks in self-learning this language and Flex Builder. Right now I'm trying to make a very simple implementation where a label effectively has its text added to multiple times over the first few seconds that the program is run. The problem I'm running into is that I can't just put all that into one function + one call on that function, as changes to the label's text are apparently not seen until that function runs its full course.
So I tried using a viewstack and cloning the canvas a few times, giving each canvas's version of that label a different bit of text. Then I set the initialize function for the viewstack to change the canvases on regular intervals over the first few seconds. But that didn't work either, as the difference isn't seen until the function runs its full course.
So then I tried putting function calls on the individual canvases' initialize attributes, and those functions aren't being called at all apparently.
What the heck? I know this probably isn't even the way that you're supposed to animate something in ActionScript or Flex, but I still would like to know how to approach the problem this way for future reference. What am I missing? Thanks!
As you've noticed, changes to the displayed output of your program can't happen in the middle of executing a function that you've written. ActionScript is single-threaded, which means that none of the framework code that updates the screen can run while your function is running.
If you're interested in learning exactly what happens in order to update the screen, do a search for "flex component lifecycle" and read some of the stuff you find. It's a bit advanced, but it was the thing that really helped me understand how the Flex framework works.
Anyway, on to your real question - how to animate something. There are many ways, but for your case of progressively adding text to a label, I'd probably use the Timer class.
Here is an example:
<?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" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var timer:Timer;
private var words:Array = ["The", "quick", "brown", "fox"];
private function startTimer(event:FlexEvent):void
{
timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, updateText);
timer.start();
}
private privatefunction updateText(event:TimerEvent):void
{
theLabel.text += words.shift() + " ";
if (words.length > 0)
{
timer.reset();
timer.start();
}
}
]]>
</fx:Script>
<s:Label id="theLabel" text="" creationComplete="startTimer(event)"/>
</s:Application>
A basic approach would be to use data binding for the label value, and setTimeout() or setInterval() to cause the delay between updates.
Here is an example:
<?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"
initialize="init()"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
[Bindable]
private var displayString:String = "Detonation in ";
private var count:int = 5;
private var timer:uint;
private function init():void {
timer = setInterval(updateDisplay, 1000);
}
private function updateDisplay():void {
displayString += count + ".. ";
if (--count == 0) {
clearInterval(timer);
}
}
]]>
</fx:Script>
<s:Label text="{displayString}"/>
</s:Application>

flashvars not loading in Flex 4.5 application in Adobe Flash Builder

I am following this adobe flashvars example to try and get flashvars loading in my flex 4.5 application. However, the code is not working. I don't really understand what I'm doing wrong, or differently from the example. here is my index.template.html code (in the html-template folder) which uses swfobject to load the application:
function embedPlayer() {
var flashvars = {};
flashvars.userLoggedIn = true;
flashvars.test = "hello";
embedSWF(SWF_FILE, SWF_ID, SWF_WIDTH, SWF_HEIGHT, "9.0", "playerProductInstall.swf", flashvars);
}
And here is the simplified code from my flex application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:d="http://ns.adobe.com/fxg/2008/dt"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:c="components.*"
initialize="mainInit()"
creationComplete="doCreationComplete()"
applicationComplete="_initializer.applicationComplete()"
xmlns:application="components.application.*"
xmlns:gui="com.gui.*" xmlns:main="com.gui.components.main.*" xmlns:photoTray="com.gui.components.main.photoTray.*">
<fx:Style source="/assets/all.css" />
<fx:Script>
<![CDATA[
import com.gui.components.main.Initializer;
import com.gui.components.main.LayoutsController;
import mx.core.FlexGlobals;
private var _initializer:Initializer;
private var _layoutsController:LayoutsController;
public var userLoggedIn:Boolean;
private function mainInit():void {
_initializer = new Initializer(this);
}
private function doCreationComplete():void {
_initializer.init();
var params:Object = FlexGlobals.topLevelApplication.parameters;
//userLoggedIn = params.userLoggedIn;
_layoutsController = new LayoutsController(this);
}
]]>
</fx:Script>
</s:Application>
I call FlexGlobals.topLevelApplication.parameters (after creationComplete) to try and access flashvars, which is what adobe says is the way to do it in flex 4.5. From my research using Application.application.parameters and root.loaderInfo.parameters are both deprecated.
Does anyone see what I am doing wrong? My application works fine in flash builder except for flashvars loading on creationComplete.
Thanks
This is how I do it in flex 3 not sure it applies to flex 4.5
Application.application.parameters.userLoggedIn
Also on this line
//userLoggedIn = params.userLoggedIn;
The value of any flash var is a string which you are trying to assign a Boolean.
So do this.
//userLoggedIn = Boolean(params.userLoggedIn);