Un langage de description d’interface UI pour des applications dynamiques avec WebView

Nous avons montré dans l’article précédent comment créer un langage de description d’interface UI permettant de générer des pages HTML dans Android Studio. Nous allons maintenant étendre notre langage spécifique afin de créer les tags au fur et à mesure des besoins rencontrés lors de la création des pages pour notre projet.

A l’issue de cet article vous saurez comment ajouter de nouveaux tag (appelé aussi widget). Vous pourrez étendre le langage de description d’interface UI et créer des applications dynamiques avec WebView Android. Pouvoir compléter le langage de description UI permet de personnaliser les outils afin d’être mieux adapté au métier cible.

Comment créer un langage de description d’interface UI générant dynamiquement des pages HTML dans WebView pour Android ? suivez le guide.

La page gestion de compte dans le langage de description d’Interface UI pour les applications dynamiques avec WebView

La page MonCompte permet de décrire l’utilisateur connecté à l’application. Nous y retrouvons les données de connexion : userName, userId, UserPassword userEmail, userToken.

Nous avons plusieurs vues pour le compte :

  • la vue recherche
  • la vue création de compte
  • la vue mot de passe perdu
  • la vue modification
  • la vue affichage

Affichage du compte

L’affichage du compte donne les informations enregistrées sur l’utilisateur.

public class MonCompteDisplay extends ScreenModel {

    Context context;

    public MonCompteDisplay(Context context) {
        super(context);
    }

    public PlugsetMessage build(PlugsetMessage message) {
        ScreenLibrary s = new ScreenLibrary(this);
        s.newPage("monCompteDisplay", "A1", "B12");
        s.label("titre", null,"mon compte", "A1", "A1");
        String userFirstName=getUserFirstName(message);
        String userLastName=getUserLastName(message);
        String userEmail=getUserEmail(message);
        String userPassword=getUserPassword(message);
        String userId=getUserId(message);
        String userToken=getUserToken(message);
        s.label("labelFirstName","firstName", "Prénom", "A3", "A3");
        s.text("firstName",  userFirstName, 1,25,"B3", "B3",  false);
        s.label("labelLastName", "lastName", "Nom", "A4", "A4");
        s.text("lastName", userLastName, 1,25,"B4", "B4",  false);
        s.label("labelEmail","email", "Adresse courriel", "A5", "A5");
        s.text("email", userEmail, 1,25,"B5", "B5",  false);
        s.label("labelPassword", "password", "Mot de passe", "A6", "A6");
        s.password("password", userPassword, 8,12,"B6", "B6", false);
        s.label("labelUserId", "userId", "identifiant", "A7", "A7");
        s.text("userId", userId, 17,17,"B7", "B7",  false);
        s.label("labelUserToken", "userToken", "Token", "A8", "A8");
        s.text("userToken", userToken,10,30, "B8", "B8", false);
        s.button("btnConnection", "Quitter", "A10", "B10", "callScreen", "menu.asp", true);
        s.button("btnUpdate", "Modifier", "A11", "B11", "callScript", "doModify", true);s.endPage();
        Repository screenRepository=s.get();
        System.out.println("AppLog.Menu.build : screenRepository="+screenRepository.getXmlString());
        //on doit construire la réponse et la mettre dans message
        message.put("page","xml",getRepository());
        return message;
    }

    private String getUserFirstName(PlugsetMessage message){
        return "Bertrand";
    }

    private String getUserLastName(PlugsetMessage message){
        return "Roussel";
    }
  
    private String getUserEmail(PlugsetMessage message){
        return "bertrand.roussel@copier-coder.com";
    }
  
    private String getUserPassword(PlugsetMessage message){
        return "brousselPassword";
    }
 
    private String getUserId(PlugsetMessage message){
        return "20220816151545689";
    }
  
    private String getUserToken(PlugsetMessage message){
        return "azDe5fH6DEn73YHxC";
    }
  
  
}

Nous avons ajouté à notre bibliothèque de fonction les tags suivants :

  • Text : qui est un input html
  • Password : un input de type password

Nous avons aussi modifié Label pour y associer un lien ‘forvers un input de type Text ou Password.

Chaque bouton est associé à une action. Nous avons deux types d’action :

  • callScreen : pour appeler une autre page, comme ce que nous avons vu dans la page Menu
  • callScript pour appeler une fonction javascript de la page courante

Pour chaque page nous avons un code javascript associé qui est appelé. Pour la page Menu nous avons le fichier javascript menu.js. Pour la page MonCompteDisplay nous avons le code javascript de monCompteDisplay.js.

Modification de HtmlEngine

Pour prendre en compte les 2 options callScreen et callScript, nous modifions le code de HtmlEngine button_start(RepositoryItem tag) :

HtmlEngine :

    public boolean button_start(RepositoryItem tag) {
        try {
            System.out.println("AppLog "+this.getClass().getName()+".button_start"+" tag=" + tag);
            String name = tag.getName();
            String caption = (String) tag.getProperty(KeyWord.CAPTION);
            String actionName = (String) tag.getProperty(KeyWord.ACTION_NAME);
            String actionParam = (String) tag.getProperty(KeyWord.ACTION_PARAM);
            String areaStart = (String) tag.getProperty(KeyWord.AREA_START);
            String areaEnd = (String) tag.getProperty(KeyWord.AREA_END);
            System.out.println("AppLog "+this.getClass().getName()+".button_start"+" name=" + name+" caption=" + caption+" actionName=" + actionName+" actionParam=" + actionParam+" areaStart=" + areaStart +" areaEnd=" + areaEnd);
            String areaClass= areaGrid.addArea(areaStart,areaEnd);
          
            StringBuilder buttonHtml=new StringBuilder();
            buttonHtml.append("<button");

            buttonHtml.append(" type=");
            buttonHtml.append(Ascii.QUOTE);
            buttonHtml.append("button");
            buttonHtml.append(Ascii.QUOTE);

            buttonHtml.append(" class=");
            buttonHtml.append(Ascii.QUOTE);
            buttonHtml.append(areaClass);
            buttonHtml.append(Ascii.QUOTE);
          
          	switch(actionName){
              case "callScript ":
                    buttonHtml.append(" onclick=");
                    buttonHtml.append(Ascii.QUOTE);
                    buttonHtml.append(actionParam);
                    buttonHtml.append("(");
                    buttonHtml.append("this");
                    buttonHtml.append(")");
                    buttonHtml.append(Ascii.QUOTE);
                	break;
                case "callScreen ":
                    buttonHtml.append(" onclick=");
                    buttonHtml.append(Ascii.QUOTE);
                    buttonHtml.append("location.href='");
                    buttonHtml.append(actionParam);
                    buttonHtml.append("'");                    
                    buttonHtml.append(Ascii.QUOTE);
                	break;
            }

            buttonHtml.append(">").append(Ascii.CRLF);
            buttonHtml.append(caption).append(Ascii.CRLF);
            buttonHtml.append("</button>");
            htmlBody.append(buttonHtml).append(Ascii.CRLF);;
        } catch (Exception e) {
            System.out.println("AppLog "+this.getClass().getName()+".button_start"+" ERROR :" + e);
        }
        return false;
    }

Nous modifions getHtmlScript pour ajouter le chargement du fichier screenName.js.

HtmlEngine :

	private String screenName;

	protected String getHtmlScript(){
        StringBuilder script=new StringBuilder();
        script.append("<script type=");
      	script.append(Ascii.QUOTE);
        script.append("text/javascript");
      	script.append(Ascii.QUOTE);
        script.append(" src=");
      	script.append(Ascii.QUOTE)
        script.append(screenName);
      	script.append(".js");
      	script.append(Ascii.QUOTE);
        script.append(">");
       	script.append("</script>");

        script.append("<script>");
        script.append(javascript);
        script.append("</script>");
        return script.toString();
    }

    public boolean screen_start(RepositoryItem tag) {
        try {
            System.out.println("AppLog "+this.getClass().getName()+".screen_start"+" tag=" + tag);
            String theScreenName = tag.getName();//le nom de l'écran
			screenName=tag.getName();//le nom de l'écran
          ...

Nous avons ajouté :

  • la propriété screenName (ligne 1)
  • l’affectation de la valeur screenName depuis screen_start (ligne 27)
  • la création des lignes 5 à 15 de getHtmlScript() pour créer le text <script type= »text/javascript » src= »screenName.js »></script>  

Nous modifions Label_start comme suit :

  • nous utilisons le html label à la place d’un div (ligne 12 et 26)
  • nous indiquons l’id du label avec la propriété name (ligne 12 à 15)
  • nous ajoutons la propriété for faisant le lien vers la zone input (ligne 20 à 24)

HtmlEngine :

    public boolean label_start(RepositoryItem tag) {
        try {
            System.out.println("AppLog "+this.getClass().getName()+".label_start"+" tag=" + tag);
            String name = tag.getName();//le nom du label
            String caption = (String) tag.getProperty(KeyWord.CAPTION);
            String labelFor = (String) tag.getProperty(KeyWord.LABEL_FOR);
            String areaStart = (String) tag.getProperty(KeyWord.AREA_START);
            String areaEnd = (String) tag.getProperty(KeyWord.AREA_END);
            System.out.println("AppLog "+this.getClass().getName()+".label_start"+" name=" + name+" labelFor=" + labelFor+" caption=" + caption+" areaStart=" + areaStart+" areaEnd=" + areaEnd);
            String areaClass= areaGrid.addArea(areaStart,areaEnd);
            StringBuilder labelHtml=new StringBuilder();
            labelHtml.append("<label id=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(name);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" class=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(areaClass);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" for=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(labelFor);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(">");
            labelHtml.append(caption);
            labelHtml.append("</label>");
            htmlBody.append(labelHtml).append(Ascii.CRLF);
        } catch (Exception e) {
            System.out.println("AppLog "+this.getClass().getName()+".label_start"+" ERROR :" + e);
        }
        return false;
    }

Modifions ScreenLibrary label :

    public final void label(String name, String labelFor, String caption, String areaStart, String areaEnd) {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagSingle();
        tag.setModel(ScreenWord.LABEL);
        tag.addProperty(KeyWord.NAME, name);
        tag.addProperty(KeyWord.LABEL_FOR, labelFor);
        tag.addProperty(KeyWord.CAPTION, caption);
        tag.addProperty(KeyWord.AREA_START,areaStart);
        tag.addProperty(KeyWord.AREA_END, areaEnd);
        get().addTag(tag);
    }

Dans le langage de description d’interface UI nous créons les deux tag Text et Password, indispensable pour créer des applications dynamiques avec WebView

Text et Password sont ajoutés.

    public final void password(String name, String value, int length, String areaStart, String areaEnd,boolean editable) {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagSingle();
        tag.setModel(ScreenWord.PASSWORD);
        tag.addProperty(KeyWord.NAME, name);
        tag.addProperty(KeyWord.VALUE, value);
        tag.addProperty(KeyWord.LENGTH, length);
        tag.addProperty(KeyWord.EDITABLE, editable);
        tag.addProperty(KeyWord.AREA_START,areaStart);
        tag.addProperty(KeyWord.AREA_END, areaEnd);
        get().addTag(tag);
    }

    public final void text(String name, String value, int minLength, int maxLength, String areaStart, String areaEnd,boolean editable) {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagSingle();
        tag.setModel(ScreenWord.TEXT);
        tag.addProperty(KeyWord.NAME, name);
        tag.addProperty(KeyWord.VALUE, value);
        tag.addProperty(KeyWord.LENGTH_MIN, minLength);
      	tag.addProperty(KeyWord.LENGTH_MAX, maxLength);
        tag.addProperty(KeyWord.EDITABLE, editable);
        tag.addProperty(KeyWord.AREA_START,areaStart);
        tag.addProperty(KeyWord.AREA_END, areaEnd);
        get().addTag(tag);
    }    

	public final void text(String name, String value, int minLength, int maxLength, String areaStart, String areaEnd,boolean editable) {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagSingle();
        tag.setModel(ScreenWord.TEXT);
        tag.addProperty(KeyWord.NAME, name);
        tag.addProperty(KeyWord.VALUE, value);
        tag.addProperty(KeyWord.LENGTH_MIN, minLength);
      	tag.addProperty(KeyWord.LENGTH_MAX, maxLength);
        tag.addProperty(KeyWord.EDITABLE, editable);
        tag.addProperty(KeyWord.AREA_START,areaStart);
        tag.addProperty(KeyWord.AREA_END, areaEnd);
        get().addTag(tag);
    }

Nous devons aussi compléter KeyWord :

  • LABEL_FOR (ligne 9) pour Label
  • VALUE (ligne 12) pour Text et Password
  • LENGTH_MIN et LENGTH_MAX (ligne 10 et 11) pour Text et Password
public enum KeyWord {

    ACTION_NAME("actionName"),
    ACTION_PARAM("actionParam"),
    AREA_START("areaStart"),
    AREA_END("areaEnd"),
    CAPTION("caption"),
    EDITABLE("editable"),
    LABEL_FOR("labelFor"),
    LENGTH_MIN("lengthMin"),
  	LENGTH_MAX("lengthMax"),
    NAME("name"),
    VALUE("value");

    private String value;

    private static final Map<String, KeyWord> BY_LABEL = new HashMap();

    static{
        for(KeyWord word:values()){
            BY_LABEL.put(word.value,word);
        }
    }

    private KeyWord(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return getValue();
    }

    public static KeyWord parse(String value)  {
        return BY_LABEL.get(value);
    }
}

Nous complétons ScreenWord avec TEXT (ligne 7) et PASSWORD (ligne 5) :

public enum ScreenWord implements ModelWord {

    BUTTON("Button"),
    LABEL("Label"),
    PASSWORD("Password"),
    SCREEN("Screen"),
    TEXT("Text");

    private final String value;

    private ScreenWord(String value) {
        this.value = value;
    }

    @Override
    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return value;
    }

    public static ScreenWord parse(String value){
        return  ModelWord.parse(ScreenWord.class,  value);
    }
}

Nous ajoutons à HtmlEngine la génération de Text et Password :

HtmlEngine, text_start :

    public boolean text_start(RepositoryItem tag) {
        try {
            System.out.println("AppLog "+this.getClass().getName()+".label_start"+" tag=" + tag);
            String name = tag.getName();//le nom du label
            String value = (String) tag.getProperty(KeyWord.VALUE);
            int minLength = (Integer) tag.getProperty(KeyWord.LENGTH_MIN);
            int maxLength = (Integer) tag.getProperty(KeyWord.LENGTH_MAX);
            boolean editable = (Boolean) tag.getProperty(KeyWord.EDITABLE);
            String areaStart = (String) tag.getProperty(KeyWord.AREA_START);
            String areaEnd = (String) tag.getProperty(KeyWord.AREA_END);
            String readOnly = (editable) ? "" : "readonly";
            System.out.println("AppLog "+this.getClass().getName()+".text_start"+" name=" + name+" value=" + value+" minLength=" + minLength+" maxLength=" + maxLength+" editable=" + editable+" readOnly=" + readOnly+" areaStart=" + areaStart+" areaEnd=" + areaEnd);
            String areaClass= areaGrid.addArea(areaStart,areaEnd);
            StringBuilder labelHtml=new StringBuilder();
            labelHtml.append("<input type=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append("text");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" id=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(name);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" value=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(value);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" minlength=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(minLength);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" maxlength=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(maxLength);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" ");
            labelHtml.append(readOnly);
            labelHtml.append(" class=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(areaClass);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(">");
            htmlBody.append(labelHtml).append(Ascii.CRLF);
        } catch (Exception e) {
            System.out.println("AppLog "+this.getClass().getName()+".text_start"+" ERROR :" + e);
        }
        return false;
    }

HtmlEngine, password_start :

    public boolean password_start(RepositoryItem tag) {
        try {
            System.out.println("AppLog "+this.getClass().getName()+".label_start"+" tag=" + tag);
            String name = tag.getName();//le nom du label
            String value = (String) tag.getProperty(KeyWord.VALUE);
            int minLength = (Integer) tag.getProperty(KeyWord.LENGTH_MIN);
            int maxLength = (Integer) tag.getProperty(KeyWord.LENGTH_MAX);
            boolean editable = (Boolean) tag.getProperty(KeyWord.EDITABLE);
            String areaStart = (String) tag.getProperty(KeyWord.AREA_START);
            String areaEnd = (String) tag.getProperty(KeyWord.AREA_END);
            String readOnly = (editable) ? "readonly" : "";
            System.out.println("AppLog "+this.getClass().getName()+".password_start"+" name=" + name+" value=" + value+" minLength=" + minLength+" maxLength=" + maxLength+" editable=" + editable+" readOnly=" + readOnly+" areaStart=" + areaStart+" areaEnd=" + areaEnd);
            String areaClass= areaGrid.addArea(areaStart,areaEnd);
            StringBuilder labelHtml=new StringBuilder();
            labelHtml.append("<input type=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append("password");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" id=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(name);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" value=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(value);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" minlength=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(minLength);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" maxlength=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(maxLength);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(" ");
            labelHtml.append(readOnly);
            labelHtml.append(" class=");
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(areaClass);
            labelHtml.append(Ascii.QUOTE);
            labelHtml.append(">");
            htmlBody.append(labelHtml).append(Ascii.CRLF);
        } catch (Exception e) {
            System.out.println("AppLog "+this.getClass().getName()+".password_start"+" ERROR :" + e);
        }
        return false;
    }

Nous devons ajouter la déclaration de text et password dans le catalogue HtmlRepositoyEngine :

    private void loadTagMethodMatch() {
        addWordMethodMatch( ScreenWord.SCREEN,  "screen");
        addWordMethodMatch( ScreenWord.LABEL,  "label");
        addWordMethodMatch( ScreenWord.BUTTON,  "button");
        addWordMethodMatch( ScreenWord.TEXT,  "text");
        addWordMethodMatch( ScreenWord.PASSWORD,  "password");
    }

Visualisation de la page générée dans le simulateur

Dans le simulateur, nous avons la page suivante :

DSL et InterfaceUI - Etape 1 - MonCompteDisplay
DSL et InterfaceUI – Etape 1 – MonCompteDisplay

La page d’authentification

La page d’authentification permet à l’utilisateur d’ouvrir une session. Le principe est celui d’une recherche avec adresse email et mot de passe. Le résultat est l’ouverture de la session.

public class MonCompteResearch extends ScreenModel {

    Context context;

    public MonCompteResearch(Context context) {
        super(context);
    }

   	public PlugsetMessage build(PlugsetMessage message) {
        ScreenLibrary s = new ScreenLibrary(this);
        s.newPage("monCompteResearch", "A1", "B12");
        s.label("titre",null, "authentification", "A1", "A1");

        s.label("labelEmail","email", "Adresse courriel", "A5", "A5");
        s.text("email", "", 1,25,"B5", "B5",  true);
        s.label("labelPassword", "password", "Mot de passe", "A6", "A6");
        s.password("password", "",8,12, "B6", "B6", true);

        s.button("btnConnection", "Valider", "A8", "B8", "callScript", "doConnect", true);
        s.button("btnPerdu", "Mot de passe perdu", "A9", "B9", "callScript", "doRenewPwd", true);
        s.button("btnQuitter", "Quitter", "A10", "B10", "callScreen", "menu.asp", true);
        s.endPage();
        Repository screenRepository=s.get();
        System.out.println("AppLog.MonCompteDisplay.build : screenRepository="+screenRepository.getXmlString());
        //on doit construire la réponse et la mettre dans message
        message.put("page","xml",getRepository());
        return message;
    }
  
}

Les scripts doConnect et doRenewPwd sont définis dans le javascript de la page monCompteResearch.js.

La fonction doRenewPwd , envoie sur une adresse courriel dédiée ou un numéro de téléphone dédié un message contenant un code ayant une durée de vie de 5mn. Puis, nous avons une redirection vers la page de changement de Mot de passe.

Visualisation de la page dans le simulateur

DSL et InterfaceUI - Etape 2 - MonCompteResearch
DSL et InterfaceUI – Etape 2 – MonCompteResearch

La page changement de mot de passe

Le changement de mot de passe suppose une double action de contrôle. Nous pouvons :

  • envoyer un courriel avec l’url de changement de mot de passe
  • envoyer un code éphémère dans un sms ou un courriel à un numéro ou une adresse dédiés à la récupération de mot de passe

La dernière option suppose de définir dans le compte utilisateur une adresse ou un numéro de téléphone dédié à la récupération de mot de passe. C’est cette méthode qui est utilisée ici, avec doGetCode qui envoie le code.

public class MonCompteChangePwd extends ScreenModel {

    Context context;

    public MonCompteChangePwd(Context context) {
        super(context);
    }

    public PlugsetMessage build(PlugsetMessage message) {
        ScreenLibrary s = new ScreenLibrary(this);
        s.newPage("monCompteChangePwd", "A1", "B12");
        s.label("titre", null,"changement du mot de passe", "A1", "B1");

        s.button("btnNewCode", "Obtenir un code", "A2", "B2", "callScript", "doGetCode", true);
        String moyenRecup=getUserRecup(message);
        s.label("message",null, "Un code vous a été adessé "+moyenRecup, "A3", "B3");
        s.label("labelCode","code", "Code", "A5", "A5");
        s.text("code", "",6,6, "B5", "B5",  true);
        s.label("labelPassword", "password", "Nouveau mot de passe", "A6", "A6");
        s.password("password", "", 8,12,"B6", "B6", true);
        s.label("labelPassword2", "password2", "Répéter mot de passe", "A7", "A7");
        s.password("password2", "", 8,12,"B7", "B7", true);

        s.button("btnConnection", "Valider", "A9", "B9", "callScript", "doChangePwd", true);
        s.button("btnQuitter", "Quitter", "A10", "B10", "callScreen", "Menu.asp", true);
        s.endPage();
        Repository screenRepository=s.get();
        System.out.println("AppLog.MonCompteChangePwd.build : screenRepository="+screenRepository.getXmlString());
        //on doit construire la réponse et la mettre dans message
        message.put("page","xml",getRepository());
        return message;
    }
      
    private String getNewCode(PlugsetMessage message){
        return "un nouveau code a été envoyé";
    }
  
  	private String getUserRecup(PlugsetMessage message){
        return "sur votre téléphone / par email";
    }
  
   	private String getSuccessPage(PlugsetMessage message){
        return "menu.asp";
    }
      
   	private String getErrorPage(PlugsetMessage message){
        return "menu.asp";
    }
}

La fonction doChangePwd envoi le code et le nouveau mot de passe. Si le code correspond au code qui avait été envoyé, nous changeons le mot de passe, puis, nous allons vers getSuccessPage.

Cette fonctionnalité utilise la fiche de l’utilisateur. Lorsque le code est généré, il est enregistré dans la fiche de l’utilisateur ainsi que la date de péremption associée.

Visualisation de la page de changement de mot de passe

DSL et InterfaceUI - Etape 3 - MonCompteChangePwd
DSL et InterfaceUI – Etape 3 – MonCompteChangePwd

Résumé des étapes pour compléter le langage de description d’interface UI et créer des applications dynamiques avec WebView

Pour étendre le langage de description d’interface UI, nous ajoutons des tag, cela permet de personaliser l’outil afin de créer des applications dynamiques métier avec WebView.

Nous venons de voir sur un cas concret les différentes étapes pour compléter notre outil de génération d’interface utilisateur :

  • la création de page utilisateur
  • la création d’un nouveau Tag

Création d’une page

Pour ajouter une page, nous créons une classe java du nom de la page :

  • La classe est de type ScreenModel (ligne 1)
  • Le nom de la page commence comme toutes les classes java par une majuscule (ligne 1)
  • La méthode build est obligatoire (ligne 9)
  • Nous utilisons la bibliothèque ScrrenLibrary (ligne 10) pour composer le design de la page
  • Dans newPage le nom de la page commence par une minuscule (ligne 11)
  • Ce nom est utilisé pour le fichier maNouvellePage.js

Nouvelle classe pour la page MaNouvellePage :

public class MaNouvellePage extends ScreenModel {

    Context context;

    public MonCompteChangePwd(Context context) {
        super(context);
    }

    public PlugsetMessage build(PlugsetMessage message) {
        ScreenLibrary s = new ScreenLibrary(this);
        s.newPage("maNouvellePage", "A1", "B12");
        ...
    }
  
    ...
}

Ajout d’un nouveau Widget dans ScreenLibrary

La création d’un nouveau tag ou widget, intervient à plusieurs endroit.

ScreenLibrary regroupe l’ensemble des widgets. ScreenLibrary permet de construire la page. C’est cette classe qui est utilisée dans la classe de construction de la page.

Puis nous devons créer la méthode pour générer le code correspondant au Widget. Cela est réalisé dans HtmlEngine.

Lorsqu’un nouvel attribut est défini comme propriété pour un Widget, nous créons cette propriété dans KeyWord.

Création du Widget dans ScreenLibrary

Ci-dessous l’exemple pour le nouveau Widget Text.

La création se fait avec XmlTagItem auquel nous passons l’ensemble des paramètres.

Avec tag.setTagSingle nous indiquons que le Widget ne contient pas d’autre widget, et un un Widget terminal.

Nous devons définir le model utilisé (ligne 4) avec tag.setModel(ScreenWord.WIDGET_NAME)

ScreenLibrary :

    public final void text(String name, String value, int length, String areaStart, String areaEnd,boolean editable) {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagSingle();
        tag.setModel(ScreenWord.TEXT);
        tag.addProperty(KeyWord.NAME, name);
        tag.addProperty(KeyWord.VALUE, value);
        tag.addProperty(KeyWord.LENGTH, length);
        tag.addProperty(KeyWord.EDITABLE, editable);
        tag.addProperty(KeyWord.AREA_START,areaStart);
        tag.addProperty(KeyWord.AREA_END, areaEnd);
        get().addTag(tag);
    }

Lorsque le Widget contient d’autre Widget, nous avons un tag de début tag.setTagStart et un tag de fin tag.setTagEnd. Nous avons par exemple newPage(), et endPage() qui embrasse toute la description de la page :

ScreenLibrary :

    public void newPage(String name, String areaStart, String areaEnd) {
        ...
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagStart();
        ...
    }
    public void endPage() {
        XmlTagItem<ScreenWord> tag = new XmlTagItem<ScreenWord>();
        tag.setTagEnd();
        ...
    }

Compléter ScreenWord avec le nom du Widget

La nom du Widget est ajouté dans ScreenWord.

ScreenWord :

public enum ScreenWord implements ModelWord {

    BUTTON("Button"),
    LABEL("Label"),
    PASSWORD("Password"),
    SCREEN("Screen"),
    TEXT("Text");
    ...
      
  }

Génération du langage de description d’interface UI pour des applications dynamiques avec WebView.

HtmlEngine est la classe qui crée la transformation des Widget en html. Nous avons pour chaque Widget 2 méthodes à créer dans HtmlEngine : widget_start() et widget_finish() :

HtmlEngine, text Widget :

 public boolean text_start(RepositoryItem tag) {
   try {
     StringBuilder textHtml=new StringBuilder();
     textHtml.append(...);
     htmlBody.append(textHtml).append(Asciiù.CRLF);
   }
   return false;
 }

public boolean text_finish(RepositoryItem tag)){
  	return false;
}

Déclarer le nouveau Widget dans HtmlRepositoryEngine

La correspondance entre le nom du Widget et le nom des méthodes de génération se fait pasr une déclaration dans HtmlRepositoryEngine

HtmlRepositoryEngine, loadTagMethodMatch :

    private void loadTagMethodMatch() {
        addWordMethodMatch( ScreenWord.SCREEN,  "screen");
        addWordMethodMatch( ScreenWord.LABEL,  "label");
        addWordMethodMatch( ScreenWord.BUTTON,  "button");
        addWordMethodMatch( ScreenWord.TEXT,  "text");
        addWordMethodMatch( ScreenWord.PASSWORD,  "password");
    }

Ajout d’un nouvel attribut

Dans ScreenLibrary, nous ajoutons les propriétés du tag. Si nous souhaitons utiliser une propriété non encore défini, nous créons dans KeyWord cette nouvelle propriété.

KeyWord :

public enum KeyWord {

    ACTION_NAME("actionName"),
    ACTION_PARAM("actionParam"),
    AREA_START("areaStart"),
    AREA_END("areaEnd"),
    CAPTION("caption"),
    EDITABLE("editable"),
    LABEL_FOR("labelFor"),
    LENGTH("length"),
    NAME("name"),
    VALUE("value");
  
  	...
      
  }

Nous avons montré toutes les étapes pour la création de page avec la création de nouveau Widget permettant d’ajouter de nouvelles description dans la page.

L’utilisation d’une bibliotheque de composition de page sous la forme d’un Specific domain Language est de pouvoir généraliser des composants de page. Pour l’instant, nous n’utilisaons aps les composants dans le HTML directement. L’utilisation de webComponent sera possible avec cette méthode. Ce la fera l’objet d’une présentation d’un autre article.

Si vous avez aimé l'article vous êtes libre de le partager :-)

Laisser un commentaire