AIR Flex Actionscript

Un blog de plus dans la galaxie AIR flex

18 novembre 2007

Faire un résume sur un download avec AIR

Je ne l'ai pas testé n'en ayant pas vraiment besoin, mais je trouve la possibilité  de le faire  intéréssante, donc pour ceux qui le souhaite, voici quelques lignes de code qui permettraient de faire un résume sur  un download raté.

http://www.richapps.de/?p=113

C'est .de mais  écrit en anglais ... faut vraiment que je m'y mette.

I haven't tested this trick, but the idea is great and possibility nice, you can resume download in your AIR application. Follow the precedent link, they 're the code and the explications.

Enjoy

Posté par StefonBlog à 04:43 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]


13 novembre 2007

Lire les ID3 d'un fichier

Lire les balises d'un mp3 peux sembler simple, c'est vrai si on accepte de lancer un objet sound.

Mais mon but étant simplement de récupérer les données pour les afficher, je ne trouvais pas très propre de  lancer  le son en arrière plan avec un volume à zéro le temps de récupérer les infos.

Heureusement Mr Ben Stucki nous a concoté un super tutoriel sur la lecture d'un fichier binaire et  la récupération des tags sur un fichier mp3

http://labs.adobe.com/wiki/index.php/AIR:Articles:Working_with_Binary_Data#Reading_binary_data

L'un des principaux problèmes de ce tuto pour les maceux, c'est l'utilisation de browse .... :( un jour peut être.
Enfin pour ça  il suffit de déterminer soit même le chemin du fichier que l'on souhaite lire.
Pour ça je donne  le path du fichier comme argument de la fonction.
Un autre  petit souci c'est que  l'exemple considère que  les fichiers sont bien tagés ce qui malheureusement  n'est pas toujours le cas, j'ai donc ajouté (en rouge )un test try ... catch pour eviter l'erreur 2030.
Et modifié (en vert) la manière de récupérer les infos notamment parce que sur certains  mp3 le titre n'est pas dans TIT2 mais TT2, une question de version je crois.

Le code original et les autres fonctions nécéssaires sont disponibles via le lien précédent.
SongTitle, SongAlbum, SongArtiste sont les noms de  mes champs textes ou variables à vous de les adapter au votre.

            private function loadLocalID3( pathDuFichier:String ):void {
                var file:File = new File();
                file.nativePath = pathDuFichier;
                var bytes:FileStream = new FileStream();
                bytes.open(file, FileMode.READ);

                // read in sequence
                var tagId:String = bytes.readUTFBytes(3);
                var majorVersion:Number = bytes.readByte();
                var minorVersion:Number = bytes.readByte();
                var flags:int = bytes.readByte();
                var tagSize:uint = convertSynchsafe(bytes.readUnsignedInt())

                trace("id: " + tagId);
                if(flags==0) {
                    //frames
                    while(bytes.position < tagSize) {
                        var id:String = bytes.readUTFBytes(4);
                        var size:uint = bytes.readUnsignedInt();
                        var flags1:int = bytes.readByte();
                        var flags2:int = bytes.readByte();
                        if(id!="") { trace(id); }

                        if(id.charAt(0)=="T") {   
                        try{
                            var encodingFlag:int = bytes.readByte();
                            var text:String = bytes.readUTFBytes(size-1);       
                            if(id == "TIT2"){   
                                SongTitle.text = text;
                            }
                            if(id == "TT2"){   
                                SongTitle.text = text;
                            }
                            if(id == "TPE1"){
                                SongArtist.text = text;
                            }
                            if(id == "TALB"){
                                SongAlbum = text;   
                            }

                        } catch(error:EOFError){
                            trace (error.message);
                        }
   

                        } else if(id == "APIC") {
                            var start:int = bytes.position;
                            var textEncoding:int = bytes.readByte();
                            var mime:String = readISO(bytes);
                            var pictureType:int = bytes.readByte();
                            var description:String = readISO(bytes);
                            var stop:int = bytes.position;
                            var imageSize:int = size-(stop-start);
                            var image:ByteArray = new ByteArray();
                            bytes.readBytes(image,0,imageSize);
                            var loader:Loader = new Loader();
                            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
                            loader.loadBytes(image);
                        } else {
                            bytes.position += size;
                        }
                    }
                    SongTitle.text = SongTitle.text+' '+SongAlbum; // Ca c'est  perso j affiche le titre et  l album dans le même champs
                }
            }

La ou Mr Stucki fait très fort, c'est  sur son blog ou il propose de récupérer le contenu des balises ID3 d'un élément distant (ce post  à pratiquement deux ans :)), mais il fonctionne avec flex3 beta 2 donc pas de soucis.
Il faut  refaire  les opérations citées précédemment dans le code car il y a  le même type de problèmes sur les fichiers qui n'ont pas de tags ou pas les mêmes.

D'ici quelques temps, j'espère être moins chargé et  faire un tutoriel complet sur le sujet, il me faut aussi un vrai blog avec de l'affichage de code et un moteur de recherche parce que là  c'est n'importe quoi :)

Posté par StefonBlog à 15:34 - AIR - Commentaires [4] - Rétroliens [0] - Permalien [#]

06 novembre 2007

Leopard AIR ... ça continu

Dans la série p'tit merdouille .....

J'ai une  appli AIR qui télécharge des fichiers, basique, jusqu'a présent (avec Tiger) aucun problème, mais  maintenant si le fichier sur le serveur à des espaces dans le nom l'urlencodage ( remplacement des espace, etc), ne se fait plus automatiquement et donc  j'ai des erreurs 404 ..... arrrgghhh

Je ne trouve rien dans la doc sur l'urlencode dans l'as3....   

[Edit]
Si il y a  effectivement  un truc, dans  les fonctions  en top level de  l'as  il y a  encodeURI() qui fait très bine  l'affaire 

        // BINARY parce que je  telecharge un fichier
       private var dataFormat:String = URLLoaderDataFormat.BINARY;
   
        public function loadIt():void{
            
            var loader:URLLoader = new URLLoader();
            loader.dataFormat = dataFormat;
            configureListeners(loader); // Des listeners  de  base  complete IO etc ...
                // urlDown est un attirbut que  je recupere lors de  l instantiation monobjet.urlDown = mon url
            urlPod = encodeURI(urlDown);
            var request:URLRequest = new URLRequest(urlDown);

            try {
                loader.load(request);
            } catch (error:Error) {
                trace("Document non trouvé");
            }
        }

Posté par StefonBlog à 13:10 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]

05 novembre 2007

DateFormatter et le tri sur les dates

J'ai un datagrid qui liste le contenu d'un répertoire. A ce niveau là pas de soucis, je veux afficher la date dans une colonne, et là je me retrouve avec la date complète en anglais à peu près comme ça "Sat Nov 30 01:20:00 GMT-0800 1974".

Il existe dans le package mx.formatters une classe DataFormatter, génial ....

Donc  on teste
    Avant de boucler sur le contenu de  mon répertoire je crée mon objet DateFormatter

            var dateFormatter:DateFormatter = new DateFormatter();
            dateFormatter.formatString ="DD/MM/YYYY";

Puis je boucle sur le contenu du répertoire et pour chaque  item je crée un objet myfile:File.

                // Je récupère la date du fichier ( j'ai eu des problèmes avec Tiger.... )
            var dateObjet:Date = myfile.creationDate;
                // Et je la mets au format défini par formatString  précedemment.
            var laDate:String = dateFormatter.format(dateObjet);

            Ensuite on en fait ce que l'on veut, moi je reconstruit un objet pour chaque fichier de ma boucle et je place tout ça dans un tableau qui se trouve être le dataprovider de mon datagrid.

Puis j'affiche ma date formatée dans une colonne, et c'est  là que se pose  le problème, comme c'est devenu une chaine de caractère (DateFormatter retourne un type String), quand je clic sur le header pour trier, j'obtiens n'importe quoi :(

Je remercie PhilFlash pour la solution http://philflash.inway.fr/flex/dgsimple/dgsimple.html
Donc on oubli tout ce que l'on vient de faire :)

On laisse la date dans  son format d'origine pour le moment et c'est sur le datagrid que l'on va faire les traitements.

Sur chaque colonne d'un datagrid on à l'évenement labelFunction qui comme son l'indique permet de déterminer une fonction pour le label ( c'est facile l'anglais, non ?  :) )

<mx:DataGridColumn headerText="DATE" dataField="date" width="45" labelFunction="showDate" sortCompareFunction="dateCompareFunction"/>

            private function showDate(item:Object, column:DataGridColumn):String
            {    
                if (dateFormat == null) {
                    dateFormat = new mx.formatters.DateFormatter();
                    dateFormat.formatString = "DD/MM/YY";
                }   
                var field:String =  column.dataField;    
                return dateFormat.format(item[field]);
            }

Donc oui ça retourne un type String, mais c'est juste pour l'affichage, les objets de notre dataprovider ont encore un vrai objet Date.

Et pour le tri
<mx:DataGridColumn headerText="DATE" dataField="date" width="45" labelFunction="showDate" sortCompareFunction="dateCompareFunction"/>

On utilise  sortCompareFunction de datagridColumn et on lui affecte une fonction de tri

     private function dateCompareFunction(obj1:Object, obj2:Object):int {
                var result:int = 0;
                result = ObjectUtil.dateCompare(obj1.date, obj2.date);
                return result;
            }

  Et là ça fonctionne  :), un bel affichage et un tri.

N'oubliez pas de faire un import des classes
    import mx.utils.ObjectUtil;
    import mx.formatters.DateFormatter;

Posté par StefonBlog à 19:04 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]

04 novembre 2007

Leopard AIR ... ça commence mal

[Edit]

Ce problème est aléatoire, ce matin il avait disparu et en faisant  une mise  à jour de mon appli il est revenu sur toutes les applis AIR :(

Bien bien bien,  je m'attendais à des petits problèmes mais là, ça va  pas être simple.

Ce n'est pas bien grave, mais c'est comment dire ...  génant.

Avec Léopard et  les applis AIR à fond transparent quand je les déplace j'ai un petit trait blanc clignotant  qui apparait sur le bord haut et droit de l'appli .... Bien sur une image vaut mieux que cette explication foireuse, je vais voir ce que je peux faire :)

Image_2

Posté par StefonBlog à 16:54 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]

23 octobre 2007

Update d'une appli AIR

Un bon tuto pour la mise  à jour d'une appli AIR http://blog.everythingflex.com/2007/10/01/air-update-manager/

En substance

Creer une classe UpdateManager, on peux copier/coller celle  de Rich Tretola

Dans  le fichier  principal de  l'appli faire l'import de la classe et  la création d'une instance de la classe

import le.path.de.la.classe.UpdateManager;
private var um:UpdateManager = new UpdateManager("http://www.tondomaine.com/appli/version.xml");

Le fichier version.xml est à faire à la main, je reviens dessus après

Dans  la fonction d'initialisation de l'appli on appelle la fonction loadApplicationFile()
um.loadApplicationFile();

Cette fonction va  lire le numero de version inscrit dans le fichier app.xml de l'appli
monappli-app.xml puis faire la comparaison avec celui de l'appli en ligne (fichier version.xml sur le serveur).

J'ai vu des exemples avec /META-INF/AIR/application.xml mais  ça n'a pas fonctionné ...
Dans cette fonction, il faut donc définir le  path du fichier dans cette ligne :

var request:URLRequest = new URLRequest("app-resource:/monappli-app.xml");

[Edit]

Mea culpa, en fait il faut bien aller chercher /META-INF/AIR/application.xml mais ça ne fonctionne  pas pendant  le debug, donc  pendant le debug aller chercher  app-resource:/monappli-app.xml et  pour la version compilée app-resource:/META-INF/AIR/application.xml.

Le fichier version.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<currentVersion version=".2"
       downloadLocation="
http://www.tondomaine.com/appli/monappli.air"   
       forceUpdate="false"
       message="les nouvelles fonctionnalités"/>

Mettre la version de l'appli qui se trouve sur le seveur, indiqué l'url de l'appli pour le téléchargement, si forceUpdate est à true la mise à jour se fait sans demander  son avis à l'utilisateur, le message s'affiche dans l'alerte, on peut  y mettre ce que l'on veut.

J'ai eu une erreur 2032, je n'avais pas bien noté  le path de l'appli à télécharger dans le fichier version.xml

Voilà c'est un résumé rapide, si vous voulez que je le fasse au ralenti, il suffit de demander :).

Posté par StefonBlog à 17:38 - AIR - Commentaires [1] - Rétroliens [0] - Permalien [#]

18 octobre 2007

MetaData video flex

J'avais vu ça il y a  un mois environ mais je ne pouvais pas  le tester car ça avait été intégré dans un nigthy build de flex, et que si vous faites du AIR vous  ne pouvez  pas jouer à récuperer ce genre de version ( si ce n est pas exact, je veux être au courant, vu le nombre de bug qui me prenne la tête et dont j'espère  la résolution).

Bref, avec la flex 3 B2 on peut maintenant lire  les metadata des videos avec le videoDisplay, il suffit pour cela  d'ajouter matadatareceived dans la déclaration du composant et  de lui associer  une fonction.

<mx:VideoDisplay id="videoDisplay"
            visible="false"
            ready="videoDisplay.visible = true;"
            metadataReceived="videoDisplay_metadataReceived(event);" />

            private function videoDisplay_metadataReceived(evt:MetadataEvent):void {
                var item:String;
                var meta:Object = evt.info; // videoDisplay.metadata;
                var value:*;
                for (item in meta) {
                    if (ObjectUtil.isSimple(meta[item])) {
                        if (meta[item] is Array) {
                            value = "[Array]";
                        } else {
                            value = meta[item]
                        }
                       trace('name: '+item +' - value: '+value);
                    }
                }
            }

Trouvé sur le très bon blog http://blog.flexexamples.com/

Posté par StefonBlog à 10:18 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]

10 octobre 2007

Dragmanager conflit de nom

En voulant  mettre en place un drag and drop d'un élément d'une liste vers bouton, j'ai rencotré  pas  mal de petits soucis.

les nativeDragEvent qui ne  fonctionnaient  pas  et des conflits entre  les classes mx.managers.DragManager et flash.desktop.DragManager

La solution est de nommer completement  DragManager quand  on l'appelle  ..
Petit exemple qui fonctionne.

<?xml version="1.0"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
   applicationComplete="initApp();">

   <mx:Script>
       <![CDATA[
       import mx.events.DragEvent;
       import mx.core.DragSource;
       import flash.events.NativeDragEvent;

       import flash.desktop.Clipboard;
       import flash.desktop.ClipboardFormats;      
       import mx.managers.DragManager;
       import flash.desktop.DragActions;
       import mx.core.UIComponent;
       import mx.collections.ArrayCollection;

           private function initApp():void {
               firstList.dataProvider = new ArrayCollection([
                   {label:"First", data:"1"},
                   {label:"Second", data:"2"},
                   {label:"Third", data:"3"},
                   {label:"Fourth", data:"4"}
               ]);

               

           }

        private function acceptIt2(event:DragEvent):void{
           trace ('----------------------------------');
               if(event.dragSource.hasFormat("items")) {
                mx.managers.DragManager.showFeedback(DragActions.COPY);
                  mx.managers.DragManager.acceptDragDrop(best);
              trace(event.type);
           }

       }
       private function performDrop2(e:DragEvent):void{
           trace('naigationControlDroite::performdrop');

       }
       ]]>
   </mx:Script>

   <mx:HBox id="myHB">
       <mx:List  id="firstList"

           dragEnabled="true"
           dragMoveEnabled="true"/>
   <mx:Button  id="best"   
        dragEnter="acceptIt2(event)"
        dragDrop="performDrop2(event)"
        top="93" horizontalCenter="15"
        label="Best"/>
   </mx:HBox>
</mx:WindowedApplication>

Merci à Iteratif  (flexx.fr)  et Gwen pour le coup de  main

Posté par StefonBlog à 13:54 - AIR - Commentaires [3] - Rétroliens [0] - Permalien [#]

06 octobre 2007

Trouver le user loggé sur l'ordi

Connaitre  l'utilisateur qui est  en train d'utiliser votre  application AIR pour afficher son nom fait  parti de  ces petites options sympa.

Pour ce faire c'est simple 

File.userDirectory.name ....  tant pis pour ceux qui ont  mis n'importe quoi  :)

Posté par StefonBlog à 20:27 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]

05 octobre 2007

Petite main ou es tu ?

Non non,  je ne viens  pas de suivre un cours de  F.......g Manager qui cherche un stagiaire, je répond  plutôt à  un demande d'utilisateur.

Mais ou est donc cette petite main chère à ma  mère qui lui indique la possibilité de cliquer ici ou là ?

Eh bien  il faut croire que chez Adobe, on considère que ce repère est une option,  même sur un composant tel qu'un 'button'.

Alors  pour corriger le tir et faire plaisir à ceux qui éprouve un grand sentiment de manque devant votre interface :

<mx:Button x="60"  useHandCursor="true" buttonMode="true"  y="10" click="onCloseClicked(event)" id="closeBtn"  toolTip="Close" />

Posté par StefonBlog à 11:07 - AIR - Commentaires [0] - Rétroliens [0] - Permalien [#]
« Accueil  1  2   Page suivante »