[Résolu] Présenter un PopOver à  partir d'un ButtonItem

busterTheobusterTheo Membre
août 2015 modifié dans API UIKit #1

Bonjour,


un truc tout simple apparemment, mais je galère cher.


J'explore la toile depuis trois jours, et j'ai fait tant de tentatives avec échec, que je reviens ici chercher une explication.


 


L'idée, c'est :


Je tape sur un "UIBarButtonItem" (Voir le dernier item plus bas -> "prefsButton") dans ma nav, pour afficher un popover.


 


 


 


Code de la nav :



// NavBar
func configureNavbar(etapeViewController: UIViewController) {

etapeViewController.navigationItem.setHidesBackButton(true, animated: false)

var fixedSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
fixedSpace.width = 36.0

var addPatientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "addButton.png"), style: .Plain, target: self, action: "nouveauPatient")
addPatientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

var patientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "patientsButton.png"), style: .Plain, target: self, action: "toggleNavPatients")
patientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

var prefsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "gearButton.png"), style: .Plain, target: self, action: "prefsPatientsContainer")
prefsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, addPatientsButton, patientsButton, prefsButton]
}

Je veux utiliser la méthode "presentPopoverFromBarButtonItem", qui me semble la plus appropriée.


 


Je teste donc dans un premier temps le "UIBarButtonItem" sur lequel j'ai cliqué :



func prefsPatientsContainer(sender: UIBarButtonItem) {
println("sender = \(sender)")
}

J'ai systématiquement ce message d'erreur :



 


unrecognized selector sent to instance ...



 


J'ai essayé avec :



sender: UIBarButtonItem

puis  :



sender: UIButton

puis :



sender: AnyObject

Toujours le même message.


 


Voilà , si quelqu'un a une idée, je suis preneur.


 


Merci d'avance.


Réponses

  • AliGatorAliGator Membre, Modérateur
    Normal, ta méthode prend un paramètre, donc le selector associé s'appelle "prefsPatientsContainer:" et non "prefsPatientsContainer", tu as oublié le ":" à  la fin. Du coup quand tu appuies sur ton bouton et qu'il déclenche l'action associée, il essaye d'appeler une méthode "prefsPatientsContainer()" qui n'existe pas, car ta méthode prend un paramètre et non aucun.

    (Les joies des reliquats d'Objective-C et de la notion de selectors qui ne sont pas trop adaptés à  Swift mais bon faut faire avec ce qu'on a comme API...)
  • busterTheobusterTheo Membre
    août 2015 modifié #3

    Oh, merci AliGator.


    Pourtant, il me semblait avoir essayé aussi ça, mais j'ai du me mélanger avec d'autres trucs. Chui une buse - Pfff


    Génial.


     


    Encore merci


     


    Par contre, maintenant, j'essaie de faire mon popOver, avec bien sûr, "presentPopoverFromBarButtonItem" et voilà  le problème.


     


    En faisant :



    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)

    J'ai ce message d'erreur :



     


    Cannot invoke 'presentPopoverFromBarButtonItem' with an argument list of type '(UIBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection, animated: Bool)'



    Et quand je regarde les pages apple, je découvre que c'est maintenant deprecated.


    Si je coche ou décoche la case "hide deprecated symbols" je vois que toutes les méthodes sont deprecated en iOs9 et qu'il n'y a pas de substitut.


     


    Donc, en gros, cannot invoke et deprecated. Je n'y comprend plus rien.


    Ils veulent qu'on fasse comment alors ?


     


    T'as une idée pour ce sac de noe“uds ?


     


    Et en plus, moi je ne suis qu'en iOs8...


  • DrakenDraken Membre
    août 2015 modifié #5

    iOS 9 ?? C'est quoi ce truc ?


    Tu ne vas pas commencer à  te poser des questions sur un OS pas encore sorti. Une application iOS7/iOS8 fonctionnera sans problème sur iOS 9. Tu n'as pas besoin de te soucier d'un éventuel futur (oui je sais, ça sort dans 5 à  6 semaines).


    Une application développée pour iOS 8 tournera sur iOS9.


    Une application développée pour iOS9 ne tournera pas sur iOS 8


  • Ok Draken, désolé.


    Mais quand même, t'en penses quoi de ce lien ?


     


     


     


    En attendant, je suis parvenu à  faire mon popOver.


     


    Voilà  le code (et l'erreur en premier) qui tombait en erreur :



     


     


    Cannot invoke 'presentPopoverFromBarButtonItem' with an argument list of type '(UIBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection, animated: Bool)'


    func prefsPatientsPopOver(sender: UIBarButtonItem) {

    menuViewController.modalPresentationStyle = .Popover
    menuViewController.preferredContentSize = CGSizeMake(500, 600)

    let popoverMenuViewController = menuViewController.popoverPresentationController
    popoverMenuViewController!.delegate = self
    popoverMenuViewController!.sourceRect = CGRectMake(100,100,0,0)

    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }

    Et le code qui fonctionne (pour ceux que ça intéresse) :



    func prefsPatientsPopOver(sender: UIBarButtonItem) {

    menuViewController.modalPresentationStyle = .Popover
    menuViewController.preferredContentSize = CGSizeMake(500, 600)

    let popoverMenuViewController = UIPopoverController(contentViewController: menuViewController)

    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }

    En conclusion, y'a quand même un paquet de code/tutos qui déconnent grave, ou qui sont super compliqués pour pas grand chose, sur le web. Mais je suis aussi un peu buse, je le reconnais. En tout cas, ça, ça fonctionne.


    J'ai enfin mon premier popOver de touteMaLife  :p


     


    Merci encore aux barmen de cocoaCafe.



  • Ok Draken, désolé.


    Mais quand même, t'en penses quoi de ce lien ?


     




    J'en pense que ce sera utile quand il s'agira de développer du code iOS 9 compatible iOS 8, ce qui n'est pas l'urgence du moment. T'as pas une dead line dans quelques semaines ?

  • le 15 septembre - ça ira ?


     


    Mais je ne comprend pas.


    Lorsque iOS9 sera ok, tu disais que le code iOS8 tournera en iOS9, alors pourquoi faudrait-il faire du code iOS9 compatible iOS8 ?


    Ne peut-on pas garder du code iOS8, puisqu'il tourne en iOS9 ?


     


    Je sais, ces questions doivent te paraà®tre débiles, mais y'a un truc qui m'échappe.


  • AliGatorAliGator Membre, Modérateur

    Voilà  le code (et l'erreur en premier) qui tombait en erreur :


    func prefsPatientsPopOver(sender: UIBarButtonItem) {

    menuViewController.modalPresentationStyle = .Popover
    menuViewController.preferredContentSize = CGSizeMake(500, 600)

    let popoverMenuViewController = menuViewController.popoverPresentationController
    popoverMenuViewController!.delegate = self
    popoverMenuViewController!.sourceRect = CGRectMake(100,100,0,0)

    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }
    Et le code qui fonctionne (pour ceux que ça intéresse) :

    func prefsPatientsPopOver(sender: UIBarButtonItem) {

    menuViewController.modalPresentationStyle = .Popover
    menuViewController.preferredContentSize = CGSizeMake(500, 600)

    let popoverMenuViewController = UIPopoverController(contentViewController: menuViewController)

    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }


    L'erreur que tu as (j'ai pas testé mais c'est ce que je comprend à  lire le code) c'est que :

    1) Dans le premier cas, tu récupères la popoverPresentationController potentiellement déjà  existante. Cette propriété est sensée te retourner le UIPopoverController dans lequel ton menuViewController est déjà  présenté (c'est à  dire si ton menuViewController est déjà  dans une Popover, ça va te retourner cette UIPopoverController qui la présente), ou nil si ton menuViewController n'est pas présenté par une Popover (mais est par exemple directement à  l'écran à  la racine de la Window ou autre).

    Cette variable popoverPresentationController est de type "UIPopoverController?", autrement dit est un Optional, ce qui est normal car elle peut retourner soit un vrai UIPopoverController, soit nil si ton menuViewController n'est PAS encore présenté dans une Popover.

    (Et d'ailleurs dans ton cas, c'est je suppose sûrement nil, puisque tu n'as pas encore présenté ton menuViewController... et que c'est justement ce que tu es en train d'essayer de faire, mais en attendant il n'a pas encore de UIPopoverController qui le présente justement...)

    L'erreur que te remonte Xcode pourrait être un peu plus explicite, je te le concède, mais elle vient du fait que ta variable "popoverMenuViewController" est de type Optional, or tu essayes d'appeler directement une méthode dessus, sans l'unwrapper avant avec un "!" ou un "?". Donc Xcode devrait plutôt te dire "You should unwrap the variable before using it" ou un truc dans le style, mais bon.

    Au passage, l'utilisation de "!" sur un Optional est à  éviter à  tout prix, sauf si tu sais vraiment ce que tu fais. Si tu vois que tu es en train d'utiliser "!" derrière un optional sans trop savoir pourquoi, c'est certainement que tu ne devrais pas l'utiliser. En effet, par exemple là  ton code va crasher et faire planter lamentablement ton application si la variable "popoverMenuViewController" est nil lors de l'exécution de ton app. Il faut toujours tant que faire se peut préférer utiliser "?" ou utiliser la construction "if let" (car sinon, en plus de risquer de faire planter ton app en utilisant des force-unwrap "!", tu perds tout l'intérêt des Optionals en Swift et de la protection qu'ils apportent à  ton code...)

    Il aurait donc mieux fallu écrire ceci, qui résout à  la fois le risque de crash au runtime si le popover est nil, et l'erreur de compilation, en utilisant la syntaxe "if let" qui ne rentre dans le "if" que si le popover n'est pas nil, et qui du coup fait de popoverMenuViewController une variable non-optional dans ce cas :

    if let popoverMenuViewController = menuViewController.popoverPresentationController {
    popoverMenuViewController.delegate = self
    popoverMenuViewController.sourceRect = CGRectMake(100,100,0,0)

    popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }


    2) Ceci dit, le code que je viens d'écrire te montre la bonne façon de coder avec les optionals, en utilisant "if let", ce que je te recommande fortement. Si tu n'es pas à  l'aise avec les Optionals et la syntaxe "if let", il est fortement conseillé d'y passer un peu de temps pour t'y mettre, car ça fait partie des fondamentaux de Swift.
    Mais pour ton besoin fonctionnel, à  savoir présenter ton menuViewController dans une popOver, ce code ne marchera pas... car "menuViewController.popoverPresentationController" va certainement retourner "nil" (puisque ton menuViewController n'est justement pas encore dans une Popover, donc demander à  iOS de te retourner "la UIPopoverController dans laquelle menuViewController est déjà  présenté" va retourner "bah y'en a pas encore, de Popover, justement" " donc nil) et donc tu ne passeras pas dans ton if (si tu avais laissé ton code précédent sans le "if let" mais avec les "!", ça aurait planté direct).

    En effet, tu ne veux pas récupérer le UIPopoverController "qui existe déjà  et présente déjà  ton menuViewController". Non, toi tu veux justement en créer un de UIPopoverController, puisqu'il n'existe pas encore, pour y présenter menuViewController dedans. C'est pour ça que ton 2ème bout de code est la bonne solution, car tu n'essayes plus de récupérer un popover existant (qui en fait n'existe pas encore) mais tu en crées bien un nouveau.
  • oula, ça a l'air sérieux tout ça.


    Encore merci AliGator pour tes explications précises et complètes.


    Je vais lire tout ça à  tête reposée.


     


    Au passage, j'ai mis un nouveau post, et le problème est peut-être lié...



  • le 15 septembre - ça ira ?


     


    Mais je ne comprend pas.


    Lorsque iOS9 sera ok, tu disais que le code iOS8 tournera en iOS9, alors pourquoi faudrait-il faire du code iOS9 compatible iOS8 ?


    Ne peut-on pas garder du code iOS8, puisqu'il tourne en iOS9 ?




    Tu auras besoin de code iOS 9 compatible iOS 8 si ton client te dit "je voudrais une nouvelle version exploitant les spécificités d'iOS 9, mais pouvant quand même tourner de manière minimale avec un device sous iOS 8".

  • ah ok - c'est logique - merci.


    Donc je men fou pour instant. Génial


  • AliGator, j'ai bien lu tes explications. J'ai à  peu-près compris. De toute façon, ça semble tellement logique...


     


    J'aime bien utiliser les if let...


     


    Mais ces histoires de nil, oprionnal, !, ?, etc., c'est quand même un peu fatiguant.


     


    Genre voilà  un code que j'ai dans le cas d'une édition (click sur tableView dans la nav de gauche - slideNav...)



    let fetchRequest = NSFetchRequest(entityName: "Preferences")
    if let fetchResults = self.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [Preferences] {
    if fetchResults.count != 0 {
    if fetchResults[0].aide == true {
    if etape0ViewController.aideEtapes == nil {
    etape0ViewController.aide()
    } else {
    etape0ViewController.aideEtapes.removeFromSuperview()
    etape0ViewController.aideEtapes = nil
    etape0ViewController.aide()
    }
    } else {
    if etape0ViewController.aideEtapes != nil {
    etape0ViewController.aideEtapes.removeFromSuperview()
    etape0ViewController.aideEtapes = nil
    }
    }
    }
    }

    T'imagines un peu le truc. Juste pour appeler une fonction :



    etape0ViewController.aide()

    tout ce qu'il faut tester avant. C'est super chiant. Mais bon, faut s'y faire, ou bien se remettre au "basic".  :'(  ou au pascal  . Personnellement, ce que je préférait, c'était l'ActionScript3 (voire le 2) - Trop bon. Mais bon, ciao flash. Dommage, quoique le soft en lui-même, une vrai daube. Mais bon, quand on le connaissais bien, on pouvait faire des trucs fabuleux.


     


    En gros, swift ne devrait pas s'appeler swift, mais swIfs. C'est le roi des ifs.


     


     


    Ou bien encore :



    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if let indexPath = self.listePatients.indexPathForSelectedRow() {
    let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject

    Bref. Merci pour la formation. J'ai encore beaucoup d'efforts à  faire, et à  monter mon degré d'acceptation en puissance.


    Comme disait, je ne sais plus, je crois que c'est Draken, bienvenu au club...  :p


  • AliGatorAliGator Membre, Modérateur
    août 2015 modifié #14
    Heu alors, dans ton code d'exemple :

    1) je ne vois nulle part du code qui rajoute un "if" uniquement à  cause du fait que Swift possède le concept d'Optionals, à  part le tout premier "if let fetchResults = ...". Donc c'est pas un très bon exemple pour dire que à  cause des Optionals j'ai plein de if partout que j'aurais pas sinon !

    2) Certes dans les autres "if" tu testes si les valeurs ne sont pas "nil", mais soit ces "ifs" seraient là  aussi si tu écrivais ce code dans un autre langage comme Objective-C, donc ça ne changerait pas le problème... et en plus, en Swift tu peux les réécrire de façon bien plus concise, en particulier en utilisant l'optional chaining (dont tu ne profites malheureusement pas dans ta façon d'écrire ton code), qui n'existe pas vraiment en ObjC justement où ces "if" seraient nécessaires !

    3) Et dans ton 2ème exemple, tu ne profites pas non plus de la syntaxe cumulative de if let non plus.

    Tout ceci t'éviterais pas mal de ifs, d'accolades et de décalage de ton code vers la droite !


    Par exemple, ton premier exemple tu devrais plutôt l'écrire ainsi, ce qui contient tu en conviendras bien moins de "if" et bien moins de décalage à  droite (et enlève aussi des "!" dangereux) !
    let fetchRequest = NSFetchRequest(entityName: "Preferences")
    let fetchResults = self.managedObjectContext?.executeFetchRequest(fetchRequest, error: nil)
    if let firstResult = fetchResults?.first as? Preferences {
    etape0ViewController.aideEtapes?.removeFromSuperview()
    etape0ViewController.aideEtapes = nil
    if firstResult.aide == true {
    etape0ViewController.aide()
    }
    }
    Et encore, ce n'est qu'une façon de l'écrire parmi d'autres.


    Explications pas à  pas du code
    • Comme je vois que tu n'utilises que le premier résultat, plutôt que de caster le tableau entier en [Preferences] j'ai choisi de d'abord récupérer le premier élément, et seulement ensuite de le caster en "Preferences". Bon, ça change pas grand chose, mais ça va bien avec le reste de la réécriture du code
    • La syntaxe "?." (optional chaining) est clé dans toute la réécriture. "x?.methode()" veut dire "si x n'est pas nil, appelle "méthode()" sur l'objet x".
      • Ainsi, "fetchResults?.first" appelle la méthode first (qui retourne le premier élément du tableau) que si fetchResults n'est pas nil, ou retourne nil si fetchResults est nil.
      • La méthode "first" elle-même retourne nil si jamais le tableau sur lequel tu l'appelles est vide (et n'a donc pas de premier élément), et le cast "as? Preferences" est aussi optional, retournant nil si l'objet n'est pas en fait de type "Preferences".
      • Ce qui fait qu'au final toute l'expression "fetchResults?.first as? Preferences" retourne un objet de type Preference si fetchResults n'est pas nil, contient au moins une valeur, et que cette valeur est bien de la classe "Preferences"... et retourne "nil" dans tous les autres cas (fetchResults nil, ou vide, ou dont le premier élément n'es pas de type Preferences).
      • En une seule instruction, grâce à  l'Optional Chaining, tu as directement ce que tu veux sans avoir besoin de faire des "if" partout.
    • De même, removeFromSuperview() ne sera appelé sur etape0ViewController.aideEtapes que si ce dernier n'est pas nil. Ca t'évite pas mal de "if" que tu avais un peu partout dans ton code !
    • Ensuite, je mets aideEtapes à  nil dans tous les cas, après tout s'il était déjà  nil c'est pas grave, donc pas vraiment besoin de faire un test pour ça
    • Du coup tout à  coup ton code se simplifie drastiquement, puisque je remarque que dans TOUS les cas tu veux faire cet appel à  "removeFromWuperview" si "aideEtapes" n'est pas nil, donc plus besoin de le mettre dans plusieurs "if". Le seul "if" qui reste c'est pour n'appeler aide() que si firstResult.aide vaut true.
    Du coup non seulement j'ai fait disparaà®tre tous les "if" superflus que tu avais inventés, mais en plus le code est plus compact, tout en restant sûr car ne risquant pas de planter (j'ai remplacé le "self.managedObjectContext!.executeFetchRequest(...)" par "self.managedObjectContext?.executeFetchRequest(...)" donc le "!" par un "?", ce qui fait que si jamais ton MOC est nil, au lieu de planter lamentablement ton application, ça va juste retourner nil et donc du coup ne pas rentrer ensuite dans ton "if"


    ---


    Les Optionals en Swift sont très puissants, et permettent de sécuriser énormément ton code. Comparativement à  par exemple de l'Objective-C où bien souvent on oubliait de tester si un objet était "nil" avant d'appeler une méthode dessus (j'ai eu pas mal de bugs à  cause de ça sur des apps clients, genre appeler [myString isEmpty] qui retourne NO si myString est nil alors qu'on s'attend évidemment à  ce que nil soit considéré comme une chaà®ne vide...), en Swift on peut toujours faire la même chose (appeler une méthode sur un objet qui peut être nil et dans ce cas ne rien faire) grâce à  l'Optional Chaining "objet?.methode()" mais au moins c'est explicite et ça te force un peu à  réaliser que le résultat lui-même peut potentiellement être nil et donc à  gérer les cas d'erreur que tu aurais oublié de gérer en ObjC, créant ainsi des bugs qui pouvaient passer inaperçus.
  • busterTheobusterTheo Membre
    août 2015 modifié #15

    Ah oui, j'aime bien ton nouveau code.


    Je pars en vacances le 9, une semaine. J'imprime mes posts avec tes cours (car pas de net où je vais - bretagne profonde) et je vais tester tes cours sur tous les posts (weak/strong, optionnal, etc.). Merci pour tout.


  • Joanna CarterJoanna Carter Membre, Modérateur
    août 2015 modifié #16


    (car pas de net où je vais - bretagne profonde)




    J'ai pu même accéder le net depuis Huelgoat, Callac Rostrenen, Botmeur, et plus. Ou iras-tu pour l'éviter ?


  • Ben je vais à  Kersain (Ploudalmezeau) ( bout du bout du finistère). J'y vais souvent et je sais que c'est galère où je vais. Y'a même pas de réseau sfr pour pouvoir faire un partage de connection sur mon iphone.


     


    J'ai juste la solution pour les cas extrême d'aller au café wifi ou chez des voisins, mais j'aime pas trop.


    Et je m'organise justement pour ne pas avoir trop à  me connecter.


     


    Sans quoi, je loge près d'Elven (Morbihan), et toi, t'es aussi en Bretagne ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    août 2015 modifié #18


    Sans quoi, je loge près d'Elven (Morbihan), et toi, t'es aussi en Bretagne ?

    Je ne suis pas encore installée ; je vais signer l'acte authentique sur ma maison à  Plestin-les-Grèves en septembre et j'espère y déménager dès que nous puissions vendre notre maison ici en Angleterre.


    Ben je vais à  Kersain (Ploudalmezeau) ( bout du bout du finistère). J'y vais souvent et je sais que c'est galère où je vais. Y'a même pas de réseau sfr pour pouvoir faire un partage de connection sur mon iphone.


    J'ai juste la solution pour les cas extrême d'aller au café wifi ou chez des voisins, mais j'aime pas trop.

    Et je m'organise justement pour ne pas avoir trop à  me connecter.

    à‰tant donné que nous nous trouverons trop loin d'un central, nous prévoyons nous servir d'une connexion satellite, dont on nous a dit que nous puissions profiter d'une subvention pour le matériel et l'installation. (22Mbps en réception / 6Mbps en transmission) :)
  • Joanna Carter


    Ah tu t'installes au-dessus de Morlaix. Bienvenue en Bretagne, pays magnifique et gens très sympathiques.



     


     


    subvention pour le matériel et l'installation. (22Mbps en réception / 6Mbps en transmission)

    Bonne nouvelle. Je vais me renseigner, ça m'intéresse, car moi je suis en Max 1Mo réception...


  • AliGator,


    j'ai imprimé mes posts (y'a d'ailleurs de quoi constituer un pur bookin - Le livre des barmen).


    Et, je m'suis préparé un p'tit  programme : optionnal chaining, magic numbers, autoLayout/constraints, uiApSharApWindowFrame, xibs, breakpoints/variables, etc.. Chouette menu hein  :D


     


    Bon, ben ce coup-ci, le post est vraiment résolu. La balle est dans mon camp.


     


    Thank's a lot. :p     :p




  • Et, je m'suis préparé un p'tit  programme : optionnal chaining, magic numbers, autoLayout/constraints, uiApSharApWindowFrame, xibs, breakpoints/variables, etc.. Chouette menu hein  :D




    Tu as de la chance d'avoir 3 mois de vacances...

  • T'as raison, j'aimerai bien ne serait-ce qu'avoir 15 jours.


    Et ma deadLine est le 15 septembre.


    Chui top angoissé...


Connectez-vous ou Inscrivez-vous pour répondre.