diff --git a/assets/data/riders.json b/assets/data/riders.json
new file mode 100644
index 0000000..0c122c1
--- /dev/null
+++ b/assets/data/riders.json
@@ -0,0 +1,213 @@
+[
+ {
+ "id": 1,
+ "name": "Maitray",
+ "firstName": "Camille",
+ "age": "11",
+ "lastLessonDate": "1757548800000",
+ "level": "1",
+ "credit": "10",
+ "address": "8 rue de Chez Douteau, 17600 Corme-Écluse",
+ "notes": "🐤",
+ "ffeLicence": "true",
+ "ffeLicenceValidityYear": "2025",
+ "ffeLicenceNumber": "6178760C",
+ "legalGuardianName": "Maitray",
+ "legalGuardianFirstName": "Vincent",
+ "legalGuardianRole": "père",
+ "legalGuardianPhoneNumber": "0640180230",
+ "legalGuardianEmail": "vincent.maitray@gmail.com"
+ },
+
+ {
+ "id": 0,
+ "name": "Durand",
+ "firstName": "Lucas",
+ "age": 12,
+ "lastLessonDate": 1711574400,
+ "level": 1,
+ "credit": 8,
+ "address": "14 rue des Acacias, 75017 Paris",
+ "notes": "Bon progrès, travaille la posture.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2025,
+ "ffeLicenceNumber": "C1234567",
+ "legalGuardianName": "Durand",
+ "legalGuardianFirstName": "Sophie",
+ "legalGuardianRole": "mère",
+ "legalGuardianPhoneNumber": "01 45 67 89 10",
+ "legalGuardianEmail": "sophie.durand@example.com"
+ },
+ {
+ "id": 1,
+ "name": "Martin",
+ "firstName": "Emma",
+ "age": 9,
+ "lastLessonDate": 1704067200,
+ "level": 0,
+ "credit": 3,
+ "address": "7 avenue Victor Hugo, 33000 Bordeaux",
+ "notes": "Très attentive, timide en groupe.",
+ "ffeLicence": false,
+ "ffeLicenceValidityYear": 2026,
+ "ffeLicenceNumber": "C7654321",
+ "legalGuardianName": "Lemoine",
+ "legalGuardianFirstName": "Claire",
+ "legalGuardianRole": "mère",
+ "legalGuardianPhoneNumber": "05 56 12 34 56",
+ "legalGuardianEmail": "claire.lemoine@example.net"
+ },
+ {
+ "id": 2,
+ "name": "Bernard",
+ "firstName": "Tom",
+ "age": 15,
+ "lastLessonDate": 1716844800,
+ "level": 2,
+ "credit": -2,
+ "address": "23 boulevard Gambetta, 59000 Lille",
+ "notes": "Doit rattraper les cours manqués.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2026,
+ "ffeLicenceNumber": "C9876543",
+ "legalGuardianName": "Bernard",
+ "legalGuardianFirstName": "Marc",
+ "legalGuardianRole": "père",
+ "legalGuardianPhoneNumber": "03 20 33 44 55",
+ "legalGuardianEmail": "marc.bernard@mail-example.fr"
+ },
+ {
+ "id": 3,
+ "name": "Petit",
+ "firstName": "Léa",
+ "age": 7,
+ "lastLessonDate": 1709548800,
+ "level": 0,
+ "credit": 12,
+ "address": "5 impasse des Lilas, 87000 Limoges",
+ "notes": "Très sociable, aime les activités créatives.",
+ "ffeLicence": false,
+ "ffeLicenceValidityYear": 2025,
+ "ffeLicenceNumber": "C2345678",
+ "legalGuardianName": "Moreau",
+ "legalGuardianFirstName": "Anne",
+ "legalGuardianRole": "grand-mère",
+ "legalGuardianPhoneNumber": "05 55 12 23 34",
+ "legalGuardianEmail": "anne.moreau@example.org"
+ },
+ {
+ "id": 4,
+ "name": "Roux",
+ "firstName": "Noah",
+ "age": 11,
+ "lastLessonDate": 1712150400,
+ "level": 1,
+ "credit": 0,
+ "address": "98 route de Grenoble, 73000 Chambéry",
+ "notes": "Besoin d'encouragement pour prendre confiance.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2025,
+ "ffeLicenceNumber": "C3456789",
+ "legalGuardianName": "Lefèvre",
+ "legalGuardianFirstName": "Isabelle",
+ "legalGuardianRole": "mère",
+ "legalGuardianPhoneNumber": "04 79 11 22 33",
+ "legalGuardianEmail": "isabelle.lefevre@example.com"
+ },
+
+ {
+ "id": 5,
+ "name": "Morel",
+ "firstName": "Mathis",
+ "age": 13,
+ "lastLessonDate": 1710326400,
+ "level": 2,
+ "credit": 5,
+ "address": "12 rue Jean Jaurès, 44000 Nantes",
+ "notes": "Technique en amélioration.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2026,
+ "ffeLicenceNumber": "C4567890",
+ "legalGuardianName": "Dubois",
+ "legalGuardianFirstName": "Caroline",
+ "legalGuardianRole": "mère",
+ "legalGuardianPhoneNumber": "02 40 12 34 56",
+ "legalGuardianEmail": "caroline.dubois@example.com"
+ },
+ {
+ "id": 6,
+ "name": "Garcia",
+ "firstName": "Chloé",
+ "age": 8,
+ "lastLessonDate": 1706784000,
+ "level": 0,
+ "credit": 10,
+ "address": "3 place Sainte-Catherine, 33000 Bordeaux",
+ "notes": "Très impliquée et souriante.",
+ "ffeLicence": false,
+ "ffeLicenceValidityYear": 2025,
+ "ffeLicenceNumber": "C1122334",
+ "legalGuardianName": "Garcia",
+ "legalGuardianFirstName": "Ismaël",
+ "legalGuardianRole": "père",
+ "legalGuardianPhoneNumber": "05 56 78 90 12",
+ "legalGuardianEmail": "ismael.garcia@mail-example.fr"
+ },
+ {
+ "id": 7,
+ "name": "Fischer",
+ "firstName": "Hugo",
+ "age": 16,
+ "lastLessonDate": 1714512000,
+ "level": 2,
+ "credit": -5,
+ "address": "45 avenue Foch, 06000 Nice",
+ "notes": "Doit respecter les règles du groupe.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2026,
+ "ffeLicenceNumber": "C9988776",
+ "legalGuardianName": "Fischer",
+ "legalGuardianFirstName": "Monique",
+ "legalGuardianRole": "grand-mère",
+ "legalGuardianPhoneNumber": "04 93 12 34 56",
+ "legalGuardianEmail": "monique.fischer@example.net"
+ },
+ {
+ "id": 8,
+ "name": "Lefort",
+ "firstName": "Maya",
+ "age": 10,
+ "lastLessonDate": 1709452400,
+ "level": 1,
+ "credit": 7,
+ "address": "28 rue Carnot, 21000 Dijon",
+ "notes": "Bonne écoute, progresser en endurance.",
+ "ffeLicence": true,
+ "ffeLicenceValidityYear": 2025,
+ "ffeLicenceNumber": "C5566778",
+ "legalGuardianName": "Lefort",
+ "legalGuardianFirstName": "Paul",
+ "legalGuardianRole": "père",
+ "legalGuardianPhoneNumber": "03 80 12 34 56",
+ "legalGuardianEmail": "paul.lefort@example.org"
+ },
+ {
+ "id": 9,
+ "name": "Dupuy",
+ "firstName": "Sacha",
+ "age": 6,
+ "lastLessonDate": 1705132800,
+ "level": 0,
+ "credit": 15,
+ "address": "6 rue des Charmilles, 67000 Strasbourg",
+ "notes": "Très créatif, participe volontiers.",
+ "ffeLicence": false,
+ "ffeLicenceValidityYear": 2026,
+ "ffeLicenceNumber": "C3344556",
+ "legalGuardianName": "Martin",
+ "legalGuardianFirstName": "Élodie",
+ "legalGuardianRole": "mère",
+ "legalGuardianPhoneNumber": "03 88 12 34 56",
+ "legalGuardianEmail": "elodie.martin@example.com"
+ }
+]
diff --git a/project.xml b/project.xml
index 7e6402e..38b937f 100644
--- a/project.xml
+++ b/project.xml
@@ -28,4 +28,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/LPTCManager2026.hx b/src/LPTCManager2026.hx
index 7cc3b62..22adb62 100644
--- a/src/LPTCManager2026.hx
+++ b/src/LPTCManager2026.hx
@@ -1,3 +1,9 @@
+import control.AppController;
+import business.Services;
+import model.AppModelLocator;
+import com.adobe.cairngorm.control.CairngormEventDispatcher;
+import control.LoadRidersEvent;
+import feathers.events.FeathersEvent;
import feathers.layout.VerticalAlign;
import components.NekoRectangle;
import feathers.controls.Application;
@@ -12,12 +18,19 @@ import openfl.Assets;
import openfl.text.Font;
class LPTCManager2026 extends Application {
- private var mainPanel:Panel;
+
+ private var model = AppModelLocator.getInstance();
+ private var services = new Services();
+ private var appController = new AppController();
+ //private var mainPanel:Panel;
// private var nav:StackNavigator;
public function new() {
super();
+
+ addEventListener(FeathersEvent.CREATION_COMPLETE, onCreationComplete);
+
}
override private function initialize():Void {
@@ -26,7 +39,7 @@ class LPTCManager2026 extends Application {
stage.displayState = NORMAL;
stage.scaleMode = NO_SCALE;
- mainPanel = new Panel();
+ /*mainPanel = new Panel();
mainPanel.autoSizeMode = STAGE;
mainPanel.backgroundSkin = new NekoRectangle(Constants.MAIN_COLOR3);
@@ -70,10 +83,21 @@ class LPTCManager2026 extends Application {
mainPanel.footer = footer;
- addChild(mainPanel);
+ addChild(mainPanel);*/
// nav = new StackNavigator();
trace(this, "--> initialize()");
}
+
+ private function loadRiders():Void {
+ trace(this + " --> loadRiders()");
+ var cgEvent:LoadRidersEvent = new LoadRidersEvent();
+ CairngormEventDispatcher.getInstance().dispatchEvent(cgEvent);
+ }
+
+ private function onCreationComplete(event:FeathersEvent):Void {
+ trace(this + " --> onCreationComplete()");
+ loadRiders();
+ }
}
diff --git a/src/business/LoadRidersDelegate.hx b/src/business/LoadRidersDelegate.hx
new file mode 100644
index 0000000..a178ab2
--- /dev/null
+++ b/src/business/LoadRidersDelegate.hx
@@ -0,0 +1,24 @@
+package business;
+
+import com.adobe.cairngorm.business.ServiceLocator;
+import feathers.rpc.IResponder;
+import feathers.rpc.http.HTTPService;
+
+class LoadRidersDelegate {
+ private var command:IResponder;
+ private var service:HTTPService;
+
+ public function new(command:IResponder) {
+ // constructor will store a reference to the service we're going to call
+ service = ServiceLocator.getInstance().getHTTPService('loadRidersService');
+ // and store a reference to the command that created this delegate
+ this.command = command;
+ }
+
+ public function loadRidersService():Void {
+ // call the service
+ var token = service.send();
+ // notify this command when the service call completes
+ token.addResponder(command);
+ }
+}
diff --git a/src/business/Services.hx b/src/business/Services.hx
new file mode 100644
index 0000000..9052e62
--- /dev/null
+++ b/src/business/Services.hx
@@ -0,0 +1,15 @@
+package business;
+
+import com.adobe.cairngorm.business.ServiceLocator;
+import feathers.rpc.http.HTTPService;
+
+class Services extends ServiceLocator {
+ public var loadRidersService:HTTPService;
+
+ public function new() {
+ super();
+ loadRidersService = new HTTPService();
+ loadRidersService.url = "data/riders.json";
+ loadRidersService.resultFormat = HTTPService.RESULT_FORMAT_JSON;
+ }
+}
diff --git a/src/command/LoadRidersCommand.hx b/src/command/LoadRidersCommand.hx
new file mode 100644
index 0000000..e980816
--- /dev/null
+++ b/src/command/LoadRidersCommand.hx
@@ -0,0 +1,54 @@
+package command;
+
+import openfl.Vector;
+import vo.Rider;
+import feathers.data.ArrayCollection;
+import openfl.Lib;
+import haxe.DynamicAccess;
+import business.LoadRidersDelegate;
+import com.adobe.cairngorm.commands.ICommand;
+import com.adobe.cairngorm.control.CairngormEvent;
+import feathers.rpc.IResponder;
+import feathers.rpc.events.ResultEvent;
+import haxe.Json;
+import model.AppModelLocator;
+
+class LoadRidersCommand implements ICommand implements IResponder {
+ private var model = AppModelLocator.getInstance();
+
+ public function execute(cgEvent:CairngormEvent):Void {
+ // create a worker who will go get some data and pass it a reference to this command so the delegate knows where to return the data
+ var delegate = new LoadRidersDelegate(this);
+ // make the delegate do some work
+ delegate.loadRidersService();
+ trace(this + "execute()");
+ }
+
+ // this is called when the delegate receives a result from the service
+ public function result(rpcEvent:Dynamic):Void {
+
+ // populate the riders DP in the model locator with the JSON results from the service call
+ var riders:Array = cast(rpcEvent, ResultEvent).result;
+ model.ridersListDP = new ArrayCollection(riders);
+
+ trace("ridersListDP.length --> " + model.ridersListDP.length);
+
+ /*var data:DynamicAccess = Json.parse(cast(rpcEvent, ResultEvent).result);
+ */
+
+ /*var data:DynamicAccess = Json.parse(e.target.data);
+ for (key => value in data){
+ ConfigValues.data[key] = value;
+ } */
+
+
+
+ }
+
+ // this is called when the delegate receives a fault from the service
+ public function fault(rpcEvent:Dynamic):Void {
+ // store an error message in the model locator
+ // labels, alerts, etc can bind to this to notify the user of errors
+ model.errorStatus = "Fault occured in LoadEmployeesCommand.";
+ }
+}
diff --git a/src/control/AppController.hx b/src/control/AppController.hx
new file mode 100644
index 0000000..db84798
--- /dev/null
+++ b/src/control/AppController.hx
@@ -0,0 +1,13 @@
+package control;
+
+import command.LoadRidersCommand;
+import com.adobe.cairngorm.control.FrontController;
+
+class AppController extends FrontController {
+ public static final LOAD_RIDERS_EVENT = "loadRidersEvent";
+
+ public function new() {
+ super();
+ addCommand(AppController.LOAD_RIDERS_EVENT, LoadRidersCommand);
+ }
+}
diff --git a/src/control/LoadRidersEvent.hx b/src/control/LoadRidersEvent.hx
new file mode 100644
index 0000000..945d223
--- /dev/null
+++ b/src/control/LoadRidersEvent.hx
@@ -0,0 +1,9 @@
+package control;
+
+import com.adobe.cairngorm.control.CairngormEvent;
+
+class LoadRidersEvent extends CairngormEvent {
+ public function new() {
+ super(AppController.LOAD_RIDERS_EVENT);
+ }
+}
diff --git a/src/model/AppModelLocator.hx b/src/model/AppModelLocator.hx
new file mode 100644
index 0000000..d569bd2
--- /dev/null
+++ b/src/model/AppModelLocator.hx
@@ -0,0 +1,76 @@
+package model;
+
+import vo.Rider;
+import feathers.data.ArrayCollection;
+import openfl.errors.Error;
+import openfl.events.Event;
+import com.adobe.cairngorm.model.IModelLocator;
+import openfl.events.EventDispatcher;
+
+class AppModelLocator extends EventDispatcher implements IModelLocator {
+
+ // events constants
+ public static final VIEWING_CHANGE = "viewingChange";
+ public static final RIDERS_LIST_DP_CHANGE = "ridersListDPChange";
+
+
+ // this instance stores a static reference to itself
+ private static var model:AppModelLocator;
+
+ // available values for the main viewstack defined as constants to help uncover errors at compile time instead of run time
+ public static final ADMIN_LOGIN = 0;
+ public static final RIDERS_LIST = 1;
+ public static final RIDER_DETAIL = 2;
+
+ // viewstack starts out on the admin login screen
+ public var viewing(default, set):Int = ADMIN_LOGIN;
+
+ private function set_viewing(value:Int):Int {
+ viewing = value;
+ dispatchEvent(new Event(VIEWING_CHANGE));
+ return viewing;
+ }
+
+ // rider object contains uid/passwd
+ // its value gets set at login and cleared at logout but nothing binds to it or uses it
+ // retained since it was used in the original Adobe CafeTownsend example app
+ /*public var user(default, set):User;
+
+ private function set_user(value:User):User {
+ user = value;
+ dispatchEvent(new Event(USER_CHANGE));
+ return user;
+ }*/
+
+ // contains the main riders list which is populated on startup
+ // mx:application's creationComplete event is mutated into a cairngorm event
+ // that calls the httpservice for the data
+ public var ridersListDP(default, set):ArrayCollection;
+
+ private function set_ridersListDP(value:ArrayCollection):ArrayCollection {
+ ridersListDP = value;
+ dispatchEvent(new Event(RIDERS_LIST_DP_CHANGE));
+ return ridersListDP;
+ }
+
+ // variable to store error messages from the httpservice
+ // nothinng currently binds to it, but an Alert or the login box could to show startup errors
+ public var errorStatus:String;
+
+
+ // singleton: constructor only allows one model locator
+ public function new() {
+ super();
+ if (AppModelLocator.model != null) {
+ throw new Error("Only one ModelLocator instance should be instantiated");
+ }
+ }
+
+ // singleton: always returns the one existing static instance to itself
+ public static function getInstance():AppModelLocator {
+ if (model == null)
+ model = new AppModelLocator();
+ return model;
+ }
+
+}
\ No newline at end of file
diff --git a/src/vo/Rider.hx b/src/vo/Rider.hx
new file mode 100644
index 0000000..8cd3485
--- /dev/null
+++ b/src/vo/Rider.hx
@@ -0,0 +1,64 @@
+package vo;
+
+class Rider {
+ private static var currentIndex = 1000;
+
+ public var id:Int;
+ public var name:String;
+ public var firstName:String;
+ public var age:Int;
+ public var lastLessonDate:Int;
+ public var level:Int;
+ public var credit:Int;
+ public var address:String;
+ public var notes:String;
+ public var ffeLicence:Bool;
+ public var ffeLicenceValidityYear:Int;
+ public var ffeLicenceNumber:String;
+ public var legalGuardianName:String;
+ public var legalGuardianFirstName:String;
+ public var legalGuardianRole:String;
+ public var legalGuardianPhoneNumber:Int;
+ public var legalGuardianEmail:String;
+
+
+ public function new(pId:Int = 0,
+ pName:String = "",
+ pFirstName:String = "",
+ pAge:Int = 0,
+ pLastLessonDate:Int,
+ pLevel:Int = 0,
+ pCredit:Int = 0,
+ pAddress:String = "",
+ pNotes:String = "",
+ pffeLicence:Bool = false,
+ pffeLicenceValidityYear:Int = 0,
+ pffeLicenceNumber:String = "",
+ pLegalGuardianName:String = "",
+ pLegalGuardianFirstName:String = "",
+ pLegalGuardianRole:String = "",
+ pLegalGuardianPhoneNumber:Int = 0,
+ pLegalGuardianEmail:String = "") {
+
+ id = (pId == 0) ? currentIndex++ : pId;
+ name = pName;
+ firstName = pFirstName;
+ age = pAge;
+ lastLessonDate = pLastLessonDate;
+ level = pLevel;
+ credit = pCredit;
+ address = pAddress;
+ notes = pNotes;
+ ffeLicence = pffeLicence;
+ ffeLicenceValidityYear = pffeLicenceValidityYear;
+ ffeLicenceNumber = pffeLicenceNumber;
+ legalGuardianName = pLegalGuardianName;
+ legalGuardianFirstName = pLegalGuardianFirstName;
+ legalGuardianRole = pLegalGuardianRole;
+ legalGuardianPhoneNumber = pLegalGuardianPhoneNumber;
+ legalGuardianEmail = pLegalGuardianEmail;
+
+ //startdate = (startdate == null) ? Date.now() : startdate;
+
+ }
+}
\ No newline at end of file