---
# System prepended metadata

title: GoStyle
tags: [server, dev mobile, GIT, version gestion, code gestion, open-source, backend, database technologies, new technologies, dart]

---

# GoStyle

[TOC]

---


## Membres du projet

- Paul Barbaux
- Ryan Jdaini - Le Hô
- Enzo Compérat

---

## Technologies utilisées
### PHP 
![](https://i.imgur.com/z4ROYIj.png =100x)
> PHP est un langage serveur qui est fréquemment utilisé en web, il permet de faire la liaison entre notre code et notre BDD afin d'effectuer des requêtes quelconques.
> Nous avons utilisé PHP pour les variables get qui communiquent avec mysql pour le back-end et qui renvoient une information en json, nous l'avons ensuite utilisée en service d'API 

###### tags: `backend`,`server`




### MySql

![](https://i.imgur.com/gOnkRcY.png =100x)

> Moteur de BDD très utilisé en web,
> il stocke toutes les données relatives aux QR codes et aux utilisateurs
> voici les modèles de nos tables de données : 

#### scan_user
| id  |    email     |   password   |  admin  |
|:---:|:------------:|:------------:|:-------:|
| int | varchar(255) | varchar(255) | booleen |

#### scan_qr


| id  | value |    promo     |  desc_promo  |
|:---:|:-----:|:------------:|:------------:|
| int | Text  | varchar(255) | varchar(255) |

#### scan_email



| id  |    email     | qr_id |
| --- |:------------:|:-----:|
| int | varchar(255) |  int  |

###### tags: `backend`,`database technologies`

### flutter 
![](https://i.imgur.com/hLOGdpc.png =100x)
> Flutter est un Framework qui permet de faire des applications natives sur android, ios, web et desktop 
> il a été lancé par google en 2017 c'est le plus grand concurrent de React native créé par Facebook

###### tags: `dev mobile`,`new technologies`,`dart`


### Github
![](https://i.imgur.com/KLA8kRU.png =100x)

>Github est un outil de gestion et de collaboration entre developpeurs
>il est connu pour son aspect open-source.
>Il utilise un outil appelé git pour pouvoir publier son code sur la plateforme.
>Cette plateforme a été rachetée par microsoft en 2018.

[le lien github du projet](https://github.com/polo5922/GoStyle)

###### tags: `open-source`,`code gestion`,`version gestion`,`GIT`


---

## Les avancements du projet
- [x] Connexion/Inscription
- [x] Liste des codes scannés
- [x] Suppression des codes utilisés
- [x] Ajout de code grâce à un QR code
- [ ] Espace admin
- [ ] Gestion des utilisateurs
- [ ] Ajout de QR code


---


## Les fonctionalités
### Connexion/Inscription
#### Package utilisé
* [http](https://pub.dev/packages/http)
#### Explication
> Pour notre système de connexion et d'inscription nous avons un formulaire qui sert à nous connecter ou à nous inscrire.
> Nos données sont envoyées à 2 pages ".dart" différentes en fonction du bouton sélectionné par l'utilisateur  
> L'envoi des données permet à la page d'effectuer une requête de connexion ou d'inscription qui vérifie si l'utilisateur existe ou si son adresse mail n'a pas déjà été utilisée,
> si jamais l'adresse n'est pas enregistrée dans la BDD l'utilisateur est redirigé vers la page d'inscription et de connexion.
#### Code
##### front-end

> Exemple d'entrée de formulaire
``` dart
TextFormField(
                decoration: const InputDecoration(
                  hintText: 'Entrer votre email',
                ),
                validator: (value) { //le validator nous permet de rendre le champ valide si jamais il est vide ou si il ne contient pas de "@" le programme retourne false
                  if (value.isEmpty) {
                    return 'Ne pas entrer de valeur vide';
                  }
                  if (value.contains('@') == false) {
                    return 'Entrez un email valide';
                  }
                  return null;
                },
                controller: myControllerEmail, // le controller nous permet de recupérer le contenu de l'input
              ),
```
> Chaque TextFormField a son propre controller pour récupérer l'information écrite par l'utilisateur

> Exemple de bouton 
``` dart
ElevatedButton(
                        onPressed: () {
                          // Validate will return true if the form is valid, or false if
                          // the form is invalid.
                          if (_formKey.currentState.validate()) {  // si le formulaire est validé nous changeons de page avec les données d'email et de mdp
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) => Login(
                                  email: myControllerEmail.text,
                                  password: myControllerPassword.text,
                                ),
                              ),
                            );
                          }
                        },
                        child: Text('Connexion'),
                      ),
```
> Ce bouton redirige vers la page de gestion de connexion avec en paramètre l'email et le mot de passe
##### back-end
> login
``` php
if ($type == "login") {
        if (isset($_GET['email'])) {
            $email = $_GET['email'];
            if (isset($_GET['password'])) {
                $password = $_GET['password'];
                $hpass = sha1(md5($password));
                $sql = "SELECT * FROM scan_user WHERE email='$email' AND password='$hpass'";
                $result = $conn->query($sql);
                if ($result->num_rows > 0) {
                    echo "good:login";
                } else {
                    echo "bad:login";
                }
            }
        }
    }
```

>register
``` php
if ($type == "register") {
        if (isset($_GET['email'])) {
            $email = $_GET['email'];
            if (isset($_GET['password'])) {
                $password = $_GET['password'];
                $hpass = sha1(md5($password));
                $sql2 = "SELECT * FROM scan_user WHERE email='$email'";
                $result2 = $conn->query($sql2);
                if ($result2->num_rows == 0) {
                    $sql = "INSERT INTO scan_user (email,password) VALUES ('$email','$hpass')";
                    if ($conn->query($sql)) {
                        echo "good:register";
                    } else {
                        echo "bad:register";
                    }
                } else {
                    echo "bad:register:email_used";
                }
            }
        }
    }
```

#### Screens
> Page de connexion
![](https://i.imgur.com/l8NrB7W.jpg =300x)

> Si la connexion est mauvaise
![](https://i.imgur.com/wbVFZpK.jpg =300x)

> Si la connexion est bonne
![](https://i.imgur.com/PloaHUZ.jpg =300x)

> Si le mail est déjà utilisé
![](https://i.imgur.com/GYVoC7N.jpg =300x)



### Liste des codes scannés
#### Package utilisé
* [http](https://pub.dev/packages/http)
#### Explication
>Afin de visualiser la liste des promotions scanées par l'utilisateur, une requête de récupération des "ID" liés à l'adresse mail de l'utilisateur a été éffectuée  
>Grâce à l'ID de la promotion qui vient d'être récupéré nous pouvons donc en déterminer les informations telles que la description et le code promo  
#### Code
> Récupération de l'ensemble des ID
``` dart
Future<Ids> fetchIds(email, type) async {
  var queryParameters = {
    'type': type,
    'email': email,
  };
  String url = 'tartapain.bzh';
  // nous paramétrons l'url de requête avec les variables get 
  var uri = Uri.https(url, '/api/scan/get.php', queryParameters);
  final response = await http.get(uri);

  if (response.statusCode == 200) { // nous vérifions si la requête n'a pas eue de problème
  // si celle-ci n'a pas eue de problème, nous envoyons dans la fonction de décodage de json le résultat
    return Ids.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed to load the post');
  }
}

class Ids {
  final List<dynamic> ids;
  final int lenght;

  //nous créons 1'objet qui a 2 variables, les IDs et la length qui est relative au nombre d'éléments
  Ids({
    this.ids,
    this.lenght,
  });

  factory Ids.fromJson(Map<String, dynamic> json) {
    return Ids( // nous retournons les différents éléments grâce au contenu du json
      ids: json['ids'],
      lenght: json['lenght'],
    );
  }
}
```

> Reponse type JSON
``` json
{
  "title": "20%SHOES",
  "desc": "20 % de réduction sur les chaussures"
}
```

> Génération des différents éléments de la liste
``` dart
FutureBuilder(
              initialData: [],
              future: futureIds,
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return Center(child: Text("Loading...")); // Affiche un texte "loading" en attente de la récuperation de tous les éléments
                }
                if (snapshot.hasData) { // nous vérifions si la réponse n'est pas vide
                  if (snapshot.data.lenght == 0) { // si jamais nous n'avons pas d'élément alors un texte "pas de QR Code scanné" s'affiche
                    return Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Center(
                        child: Container(
                          width: 200,
                          height: 50,
                          decoration: new BoxDecoration(
                            color: Colors.blue,
                            borderRadius: new BorderRadius.all(
                              Radius.circular(20.0),
                            ),
                          ),
                          child: Center(
                            child: Text(
                              "Pas de QR Code scanné",
                              style: TextStyle(
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14),
                            ),
                          ),
                        ),
                      ),
                    );
                  } else {
                    return SingleChildScrollView(
                      child: Column(
                        children: [ // si des données sont récupérées alors un widget custom CardDisplay est généré avec pour paramètres l'ID de la promotion scannée ainsi que le mail de l'utilisateur connecté
                          for (var i = 0; i < snapshot.data.lenght; i++)
                            CardDisplay(
                              id: snapshot.data.ids[i],
                              email: widget.email,
                            ),
                        ],
                      ),
                    );
                  }
                } else if (snapshot.hasError) {
                // si il y a des erreurs, nous les affichons via cette fonction
                  return Text('${snapshot.error}');
                } else {
                  return CircularProgressIndicator(
                      valueColor:
                          new AlwaysStoppedAnimation<Color>(Colors.black));
                }
              },
            ),
```
#### Screens
![](https://i.imgur.com/0W8cEqO.jpg =300x)

### Suppression des codes utilisés
#### Package utilisé
* [http](https://pub.dev/packages/http)
* [flutter_slidable](https://pub.dev/packages/flutter_slidable)
#### Explication
>Nous avons utilisé le package "flutter_slidable" pour nous permettre de rajouter des boutons d'action par effet de glissement (ce bouton ne peut apparaître que si l'utilisateur glisse un élément de la liste vers la droite). 
>Ce bouton est généré en même temps que les blocs de codes promos pour pouvoir être lié à l'ID d'un de ces blocs.
#### Code

> ajout du bouton de suppression
``` dart
return Slidable(
                        actionPane: SlidableScrollActionPane(),
                        actions: <Widget>[
                          IconSlideAction(
                            caption: 'Remove',
                            color: Colors.red,
                            icon: Icons.remove_circle_outline,
                            onTap: () => {
                              Navigator.push(
                                context,
                                MaterialPageRoute(
                                  builder: (context) => Remove(
                                    email: widget.email, //email de l utilisateur
                                    id: widget.id, // id du qr code
                                  ),
                                ),
                              ),
                            },
                          ),
                        ],
                        actionExtentRatio: 1 / 5,
```

> le back relié à cette fonction
``` php
if ($type == 'remove') {
        if (isset($_GET['id'])) {
            $id = $_GET['id']; // id du qr code
            if (isset($_GET['email'])) {
                $email = $_GET['email']; // email de l'utilisateur
                $sql = "DELETE FROM scan_email WHERE qr_id='$id' AND email='$email'";
                if ($conn->query($sql)) {
                    echo "code promo bien supprimé de votre profil";
                }
            }
        }
    }
```

#### Screens
> Bouton de suppression
![](https://i.imgur.com/mnYIozp.jpg =300x)

> Confirmation de la suppression
![](https://i.imgur.com/JiWr2WN.jpg =300x)


### Ajout de code grâce à un QR code
#### Package utilisée
* [http](https://pub.dev/packages/http)
* [flutter_barcode_scanner](https://pub.dev/packages/flutter_barcode_scanner)

#### Explication
> Nous avons utilisé le package "flutter_barcode_scanner" pour pouvoir simplifier le scan de QR code en quelques fonctions.
> Nous récupérons ensuite la valeur du QR code scanné afin de vérifier si l'utilisateur a déjà lié ce code à son compte, si ce n'est pas le cas, nous pouvons l'enregistrer dans la BDD
> > Si cet utilisateur a déjà scanné ce QR code alors il aura un message d'erreur lui indiquant qu'il l'a déjà scanné.
#### Code
>Ajout de la fonction de scan de QR CODE
``` dart
Future<void> scanQR() async {
    String barcodeScanRes;

    try {
      barcodeScanRes = await FlutterBarcodeScanner.scanBarcode(
          "#ff6666", "Cancel", true, ScanMode.QR);
          // nous paramétrons le qr code avec le package "flutter_barcode_scanner"
      print(barcodeScanRes);
    } on PlatformException {
      barcodeScanRes = 'Failed to get platform version.';
      // affichage de l'erreur si il y en a une
    }

    if (!mounted) return;

    setState(() {
      _scanBarcode = barcodeScanRes;
      // récupération de la valeur du qr code
      Navigator.push(
          context,
          MaterialPageRoute( // envois vers la page de traitement du qr code
              builder: (context) => QrResult(
                    email: widget.email, // email de l'utilisateur
                    qrValue: _scanBarcode, // valeur du qr code
                  )));
    });
  }
```

> Page de traitement du qr code
``` php
if ($type == 'add_user_qr') {
        if (isset($_GET['qr_value'])) {
            $qr_value = $_GET['qr_value']; // valeur du qr code
            if (isset($_GET['email'])) {
                $email = $_GET['email']; // valeur email de l'utilisateur
                $sql = "SELECT * FROM scan_qr WHERE value='$qr_value'";
                // récupération de l'id du qr code dans la BDD
                $result = $conn->query($sql);
                if ($result->num_rows > 0) {
                    while ($row = $result->fetch_assoc()) {
                        $id = $row['id'];
                        $sql2 = "SELECT * FROM scan_email WHERE qr_id='$id' AND email='$email'";
                        // recherche si l'utilisateur a déjà scanné le qr code
                        $result2 = $conn->query($sql2);
                        if ($result2->num_rows == 0) {
                            $sql3 = "INSERT INTO scan_email (email,qr_id) VALUES ('$email','$id')";
                            if ($conn->query($sql3)) {
                                echo '{"title":"Promotion bien sauvegardée","color":"green"}';
                                // si cet utilisateur n'avais pas déjà scanné le qr code alors celui-ci est ajouté à la liste
                            }
                        } else {
                        // sinon il est indiqué comme étant déjà utilisé
                            echo '{"title":"vous avez déjà scanné ce qr code","color":"red"}';
                        }
                    }
                } else {
                // si le qr code n'est pas dans la BDD je renvoie donc à l'utilisateur que le QR code n'est pas valide
                    echo '{"title":"ce n\'est pas un qr code valide","color":"red"}';
                }
            }
        }
    }
```
#### Screens

> Ajout du QR code
![](https://i.imgur.com/S2E3cZ8.jpg =300x)

> QR code déjà scanné
![](https://i.imgur.com/XiOWSwc.jpg =300x)


---

### Espace admin 
> En cours de développement

#### Explication
> Un espace de gestion des différents utilisateurs ainsi que des différentes promotions en cours.
> Panels :
- Utilisateur
- Code promo

### Ajout de QR code
> En cours de développement

#### Explication
> Un élément qui permettra de mettre en ligne des nouvelles promotions 
> en rentrant 
- Le Code Promo
- La Description
> ce qui va permettre de le sauvegarder en ligne et d'envoyer à l'utilisateur l'image du QR code dans sa galerie pour pouvoir ensuite l'utiliser dans ses publicités.