La couche Controller
Les Events
Ici nous avons seulement un unique Event pour ce projet. C’est assez rare, le projet est vraiment petit.
package controller.events { import model.vo.Entry; import flash.events.Event; public class DiaporamaEvent extends Event { // événements concernant l'application public static const STARTUP : String = 'startup'; public static const CONFIG_COMPLETE : String = 'configComplete'; public static const NEXT : String = 'next'; public static const PREVIOUS : String = 'previous'; // événements concernant la View public static const REFRESH : String = 'refresh'; public static const LOAD_COMPLETE : String = 'loadComplete'; public var entry : Entry; public function DiaporamaEvent( type : String, bubbles : Boolean = false, cancelable : Boolean = false, entry : Entry = null ) { super(type, bubbles, cancelable); this.entry = entry; } public override function clone():Event { return new DiaporamaEvent( type, bubbles, cancelable, entry ); } public override function toString():String { return formatToString("DiaporamaEvent", "type", "bubbles", "cancelable", "eventPhase"); } } }
On distingue 2 catégories d’Event.TYPE dans cette classe. On a vu plus haut que REFRESH ne concerne qu’un Mediator, c’est la même chose pour LOAD_COMPLETE. J’ai donc bien distingué ces deux catégories dans mes commentaires.
En effet, si tous les Event donnant lieu à une Command sont listés dans mon Context, les handlers présents dans les Mediators sont moins facilement repérables. Cela m’aidera à me relire que de le préciser dans ma classe DiaporamaEvent.
Les Commands
Les Commands contiennent la logique de l’application, ici nos seules fonctionnalités sont les clics sur suivant et précédent. On retrouve donc ces 2 Commands, prenons-en une sur les 2, elles sont très semblables :
package controller.commands { import model.DiaporamaData; import org.robotlegs.mvcs.Command; public class NextCommand extends Command { [Inject] public var diaporamaData : DiaporamaData; override public function execute() : void { diaporamaData.next(); } } }
Lorsque l’événement DiaporamaEvent.NEXT survient, la Command est éxecutée, le Model est injecté, et on agit sur le Model par un appel de méthode publique. Voilà qui colle plutôt bien à la définition du Controller qu’on a donnée plus tôt, et à notre petit schéma.
Dans une Command, on agit sur le Model.
Si on relis DiaporamaContext, on a une StartupCommand, dispatchée au lancement de l’application :
package controller.commands { import model.DiaporamaData; import org.robotlegs.mvcs.Command; public class StartupCommand extends Command { [Inject] public var diaporamaData : DiaporamaData; override public function execute() : void { diaporamaData.load(); } } }
Enfin on a une ConfigCompleteCommand, qui est appelée à la fin du chargement du XML. Pour l’instant, nous n’avons rien de visible sur la scène, notre appli est vide!
package controller.commands { import controller.events.DiaporamaEvent; import view.components.DiaporamaDisplay; import view.components.DiaporamaControls; import org.robotlegs.mvcs.Command; /** * appelée à la fin du chargement du .XML */ public class ConfigCompleteCommand extends Command { // on récupére l'Event déclencheur [Inject] public var event : DiaporamaEvent; override public function execute() : void { // on crée la vue contextView.addChild( new DiaporamaDisplay() ); contextView.addChild( new DiaporamaControls() ); // on force le refresh de la vue, pour afficher la première image dispatch( new DiaporamaEvent( DiaporamaEvent.REFRESH, false, false, event.entry ) ); } } }
C’est donc là qu’est créé la couche visible de notre application! On notera 2 choses très importantes sur cette Command :
- l’injection d’un event : en effet, une Command on l’a compris est une sorte de gros handler d’événement. Pour récupérer les paramètres de l’Event déclencheur (ici entry nous intéresse), on injecte l’event.
- l’appel à contextView : pour récupérer une référence vers la Stage et ajouter des éléments à la DisplayList, RobotLegs fourni une référence nommée contextView vers la variable du même nom déclarée dans DiaporamaContext.
Note :plutôt qu’un appel à contextView, dans certains cas (menu clic-droit custom, resize de stage, curseur custom, multi-fenêtre sous AIR, etc), il est indiqué de créer un StageMediator.
Aller plus loin
Sur ce tutoriel en particulier, les choses suivantes peuvent être effectuées pour s’entraîner :
- séparer correctement DiaporamaEvent en plusieurs événements disctincts.
- ajouter un StageMediator et customiser le menu du clic-droit
- passer l’adresse du XML en FlashVars
- ajouter du son : un indice, un son est une View.
Sur un plan plus général :
- Beaucoup d’exemples ici : http://www.robotlegs.org/examples/
- RobotLegs a le site de support le mieux fichu qui soit : http://knowledge.robotlegs.org/
- Les best-practices sont ici : http://github.com/robotlegs/robotlegs-framework/wiki/Best-Practices