Navigateur 2.0 SALVAN Corentin 19 mai 2022 1 Mise en place 1.1 Mot cl ́ e with Le mot cl ́ e with permet d’ ́ etendre une classe avec des M ixin ou des classes sans constructeurs. Les M ixin sont des classes sp ́ eciales ne poss ́ edant pas de constructeurs et ne pouvant pas ˆ etre ́ etendu par autre classe ou un autre M ixin . On l’utilise lorsqu’une fonctionnalit ́ e ne peut ˆ etre impl ́ ement ́ e dans une des classes m` ere ou que cela devient absurde de le faire, par exemple : Figure 1 – Hi ́ erarchie de classe permettant l’utilisation du with Dans le sch ́ ema ci-dessus, nous pouvons voir que des esp` eces ont des capacit ́ es communes, cependant ces capacit ́ es ne d ́ ependent pas forc ́ ement de la classe m` ere. L’objectif serait de cr ́ eer des classes Voler et Nager, pour ensuite faire h ́ eriter les classes concern ́ ees. Or, dans Dart une classe ne peut qu’h ́ eriter d’une seule classe m` ere. Nous allons donc d ́ efinir des M ixin Voler et Nager, ce qui donne : 1.2 D ́ efinition de la classe AppRouter Dans le sch ́ ema ci-dessous nous pouvons voir les conditions de transition entre les pages. Les variables bool ́ eennes correspondent aux conditions n ́ ecessaires pour passer ` a la page suivante. Ces variables sont indispensables pour le navigateur 2.0, nous verrons plus tard comment elles seront utilis ́ ees. Par la suite on utilisera ce sch ́ ema comme r ́ ef ́ erence pour l’impl ́ ementation du router. 1 Figure 2 – Hi ́ erarchie de classe avec utilisation du with 1.2.1 Cr ́ eation de la classe On d ́ efinit la classe AppRouter de la mani` ere suivante : class AppRouter extends RouterDelegate < AppRouteInfo > with ChangeNotifier , PopNavigatorRouterDelegateMixin < AppRouteInfo > implements RouteInformationParser < AppRouteInfo > — RouterDelegate < T > : C’est une classe abstraite, ́ el ́ ement principal du widget Router, elle est appel ́ e au d ́ emarrage du Router avec la structure que RouteInformationParser a obtenue en analysant la route initiale. — P opN avigatorRouterDelegateM ixin < T > : Mixin permettant de faire le lien avec RouterDelegate.popRoute L’utilisation de ce mixin garantit que le bouton de retour respecte toujours les itin ́ eraires sans page dans le navigateur. — RouteInf ormationP arser < AppRouteInf o > : Permet de parser l’information de la route vers une configuration de type T. — AppRouteInf o : Correspond au type d ́ efini pour le RouterDelegate , elle contient tous les ́ etats n ́ ecessaires pour choisir la page ` a afficher. 1.2.2 D ́ efinition des attributs D’abord, on red ́ efinit l’attribut suivant : @override GlobalKey < NavigatorState > ? navigatorKey = GlobalKey (); Cet attribut, h ́ erit ́ e du Mixin P opN avigatorRouterDelegateM ixin , est utilis ́ e pour retrouver le navigateur courant. On lui affecte une instance de la classe GlobalKey (), on l’utilise uniquement lors du debuggage. Comme nous pouvons le voir sur la figure 4, certaines conditions sont n ́ ecessaires pour pouvoir passer ` a une nouvelle page, ces conditions seront repr ́ esent ́ ees par des attributs de type bool dans la classe AppRouter 1.2.3 Red ́ efinition des m ́ ethodes 2 Figure 3 – Sch ́ ema de navigation Widget build ( BuildContext context ) { final pages = < Page > []; return Navigator ( pages : pages ); 3 } La m ́ ethode parseRouteInformation permet de convertir une information de route en donn ́ ee pars ́ e pour ensuite le passer au RouterDelegate. Dans notre cas, la classe ` a parser correspond ` a la classe AppRouteInf o . Le parsing ́ etant asynchrone, nous utilisons la classe F uture , ce qui va permettre d’attendre la fin de sa cr ́ eation avant de continuer l’ex ́ ecution. @override RouteInformation ? restoreRouteInformation ( AppRouteInfo configuration ) { return const RouteInformation ( location : ”/”); } La m ́ ethode restoreRouteInformation permet de restaurer l’information de la route depuis la confi- guration donn ́ ee. Cette m ́ ethode peut retourner une valeur nulle ` a chaque fois que l’historique de navigation n’est pas mis ` a jour et que la restauration de l’ ́ etat est d ́ esactiv ́ ee. Dans notre cas, nous allons retourner la racine de l’application. Pour cela il faut retourner une instance de la classe RouteInformation et passer en argument le chemin de la racine de l’application. Dans notre cas ”/”. Ce chemin est ́ equivalent ` a l’URL d’une application web o` u la racine de l’application se trouve sur le chemin ”/”. @override Future < void > setNewRoutePath ( AppRouteInfo configuration ) { return Future < AppRouteInfo > (() = > AppRouteInfo ()); } La m ́ ethode setNewRoutePath est appel ́ ee par le router lorsqu’une nouvelle route a ́ et ́ e transmise par l’application au syst` eme d’exploitation. Le symbole ” ?” sur le type de retour des m ́ ethodes en flutter signifie que la m ́ ethode peut retourner la valeur null . On red ́ efinit ensuite la m ́ ethode build : Widget build ( BuildContext context ) { final pages = < Page > []; pages add ( MaterialPage ( child : HomeView ( controller : HomeController ( homeRouter : this)))); if ( cardPage ) { pages add ( MaterialPage ( child : CardRoute ( router : this))); } if ( qrCodePage ) { pages add ( MaterialPage ( child : QRCodeView ( number : userId ))); } else if ( barCodePage ) { pages add ( MaterialPage ( child : BarCodeView ( number : userId ))); } else if ( nfcPage ) { pages add ( MaterialPage ( child : NfcView ( recup : userId ))); } return Navigator ( pages : pages ); } La m ́ ethode build est en charge de choisir la page ` a afficher. Cette m ́ ethode sera ex ́ ecut ́ ee ` a chaque fois qu’on appel la m ́ ethode notif yListeners (). Lorsque l’on met ` a jour les variables de transitions, cette m ́ ethode doit ˆ etre appel ́ e pour pouvoir afficher la page correspondante. La derni` ere page ajout ́ ee sera affich ́ ee. Dans le code ci-dessus, on ajoute par d ́ efaut la page principale, cela ajoute une s ́ ecurit ́ e, en effet puisque la liste pages contient forc ́ ement un ́ el ́ ement il y aura toujours une page ` a afficher, dans le cas contraire, si la liste pages est vide alors le programme provoque une erreur. Le diagramme ci-dessous repr ́ esente les interactions du router et l’ ́ etat de l’application. 1.2.4 Gestion du retour arri` ere avec le bouton de navigation Chaque appareil android poss` ede un bouton de retour vers la page pr ́ ec ́ edente : 4 Figure 4 – Interaction entre les classes du Router et ́ etat de l’application [https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade] Figure 5 – Bouton retour sur un smartphone android Pour l’utiliser avec le navigateur 2.0, nous allons red ́ efinir la m ́ ethode F uture < bool > popRoute () dans la classe AppRouter de la mani` ere suivante : 5 @override Future < bool > popRoute () { if ( cardPage ) { if ( qrCodePage ) { qrCodePage = false; } else if ( barCodePage ) { barCodePage = false; } else if ( nfcPage ) { nfcPage = false; } else { cardPage = false; } } notifyListeners (); return Future value (true); } Nous mettons ` a jour les variables de transition de sorte ` a ce que la navigation se d ́ eroule comme sur la figure 4. Ensuite, il suffit de mettre ` a jour l’affichage en appelant la m ́ ethode notifyListeners(). Mettre comme valeur de retour F uture.value ( f alse ) fermera l’application lors de l’appui sur le bouton retour. 1.3 Classe Router dans les composants de l’application Dans chacun des composants de notre application, nous cr ́ eons une classe abstraite dans laquelle chaque m ́ ethode abstraite correspondra ` a un changement de page. Ces m ́ ethodes seront appel ́ ees dans la classe Controller du composant et seront impl ́ ement ́ ees par la classe AppRouter . En prenant exemple sur la figure 4, pour passer de la premi` ere page vers la page du choix du type de d ́ emat ́ erialisation, nous cr ́ eons la classe abstraite suivante : abstract class HomeRouter { void goToCard (); } On impl ́ emente cette classe dans la classe AppRouter et on met le code suivant : @override void goToCard () { cardPage = true; notifyListeners (); } Tels que montr ́ ee sur la figure 4, lorsque cardP age est ` a true , on passe sur la page du choix de d ́ emat ́ erialisation. On appel ensuite notif yListeners () pour que l’application lance la nouvelle page. Dans le contrˆ oleur du composant de la page principale, il faudra cr ́ eer une instance de la classe abstraite HomeRouter ce qui permettra d’appeler la m ́ ethode goT oCard () lors de l’appuie sur le bouton. 6