• Aucun résultat trouvé

Déroulement de l’application

D. Internationalisation

V. Déroulement de l’application

Lors du lancement de l’application, nous devions récupérer les données des fichiers de données. Pour cela, en fonction des situations, le logiciel peut être amené à :

- Télécharger des fichiers XML et JSON depuis un serveur - Parser les fichiers XML et JSON

- Insérer les données dans une base de données SQLite - Récupérer les données depuis une base de données Ces fonctions sont détaillées dans leur partie respective.

Voici un diagramme d’état présentant le déroulement de l’initialisation de l’application :

A la fin de l’initialisation, les structures de données brutes sont remplies et nous initialisons les arbres, bases de l’application.

La racine de l’arbre est envoyée à un contrôleur qui va s’occuper de gérer l’affichage du nœud.

Rapport Final

Rapport Final : Modèle de l’application

1 2

VI. Modèle de l’application A. Récupération des informations

Il s’agissait ici de concevoir les classes et méthodes Java permettant d’effectuer la lecture et l’interprétation (parsage) des informations contenues dans les fichiers de contenu de l’application. En effet, toutes les informations relatives à l’offre de formation et aux infrastructures disponibles dans l’école sont contenues dans ces fichiers sous un format particulier, et c’est ce contenu qui est affiché sur tous les écrans de l’application.

Les fichiers en question sont de deux types, différents par leur format (dans le sens informatique du terme) et le type de leur contenu, et donc ayant imposé un parsage différent : les fichiers JSON et les fichiers XML. Pour en faciliter l’accès, les deux types de fichiers ont été stockés dans le répertoire Assets du projet Java.

Par ailleurs, dans le but de faciliter l’accès aux informations de contenu dans ces fichiers, et comptant sur les caractéristiques techniques du support matériel qu’est le Samsung Galaxy S2, nous avons adopté comme stratégie de développement un système de poupées russes.

Il s’agit d’un système de contenants, rangeant par étage les informations les unes dans les autres, selon le modèle des fichiers à parser. Concrètement, cela impliquait la création de classes correspondant à chaque information complexe et pertinente parsée. Ainsi, une information constituée d’un ensemble de valeurs correspondait, en code, à une classe renfermant ces données en attributs ; et une information encapsulant la précédente et d’autres encore était représentée par une classe à un niveau plus élevé, et ainsi de suite. L’avantage de cette méthode était de nous faciliter l’accès aux informations parsées, en attente de la base de données. Ces données, une fois parsées, sont donc directement disponibles à l’utilisation dans les autres parties de l’application, par les instances des classes les plus élevées du modèle décrit précédemment.

FIGURE 3-MODELE DE LA STRUCTURE EN POUPEES RUSSES MISE EN PLACE POUR LA SAUVEGARDE DES DONNEES ISSUES DU PARSAGE

Attribut 1 Attribut 2

Rapport Final

Rapport Final : Modèle de l’application

1 3

Les fichiers JSON

Ces fichiers contiennent les informations annexes, c’est-à-dire non relatives à l’offre de formation. Ce sont toutes les informations propres à l’ENSIM, rangées dans des fichiers JSON différents, dont le nom indique le contenu : un fichier pour chaque association de l’école, un pour la BU, etc.

Comme dit précédemment lors de la conception, pour en faciliter l’accès, nous les avons tous placés dans le répertoire Assets/Json du projet Java. Le parsage de ces fichiers est particulièrement aisé du fait de leur structure très proche du langage naturel, mais néanmoins très adapté au travail informatique.

FIGURE 4-MODELE DE LA STRUCTURE DUN FICHIER JSON

Dans le but de faciliter l’accès à toutes ces informations, un schéma de poupées russes a été utilisé pour sauvegarder les informations parsées en attente de la base de données. La structure de base de ce schéma découle de celle des fichiers JSON, qui est assez stable dans l’ensemble : JData -> Vidéos, Photos, Datasources -> Data -> Header, Row

FIGURE 5-MODELE POUPEES RUSSES DUN FICHIER JSON

JData DataSources

Videos Photos

Data

Header Row

Rapport Final

Rapport Final : Modèle de l’application

1 4

Les JData représentent l’ensemble du contenu d’un fichier JSON. Elles sont constituées d’une liste de datasources. Ces dernières quant à elles peuvent être des vidéos, des photos ou des Data. Les Data pour finir, sont le contenu primaire des fichiers JSON. Constituée d’un Header et d’un Row ou liste d’informations, une Data peut constituer un paragraphe entier de l’application.

Le parsage de ces informations est grandement facilité par l’utilisation de la librairie org.json de Java. En effet, cette librairie met à disposition des classes pour chaque type de contenu d’un fichier JSON, ainsi que des méthodes d’accès toutes faites, permettant de récupérer exactement le contenu souhaité. Pour ce faire, elle charge tout le contenu du fichier pour construire une instance de la classe JSONObject, ce qui en simplifie l’accès, comme pour le DOM avec des fichiers XML, le principal avantage étant la légèreté des fichiers JSON, induite par leur simplicité d’écriture.

Les fichiers XML

Ces derniers ont, quant à eux, été un peu plus délicats à parser, du fait de leur complexité, mais surtout de leur longueur. En effet, ils contiennent toute l’offre de formation détaillée de l’ENSIM, ainsi que les informations nécessaires pour représenter cette dernière dans l’application. Nous disposions de trois fichiers XML, respectivement pour l’offre de formation, sa représentation dans l’application, et la représentation des informations annexes.

Le premier fichier est formaté selon la norme CDM de représentation des offres de formation des établissements supérieurs. Il s’agit là donc d’un format règlementé, au contraire des fichiers JSON sur lesquels nous avions plus ou moins la main et pouvions être force de proposition quant à leur modification.

Les deux autres étaient présentés sous un format similaire, mais beaucoup moins strict.

Ils étaient également largement moins longs que le premier qui, à lui seul, faisait presque 3500 lignes d’information, voire plus.

Pour parser ces fichiers, nous avons utilisé l’API XmlPullParser de Java, fournie par la XmlFactory et basée sur l’implémentation de la technologie Stax, permettant de parcourir le fichier ligne par ligne jusqu’à la fin pour en récupérer les données. Cette API dispose de plusieurs méthodes permettant de récupérer les données précises de la ligne lue. Par contre, il est bien entendu totalement impossible de revenir en arrière dans le parsage pour savoir à quel niveau l’on en est.

Fort de ce constat, nous avons développé une méthode de parsage particulière basée sur la puissance de la récursivité et sur la structure des poupées russes précédemment mentionnées ; et permettant de remplir ces dernières au fur et à mesure de l’avancée dans le fichier. La classe de base se construit alors progressivement à partir des informations récupérées au cours de la progression (comme la classe JSONObject pour les fichiers JSON) et permet par la suite d’y avoir accès aisément.

Cette méthode a été peaufinée au fur et à mesure de nos développements, et utilisée pour l’implémentation du parsage des trois fichiers.

Rapport Final

Rapport Final : Modèle de l’application

1 5

Le constat final en est d’ailleurs que le parsage des fichiers sur la version Android se fait incroyablement plus vite que sur la version iPhone, obligeant même à ralentir le splashscreen et remettant en cause l’utilité de la base de données.

B. Insertion et Récupération dans la base de données

La base de données est un composant indispensable pour le bon fonctionnement de l’application Allschools. Elle permet en effet de stocker de manière cohérente et structurée les données contenues dans les différentes rubriques et de les mettre à jour. Plusieurs programmes peuvent accéder à ces données simultanément, mais dans notre cas, sous Android, la base de données est intégrée à l’application.

Notre base utilise le moteur SQLite qui ne nécessite aucune administration et nulle mise en place de services. La première étape de l’implémentation a été de comprendre le fonctionnement, les enjeux de SQLite et les relations entre la base et le reste de l’application.

Nous sommes partis sur un déroulement en trois blocs : le parsage, la base de données et l’instanciation des classes présentes dans la base.

Pour déterminer le contenu de ces classes, il a fallu examiner minutieusement la structure des fichiers XML et JSON et analyser les dépendances entre les balises. La complexité de ces fichiers a été la première source de difficulté, car certaines balises se retrouvaient parfois filles et parentes d’une autre. Il a non seulement fallu extraire le nom des classes et des attributs associés, mais également définir les connexions entre elles, via des identifiants.

Contrairement à MySQL, SQLite fonctionne sans l’installation d’un serveur de base de données. Son fonctionnement s’avère par conséquent simplifié : des classes inclues dans Android nous ont permis de réaliser la création des tables, à l’instar de SQLiteOpenHelper qui contient les méthodes de création et de mises à jour. Une classe statique a suffi pour implémenter ces méthodes, utilisant par ailleurs des requêtes SQL. Dans la hiérarchie d’Allschools, la base de données se situe au niveau du modèle, tout comme les classes issues de la structure interne des fichiers XML et JSON. Le contrôleur fait appel à elle après l’exécution du parsage, mais elle n’agit que sur les classes du modèle.

Suite au parsage des fichiers XML et JSON fournis dans le contrat du projet, la base de données avait pour tâche d’insérer les informations parsées dans les classes correspondantes.

Les fichiers JSON sont les plus simples, étant donné leur redondante structure composée d’un entête et de lignes. Les fichiers XML, en revanche, ont dû être divisés en trois catégories différentes, chacune possédant une structure particulière : les Cdm, les CdmApp et les App. Des packages ont été créés pour ces divisions, dans lesquels ont été implémentées les classes relatives aux balises répertoriées dans la première partie du projet. Par rapport à elles, la base de données est composée de tables qui sont le reflet des classes. Chaque table a pour nom celui d’une classe, et pour champs les attributs de cette même classe. Par exemple, pour les fichiers Cdm, la classe Card, dotée de quatre attributs (photo, imageName, frameColor et title) correspond à une table Card comportant les champs « photo, image, frameColor et title », en plus d’un identifiant nécessaire.

Voici une représentation des classes du fichier Cdm, avec les références. Chaque classe est une table de la base de données.

Rapport Final

Rapport Final : Modèle de l’application

1 6

FIGURE 6– DIAGRAMME ENTITES/RELATIONS DU FICHIER CDM

Rapport Final

Rapport Final : Modèle de l’application

1 7

On se rend compte que les dépendances sont nombreuses, et certaines ne sont pas représentées sur le schéma pour le simplifier. Chaque table est déclarée dans la classe de la base de données, sobrement intitulée BaseSQLite, sous la forme d’une requête SQL avec les attributs et leur type.

Le diagramme des App est plus simple que celui des Cdm.

FIGURE 7-DIAGRAMME ENTITES/RELATIONS DU FICHIER APP

Les tables des App et des Cdm n’interagissent pas entre elles. Toutes cependant ont été déclarées dans la même classe, par souci de simplicité. Le diagramme des fichiers JSON a été représenté et finalisé en premier, car plus accessible, notamment pour tester l’insertion dans la base.

Rapport Final

Rapport Final : Modèle de l’application

1 8

FIGURE 8-DIAGRAMME ENTITES/RELATIONS DES FICHIERS JSON

Les clés primaires sont soulignées, et s’incrémentent au fur et à mesure des insertions dans la base. Les clés étrangères ne sont pas toutes présentées sur les schémas, mais elles ont dû être soigneusement adaptées dans le code. Le diagramme des CdmApp est le plus simple :

FIGURE 9-DIAGRAMME ENTITES/RELATIONS DU FICHIER CDMAPP

Rapport Final

Rapport Final : Interface de l’application

1 9

La table coupée en haut n’est autre que CourseCdm, à ne pas prendre en compte. On remarque néanmoins que la table Program est liée à la fois aux Cdm et aux CdmApp, ce qui n’est pas vraiment exact. Une table ProgramApp n’a pas été représentée, par oubli, mais c’est elle qui est reliée aux tables des CdmApp, tandis que Program n’appartient qu’aux Cdm. Toujours est-il qu’une fois les tables créées dans BaseSQLite, notre travail s’est orientée vers les méthodes propres à chaque classe des Cdm, des App, des CdmApp et des JSON. Ces méthodes ne sont autres que les getters et setters des attributs de classes, ainsi qu’une méthode toString qui renvoie les valeurs sous forme de chaînes de caractères.

Une difficulté majeure s’est posée au moment d’implémenter l’insertion des données dans la base. Après quelques recherches, nous avons trouvé une classe baptisée ContentValues qui nous permettrait de stocker un ensemble de valeur selon la typologie clé/valeur. Nous avons donc écrit pour chacune des tables une méthode d’insertion basée sur le principe des ContentValues et se terminant avec l’appel de la méthode insert() dans la table concernée. Ainsi, les valeurs intégrées dans le ContentValues sont insérées dans la table lorsque la méthode est appelée.

De nombreux problèmes d’incompatibilité entre les attributs de classe et les champs des tables de la base nous ont contraints à réécrire plusieurs fois ces méthodes, à l’aide du mode de débuggage. La phase suivante a été d’écrire les méthodes d’insertions dans les classes cette fois-ci. Par exemple, dans la classe Association du App, nous avons une méthode insertSQL() qui initialise les identifiants des tables en relation 1/1 avec elle, puis appelle les insertSQL() de ces tables-là ainsi que la méthode insertAssociation() définie dans BaseSQLite. Cet enchaînement de fonctions réalise l’insertion dans la base.

De même, les méthodes de récupération ont été écrites dans chaque classe, faisant appel aux méthodes get() de BaseSQLite, qui effectuent des requête de sélection dans les tables. Des difficultés à propos des types se sont posés, notamment l’utilisation d’AtomicInteger au lieu d’Integer. Le plus délicat dans cette partie du projet a été de s’assurer de la bonne concordance des noms de variables entre celles du parsage et celle de la base. Une seule incohérence lors de la création des tables, de l’insertion ou de la récupération arrêtait le programme et les erreurs n’étaient pas toujours évidentes à identifier. Nous avons fait usage du programme SQLiteDatabaseBrowserPortable pour vérifier que les champs des tables se remplissaient correctement après l’exécution, ce qui nous a été d’une aide précieuse. Au final, malgré quelques minimes incohérences pendant l’insertion des Cdm, la base de données a bien été réalisée à partir de zéro.

VII. Interface de l’application A. Carrousel

Le carrousel est un élément d’interface permettant d’afficher une liste. Les items de la liste sont affichés sous la forme de cartes placées dans un environnement 3D disposé en cercle. Une carte est affichée au milieu au premier plan et est cliquable. Deux types d’interactions sont possibles :

- Un clic sur la carte de gauche ou de droite de la carte centrale fait bouger le carrousel pour placer la carte cliquée au centre, elle devient alors cliquable.

- Un mouvement horizontal du doigt fait bouger le carrousel dans le sens du mouvement.

Rapport Final

Rapport Final : Interface de l’application

2 0

Dans ce carrousel, chaque carte correspond à un nœud, et un clic sur cette carte entraînera l’affichage du nœud correspondant par le contrôleur.

Le carrousel est basé sur celui développé par Igor Kushnarev en 2011. Ce dernier se base sur la librairie 2D d’Android. L’objet Camera issu du package android.graphics permet la transformation 3D d’objets 2D par le biais d’une matrice.

Le problème de base est que le carrousel d’origine ne répond pas aux besoins du projet.

En effet, il est conçu pour afficher de petites icônes non cliquables, il est plutôt orienté présentation que navigation, il faut alors le modifier.

Il existe quatre types de carrousel, ayant chacun ses spécificités de conception :

- Les carrousels mono utilisés pour afficher une seule carte. Ici, on a désactivé les mouvements du carrousel. Nous n’affichons qu’une seule carte, à l’endroit où est placé la carte de devant sur les autres carrousels.

- Les carrousels duo utilisés pour afficher 2 cartes. Comme pour le mono, on désactive les mouvements, mais en plus on détermine la carte qui a été cliquée, non pas en récupérant les coordonnées, mais en calculant le milieu du carrousel. Si c’est à gauche du milieu, c’est la première carte et vice versa.

-- Les carrousels simples utilisés pour afficher trois à six cartes. C’est le carrousel de base qui a été implémenté ici.

Rapport Final

Rapport Final : Interface de l’application

2 1

- Les carrousels complexes utilisés pour afficher sept cartes et plus. On affiche un effet de dégradé progressif sur les cartes au fur et à mesure qu’elles vont vers le fond pour simuler un effet d’infini. On remplace la carte, invisible, du fond en fonction du mouvement du carrousel.

-Chaque type de carrousel est implémenté par une classe qui hérite de CarouselView. Le contrôleur du carrousel appelle, en fonction du nombre de cartes dont il dispose, l’une de ces classes.

Ensuite, le carrousel implémente un écouteur de mouvement du doigt, en l’occurrence nous n’en gardons que deux : onFling pour un jeté du doigt et onSingleTap pour le simple clic. En ce qui concerne l’onFling, on récupère le signe de la composante horizontale de la vélocité (x).

S’il est positif, on pivote le carrousel de gauche à droite, sinon dans le sens inverse. Pour le single tap, on vérifie que la zone cliquée ne correspond pas à une carte cliquable. Pour cela, on récupère les coordonnées de la carte centrale (seule cliquable), et on les compare à celles de la zone cliquée. Si le clic n’est pas compris dans cette zone, on vérifie si elle se situe à gauche ou à droite et en fonction, on pivote le carrousel.

L’une des premières nécessités était d’afficher du texte en dessous des cartes. Pour cela, nul besoin de modifier le carrousel, il suffit de traiter les images des cartes pour incruster du texte sur une portion d’une image transparente.

Il faut ensuite gérer une transparence progressive dans le cas du carrousel complexe.

Pour cela, on va modifier l’alpha en fonction de l’angle de la carte. L’angle 0 étant la carte centrale au premier plan. Il suffit de calculer un alpha proportionnel à l’angle.

Comme dit au début, l’une des difficultés sous Android est l’adaptation à la taille de l’écran. C’est d’autant plus difficile que le Carrousel, à cause des transformations matricielles, est difficile à dimensionner au besoin de l’écran. Pour respecter cette contrainte, nous avons défini un ratio minimum entre la largeur du carrousel et sa hauteur. Cette contrainte empêche pour l’instant le carrousel d’être optimisé pour l’affichage horizontal. Pour le cacher, nous avons désactivé la rotation du téléphone.

Rapport Final

Rapport Final : Interface de l’application

2 2

B. Article

Un article est tout d’abord un type de nœud. Il est composé de paragraphes, chacun étant composé d’un titre et d’un texte. Il y a quatre types de paragraphes :

- Titre : affiche un titre, utilisé classiquement au début d’un article. Il n’y a généralement qu’un texte.

- Table : paragraphe modélisant un tableau à deux colonnes.

- Liste : énumération.

- Paragraphe : texte simple sans organisation particulière.

Ces articles sont ensuite affichés par l’ArticleController par la classe correspondant à

Ces articles sont ensuite affichés par l’ArticleController par la classe correspondant à

Documents relatifs