« Sencha touch contacts » : différence entre les versions

De Wikilipo
Aller à la navigation Aller à la recherche
 
(12 versions intermédiaires par le même utilisateur non affichées)
Ligne 27 : Ligne 27 :


créer assets/www/index.html
créer assets/www/index.html
<pre>
<source lang="html5">
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
   <title>Learning sencha</title>
   <title>Learning sencha</title>
   <script type="text/javascript" src="lib/touch/sencha-touch-debug-w-comments.js"></script>
   <script type="text/javascript" src="lib/touch/sencha-touch-debug-w-comments.js"></script>
Ligne 37 : Ligne 37 :
</head><body></body>
</head><body></body>
</html>
</html>
</pre>
</source>


Pendant le développement, on utilise la version lisible de la librairie sencha-touch-debug-w-comments.js.  
Pendant le développement, on utilise la version lisible de la librairie sencha-touch-debug-w-comments.js.  


créer assets/www/js/application.js  
créer assets/www/js/application.js  
(application0.js)
(version 0)
<pre>
<source lang="javascript">
Ext.setup({
Ext.setup({
       onReady: function() {
       onReady: function() {
Ligne 56 : Ligne 56 :
       });
       });
  }});
  }});
</pre>
</source>


Selon la doc Ext.setup reçoit un objet avec des attributs;
Selon la doc Ext.setup reçoit un objet avec des attributs;
Ligne 76 : Ligne 76 :
Pour l'inclure dans l'application, il faut faire une version modifiée d'index.html,  
Pour l'inclure dans l'application, il faut faire une version modifiée d'index.html,  
qu'on peut appeler servage.html et dans lequel on change l'adresse des fichiers sencha
qu'on peut appeler servage.html et dans lequel on change l'adresse des fichiers sencha
<pre>
<source lang="html5">
   <script type="text/javascript" src="../lib/touch/sencha-touch.js"></script>
   <script type="text/javascript" src="../lib/touch/sencha-touch.js"></script>
   <link href="../lib/touch/resources/css/sencha-touch.css" rel="stylesheet" type="text/css" />
   <link href="../lib/touch/resources/css/sencha-touch.css" rel="stylesheet" type="text/css" />
</pre>
</source>
* Déployer l'application sur le serveur, y accéder par téléphone http://infolipo.net/cours/[votre nom]/servage.html
 


=== exercice ===
=== exercice ===
changer la couleur de fond de l'application
# changer la couleur de fond de l'application


=== déboguer sur le téléphone ===
# démarrer une console dos, tape ipconfig et noter l'adresse ip du pc
# ajouter ceci dans servage.html: <script src="http://[adresse ip]:8081/target/target-script-min.js"></script>
# copier servage.html sur le serveur
# dans la console:
#* cd h:/weinre-jar
#* java -jar weinre.jar --boundHost [adresse ip] --httpPort 8081
# aller sur http://infolipo.net/cours/[votre nom]/servage.html avec le téléphone
# dans chrome aller sur http://localhost:8081 et cliquer sur client


== créer une liste ==
== créer une liste ==
Ligne 89 : Ligne 100 :
Le code de la demo kitchensink est un peu compliqué,  
Le code de la demo kitchensink est un peu compliqué,  
mais on peut chercher List dans la doc.
mais on peut chercher List dans la doc.
On peut carrément copier l'exemple donné dans application.js,
On peut carrément copier l'exemple donné dans application.js (version 1),
et ajouter la liste dans les items du panel:
et ajouter la liste dans les items du panel:
(application1.js)
<source lang="javascript">
<pre>
Ext.setup({
Ext.setup({
       onReady: function() {
       onReady: function() {
Ligne 127 : Ligne 137 :
       });
       });
  }});
  }});
</pre>
</source>
On voit que la liste contient un '''store''', qui utilise un modèle,  
On voit que la liste contient un '''store''', qui utilise un modèle,  
qui est défini par Ext.regModel, qui crée un objet Ext.data.Model
qui est défini par Ext.regModel, qui crée un objet Ext.data.Model
Ligne 138 : Ligne 148 :
Toutes ces fonctionnalités vont au-delà du coté graphique pour lequel nous avons choisi sencha touch.
Toutes ces fonctionnalités vont au-delà du coté graphique pour lequel nous avons choisi sencha touch.


=== Model / View / Controller ===
=== model / view / controller ===
Au delà des composants graphiques, sencha offre un framework pour construire des applications.
Au delà des composants graphiques, sencha offre un framework pour construire des applications.
Le framework offre des fonctionnalités que dont les applications ont en général besoin,
Le framework offre des fonctionnalités que dont les applications ont en général besoin,
Ligne 155 : Ligne 165 :
*  Chaque élément de la liste va être représenté par ce texte, ou les variables '''{firstName}''' et '''{lastName}''' sont remplacées par leur valeur dans le modèle représenté.
*  Chaque élément de la liste va être représenté par ce texte, ou les variables '''{firstName}''' et '''{lastName}''' sont remplacées par leur valeur dans le modèle représenté.
*  On peut ajouter du texte à la template:
*  On peut ajouter du texte à la template:
<pre>  itemTpl : 'Prénom: {firstName}, Nom: {lastName}',</pre>
<source lang="javascript">  itemTpl : 'Prénom: {firstName}, Nom: {lastName}',</source>
:*  On peut même ajouter des éléments html
:*  On peut même ajouter des éléments html
<pre>   itemTpl : 'Prénom: {firstName}, <b>Nom</b>: <span style="color:red">{lastName}</span>',</pre>
<source lang="javascript"> itemTpl : 'Prénom: {firstName}, <b>Nom</b>: <span style="color:red">{lastName}</span>',</source>
:*  La documentation d'itemTpl mentionne qu'elle suit une structure de XTemplate. En cherchant XTemplate on trouve la documentation sur le langage de template. Dans les exemples on voit que la variable {#} indique le numéro de l'élément.
:*  La documentation d'itemTpl mentionne qu'elle suit une structure de XTemplate. En cherchant XTemplate on trouve la documentation sur le langage de template. Dans les exemples on voit que la variable {#} indique le numéro de l'élément.
<pre>   itemTpl : '{#}. {firstName} {lastName}',</pre>
<source lang="javascript"> itemTpl : '{#}. {firstName} {lastName}',</source>
:*  On voit qu'on peut tester des conditions
:*  On voit qu'on peut tester des conditions
<pre>  itemTpl : '{#}. {firstName} {lastName} <tpl if="firstName[0]==\'T\'"> (commence par T)</tpl>',</pre>
<source lang="javascript">  itemTpl : '{#}. {firstName} {lastName} <tpl if="firstName[0]==\'T\'"> (commence par T)</tpl>',</source>
(Ici, il a fallu écrire \' pour éviter que les guillemets ne se ferment)
(Ici, il a fallu écrire \' pour éviter que les guillemets ne se ferment)


'''grouped''' indique si les éléments doivent être groupés. Si on veut grouper les éléments,il faut donner au store une méthode getGroupString qui retourne le string qui sert à grouper les éléments. ici on a  
'''grouped''' indique si les éléments doivent être groupés. Si on veut grouper les éléments,il faut donner au store une méthode getGroupString qui retourne le string qui sert à grouper les éléments. ici on a  
<pre> getGroupString : function(record) { return record.get('lastName')[0];},</pre>
<source lang="javascript"> getGroupString : function(record) { return record.get('lastName')[0];},</source>
Pour grouper les éléments par la deuxième lettre du prénom, on peut écrire
Pour grouper les éléments par la deuxième lettre du prénom, on peut écrire
<pre> getGroupString : function(record) { return record.get('firstName')[1];},</pre>
<source lang="javascript"> getGroupString : function(record) { return record.get('firstName')[1];},</source>


=== exercices ===
=== exercices ===
# Essayer les différentes manières de faire des templates, et examiner le code généré dans chrome. [clef à molette] > Outils > Outils de développement (ou directement ctrl+maj+I)
# Essayer les différentes manières de faire des templates, et examiner le code généré dans chrome. [clef à molette] > Outils > Outils de développement (ou directement ctrl+maj+I)
# Mettre ça sur le serveur et le regarder avec le téléphone.
# Supprimer la liste alphabétique qui apparait à droite
# supprimer la liste alphabétique qui apparait à droite
# Trouver comment ajouter le bouton à droite des éléments qui apparait dans l'exemple List du kitchensink quand on clique sur Disclosure
# trouver comment ajouter le bouton à droite des éléments qui apparait dans l'exemple List du kitchensink quand on clique sur Disclosure
# Trouver comment executer du code quand le bouton est appuyé.
# trouver comment executer du code quand le bouton est appuyé.
pistes: regarder la doc sencha, le code des exemples livrés avec sencha
pistes: regarder la doc sencha, le code des exemples livrés avec sencha


Ligne 197 : Ligne 206 :
*  click droit sur libs/phonegap-1.2.0.jar > Build path > Add to build path
*  click droit sur libs/phonegap-1.2.0.jar > Build path > Add to build path
*  modifier src/org.infolipo/SenchacontactsActivity.java
*  modifier src/org.infolipo/SenchacontactsActivity.java
<pre>
<source lang="java">
     public class SenchacontactsActivity extends DroidGap { //Activity {
     public class SenchacontactsActivity extends DroidGap { //Activity {
     super.loadUrl("file:///android_asset/www/index.html"); //setContentView(R.layout.main);
     super.loadUrl("file:///android_asset/www/index.html"); //setContentView(R.layout.main);
</pre>
</source>
* Source > Organize imports (ou ctrl-shift-o)
* Source > Organize imports (ou ctrl-shift-o)
* click droit sur AndroidManifest.xml > open with > text editor
* click droit sur AndroidManifest.xml > open with > text editor
* insérer ceci après versionname
* insérer ceci après versionname
<pre>
<source lang="xml">
   <supports-screens
   <supports-screens
   android:largeScreens="true"
   android:largeScreens="true"
Ligne 226 : Ligne 235 :
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
</pre>
</source>


* ajouter ''android:configChanges="orientation|keyboardHidden"'' dans
* ajouter ''android:configChanges="orientation|keyboardHidden"'' dans
<pre>
<source lang="xml">
         <activity
         <activity
             android:label="@string/app_name"
             android:label="@string/app_name"
             android:name=".SenchacontactsActivity"  
             android:name=".SenchacontactsActivity"  
             android:configChanges="orientation|keyboardHidden">
             android:configChanges="orientation|keyboardHidden">
</pre>
</source>
* ajouter une deuxieme activité après la première
* ajouter une deuxieme activité après la première
<pre>
<source lang="xml">
         <activity android:name="com.phonegap.DroidGap"  
         <activity android:name="com.phonegap.DroidGap"  
                   android:label="@string/app_name"  
                   android:label="@string/app_name"  
Ligne 242 : Ligne 251 :
           <intent-filter> </intent-filter>
           <intent-filter> </intent-filter>
         </activity>
         </activity>
</pre>
</source>


* changer la version du sdk pour correspondre au téléphone (sur le téléphone Réglages > A propos du téléphone, Version Android)    http://developer.android.com/guide/appendix/api-levels.html
* changer la version du sdk pour correspondre au téléphone (sur le téléphone Réglages > A propos du téléphone, Version Android)    http://developer.android.com/guide/appendix/api-levels.html
<pre>  
<source lang="xml">
     <uses-sdk android:minSdkVersion="10" />
     <uses-sdk android:minSdkVersion="10" />
</pre>
</source>


* copier le répertoire assets du projet précédent (senchagui)
* copier le répertoire assets du projet précédent (senchagui)
* inclure la librairie phonegap dans index.html
* inclure la librairie phonegap dans index.html
<pre>
<source lang="html5">
   <script type="text/javascript" src="lib/phonegap-1.2.0.js"></script>
   <script type="text/javascript" src="lib/phonegap-1.2.0.js"></script>
</pre>
</source>
* effacer servage.html: on ne peut pas mettre une application phonegap sur un serveur.
* effacer servage.html: on ne peut pas mettre une application phonegap sur un serveur.


Ligne 259 : Ligne 268 :


Avant de commencer à travailler, il faut s'assurer à la fois que phonegap et que sencha sont bien initialisés. Phonegap est initialisé quand quand l'événement deviceReady est lancé. On peut s'y abonner en y ajoutant cette ligne dans '''index.html'''.
Avant de commencer à travailler, il faut s'assurer à la fois que phonegap et que sencha sont bien initialisés. Phonegap est initialisé quand quand l'événement deviceReady est lancé. On peut s'y abonner en y ajoutant cette ligne dans '''index.html'''.
<pre>
<source lang="html5">
   <script type="text/javascript">
   <script type="text/javascript">
       document.addEventListener("deviceready", initializer.onPhonegapReady, false);
       document.addEventListener("deviceready", initializer.onPhonegapReady, false);
   </script>
   </script>
</pre>
</source>
Ainsi l'événement deviceReady déclenche l'appel de la fonction initializer.onPhonegapReady. On définit la fonction onPhonegapReady sur un nouvel objet initializer dans '''application.js''':
Ainsi l'événement deviceReady déclenche l'appel de la fonction initializer.onPhonegapReady. On définit la fonction onPhonegapReady sur un nouvel objet initializer dans '''application.js''':
<pre>
<source lang="javascript">
   var initializer = {
   var initializer = {
  onPhonegapReady: function(){ initializer.phonegapReady = true; },
  onPhonegapReady: function(){ initializer.phonegapReady = true; },
onSenchaReady: function(){ initializer.senchaReady = true; }
onSenchaReady: function(){ initializer.senchaReady = true; }
   };
   };
</pre>
</source>


La méthode '''onSenchaReady''' sert à être appelée quand sencha est prêt. On l'appelle depuis la fonction '''onReady''' de la configuration passée en argument au setup.(application2.js)
La méthode '''onSenchaReady''' sert à être appelée quand sencha est prêt. On l'appelle depuis la fonction '''onReady''' de la configuration passée en argument au setup. Déployer ce code pour voir l'alerte.(application.js version 2)
<pre>
<source lang="javascript">
Ext.setup({ onReady: function() { initializer.onSenchaReady();}});
Ext.setup({ onReady: function() { initializer.onSenchaReady();}});
</pre>


On rajoute à l'initializer une méthode appelée quand phonegap et sencha sont prêts
//On rajoute à l'initializer une méthode appelée quand phonegap et sencha sont prêts
<pre>
  var initializer = {
  var initializer = {
  onPhonegapReady: function(){  
  onPhonegapReady: function(){  
Ligne 292 : Ligne 299 :
}
}
  };
  };
</pre>
</source>


* Déployer et voir l'alerte
On peut maintenant rajouter dans '''onEverythingReady''' le code pour créer la liste.(application.js version 3):
 
<source lang="javascript">
On peut maintenant rajouter dans '''onEverythingReady''' le code pour créer la liste.(application3.js):
<pre>
  Ext.setup({ onReady: function() { initializer.onSenchaReady();}});
  Ext.setup({ onReady: function() { initializer.onSenchaReady();}});


Ligne 342 : Ligne 347 :
       });
       });
  };
  };
</pre>
</source>


== lire les contacts du téléphone ==
== lire les contacts du téléphone ==


On peut s'inspirer du projet exemple que nous avons vu en premier, ou de la documentation phonegap. Pour contacts.find elle donne l'exemple suivant:
On peut s'inspirer du projet exemple que nous avons vu en premier, ou de la documentation phonegap. Pour contacts.find elle donne l'exemple suivant:
<pre>
<source lang="javascript">
     // PhoneGap is ready
     // PhoneGap is ready
     //
     //
Ligne 371 : Ligne 376 :
         alert('onError!');
         alert('onError!');
     }
     }
</pre>
</source>


Il s'agit d'appeler  
Il s'agit d'appeler  
<pre> navigator.contacts.find(fields, onSuccess, onError, options); </pre>
<source lang="javascript"> navigator.contacts.find(fields, onSuccess, onError, options); </source>


;fields : contient les noms des champs de Contact à retourner. La doc de Contact nous donne le nom des champs disponibles.
;fields : contient les noms des champs de Contact à retourner. La doc de Contact nous donne le nom des champs disponibles.
Ligne 381 : Ligne 386 :


Pour commencer simplement, nous allons juste afficher tous les noms sur la console. Ajouter ceci à la fin de onEverythingReady (application4.js):
Pour commencer simplement, nous allons juste afficher tous les noms sur la console. Ajouter ceci à la fin de onEverythingReady (application4.js):
<pre>
<source lang="javascript">
       function findSuccess(contacts){
       function findSuccess(contacts){
               for (var i=0; i<contacts.length; i++) {
               for (var i=0; i<contacts.length; i++) {
Ligne 393 : Ligne 398 :
           function(error){ console.log("error: " + error) }
           function(error){ console.log("error: " + error) }
       );
       );
</pre>
</source>


regarder l'application dans l'émulateur. Ouvrir la console dans chrome: Outils > Console Javascript. Vérifier que les noms sont affichés.
regarder l'application dans l'émulateur. Ouvrir la console dans chrome: Outils > Console Javascript. Vérifier que les noms sont affichés.
Ligne 400 : Ligne 405 :
et en mettant "Web Console" dans le champ "by Log Tag".
et en mettant "Web Console" dans le champ "by Log Tag".


== exercice ==
=== exercice ===


Nous savons afficher des contacts, et nous savons lire les contacts du téléphone. Il faut maintenant remplacer les données fictives définies dans l'objet store par les contacts du téléphone. Il est suffisant d'afficher juste le champ displayName.
Nous savons afficher des contacts, et nous savons lire les contacts du téléphone. Il faut maintenant remplacer les données fictives définies dans l'objet store par les contacts du téléphone. Il est suffisant d'afficher juste le champ displayName.

Dernière version du 2 décembre 2011 à 11:36

Il s'agit de représenter les contacts du téléphone avec les composants graphiques de sencha touch.


demo

Pour se faire une idée de ce qu'on peut faire avec sencha touch, c'est bien d'aller voir les demos sur leur site: http://dev.sencha.com/deploy/touch/examples/

Les demos sont aussi comprises dans la distribution de sencha qu'on peut télécharger ici: http://www.sencha.com/products/touch/download Déballer sencha-touch-1.1.0.zip dans h:/work, et ouvrir les démos dans chrome: file:///h:/work/sencha-touch-1.1.0/examples/index.html

Voir le kitchen sink qui est une demonstration de la plupart des composants graphiques. L'exemple sous User Interface > List serait approprié

Pour examiner le code source des exemples, et tout le reste de sencha, c'est bien de créer un projet sencha dans eclipse et d'importer tous les fichiers sous h:/work/sencha-touch-1.1.0

Il y a aussi beaucoup à apprendre dans la documentation en ligne: http://docs.sencha.com/touch/1-1/

ossature du projet

créer un nouveau projet senchagui créer les répertoires assets/www/js

créer assets/www/lib/touch y copier les fichiers du répertoire c:/work/sencha-touch-1.1.0 ainsi que les sous-répertoires pkgs, resources, src !! au déploiement faudra garder que le js et css nécessaire

créer assets/www/index.html <source lang="html5"> <!DOCTYPE html> <html> <head>

  <title>Learning sencha</title>
  <script type="text/javascript" src="lib/touch/sencha-touch-debug-w-comments.js"></script>
  <link href="lib/touch/resources/css/sencha-touch.css" rel="stylesheet" type="text/css" />
  <script type="text/javascript" src="js/application.js"></script>

</head><body></body> </html> </source>

Pendant le développement, on utilise la version lisible de la librairie sencha-touch-debug-w-comments.js.

créer assets/www/js/application.js (version 0) <source lang="javascript"> Ext.setup({

     onReady: function() {
      var toolbar = new Ext.Toolbar({dock: 'top',title: 'une barre' });
      new Ext.Panel({
           fullscreen: true,
           //html: "toute l'application va être à l'intérieur de ce panneau",
           items: [{html:"toute l'application va être à l'intérieur de ce panneau"}],
           dockedItems: [toolbar]
      });
}});

</source>

Selon la doc Ext.setup reçoit un objet avec des attributs;

  • l'attribut onReady est une fonction qui va être appelée quand la page est chargée

Ext.Panel

  • il y a deux manières de mettre le html
  • on voit un exemple ou la toolbar est définie d'une autre manière
  • une recherche sur xtype mène au tableau de correspondance entre xtype et classes: http://docs.sencha.com/touch/1-1/#!/api/Ext.Component
  • dockedItem est un composant qu'on peut coller au bord du panel. Il a un attribut dock qui peut être top, right, left ou bottom

on peut ouvrir ça dans chrome

Pour y accéder depuis le téléphone, on peut mettre le projet sur infolipo.net avec le client ftp filezilla. L'adresse du serveur est ftp.servage.net, l'utilisateur est smartcours et je vais vous donner le mot de passe.

  • Créer un répertoire à son nom (le mien s'appelle andreas)
  • Sencha est déjà sur le serveur, pour éviter que chacun doive le copier dans son projet.

Pour l'inclure dans l'application, il faut faire une version modifiée d'index.html, qu'on peut appeler servage.html et dans lequel on change l'adresse des fichiers sencha <source lang="html5">

  <script type="text/javascript" src="../lib/touch/sencha-touch.js"></script>
  <link href="../lib/touch/resources/css/sencha-touch.css" rel="stylesheet" type="text/css" />

</source>


exercice

  1. changer la couleur de fond de l'application

déboguer sur le téléphone

  1. démarrer une console dos, tape ipconfig et noter l'adresse ip du pc
  2. ajouter ceci dans servage.html: <script src="http://[adresse ip]:8081/target/target-script-min.js"></script>
  3. copier servage.html sur le serveur
  4. dans la console:
    • cd h:/weinre-jar
    • java -jar weinre.jar --boundHost [adresse ip] --httpPort 8081
  5. aller sur http://infolipo.net/cours/[votre nom]/servage.html avec le téléphone
  6. dans chrome aller sur http://localhost:8081 et cliquer sur client

créer une liste

Le code de la demo kitchensink est un peu compliqué, mais on peut chercher List dans la doc. On peut carrément copier l'exemple donné dans application.js (version 1), et ajouter la liste dans les items du panel: <source lang="javascript"> Ext.setup({

     onReady: function() {
      Ext.regModel('Contact', {fields: ['firstName', 'lastName']} );
      var store = new Ext.data.JsonStore({
        model  : 'Contact',
        sorters: 'lastName',
        getGroupString : function(record) { return record.get('lastName')[0];},
        data: [
          {firstName: 'Tommy',   lastName: 'Maintz'},
          {firstName: 'Rob',     lastName: 'Dougan'},
          {firstName: 'Ed',      lastName: 'Spencer'}
          //...
        ]
      });
      var list = new Ext.List({
        fullscreen: true, 
        itemTpl : '{firstName} {lastName}',
        grouped : true,
        indexBar: true,
        store: store});      
      var toolbar = new Ext.Toolbar({dock: 'top',title: 'Contacts' });
      new Ext.Panel({
           fullscreen: true,
           //html: "toute l'application va être à l'intérieur de ce panneau",
           //items: [{html:"toute l'application va être à l'intérieur de ce panneau"}],
           items: [list],
           dockedItems: [toolbar]
      });
}});

</source> On voit que la liste contient un store, qui utilise un modèle, qui est défini par Ext.regModel, qui crée un objet Ext.data.Model http://docs.sencha.com/touch/1-1/#!/api/Ext.data.Model

Un tour dans la doc montre qu'un modèle offre toute une série de fonctionnalités:

  • la validation permet de vérifier que les champs contiennent des valeurs correctes.
  • on peut les associer à d'autres modèles
  • on peut les enregistrer de différentes manières

Toutes ces fonctionnalités vont au-delà du coté graphique pour lequel nous avons choisi sencha touch.

model / view / controller

Au delà des composants graphiques, sencha offre un framework pour construire des applications. Le framework offre des fonctionnalités que dont les applications ont en général besoin, et il offre aussi une manière d'organiser le code, qui suit un principe d'architecture connu: le pattern Model/View/Controller. http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

Les modèles
représentent les données, par exemple les contacts que nous avons défini par les champs firstName et lastName.
Les vues
servent à représenter les données graphiquement. Si on suit la structure voulue par Sencha, il faut créer des objets View à base de composants graphiques comme Ext.Panel, Ext.List etc..
Les controllers
font le lien entre les vues et les modèles. Un bouton, qui fait partie de la vue, appelle un controller quand il est appuyé, et le controleur apporte des modifications au modèle. Souvent ce n'est pas tout à fait évident de dire ou s'arrete la responsabilité du modele ou de la vue et ou commence le controller.

C'est tout à fait légitime d'ignorer tout celà si on en a pas besoin, et de continuer à se servir juste des composants graphiques. Les questions d'architecture deviennent plus importantes pour des plus grosses applications.

configuration de List

itemTpl est une template.

  • Chaque élément de la liste va être représenté par ce texte, ou les variables {firstName} et {lastName} sont remplacées par leur valeur dans le modèle représenté.
  • On peut ajouter du texte à la template:

<source lang="javascript"> itemTpl : 'Prénom: {firstName}, Nom: {lastName}',</source>

  • On peut même ajouter des éléments html

<source lang="javascript"> itemTpl : 'Prénom: {firstName}, Nom: {lastName}',</source>

  • La documentation d'itemTpl mentionne qu'elle suit une structure de XTemplate. En cherchant XTemplate on trouve la documentation sur le langage de template. Dans les exemples on voit que la variable {#} indique le numéro de l'élément.

<source lang="javascript"> itemTpl : '{#}. {firstName} {lastName}',</source>

  • On voit qu'on peut tester des conditions

<source lang="javascript"> itemTpl : '{#}. {firstName} {lastName} <tpl if="firstName[0]==\'T\'"> (commence par T)</tpl>',</source> (Ici, il a fallu écrire \' pour éviter que les guillemets ne se ferment)

grouped indique si les éléments doivent être groupés. Si on veut grouper les éléments,il faut donner au store une méthode getGroupString qui retourne le string qui sert à grouper les éléments. ici on a <source lang="javascript"> getGroupString : function(record) { return record.get('lastName')[0];},</source> Pour grouper les éléments par la deuxième lettre du prénom, on peut écrire <source lang="javascript"> getGroupString : function(record) { return record.get('firstName')[1];},</source>

exercices

  1. Essayer les différentes manières de faire des templates, et examiner le code généré dans chrome. [clef à molette] > Outils > Outils de développement (ou directement ctrl+maj+I)
  2. Supprimer la liste alphabétique qui apparait à droite
  3. Trouver comment ajouter le bouton à droite des éléments qui apparait dans l'exemple List du kitchensink quand on clique sur Disclosure
  4. Trouver comment executer du code quand le bouton est appuyé.

pistes: regarder la doc sencha, le code des exemples livrés avec sencha

intégrer les contacts du téléphone

ossature du projet phonegap

on suit les instructions de http://phonegap.com/start/#android

Il faut créer un nouveau projet qui intègre phonegap.

  • File > new > other > Android project
  • Project name: senchacontacts
  • Build Target: Android 4.0
  • Package Name: org.infolipo
  • new folders: libs assets/www
  • copier depuis callback-phonegap-9f0856d\Android
    • phonegap-1.2.0.jar vers libs
    • phonegap-1.2.0.js vers assets/www
    • xml vers res

Retour dans eclipse

  • click droit senchacontacts > refresh
  • click droit sur libs/phonegap-1.2.0.jar > Build path > Add to build path
  • modifier src/org.infolipo/SenchacontactsActivity.java

<source lang="java">

   public class SenchacontactsActivity extends DroidGap { //Activity {
   super.loadUrl("file:///android_asset/www/index.html"); //setContentView(R.layout.main);

</source>

  • Source > Organize imports (ou ctrl-shift-o)
  • click droit sur AndroidManifest.xml > open with > text editor
  • insérer ceci après versionname

<source lang="xml">

  <supports-screens
  android:largeScreens="true"
  android:normalScreens="true"
  android:smallScreens="true"
  android:resizeable="true"
  android:anyDensity="true"
  />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.VIBRATE" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
  <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.RECEIVE_SMS" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
  <uses-permission android:name="android.permission.READ_CONTACTS" />
  <uses-permission android:name="android.permission.WRITE_CONTACTS" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />

</source>

  • ajouter android:configChanges="orientation|keyboardHidden" dans

<source lang="xml">

       <activity
           android:label="@string/app_name"
           android:name=".SenchacontactsActivity" 
           android:configChanges="orientation|keyboardHidden">

</source>

  • ajouter une deuxieme activité après la première

<source lang="xml">

       <activity android:name="com.phonegap.DroidGap" 
                 android:label="@string/app_name" 
                 android:configChanges="orientation|keyboardHidden"> 
          <intent-filter> </intent-filter>
       </activity>

</source>

<source lang="xml">

   <uses-sdk android:minSdkVersion="10" />

</source>

  • copier le répertoire assets du projet précédent (senchagui)
  • inclure la librairie phonegap dans index.html

<source lang="html5">

  <script type="text/javascript" src="lib/phonegap-1.2.0.js"></script>

</source>

  • effacer servage.html: on ne peut pas mettre une application phonegap sur un serveur.

initialisation de l'application

Avant de commencer à travailler, il faut s'assurer à la fois que phonegap et que sencha sont bien initialisés. Phonegap est initialisé quand quand l'événement deviceReady est lancé. On peut s'y abonner en y ajoutant cette ligne dans index.html. <source lang="html5">

  <script type="text/javascript">
     document.addEventListener("deviceready", initializer.onPhonegapReady, false);
  </script>

</source> Ainsi l'événement deviceReady déclenche l'appel de la fonction initializer.onPhonegapReady. On définit la fonction onPhonegapReady sur un nouvel objet initializer dans application.js: <source lang="javascript">

 var initializer = {
	onPhonegapReady: function(){ initializer.phonegapReady = true; },

onSenchaReady: function(){ initializer.senchaReady = true; }

 };

</source>

La méthode onSenchaReady sert à être appelée quand sencha est prêt. On l'appelle depuis la fonction onReady de la configuration passée en argument au setup. Déployer ce code pour voir l'alerte.(application.js version 2) <source lang="javascript"> Ext.setup({ onReady: function() { initializer.onSenchaReady();}});

//On rajoute à l'initializer une méthode appelée quand phonegap et sencha sont prêts

var initializer = {
	onPhonegapReady: function(){ 

initializer.phonegapReady = true; if(initializer.senchaReady){ initializer.onEverythingReady(); } }, onSenchaReady: function(){

          initializer.senchaReady = true;
          if(initializer.phonegapReady){ initializer.onEverythingReady(); }

}, onEverythingReady: function(){ alert("phonegapReady: " + initializer.phonegapReady + "\nsenchaReady:" + initializer.senchaReady); }

};

</source>

On peut maintenant rajouter dans onEverythingReady le code pour créer la liste.(application.js version 3): <source lang="javascript">

Ext.setup({ onReady: function() { initializer.onSenchaReady();}});
var initializer = {
	onPhonegapReady: function(){
		initializer.phonegapReady = true;
		if (initializer.senchaReady){ initializer.onEverythingReady();}
	},
	onSenchaReady: function(){
		initializer.senchaReady = true;
		if (initializer.phonegapReady){ initializer.onEverythingReady();}
	}
 };

// j'ai sorti de l'initializer la définition de la fonction qui lance tout
// pour bien la mettre en évidence
initializer.onEverythingReady = function(){
      Ext.regModel('Contact', {fields: ['firstName', 'lastName']} );
      var store = new Ext.data.JsonStore({
        model  : 'Contact',
        sorters: 'lastName',
        getGroupString : function(record) { return record.get('lastName')[0];},
        data: [
          {firstName: 'Tommy',   lastName: 'Maintz'},
          {firstName: 'Rob',     lastName: 'Dougan'},
          {firstName: 'Ed',      lastName: 'Mencer'}
        ]
      });
      var list = new Ext.List({
        fullscreen: true, 
        itemTpl : '{firstName} {lastName}',
        indexBar:true,
        grouped : true,
        store: store});      
      var toolbar = new Ext.Toolbar({dock: 'top',title: 'Contacts' });
      new Ext.Panel({
           fullscreen: true,
           items: [list],
           dockedItems: [toolbar]
      });
};

</source>

lire les contacts du téléphone

On peut s'inspirer du projet exemple que nous avons vu en premier, ou de la documentation phonegap. Pour contacts.find elle donne l'exemple suivant: <source lang="javascript">

   // PhoneGap is ready
   //
   function onDeviceReady() {
       // find all contacts with 'Bob' in any name field
       var options = new ContactFindOptions();
       options.filter="Bob"; 
       var fields = ["displayName", "name"];
       navigator.contacts.find(fields, onSuccess, onError, options);
   }
   // onSuccess: Get a snapshot of the current contacts
   //
   function onSuccess(contacts) {
       for (var i=0; i<contacts.length; i++) {
           console.log("Display Name = " + contacts[i].displayName);
       }
   }
   // onError: Failed to get the contacts
   //
   function onError(contactError) {
       alert('onError!');
   }

</source>

Il s'agit d'appeler <source lang="javascript"> navigator.contacts.find(fields, onSuccess, onError, options); </source>

fields
contient les noms des champs de Contact à retourner. La doc de Contact nous donne le nom des champs disponibles.
onSuccess et onError
sont les fonctions à appeler après l'execution.
options
Les options servent à préciser quels contacts on cherche. Elles sont facultatives.

Pour commencer simplement, nous allons juste afficher tous les noms sur la console. Ajouter ceci à la fin de onEverythingReady (application4.js): <source lang="javascript">

     function findSuccess(contacts){
             for (var i=0; i<contacts.length; i++) {
               console.log("Display Name = " + contacts[i].displayName);
             }
     };
     navigator.contacts.find(
          ["displayName"], 
          findSuccess,
          function(error){ console.log("error: " + error) }
     );

</source>

regarder l'application dans l'émulateur. Ouvrir la console dans chrome: Outils > Console Javascript. Vérifier que les noms sont affichés.

Charger l'application sur le téléphone,les noms devraient s'afficher dans logCat. Mettre un filtre dans logCat en cliquant sur + et en mettant "Web Console" dans le champ "by Log Tag".

exercice

Nous savons afficher des contacts, et nous savons lire les contacts du téléphone. Il faut maintenant remplacer les données fictives définies dans l'objet store par les contacts du téléphone. Il est suffisant d'afficher juste le champ displayName.