I've had great success with a modular application whereby the main application basically consists of a module loader, that initially loads a logon module.
Once the logon module has done it's stuff (in my case validated inputs, called the logon service and retrieved a token), it dispatches an event (imaginatively called "LogonEvent") that contains details required by the main application. I should point out that the logon module itself is just a wrapper for a logon component that does all the real work (so the logon component can be used in a module or ViewStack etc). Having a LogonEvent makes all the difference.
The wrapper application processes the logon event by unloading the logon module, loading the main module that contains the guts of the application, and then sets the required logon details on the loaded module.
The log off button is in the wrapper application so that it can unload the main module and reload the logon module ready for logging in again.
The benefit of this kind of layout is that the relatively small logon module loads pretty quickly. And while the user is logging on, the main module is already getting pre-loaded, so there is generally no wait for the main module to load after log on. If you have one large monolithic application the initial load time could be off putting.
Some bits of code that may help...
private var mainModuleLogOnEventDispatcher:*;
[Bindable]
private var _logOnDetails:LogOnDetails = new LogOnDetails();
private function onCreationComplete(event:Event):void
{
// Load log on module.
loadMainModule("LogOnModule.swf");
// Pre-load main module while user is logging on.
var mm:IModuleInfo = ModuleManager.getModule("MainModule.swf");
mm.load();
}
[Bindable]
private function set logOnDetails(value:LogOnDetails):void
{
_logOnDetails = value;
}
private function get logOnDetails():LogOnDetails
{
return _logOnDetails;
}
private function loadMainModule(moduleName:String):void
{
// Unload anything already loaded.
if (mainModule.url.length > 0)
{
mainModule.unloadModule();
mainModule.url = "";
}
mainModule.addEventListener(ModuleEvent.READY, handleMainModuleReadyEvent);
mainModule.url = moduleName;
}
private function handleMainModuleReadyEvent(event:ModuleEvent):void
{
// Remove listener, we've caught the event now.
mainModule.removeEventListener(ModuleEvent.READY, handleMainModuleReadyEvent);
// Add listeners to other events or apply data.
if (mainModule.url == "LogOnModule.swf")
{
mainModuleLogOnEventDispatcher = mainModule.child;
if (mainModule.child != null) {
mainModuleLogOnEventDispatcher.addEventListener("logOnEvent", handleLogOnEvent);
}
}
if (mainModule.url == "MainModule.swf")
{
var mm:* = mainModule.child;
if (mainModule.child != null)
{
mm.logOnDetails = logOnDetails;
}
}
}
private function handleLogOnEvent(logOnEvent:LogOnEvent):void
{
mainModuleLogOnEventDispatcher.removeEventListener("logOnEvent", handleLogOnEvent);
logOnDetails = logOnEvent.logOnDetails;
// Now get person's details and swap in main module if successful.
var parameters:Object = new Object();
parameters.cmd = "viewPerson";
parameters.token = logOnDetails.logOnToken;
viewPersonRequest.send(parameters);
}
private function handleViewPersonRequestResult(event:ResultEvent):void
{
//*** Loads of setting logonDetails and error handling removed!!! ***//
loadMainModule("MainModule.swf");
currentState = "LoggedOn";
return;
}
private function onLogOff(event:MouseEvent):void
{
// Make sure we don't auto-logon when we log off.
var logOnPrefs:SharedObject = SharedObject.getLocal("LogOn", "/");
logOnPrefs.data.loggedOff = true;
var parameters:Object = new Object();
parameters.cmd = "logoff";
parameters.token = logOnDetails.logOnToken;
logoffRequest.send(parameters);
loadMainModule("LogOnModule.swf");
currentState = "";
}
<!-- *** Loads of view state related mxml removed *** -->
<mx:VBox width="100%" height="100%" horizontalAlign="center" verticalAlign="middle" id="mainModuleVBox">
<basic:IJModuleLoader id="mainModule" url="" width="100%" height="100%" horizontalAlign="center" verticalAlign="middle"/>
</mx:VBox>
I should also note that this wrapper application isn't actually an application! This is actually a module itself, which is loaded by either a Flex or AIR application. This way I can have separate Flex and AIR projects that reference a core library project that holds the application module, logon module, main (post logon) module and basically all other components and classes used by the application.