web-dev-qa-db-fra.com

Comment ajouter par programme une barre de chargement (progression) simple par défaut dans l'application iphone

J'utilise la communication http dans l'application Mon iPhone. Je souhaite afficher une barre de progression pendant le chargement des données du serveur. Comment puis-je le faire par programme?

Je veux juste une barre de progression par défaut. Rien d'extraordinaire, comme c'est le cas avec Android, ProgressDialog.show();, existe-t-il une seule ligne permettant d'afficher la barre de progression dans l'iphone?

37
user517491
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
indicator.center = self.view.center;    
[self.view addSubview:indicator];
[indicator bringSubviewToFront:self.view];
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;

Écrivez ci-dessous le code lorsque vous voulez afficher l'indicateur 

[indicator startAnimating];

écrivez ci-dessous le code quand vous voulez cacher l'indicateur 

[indicator stopAnimating];
79
Hiren

Traduire la réponse de @ Hiren en Swift

 var indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
 indicator.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
 indicator.center = view.center
 self.view.addSubview(indicator)
 self.view.bringSubview(toFront: indicator)
 UIApplication.shared.isNetworkActivityIndicatorVisible = true

Afficher l'indicateur

indicator.startAnimating()

Indicateur d'arrêt

indicator.stopAnimating()
32
enrique7mc

Je recommanderais d'utiliser NSURLConnection. Les méthodes dont vous auriez besoin sont:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
  [self.resourceData setLength:0];
  self.filesize = [NSNumber numberWithLongLong:[response expectedContentLength]];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
  [self.resourceData appendData:data];
  NSNumber *resourceLength = [NSNumber numberWithUnsignedInteger:[self.resourceData length]];
  self.progressBar.progress = [resourceLength floatValue] / [self.filesize floatValue];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  self.progressBar.hidden = YES;
}

Et le fichier d'en-tête:

@property (nonatomic, retain) UIProgressView *progressBar;
@property (nonatomic, retain) NSMutableData *resourceData;
@property (nonatomic, retain) NSNumber *filesize;

J'espère que ça aide

11
Novarg

Pour maintenir cette question totalement à jour, j'ai traduit la réponse de @ enrique7mc en Swift3.0 à la suite de sa traduction de la réponse de @ Hiren.

var indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
indicator.frame = CGRect(x: 0.0, y: 0.0, width: 40.0, height: 40.0)
indicator.center = view.center
view.addSubview(indicator)
indicator.bringSubview(toFront: view)
UIApplication.shared.isNetworkActivityIndicatorVisible = true

Pour démarrer et arrêter la barre de progression, suivez les instructions de @ enrique7mc.

indicator.startAnimating()
indicator.stopAnimating()
9
Francisco Romero

UIProgressView est la classe que vous recherchez: Apple Docs

Vous devez utiliser la méthode setProgress:animated: pour mettre à jour la progression affichée. Très probablement où vous manipulez les données reçues du réseau.

6
Engin Kurutepe

Vous pouvez utiliser IOS UIProgressView intégré. Ci-dessous l'extrait de code:

UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[self.view addSubview:progressView];
[progressView setProgress:50.0];

Vous pouvez utiliser setFrame: pour le positionnement de la barre de progression sur l'affichage.

6
Jeet

Essayez ci-dessous le code

float progress;

//components
UIProgressView *progressBar;
progressBar=[[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
[progressBar setFrame:CGRectMake(30.0, 75.0, 200.0, 80.0)];

int prog=progress*100;
progressStr=[NSString stringWithFormat:@"%d%%",prog];
[progressBar setProgress:progress];
5
Kuldeep

Je sais que c’est une question plus ancienne, mais j’ai écrit une méthode statique globale pour effectuer ce type de travail depuis n’importe quel point de vue, en fonction des réponses ci-dessus.

Les principales mises à jour sont:

  • prend en charge la superposition opaque facultative derrière l'indicateur d'activité 
  • utiliser la taille de trame par défaut pour l'indicateur d'activité 
  • utiliser le style d'indicateur .WhiteLarge

Dans mon AppHelper.Swift:

static func showActivityIndicator(view: UIView, withOpaqueOverlay: Bool) {

    // this will be the alignment view for the activity indicator
    var superView: UIView = view

    // if we want an opaque overlay, do that work first then put the activity indicator within that view; else just use the passed UIView to center it
    if withOpaqueOverlay {
        let overlay = UIView()
        overlay.frame = CGRectMake(0.0, 0.0, view.frame.width, view.frame.height)
        overlay.layer.backgroundColor = UIColor.blackColor().CGColor
        overlay.alpha = 0.7
        overlay.tag = activityIndicatorOverlayViewTag

        overlay.center = superView.center
        overlay.hidden = false
        superView.addSubview(overlay)
        superView.bringSubviewToFront(overlay)

        // now we'll work on adding the indicator to the overlay (now superView)
        superView = overlay
    }

    let indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)

    indicator.center = superView.center
    indicator.tag = activityIndicatorViewTag
    indicator.hidden = false

    superView.addSubview(indicator)
    superView.bringSubviewToFront(indicator)

    indicator.startAnimating()

    // also indicate network activity in the status bar
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}

static func hideActivityIndicator(view: UIView) {

    // stop the network activity animation in the status bar
    UIApplication.sharedApplication().networkActivityIndicatorVisible = false

    // remove the activity indicator and optional overlay views
    view.viewWithTag(activityIndicatorViewTag)?.removeFromSuperview()
    view.viewWithTag(activityIndicatorOverlayViewTag)?.removeFromSuperview()
}
4
the_dude_abides

Essayez MBProgressHUD

C'est assez simple, il dispose de plusieurs options d'animation de progression et permet d'ajouter des personnalisations. Il affiche en plein écran. Et cela devrait fonctionner avec toutes les versions récentes d'iOS.

Ou essayez LDProgressView si vous voulez quelque chose de plus sophistiqué :) Cela ressemble en quelque sorte à la barre de progression OSX.

2
Hlung

Je voulais publier une solution que j'ai créée et qui affichera une barre de progression dans une fenêtre distincte pour indiquer la progression avec les résultats pouvant être répertoriés.

Ci-dessous, une image de ce à quoi elle ressemble.

 enter image description here

Compatibilité: Swift 3

Caractéristiques: Code fileté pour exécuter et annuler + bouton Terminé. Affiche automatiquement le montant de progression restant si vous vouliez utiliser la fonction updateProgress.

Le code est très simple et facile à modifier, juste un storyboard et un viewcontroller. 

  1. Utilisez le XML ci-dessous et enregistrez avec le nom final que je suggère ci-dessous quelque part dans votre projet.

ProgressWindow.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.Apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.Apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Progress-->
        <scene sceneID="5gE-ws-FsC">
            <objects>
                <viewController storyboardIdentifier="progressWindow" title="Progress" id="IB9-Dc-dCV" customClass="ProgressWindowViewController" customModule="WorkOrders" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Lvc-9P-nmJ"/>
                        <viewControllerLayoutGuide type="bottom" id="xJS-yG-jWM"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="iDk-68-mde">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please Wait..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9ui-W7-ucD">
                                <rect key="frame" x="16" y="84" width="343" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ov7-yH-A5z">
                                <rect key="frame" x="16" y="113" width="343" height="2"/>
                            </progressView>
                            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" text="Starting Up..." textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bwA-YT-FcE">
                                <rect key="frame" x="16" y="123" width="343" height="464"/>
                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
                            </textView>
                            <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RPs-Mo-Cfx">
                                <rect key="frame" x="-4" y="20" width="383" height="44"/>
                                <items>
                                    <navigationItem title="Starting Sync..." id="Y87-LY-5o5">
                                        <barButtonItem key="rightBarButtonItem" title="Cancel" id="AD3-in-E6j">
                                            <connections>
                                                <action selector="cancelNavItemButtonActionWithSender:" destination="IB9-Dc-dCV" id="IF1-MG-v2x"/>
                                            </connections>
                                        </barButtonItem>
                                    </navigationItem>
                                </items>
                            </navigationBar>
                            <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6lh-KK-lX1">
                                <rect key="frame" x="113" y="595" width="150" height="42"/>
                                <fontDescription key="fontDescription" type="system" pointSize="25"/>
                                <state key="normal" title="Done"/>
                                <state key="disabled" title="Please Wait..."/>
                                <connections>
                                    <action selector="doneButtonActionWithSender:" destination="IB9-Dc-dCV" eventType="touchUpInside" id="KQH-Th-NAC"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="leadingMargin" secondItem="ov7-yH-A5z" secondAttribute="leading" id="9Gm-bd-GY6"/>
                            <constraint firstItem="xJS-yG-jWM" firstAttribute="top" secondItem="bwA-YT-FcE" secondAttribute="bottom" constant="20" id="CT1-0k-Skt"/>
                            <constraint firstItem="6lh-KK-lX1" firstAttribute="top" secondItem="bwA-YT-FcE" secondAttribute="bottom" constant="8" symbolic="YES" id="Fb8-eP-lxu"/>
                            <constraint firstItem="RPs-Mo-Cfx" firstAttribute="leading" secondItem="iDk-68-mde" secondAttribute="leadingMargin" constant="-20" id="JSY-Na-oAF"/>
                            <constraint firstItem="xJS-yG-jWM" firstAttribute="top" secondItem="6lh-KK-lX1" secondAttribute="bottom" constant="30" id="NHY-fO-W26"/>
                            <constraint firstAttribute="trailingMargin" secondItem="RPs-Mo-Cfx" secondAttribute="trailing" constant="-20" id="QxH-pj-oOA"/>
                            <constraint firstItem="RPs-Mo-Cfx" firstAttribute="top" secondItem="Lvc-9P-nmJ" secondAttribute="bottom" id="VIf-63-vaw"/>
                            <constraint firstAttribute="trailingMargin" secondItem="bwA-YT-FcE" secondAttribute="trailing" id="WxH-hu-ZVQ"/>
                            <constraint firstAttribute="leadingMargin" secondItem="bwA-YT-FcE" secondAttribute="leading" id="XEd-Ba-ZfL"/>
                            <constraint firstItem="bwA-YT-FcE" firstAttribute="top" secondItem="ov7-yH-A5z" secondAttribute="bottom" constant="8" id="Xjr-bH-ILB"/>
                            <constraint firstItem="6lh-KK-lX1" firstAttribute="centerY" secondItem="iDk-68-mde" secondAttribute="centerY" id="ZU1-pD-czP"/>
                            <constraint firstItem="ov7-yH-A5z" firstAttribute="top" secondItem="9ui-W7-ucD" secondAttribute="bottom" constant="8" symbolic="YES" id="avI-Ab-G29"/>
                            <constraint firstAttribute="leadingMargin" secondItem="9ui-W7-ucD" secondAttribute="leading" id="dse-zV-g00"/>
                            <constraint firstItem="6lh-KK-lX1" firstAttribute="centerX" secondItem="iDk-68-mde" secondAttribute="centerX" id="i5Q-oY-DdV"/>
                            <constraint firstAttribute="trailingMargin" secondItem="9ui-W7-ucD" secondAttribute="trailing" id="jqu-1f-IuA"/>
                            <constraint firstItem="9ui-W7-ucD" firstAttribute="top" secondItem="RPs-Mo-Cfx" secondAttribute="bottom" constant="20" id="nrH-ey-Zcm"/>
                            <constraint firstAttribute="trailingMargin" secondItem="ov7-yH-A5z" secondAttribute="trailing" id="qha-Es-6Au"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="ZU1-pD-czP"/>
                                <exclude reference="CT1-0k-Skt"/>
                            </mask>
                        </variation>
                    </view>
                    <connections>
                        <outlet property="cancelNavButton" destination="AD3-in-E6j" id="SJc-Bc-N6j"/>
                        <outlet property="currentProgressLabel" destination="9ui-W7-ucD" id="zij-yQ-MFX"/>
                        <outlet property="doneButton" destination="6lh-KK-lX1" id="rh2-RF-4ak"/>
                        <outlet property="navItemLabel" destination="Y87-LY-5o5" id="ijO-a7-TrD"/>
                        <outlet property="navigationBar" destination="RPs-Mo-Cfx" id="WEq-F4-Pup"/>
                        <outlet property="theProgressBar" destination="ov7-yH-A5z" id="FUE-9J-iBh"/>
                        <outlet property="theTextView" destination="bwA-YT-FcE" id="1sR-23-NZH"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="TH6-NB-Eos" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-492" y="1474"/>
        </scene>
    </scenes>
</document>
  1. Enregistrez le code suivant ci-dessous dans votre projet sous le nom ProgressWindowViewController.Swift.

ProgressWindowViewController.Swift

import UIKit

protocol progressWindowDelegate : class{
    var titleToGive : String {get}
    func codeToRun(progressWindowViewController:ProgressWindowViewController)
    var codeToCancel : ()->() {get}
}


class ProgressWindowViewController: UIViewController {

    @IBOutlet weak var theTextView: UITextView!
    @IBOutlet weak var currentProgressLabel: UILabel!
    @IBOutlet weak var theProgressBar: UIProgressView!
    @IBOutlet weak var navItemLabel: UINavigationItem!
    @IBOutlet weak var doneButton: UIButton!
    @IBOutlet weak var cancelNavButton: UIBarButtonItem!
    @IBOutlet weak var navigationBar: UINavigationBar!

    //For showing network activity
    var indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)

    //Sets delegate
    weak var controllerDelegate:progressWindowDelegate? = nil

    override func viewDidLoad() {
        super.viewDidLoad()

        navItemLabel.title = controllerDelegate!.titleToGive

        //Run on the main thread first then in background thread.
        DispatchQueue.main.async {
            DispatchQueue.global(qos: .background).async{
                self.controllerDelegate?.codeToRun(progressWindowViewController: self)
            }
        }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func writeToProgressWindow(text:NSMutableAttributedString){
        DispatchQueue.main.async(execute: {
            print("dispatch_queue_get_main_queue -> writeToProgressWindow()")
            self.theTextView.attributedText = text
        })
    }

    func updateNetworkIndicator(active:Bool){
        DispatchQueue.main.async(execute: {
            if(active){
                UIApplication.shared.isNetworkActivityIndicatorVisible = true
            }else{
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
            }
        })
    }

    func updateProgress(updatetext:String,amount:Int,left:Int){
        DispatchQueue.main.async(execute: {
            print("dispatch_queue_get_main_queue -> updatingProgress()")
            self.currentProgressLabel.text = updatetext+" : \(amount) / \(left)"
            self.theProgressBar.setProgress(Float(amount/left), animated: true) //progress is represented as a percentage of the total
        })
    }

    func updateProgressWindowWeFinished(title:String){
        //Enable done button and Disable/Hide Cancel Button.  Add Final Messages
        DispatchQueue.main.async(execute: {
            self.doneButton.isEnabled = true
            self.navItemLabel.title = title
            self.cancelNavButton.isEnabled = false
            self.cancelNavButton.tintColor = UIColor.clear
        })
    }

    @IBAction func cancelNavItemButtonAction(sender: UIBarButtonItem) {
        //Run on the main thread first then in background thread.
        DispatchQueue.main.async {
            DispatchQueue.global(qos: .background).sync{
                print("dispatch_queue_priority_default")
                self.controllerDelegate?.codeToCancel()
            }
            self.dismiss(animated: true, completion: nil)//closes the window.
        }
    }


    @IBAction func doneButtonAction(sender: UIButton) {
        self.dismiss(animated: true, completion: nil)//closes the window.
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

3.) Pour l’utiliser, il suffit de définir le contrôleur de vue qui l’a appelé sur progressWindowDelegate et de fournir les informations nécessaires pour communiquer avec le popover.

 enter image description here

Quelques exemples de code ci-dessous si vous en avez besoin:

SampleViewControllerWithYesButton.Swift

class SyncViewController: UIViewController, progressWindowDelegate {

    var codeToCancel = {print("code to cancel")}
    var titleToGive = "Starting Sync..."

    func codeToRun(progressWindowViewController:ProgressWindowViewController) {
        print("code to run")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func yesButtonAction(_ sender: UIButton) {







            let storyboard = UIStoryboard(name: "ProgressWindow", bundle: nil)
            let controller = storyboard.instantiateViewController(withIdentifier: "progressWindow") as! ProgressWindowViewController
            controller.controllerDelegate = self
            self.present(controller, animated: true, completion: nil)


    }

    @IBAction func noButtonAction(_ sender: UIButton) {
        tabBarController?.selectedIndex = 1 //Send them to the list then.
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

Quoi que vous mettiez dans le codeToRun () sera exécuté comme un thread d'arrière-plan. Pour accéder à n'importe quelle interface utilisateur, codeToRun a accès au progressWindowViewController qui a été préconfiguré pour se connecter à l'interface utilisateur avec ces éléments sous votre contrôle.

@IBOutlet weak var theTextView: UITextView!
    @IBOutlet weak var currentProgressLabel: UILabel!
    @IBOutlet weak var theProgressBar: UIProgressView!
    @IBOutlet weak var navItemLabel: UINavigationItem!
    @IBOutlet weak var doneButton: UIButton!
    @IBOutlet weak var cancelNavButton: UIBarButtonItem!
    @IBOutlet weak var navigationBar: UINavigationBar!

J'utilise ceci dans tous mes projets chaque fois que je fais une synchronisation, un téléchargement ou une tâche réseau fastidieuse.

Cela montre également l'indicateur d'activité pour montrer que vous essayez de faire quelque chose. Tout cela peut être personnalisé car il est très facile de regarder et de comprendre son fonctionnement. J'espère que cela vous aidera à gagner du temps en obtenant rapidement une fenêtre de type progression. 

1
Joseph Astrahan

Swift 3 version de la solution @ enrique7mc

    var indicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
    indicator.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
    indicator.center = view.center
    view.addSubview(indicator)
    indicator.bringSubview(toFront: view)
    UIApplication.shared.isNetworkActivityIndicatorVisible = true


    indicator.startAnimating()
    indicator.stopAnimating()
1
tsik

Traduction de la réponse de @ hiren en Swift4.0

let indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorView.Style.gray)
        indicator.frame = CGRect(x: 0.0, y: 0.0, width: 40.0, height: 40.0)
        indicator.center = view.center
        view.addSubview(indicator)
        indicator.bringSubviewToFront(view)
        UIApplication.shared.isNetworkActivityIndicatorVisible = true


indicator.startAnimating()
indicator.stopAnimating()
1
GritfulOne

Ajouter une propriété

@property (strong, nonatomic) indicateur IBOutlet UIActivityIndicatorView *;

Pour commencer l'animation

[self.indicator startAnimating];

Pour arrêter l'animation

[auto.indicateur stopAnimating];

0
Sreenath S

Je vais mettre dans mes deux cents ici aussi:

J'ai créé ce ARSLineProgress preloader, que vous pouvez également tester ici sur Appetize .

0
Soberman