# GoStyle
[TOC]
---
## Membres du projet
- Paul Barbaux
- Ryan Jdaini - Le Hô
- Enzo Compérat
---
## Technologies utilisées
### PHP

> 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

> 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

> 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

>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

> Si la connexion est mauvaise

> Si la connexion est bonne

> Si le mail est déjà utilisé

### 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

### 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

> Confirmation de la suppression

### 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

> QR code déjà scanné

---
### 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.