Compare commits

..

119 Commits

Author SHA1 Message Date
Emre KARTAL 9a125512c2 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 0436c41d08 Merge pull request 'Api_Vertx' (#29) from Api_Vertx into master
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA 95194524fb Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA 15b48d1835 Mise à jour de 'Sources/API/Quarkus/.dockerignore'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 4cb2f67d1d Mise à jour de 'Sources/API/Quarkus/src/main/resources/application.properties'
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA 44ff096619 Mise à jour de 'Sources/API/Quarkus/.dockerignore'
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA 9bc4bf6837 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 0878b5f43f Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA f2291956a9 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
root f997d3078e Add test Controller for deployment
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA b0759815be Mise à jour de 'Sources/API/Quarkus/src/main/resources/application.properties'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 90c6c0d07d Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 12b0b5d0ea Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 9d6451b35e Mise à jour de '.drone.yml'
continuous-integration/drone/push Build encountered an error Details
2 years ago
David D'ALMEIDA 7f17250922 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL edd015c133 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 076ae48a67 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 8669409b55 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 27dae0eca8 Merge branch 'Api_Vertx' of https://codefirst.iut.uca.fr/git/BowlDev/Bowl_in into Api_Vertx
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 4e9624e8ea clean package mvn
2 years ago
David D'ALMEIDA 892e0c9529 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 7dbadc7757 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 348a7d4b51 Mise à jour de 'Sources/API/Quarkus/src/main/docker/Dockerfile.jvm'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 0a8c6c1def Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL a5cfb7cc5d Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
David D'ALMEIDA a56c5c8431 async one
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f49ef5bac5 Cleaner code ♻️
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 891c661dbb Merge pull request 'ContinueLocalManager' (#28) from ContinueLocalManager into master
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 0150ab9636 Correct code smells 🐛
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 8dc7454e26 Storage of gameDetails and players in it done
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier dc3eefcac8 fix responsive main page
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier fe6bd7f8df Unselect a num for user mistakes.
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 74dd646860 Merge remote-tracking branch 'origin/master'
2 years ago
Emre KARTAL af233c821b Storing stats done
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 4126bb5195 Readjust the size of the Images ♻️
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL a32b89243a Fixed small errors 🐛
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL e32f93348f Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL b4b031f7dd Create Mapper and Field for GameDetails
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 73204ba03a Addition of the Game table and modifications of the ReadUser and UpdateUser functions 🔨
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 205708fce7 Merge with master and UserDatabase works
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 640c1a6bb8 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 98e8a37a96 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 6e5012edd3 Transférer les fichiers vers 'Documentation/Images'
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas DELANIER 5cf7095197 Transférer les fichiers vers 'Documentation/Images'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 7d02d4747a Adding sqflite and creating the database, mappers and User Field 🔨
continuous-integration/drone/push Build is passing Details
2 years ago
Louison PARANT 52ab4cd1d8 Fix Code Smell (Emre's ones)
continuous-integration/drone/push Build is passing Details
2 years ago
Louison PARANT fec6c8b78b Removing useless attributes (StubData + IManager)
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 23b010e994 fix icon app for all version android
2 years ago
Lucas Delanier 27ea3b3e9e change app name displayed
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 093a386472 change android icon
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 43043cc807 fix code smells
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 968ff20d4f add missing app icon and change onPrimary and primary to foreground and background color attribut not depressiate
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 3c83867d48 fix code smells
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 03421f4761 goback to old onprimary and primary for color of button
continuous-integration/drone/push Build was killed Details
2 years ago
Arthur VALIN 5cf8668cc2 Merge branch 'Arthur_Tests'
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 416e94db35 Adding more tests and removing unnecessary attributes from our models
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN f013a32158 Testing rounds
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 3a5d487041 Merge branch 'code_smells' into Arthur_Tests
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 8855a61c6e code smells clean
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier 9ce2225ca6 code smells clean
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 57b1be8767 Testing a classic game
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN bc0a33d54a Testing manager
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 6d5a4a170a Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 5cdd40cf57 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 2adcebbf17 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 087442dfe7 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 470a3f156c Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN e6dd6a9006 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 8fdfc6414e Starting CI w/ Emre
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN af22750cc9 Testing game with only strikes
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 0e265bbead Readjust the LocalManager of louison and new functions in the UserManager
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 723808a563 Correcting bug when computing points
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN aef6be1c0e Merge pull request 'Arthur_UserGame' (#25) from Arthur_UserGame into master
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN b8b67380c1 Adding reordering on game creation
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 316eda5ef6 Computing ID and correcting bugs with ScoreBoard modal
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 36031ebf07 Adding deletion of players during game creation
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN c64d8926ab Adding players to game on creation
continuous-integration/drone/push Build is passing Details
2 years ago
Lucas Delanier e19e44f4e0 add effect of button add player and textfield on guest player to rename them
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN bf4da7a38a Correcting bug with NumberPad maxvalue
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 62a785f489 Computing stats after game
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 8a8e51b700 Computing stats after game
2 years ago
Arthur VALIN 87d7c7c5a7 Adding game to user when finished
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN 824e8efc9d Merge pull request 'Arthur_BowlingAlgo' (#23) from Arthur_BowlingAlgo into master
continuous-integration/drone/push Build is passing Details
2 years ago
Arthur VALIN f28812bc97 Correcting bugs when computing points
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier 47a1e3cf11 final scoreboard works well 🎉
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier ea391fc0e8 make buttons selectable following scoe of the previous throw
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 86d6f5afb5 Implementing bowling game algorithm
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL fa5caf5d21 Add project badges 📌
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 32867914e0 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 6499695a1b Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL b775938cd0 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier a2257a8711 change screen call with parameter to reconize witch screen to display
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 25d036cc63 Starting implementation of the bowling game algorithm
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 09adc10a76 Starting implementation of the bowling game algorithm
continuous-integration/drone/push Build is failing Details
2 years ago
Louison PARANT ebe1d4bf84 Mise à jour de 'README.md'
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas DELANIER f56e66708b Mise à jour de 'README.md'
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas DELANIER 2e4fd7e0ef Mise à jour de 'README.md'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 9280059ab7 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL d2d6c692e3 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL ee15c1c682 Correct error merge
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 981b3cc8eb Merge pull request 'stubdata' branche
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier 50beb48c93 make ranking working and add new stats
continuous-integration/drone/push Build is failing Details
2 years ago
root bc89c0ea90 Testing and functions of Managers for the Stub Data completed
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier b85825b81d push new binding
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 9aeca9c1de Correction model (UUID to int), more test and complete function for User and Game Manager
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 477bea5aa5 Correction model (UUID to int), more test and complete function for User and Game Manager
2 years ago
Lucas Delanier 0687867f3d push new binding
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier 9f30fce136 binding profile page and home page
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier 568f7a8b0b Merge remote-tracking branch 'origin/master'
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas Delanier 6953ae96e2 fix new model
2 years ago
Lucas Delanier aa18451fce rank working and add some stub data
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN dc3612ab0b Supprimer '.gitattributes'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN bea2d7ac7c Mise à jour de '.gitattributes'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 84a01f2793 Mise à jour de '.gitattributes'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 7099455673 Mise à jour de '.gitattributes'
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 4174496eff Ajouter '.gitattributes'
continuous-integration/drone/push Build is failing Details
2 years ago
Lucas DELANIER f420a4fd5e Merge pull request 'StubManager_Test' (#17) from StubManager_Test into master
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 9da23d8b28 Correction of errors in the model and start of the StubManager
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 9d9606b960 Add test GameDetail and ManagerStub create
continuous-integration/drone/push Build is passing Details
2 years ago

@ -23,17 +23,24 @@ steps:
- flutter test --machine --coverage
depends_on: [ app-build ]
- name: docker-build-and-push
- name: docker-build
image: maven:3-jdk-11
commands:
- cd ./Sources/API/Quarkus
- mvn clean package -DskipTests
- name: docker-push
image: plugins/docker
settings:
dockerfile: Sources/API/Quarkus/src/main/docker/Dockerfile.jvm
context: Sources/API/Quarkus/src/main/docker/
dockerfile: Sources/API/Quarkus/src/main/docker/Dockerfile
context: Sources/API/Quarkus/
registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/lucas.delanier/bowl_in
username:
from_secret: SECRET_REGISTRY_USERNAME
password:
from_secret: SECRET_REGISTRY_PASSWORD
depends_on: [ docker-build ]
#container deployment
- name: deploy-container
@ -44,8 +51,7 @@ steps:
COMMAND: create
OVERWRITE: true
ADMINS: emrekartal,louisonparant,davidd_almeida,lucasdelanier,arthurvalin
depends_on: [ docker-build-and-push ]
depends_on: [ docker-push ]
# build CONTAINER for sonar on flutter IMAGE
- name: code-analysis
@ -70,8 +76,8 @@ steps:
IMAGENAME: postgres:latest
CONTAINERNAME: postgresql
COMMAND: create
# OVERWRITE: false
PRIVATE: true
OVERWRITE: false
PRIVATE: false
CODEFIRST_CLIENTDRONE_ENV_POSTGRES_ROOT_PASSWORD:
from_secret: db_root_password
CODEFIRST_CLIENTDRONE_ENV_POSTGRES_DB:

@ -1,27 +0,0 @@
<component name="libraryTable">
<library name="Dart SDK">
<CLASSES>
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/async" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/cli" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/collection" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/convert" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/core" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/developer" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/ffi" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/html" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/indexed_db" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/io" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/isolate" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/js" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/js_util" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/math" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/mirrors" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/svg" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/typed_data" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/web_audio" />
<root url="file://$PROJECT_DIR$/../../../../src/flutter/bin/cache/dart-sdk/lib/web_gl" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 688 KiB

@ -5,20 +5,27 @@
</div>
<div align = center>
[Présentation](#présentation) | [Répartion](#répartition-du-gitlab) | [Fonctionnement](#fonctionnement-&#x1F4D1;) | [Deploiement](#deploiement-&#x1F680;) | [Techniciens](#technicien-en-charge-de-l'application) | [Remerciements](#remerciements-&#x1F44B;) | [Wiki](https://codefirst.iut.uca.fr/git/BowlDev/Bowl_in/wiki)
---
&nbsp; ![Dart](https://img.shields.io/badge/Dart-000?style=for-the-badge&logo=dart&logoColor=blue&color=white)
&nbsp; ![Quarkus](https://img.shields.io/badge/Quarkus-000?style=for-the-badge&logo=Quarkus&logoColor=white&color=blue)
&nbsp; ![Flutter](https://img.shields.io/badge/Flutter-000?style=for-the-badge&logo=flutter&logoColor=blue&color=white)
&nbsp; ![PostgreSQL](https://img.shields.io/badge/Postgresql-000?style=for-the-badge&logo=postgresql&logoColor=white&color=blue)
</br>
[![Quality Gate Status](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=alert_status&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
[![Duplicated Lines (%)](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=duplicated_lines_density&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
[![Security Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=security_rating&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
[![Vulnerabilities](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=vulnerabilities&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
[![Lines of Code](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=ncloc&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
[![Coverage](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Bowl_in&metric=coverage&token=88dd5f9f10bb02aede7a82a2bccf8c987af1ecab)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Bowl_in)
---
</div>
## Deploiement
- [x] &nbsp; ![IOS](https://img.shields.io/badge/IOS-000?style=for-the-badge&logo=apple&logoColor=black&color=white)
- [x] &nbsp; ![Android](https://img.shields.io/badge/Android-000?style=for-the-badge&logo=android&logoColor=white&color=green)
## Présentation
**Nom de l'application** : Bowl'in :bowling:
@ -26,7 +33,7 @@
**Récapitulation du Projet**: 👇
</br>
:information_source: Une application mobile permettant de saisir les scores de bowling pendant une partie avec possibilité d'obtenir des statistiques (points moyens, classement, etc.) et partage. Mais aussi de rentrer le nom des joueurs et de stocker les résultats.
@ -43,13 +50,83 @@ La racine de notre gitlab est composé de deux dossier essentielles au projet:
:warning: Code de l'application en cours!
## Fonctionnement &#x1F4D1;
- Comment récuperer le projet ?
Tout d'abord, si ce n'est pas déjà fait, clonez le dépôt de la branche **master/main**. Pour cela, copiez l'URL du dépôt Git :
<div align = center>
![Comment cloner](Documentation/Images/HowToClone.gif)
</div>
En utilisant ce lien, vous pouvez cloner le dépôt soit dans un terminal, soit via Tortoise. Si vous ne savez pas comment faire, vous devez avoir d'abord installer Git for Windows en suivant ce [lien](https://gitforwindows.org/), puis suivre le [tutoriel](https://docs.github.com/fr/repositories/creating-and-managing-repositories/cloning-a-repository))
:information_source: *Si vous n'êtes pas familier avec Git, vous pouvez également télécharger le dépôt au format zip en cliquant simplement sur le bouton situé à droite de l'URL.*
:warning: Maintenant, vient l'étape un peu plus complexe : **Android Studio** !
Avant de pouvoir exécuter l'application, vous devez installer le SDK de Flutter et l'IDE Android Studio. Tout d'abord, rendez-vous sur le site de [Flutter](https://docs.flutter.dev/get-started/install/windows) qui explique en détail comment procéder :heavy_exclamation_mark:
Pour *Android Studio*, vous n'avez qu'à installer l'application en suivant ce [lien](https://developer.android.com/studio) et en suivant les étapes !
Une fois qu'*Android Studio* est installé, il ne vous reste plus qu'à ouvrir le projet que vous avez récupéré préalablement à partir de ce dépôt :
<div align = center>
![Comment ouvrir le projet](Documentation/Images/HowToLaunch.png)
</div>
Il ne vous reste plus qu'à connecter votre téléphone **Android** (n'oubliez pas d'activer le mode développeur et le débogage USB) ou à utiliser un **émulateur** (je vous invite à regarder une vidéo qui vous explique comment faire si vous ne savez pas) qui est également une option valable, mais il prend beaucoup de place en mémoire :cd:
:information_source: *N'oubliez pas de configurer le lancement de l'application en sélectionnant le fichier [main.dart](Sources/bowlin_project/lib/main.dart)*
- Comment utiliser l'application ?
L'application à été réaliser à un très simple pour n'importe quel utilisateur et se résume en 4 grande pages :
<div align = center>
<img src="Documentation/Images/Home-Page.png" width="250" >
<img src="Documentation/Images/Ranking-Page.png" width="250" >
<img src="Documentation/Images/Analysis-Page.png" width="250" >
<img src="Documentation/Images/Profile-Page.png" width="250" >
</div>
<br>
:confounded: Pas de panique, ce n'est pas si compliqué que ça !
Pour la première page, qui est la page **Home** de l'application, nous pouvons lancer des parties ou rejoindre celles de nos amis. Ces parties sont alors répertoriées du plus récent au plus ancien.
La page **Ranking** quant à elle permet d'obtenir un classement entre amis et de savoir quelle personne a obtenu le meilleur score.
Dois-je vraiment expliquer la page d'**analyse** ? Elle permet, comme n'importe quelle page, d'afficher des statistiques sur l'ensemble de vos parties, que ce soit votre ratio de victoires, de spares, etc.
Enfin, la dernière et non des moindres, la page **profil** qui regroupe les informations de votre compte, telles que votre meilleur score, votre dernière connexion... mais aussi les *succès* (plus communément appelés "achievements") que vous avez obtenus au cours de vos parties.
``` Amusez-vous bien !```
## Deploiement &#x1F680;
- [x] &nbsp; ![IOS](https://img.shields.io/badge/IOS-000?style=for-the-badge&logo=apple&logoColor=black&color=white)
- [x] &nbsp; ![Android](https://img.shields.io/badge/Android-000?style=for-the-badge&logo=android&logoColor=white&color=green)
## Technicien en charge de l'application
- Emre KARTAL
- Lucas DELANIER
- Arthur VALIN
- David D'ALMEIDA
- Louison PARANT
- Emre KARTAL : emre.kartal@etu.uca.fr
- Lucas DELANIER : lucas.delanier@etu.uca.fr
- Arthur VALIN : arthur.valin@etu.uca.fr
- David D'ALMEIDA : david.d_almeida@etu.uca.fr
- Louison PARANT : louison.parant@etu.uca.fr
## Remerciements &#x1F44B;
:information_source: Un remerciement chaleureux est adressé à tous ceux qui ont participé à la réalisation du projet, en particulier à M. Chevaldonné et Mme Chatti pour leur aide précieuse.
<div align = center>
© PM2

@ -58,22 +58,16 @@
<scope>test</scope>
</dependency>
<!-- Hibernate Reactive dependency -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<!-- Reactive SQL client for PostgreSQL -->
<!-- Reactive SQL client for PostgreSQL -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
<!-- Dependency for Swagger -->
<dependency>
<groupId>io.quarkus</groupId>
@ -95,7 +89,10 @@
<artifactId>quarkus-keycloak-authorization</artifactId>
</dependency> -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

@ -76,8 +76,6 @@
#
###
FROM registry.access.redhat.com/ubi8/openjdk-11:1.14
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/

@ -14,8 +14,12 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.quarkus.hibernate.reactive.panache.common.ProjectedFieldName;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.smallrye.mutiny.Uni;
import io.quarkus.runtime.annotations.RegisterForReflection;
import java.time.LocalDate;
import java.util.List;
// @RegisterForReflection
// @Schema(description = "A DTO for transferring game details")
@ -51,7 +55,7 @@ public class GameDto {
public Long id;
@JsonProperty("players")
public List<ParticipeDto> players;
public Uni<List<ParticipeDto>> players;
@JsonProperty("date")
@JsonFormat(pattern = "yyyy-MM-dd")
@ -65,7 +69,7 @@ public class GameDto {
@JsonIgnore
@JsonProperty("rounds")
public List<RoundDto> rounds;
public Uni<List<RoundDto>> rounds;
public GameDto() {
// Constructeur vide pour la désérialisation
@ -73,11 +77,11 @@ public class GameDto {
// Constructeur avec tous les champs sauf l'ID (généré automatiquement)
public GameDto(Long id,
List<ParticipeDto> players,
Uni<List<ParticipeDto>> players,
LocalDate time,
Long ownerGame,
UserTinyDTO winner,
List<RoundDto> rounds) {
Uni<List<RoundDto>> rounds) {
this.players = players;
this.date = time;
this.hostID = ownerGame;

@ -1,7 +1,8 @@
package org.acme.Api.DTO;
import io.quarkus.hibernate.orm.panache.common.ProjectedFieldName;
import io.quarkus.hibernate.reactive.panache.common.ProjectedFieldName;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.acme.Hibernates.entities.UserStatsEntity;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@RegisterForReflection

@ -1,5 +1,6 @@
package org.acme.Api.DTO;
import io.quarkus.hibernate.reactive.panache.common.ProjectedFieldName;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@ -8,7 +9,6 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
public class UserTinyDTO {
public Long id;
public String name;
public UserTinyDTO(Long id, String name) {
this.id = id;
this.name = name;

@ -3,11 +3,13 @@ package org.acme.Api.Manager;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.NotFoundException;
import org.acme.Api.DTO.GameDto;
import org.acme.Api.Mappeur.GameMappeur;
import org.acme.Hibernates.entities.GameEntity;
import io.smallrye.mutiny.Uni;
public class GameManager {
@ -17,30 +19,30 @@ public class GameManager {
this.dbManager = dbManager;
}
public GameDto saveGame(GameDto game) {
GameEntity entity = GameMappeur.toEntity(game, dbManager.dbContext);
dbManager.dbContext.gameRepository.persist(entity);
return GameMappeur.toDto(entity, dbManager.dbContext);
public Uni<GameDto> saveGame(GameDto game) {
return dbManager.dbContext.gameRepository.persist(GameMappeur.toEntity(game, dbManager.dbContext))
.onItem().transform(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext));
}
public GameDto getDetailsGameById(Long gameId) {
GameEntity g = dbManager.dbContext.gameRepository.findById(gameId);
if (g == null) {
throw new NotFoundException("Game not found");
}
return GameMappeur.toDto(g, dbManager.dbContext);
public Uni<GameDto> getDetailsGameById(Long gameId) {
return dbManager.dbContext.gameRepository.findById(gameId)
.onItem().ifNull().failWith(new NotFoundException("Game not found"))
.onItem().transform(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext));
}
public List<GameDto> getAllGames() {
List<GameEntity> games = dbManager.dbContext.gameRepository.findAll().list();
return games.stream()
.map(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext))
.collect(Collectors.toList());
public Uni<List<GameDto>> getAllGames() {
return dbManager.dbContext.gameRepository.findAll().list()
.onItem().transform(games -> games.stream()
.map(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext))
.collect(Collectors.toList()))
.onFailure().invoke(throwable -> {
// Log the error or perform any other error handling here
throwable.printStackTrace();
});
}
public Long countGame() {
public Uni<Long> countGame() {
return dbManager.dbContext.gameRepository.count();
}
}

@ -5,27 +5,35 @@ import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.acme.Api.DTO.ParticipeDto;
import org.acme.Api.DTO.RoundDto;
import org.acme.Hibernates.entities.ParticipeEntity;
import org.acme.Hibernates.entities.RoundEntity;
import io.smallrye.mutiny.Uni;
public class Extensions {
public static List<RoundDto> toRoundDtoList(List<RoundEntity> entities) {
List<RoundDto> dtos = new ArrayList<>();
for (RoundEntity entity : entities) {
dtos.add(RoundMappeur.toDto(entity));
}
return dtos;
public static Uni<List<RoundDto>> toRoundDtoList(Uni<List<RoundEntity>> uni) {
return uni.map(roundEntities -> roundEntities.stream()
.map(RoundMappeur::toDto)
.collect(Collectors.toList()));
}
public static List<ParticipeDto> toParticipeDtoList(List<ParticipeEntity> entities) {
List<ParticipeDto> dtos = new ArrayList<>();
for (ParticipeEntity entity : entities) {
dtos.add(ParticipeMappeur.toDto(entity));
}
return dtos;
public static Uni<List<ParticipeDto>> toParticipeDtoList(Uni<List<ParticipeEntity>> uni) {
return uni
.onItem().transformToUni(participes -> {
List<ParticipeDto> dtos = new ArrayList<>();
for (ParticipeEntity entity : participes) {
dtos.add(ParticipeMappeur.toDto(entity));
}
return Uni.createFrom().item(dtos);
})
.onFailure().invoke(throwable -> {
// Log the error or perform any other error handling here
throwable.printStackTrace();
});
}
public static LocalDate toLocalDate(Date date) {

@ -18,11 +18,10 @@ public class GameMappeur {
public static GameDto toDto(GameEntity entity, BowlDbContext dbContext) {
GameDto dto = new GameDto();
dto.id = entity.id;
dto.players = Extensions.toParticipeDtoList(dbContext.participeRepository.findByGameId(entity.id));
dto.players = dbContext.participeRepository.findByGameIdQ(entity.id);
dto.date = Extensions.toLocalDate(entity.time);
dto.hostID = entity.ownerGame.id;
dto.winner = dbContext.userRepository.findByBowlinIdTiny(new Long(0));
dto.rounds = Extensions.toRoundDtoList(dbContext.roundRepository.findByGameId(entity.id));
return dto;
}

@ -12,9 +12,6 @@ public class UserMappeur {
}
public static UserTinyDTO toUserTinyDTO(UserEntity entity) {
if (entity == null) {
throw new IllegalArgumentException("entity must not be null");
}
return new UserTinyDTO(entity.id, entity.name);
}
}

@ -29,6 +29,7 @@ import org.acme.Hibernates.entities.GameEntity;
import org.acme.Hibernates.entities.UserEntity;
import org.jboss.logging.Logger;
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;
@ -42,39 +43,38 @@ public class GameController {
DbManager dbManager;
@GET
public List<GameDto> getUsers() {
public Uni<List<GameDto>> getUsers() {
LOGGER.info("Getting all game");
List<GameDto> allGames = dbManager.gameManager.getAllGames();
Uni<List<GameDto>> allGames = dbManager.gameManager.getAllGames();
return allGames;
}
@GET
@Path("/{id}")
public Response getGameById(@PathParam("id") Long id) {
public Uni<Response> getGameById(@PathParam("id") Long id) {
LOGGER.info("Get game with id : " + id);
GameDto entity = dbManager.gameManager.getDetailsGameById(id);
if (entity == null) {
Response.status(Status.NOT_FOUND);
}
return Response.ok(entity).status(200).build();
return dbManager.gameManager.getDetailsGameById(id)
.onItem()
.transform(
entity -> entity == null ? Response.status(Status.NOT_FOUND) : Response.ok(entity).status(200))
.onItem().transform(Response.ResponseBuilder::build);
}
@POST
@Transactional
public Response createGame(GameDto game) {
@ReactiveTransactional
public Uni<Response> createGame(GameDto game) {
if (game == null) {
throw new WebApplicationException("user was invalidly set on request.", 422);
}
GameDto entity = dbManager.gameManager.saveGame(game);
if (entity == null) {
return Response.status(Status.BAD_REQUEST).build();
}
LOGGER.info("creating game: ");
return Response.created(URI.create("/game/" + game.id)).build();
return dbManager.gameManager.saveGame(game)
.map(persistedGame -> Response
.created(URI.create("/game/" + game.id))
.entity(persistedGame)
.build())
.onFailure().recoverWithItem(Response.status(Status.BAD_REQUEST).build());
}
// @DELETE
@ -89,7 +89,7 @@ public class GameController {
@GET
@Path("/count")
public Long count() {
public Uni<Long> count() {
return dbManager.gameManager.countGame();
}
}

@ -0,0 +1,32 @@
package org.acme.Api.controllers;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
@Path("/test")
public class TestController {
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/po")
public String hello() {
return "Hello from RESTEasy Reactive";
}
}

@ -20,6 +20,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import io.quarkus.hibernate.reactive.panache.PanacheQuery;
import org.acme.Api.BowlDbContext;
import org.acme.Api.DTO.UserDTO;
import org.acme.Api.DTO.UserTinyDTO;
@ -29,6 +31,7 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.jboss.logging.Logger;
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;
@ -45,7 +48,7 @@ public class UserController {
@GET
@Operation(summary = "Get all users")
@Produces(MediaType.APPLICATION_JSON)
public List<UserDTO> getUsers() {
public Uni<List<UserDTO>> getUsers() {
LOGGER.info("Get all users");
return service.userRepository.findAll().project(UserDTO.class).list();
}
@ -55,14 +58,13 @@ public class UserController {
@APIResponse(responseCode = "200", description = "OK")
@APIResponse(responseCode = "404", description = "User not found")
@Path("/{id}")
public Response getUserById(@PathParam("id") Long id) {
public Uni<Response> getUserById(@PathParam("id") Long id) {
LOGGER.info("Get user with id : " + id);
List<UserDTO> d = service.userRepository.findByBowlinId(id);
if (d == null) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok(d).status(200).build();
return service.userRepository.findByBowlinId(id)
.onItem()
.transform(
entity -> entity == null ? Response.status(Status.NOT_FOUND) : Response.ok(entity).status(200))
.onItem().transform(Response.ResponseBuilder::build);
}
@ -70,53 +72,53 @@ public class UserController {
@Operation(summary = "Create a new User")
@APIResponse(responseCode = "201", description = "User successfully created")
@APIResponse(responseCode = "422", description = "User invalidly set on request")
@Transactional
public Response createUser(UserEntity user) {
@ReactiveTransactional
public Uni<Response> createUser(UserEntity user) {
if (user == null) {
throw new WebApplicationException("user was invalidly set on request.", 422);
}
LOGGER.info("creating user: " + user.getName());
service.userRepository.persist(user);
return Response.created(URI.create("/user/" + user.id)).build();
return service.userRepository.persist(user)
.map(persistedUser -> Response
.created(URI.create("/users/" + user.id))
.entity(persistedUser)
.build())
.onFailure().recoverWithItem(Response.status(Status.BAD_REQUEST).build());
}
// @PUT
// @Operation(summary = "Update a User")
// @APIResponse(responseCode = "200", description = "OK")
// @APIResponse(responseCode = "404", description = "User not found")
// @Path("/{id}")
// @ReactiveTransactional
// public Uni<Response> updateUser(@PathParam("id") Long id, UserEntity newUser)
// {
// LOGGER.info("Update user with id : " + id);
// return service.userRepository.findById(id)
// .onItem().ifNull().failWith(() -> new WebApplicationException("User not
// found", Status.NOT_FOUND))
// .onItem().ifNotNull().invoke(oldUser -> {
// oldUser.setName(newUser.getName());
// })
// .onItem().ifNotNull().transform(entity -> Response.ok(entity).build());
// }
@PUT
@Operation(summary = "Update a User")
@APIResponse(responseCode = "200", description = "OK")
@APIResponse(responseCode = "404", description = "User not found")
@Path("/{id}")
@ReactiveTransactional
public Uni<Response> updateUser(@PathParam("id") Long id, UserEntity newUser) {
LOGGER.info("Update user with id : " + id);
return service.userRepository.findById(id)
.onItem().ifNull().failWith(() -> new WebApplicationException("User not found", Status.NOT_FOUND))
.onItem().ifNotNull().invoke(oldUser -> {
oldUser.setName(newUser.getName());
})
.onItem().ifNotNull().transform(entity -> Response.ok(entity).build());
}
@DELETE
@Operation(summary = "Delete a User")
@APIResponse(responseCode = "200", description = "User successfully deleted")
@APIResponse(responseCode = "404", description = "User not found")
@Path("/{id}")
@Transactional
public Response delete(@PathParam("id") Long id) {
@ReactiveTransactional
public Uni<Response> delete(@PathParam("id") Long id) {
LOGGER.info("Delete user with id : " + id);
if (!service.userRepository.deleteById(id)) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().status(200).build();
return service.userRepository.deleteById(id)
.onItem().transform(entity -> !entity ? Response.status(Status.NOT_FOUND).build()
: Response.ok().status(200).build());
}
@GET
@Operation(summary = "Get the number of users")
@Path("/count")
public Long count() {
public Uni<Long> count() {
LOGGER.info("Get user count");
return service.userRepository.count();
}

@ -3,18 +3,23 @@ package org.acme.Api.service;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.NotFoundException;
import org.acme.Api.DTO.GameDto;
import org.acme.Api.Mappeur.GameMappeur;
import org.acme.Hibernates.entities.GameEntity;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class GameRepository implements PanacheRepository<GameEntity> {
public List<GameEntity> findwithName(Long id) {
public Uni<List<GameEntity>> findwithName(Long id) {
return list("id", id);
}
public List<GameEntity> findByIdGame(Long id) {
return find("id", id).list();
public Uni<List<GameDto>> findByIdGame(Long id) {
return find("id", id).project(GameDto.class).list();
}
}
// public Uni<GameDto> getDetailsGameById(Long gameId) {

@ -7,17 +7,17 @@ import javax.enterprise.context.ApplicationScoped;
import org.acme.Api.DTO.ParticipeDto;
import org.acme.Hibernates.entities.ParticipeEntity;
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.hibernate.reactive.panache.PanacheQuery;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class ParticipeRepository implements PanacheRepository<ParticipeEntity> {
public List<ParticipeEntity> findByGameId(Long gameId) {
public Uni<List<ParticipeEntity>> findByGameId(Long gameId) {
return list("game.id", gameId);
}
public List<ParticipeDto> findByGameIdQ(Long gameId) {
public Uni<List<ParticipeDto>> findByGameIdQ(Long gameId) {
PanacheQuery<ParticipeDto> query = find("game.id", gameId).project(ParticipeDto.class);
return query.list();
}

@ -7,13 +7,13 @@ import javax.enterprise.context.ApplicationScoped;
import org.acme.Hibernates.entities.GameEntity;
import org.acme.Hibernates.entities.RoundEntity;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class RoundRepository implements PanacheRepository<RoundEntity> {
public List<RoundEntity> findByGameId(Long gameId) {
public Uni<List<RoundEntity>> findByGameId(Long gameId) {
return find("game.id", gameId).list();
}

@ -4,7 +4,7 @@ import javax.enterprise.context.ApplicationScoped;
import org.acme.Hibernates.entities.ThrowEntity;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
@ApplicationScoped
public class ThrowRepository implements PanacheRepository<ThrowEntity> {

@ -8,7 +8,8 @@ import org.acme.Api.DTO.UserDTO;
import org.acme.Api.DTO.UserTinyDTO;
import org.acme.Hibernates.entities.UserEntity;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class UserRepository implements PanacheRepository<UserEntity> {
@ -16,18 +17,14 @@ public class UserRepository implements PanacheRepository<UserEntity> {
// return UserEntity.find("name", name).firstResult();
// }
public List<UserEntity> findwithName(String name) {
public Uni<List<UserEntity>> findwithName(String name) {
return list("name", name);
}
public List<UserDTO> findByBowlinId(Long id) {
public Uni<List<UserDTO>> findByBowlinId(Long id) {
return find("id", id).project(UserDTO.class).list();
}
public UserTinyDTO findByBowlinIdTiny(Long id) {
return find("id", id).project(UserTinyDTO.class).firstResult();
}
// public Uni<Long> deleteUser() {
// return delete("name", "Stef");
// }

@ -1,20 +1,19 @@
# achanger
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = postgres
quarkus.datasource.password = achanger
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/postgres
quarkus.datasource.username = Garderie
quarkus.datasource.password = mdp
quarkus.datasource.reactive.url = vertx-reactive:postgresql://bowldev-postgresql:5432/BowlInDB
#BowlDev-postgresql
quarkus.hibernate-orm.log.sql=true
quarkus.hibernate-orm.sql-load-script=import.sql
#HTTPS Configuration
# #HTTPS Configuration
quarkus.http.ssl.certificate.key-files=https/privkey.pem
quarkus.http.ssl.certificate.files=https/cert.pem
# quarkus.http.ssl.certificate.key-files=https/privkey.pem
# quarkus.http.ssl.certificate.files=https/cert.pem
# Disable the HTTP server
quarkus.http.insecure-requests=redirect
# # Disable the HTTP server
# quarkus.http.insecure-requests=redirect
# # OIDC Configuration
# quarkus.oidc.auth-server-url=http://localhost:8080/realms/BowlinAuth

@ -51,9 +51,9 @@
-- (4, 2, 3, 7);
INSERT INTO users (name, password) VALUES ('Alice', 'password123');
INSERT INTO users (Id, name, Password) VALUES
(2, 'Bob', 'password2'),
(3, 'Charlie', 'password3');
INSERT INTO users (name, Password) VALUES
('Bob', 'password2'),
('Charlie', 'password3');
INSERT INTO games (isFinished, nbPoints, time, winner, host_id) VALUES (false, 0, CURRENT_TIMESTAMP, 0, 1);
INSERT INTO participe (idGame, position, guestname, totalpoints, iduser) VALUES (1, 1, 'Alice', 0, 1);
INSERT INTO round (game_id, idGame, position, turnNumber, points) VALUES (1, 1, 1, 1, 0);

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bowlin_project">
<application
android:label="bowlin_project"
android:label="Bowl'In"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

@ -3,10 +3,4 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

@ -3,10 +3,4 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@ -1,17 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 32 KiB

@ -1,3 +1,6 @@
import 'package:bowl_in/model/AbstractRound.dart';
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/views/ingame_screen2.dart';
import 'package:flutter/cupertino.dart';
import 'package:go_router/go_router.dart';
@ -6,6 +9,7 @@ import '../views/ingame_screen.dart';
import '../views/main_screen.dart';
import '../views/rank_screen.dart';
import '../views/welcome_screen.dart';
import '../widgets/ingame_widgets.dart';
final GoRouter router = GoRouter(
routes: <RouteBase>[
@ -36,7 +40,16 @@ final GoRouter router = GoRouter(
GoRoute(
path: 'in-game',
builder: (BuildContext context, GoRouterState state) {
return const InGameScreen();
if (state.extra is AbstractRound) {
return InGameScreen2(currentRound: state.extra as AbstractRound);
}
return InGameScreen();
},
),
GoRoute(
path: 'scoreboard',
builder: (BuildContext context, GoRouterState state) {
return FinalScoreBoard(gameDetail: state.extra as GameDetail);
},
),
],

@ -0,0 +1,10 @@
class GameFields {
static final List<String> values = [
id, date, pointsCurrentUser, userId
];
static final String id = '_id';
static final String date = '_date';
static final String pointsCurrentUser = '_points_current_user';
static final String userId = '_user_id';
}

@ -0,0 +1,10 @@
class GameDetailFields {
static final List<String> values = [
id, date, nameWinner, host
];
static final String id = '_id';
static final String date = '_date';
static final String nameWinner = '_winner_id';
static final String host = '_host';
}

@ -0,0 +1,10 @@
class GameFields {
static final List<String> values = [
id, date, pointsCurrentUser, userId
];
static final String id = '_id';
static final String date = '_date';
static final String pointsCurrentUser = '_points_current_user';
static final String userId = '_user_id';
}

@ -0,0 +1,10 @@
class PlayerFields {
static final List<String> values = [
idGame, name, image
];
static final String idGame = '_idGame';
static final String name = '_name';
static final String image = '_image';
}

@ -0,0 +1,16 @@
class StatFields {
static final List<String> values = [
idUser, nbVictory, nbGames, highscore, nbStrikes, nbSpares, nbScore, avgScore, avgPinsPerRound
];
static final String nbVictory = '_nbVictory';
static final String nbGames = '_nbGames';
static final String highscore = '_highscore';
static final String nbStrikes = '_nbStrikes';
static final String nbSpares = '_nbSpares';
static final String nbScore = '_nbScore';
static final String avgScore = '_avgScore';
static final String avgPinsPerRound = '_avgPinsPerRound';
static final String idUser = '_idUser';
}

@ -0,0 +1,12 @@
class UserFields {
static final List<String> values = [
id, name, image, mail
];
static final String id = '_id';
static final String name = '_name';
static final String image = '_image';
static final String mail = '_mail';
}

@ -0,0 +1,26 @@
import 'package:bowl_in/model/GameDetail.dart';
import '../../model/Player.dart';
import '../fields/GameDetailFields.dart';
class GameDetailMapper {
static Map<String, dynamic> toJson(GameDetail gameDetail) {
return {
GameDetailFields.id: gameDetail.id,
GameDetailFields.date: gameDetail.time.toIso8601String(),
GameDetailFields.nameWinner: gameDetail.winner?.name,
GameDetailFields.host: gameDetail.host
};
}
static GameDetail toModel(
Map<String, dynamic> json, Player? winner, List<Player> players) {
String dateString = json[GameDetailFields.date];
return GameDetail(
json[GameDetailFields.id],
DateTime.parse(dateString),
winner,
json[GameDetailFields.host],
players);
}
}

@ -0,0 +1,24 @@
import 'package:bowl_in/model/Game.dart';
import '../../model/Player.dart';
import '../../model/User.dart';
import '../fields/GameFields.dart';
class GameMapper {
static Map<String, dynamic> toJson(Game game, User user) {
return {
GameFields.id: game.id,
GameFields.date: game.date.toIso8601String(),
GameFields.pointsCurrentUser: game.pointsCurrentUser,
GameFields.userId: user.id,
};
}
static Game toModel(Map<String, dynamic> json, List<Player> players) {
return Game(
json[GameFields.id],
DateTime.parse(json[GameFields.date]),
json[GameFields.pointsCurrentUser],
players
);
}
}

@ -0,0 +1,21 @@
import 'package:bowl_in/database/fields/PlayerFields.dart';
import '../../model/Game.dart';
import '../../model/Player.dart';
class PlayerMapper {
static Map<String, dynamic> toJson(Player player, Game game) {
return {
PlayerFields.idGame: game.id,
PlayerFields.name: player.name,
PlayerFields.image: player.image,
};
}
static Player toModel(Map<String, dynamic> json) {
return Player(
json[PlayerFields.name],
json[PlayerFields.image]
);
}
}

@ -0,0 +1,32 @@
import 'package:bowl_in/database/fields/StatFields.dart';
import '../../model/Stat.dart';
import '../../model/User.dart';
class StatMapper {
static Map<String, dynamic> toJson(Stat stat, User user) {
return {
StatFields.idUser: user.id,
StatFields.nbVictory: stat.nbVictory,
StatFields.nbGames: stat.nbGames,
StatFields.highscore: stat.highscore,
StatFields.nbStrikes: stat.nbStrikes,
StatFields.nbSpares: stat.nbSpares,
StatFields.nbScore: stat.nbScore,
StatFields.avgScore: stat.avgScore,
StatFields.avgPinsPerRound: stat.avgPinsPerRound
};
}
static Stat toModel(Map<String, dynamic> json) {
return Stat(
json[StatFields.nbVictory],
json[StatFields.nbGames],
json[StatFields.highscore],
json[StatFields.nbStrikes],
json[StatFields.nbSpares],
json[StatFields.nbScore],
json[StatFields.avgScore],
json[StatFields.avgPinsPerRound]
);
}
}

@ -0,0 +1,26 @@
import '../../model/Stat.dart';
import '../../model/User.dart';
import '../fields/UserFields.dart';
class UserMapper {
static Map<String, dynamic> toJson(User user) {
return {
UserFields.id: user.id,
UserFields.name: user.name,
UserFields.image: user.image,
UserFields.mail: user.mail,
};
}
static User toModel(Map<String, dynamic> json, Stat stat) {
return User.withStat(
json[UserFields.id],
json[UserFields.name],
json[UserFields.image],
json[UserFields.mail],
[],
[],
stat
);
}
}

@ -0,0 +1,336 @@
import 'package:bowl_in/database/fields/PlayerFields.dart';
import 'package:bowl_in/database/mappers/GameMapper.dart';
import 'package:bowl_in/database/mappers/PlayerMapper.dart';
import 'package:bowl_in/database/mappers/StatMapper.dart';
import 'package:bowl_in/model/Game.dart';
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/model/User.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../../model/Player.dart';
import '../../model/Stat.dart';
import '../fields/GameDetailFields.dart';
import '../fields/GameFields.dart';
import '../fields/StatFields.dart';
import '../fields/UserFields.dart';
import '../mappers/GameDetailMapper.dart';
import '../mappers/UserMapper.dart';
class BowlInDatabase {
BowlInDatabase();
static final BowlInDatabase instance = BowlInDatabase._init();
static Database? _database;
BowlInDatabase._init();
static const String tableUser = 'users';
static const String tableGame = 'games';
static const String tableGameDetail = 'gameDetails';
static const String tableStat = 'stats';
static const String tablePlayer = 'players';
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('user.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(path,
version: 6, onCreate: _createDB, onUpgrade: _upgradeDB);
}
Future _createDB(Database db, int version) async {
const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
const textType = 'TEXT NOT NULL';
const boolType = 'BOOLEAN NOT NULL';
const integerType = 'INTEGER NOT NULL';
const realType = 'REAL NOT NULL';
await db.execute('''
CREATE TABLE $tableUser (
${UserFields.id} $idType,
${UserFields.name} $boolType,
${UserFields.image} $textType,
${UserFields.mail} $textType
)
''');
await db.execute('''
CREATE TABLE $tableGame (
${GameFields.id} $idType,
${GameFields.date} $textType,
${GameFields.pointsCurrentUser} $integerType,
${GameFields.userId} $integerType,
FOREIGN KEY(${GameFields.userId}) REFERENCES $tableUser(${UserFields.id})
)
''');
await db.execute('''
CREATE TABLE $tableGameDetail (
${GameDetailFields.id} $idType,
${GameDetailFields.date} $textType,
${GameDetailFields.nameWinner} $textType,
${GameDetailFields.host} $integerType
)
''');
await db.execute('''
CREATE TABLE $tableStat (
${StatFields.idUser} $integerType,
${StatFields.nbVictory} $integerType,
${StatFields.nbGames} $integerType,
${StatFields.highscore} $integerType,
${StatFields.nbStrikes} $integerType,
${StatFields.nbSpares} $integerType,
${StatFields.nbScore} $integerType,
${StatFields.avgScore} $realType,
${StatFields.avgPinsPerRound} $realType,
FOREIGN KEY(${StatFields.idUser}) REFERENCES $tableUser(${UserFields.id})
)
''');
await db.execute('''
CREATE TABLE $tablePlayer (
id $idType,
${PlayerFields.name} $textType,
${PlayerFields.image} $textType,
${PlayerFields.idGame} $integerType,
FOREIGN KEY(${PlayerFields.idGame}) REFERENCES $tableGame(${GameFields.id})
)
''');
}
Future<void> _upgradeDB(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 6 ) {
await db.execute('DROP TABLE IF EXISTS $tableUser');
await db.execute('DROP TABLE IF EXISTS $tableGame');
await db.execute('DROP TABLE IF EXISTS $tableGameDetail');
await db.execute('DROP TABLE IF EXISTS $tableStat');
await db.execute('DROP TABLE IF EXISTS $tablePlayer');
await _createDB(db, newVersion);
}
}
// User
Future<void> createUser(User user) async {
final db = await instance.database;
await db.insert(tableUser, UserMapper.toJson(user));
await createStat(user);
}
Future<User?> readUser(int id) async {
final db = await instance.database;
final result = await db
.query(tableUser, where: '${UserFields.id} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
final stat = await readStat(id);
User user;
if (stat != null) {
user = UserMapper.toModel(result.first, stat);
} else {
user = UserMapper.toModel(result.first, Stat.empty());
}
final games = await readGame(id);
for (var game in games) {
user.games.add(game);
}
return user;
} else {
return null;
}
}
Future<void> updateUser(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.update(tableUser, UserMapper.toJson(user),
where: '${UserFields.id} = ?', whereArgs: [user.id]);
await txn.update(tableStat, StatMapper.toJson(user.stat, user),
where: '${StatFields.idUser} = ?', whereArgs: [user.id]);
// Insert new games for the user
for (var game in user.games) {
var result = await txn.query(tableGame,
where: '${GameFields.id} = ? AND ${GameFields.userId} = ?',
whereArgs: [game.id, user.id]);
if (result.isNotEmpty) {
await txn.update(tableGame, GameMapper.toJson(game, user),
where: '${GameFields.id} = ? AND ${GameFields.userId} = ?',
whereArgs: [game.id, user.id]);
} else {
await txn.insert(tableGame, GameMapper.toJson(game, user));
for (var player in game.players) {
await txn.insert(tablePlayer, PlayerMapper.toJson(player, game));
}
}
}
});
}
Future<int> deleteUser(int id) async {
final db = await instance.database;
await deleteGame(id);
await deleteStat(id);
return await db.delete(
tableUser,
where: '${UserFields.id} = ?',
whereArgs: [id],
);
}
// GameDetail
Future<void> createGameDetail(GameDetail gameDetail) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.insert(tableGameDetail, GameDetailMapper.toJson(gameDetail));
});
}
Future<List<GameDetail>> readGameDetail() async {
final db = await instance.database;
final result = await db.query(tableGameDetail);
if (result.isNotEmpty) {
List<GameDetail> gameDetails = [];
for (var gameDetail in result) {
List<Player> players = [];
Player? winner = null;
final resultPlayer = await db.query(tablePlayer,
where: '${PlayerFields.idGame} = ?',
whereArgs: [gameDetail[GameDetailFields.id]]);
for (var player in resultPlayer) {
var rPlayer = PlayerMapper.toModel(player);
players.add(rPlayer);
if (rPlayer.name == gameDetail[GameDetailFields.nameWinner]) {
winner = rPlayer;
}
}
gameDetails.add(GameDetailMapper.toModel(gameDetail, winner, players));
}
return gameDetails;
} else {
return [];
}
}
Future<int> deleteGameDetail() async {
final db = await instance.database;
return await db.delete(tableGameDetail);
}
// Game
Future<void> createGame(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
for (var game in user.games) {
await txn.insert(tableGame, GameMapper.toJson(game, user));
}
});
}
Future<List<Game>> readGame(int id) async {
final db = await instance.database;
final result = await db
.query(tableGame, where: '${GameFields.userId} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
List<Game> games = [];
for (var game in result) {
List<Player> players = [];
final resultPlayer = await db.query(tablePlayer,
where: '${PlayerFields.idGame} = ?', whereArgs: [game[GameFields.id]]);
for (var player in resultPlayer) {
players.add(PlayerMapper.toModel(player));
}
games.add(GameMapper.toModel(game, players));
players = [];
}
return games;
} else {
return [];
}
}
Future<int> deleteGame(int id) async {
final db = await instance.database;
return await db.transaction((txn) async {
await txn.delete(
tablePlayer,
where: '${PlayerFields.idGame} IN (SELECT ${GameFields.id} FROM $tableGame WHERE ${GameFields.userId} = ?)',
whereArgs: [id],
);
return await txn.delete(
tableGame,
where: '${GameFields.userId} = ?',
whereArgs: [id],
);
});
}
// Stat
Future<void> createStat(User user) async {
final db = await instance.database;
await db.insert(tableStat, StatMapper.toJson(Stat.empty(), user));
}
Future<Stat?> readStat(int id) async {
final db = await instance.database;
final result = await db
.query(tableStat, where: '${StatFields.idUser} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
Stat stat = StatMapper.toModel(result.first);
return stat;
} else {
return null;
}
}
Future<void> updateStat(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.update(tableStat, StatMapper.toJson(user.stat, user),
where: '${StatFields.idUser} = ?', whereArgs: [user.id]);
});
}
Future<int> deleteStat(int id) async {
final db = await instance.database;
return await db.delete(
tableStat,
where: '${StatFields.idUser} = ?',
whereArgs: [id],
);
}
Future close() async {
final db = await instance.database;
db.close();
}
}

@ -1,19 +1,19 @@
import 'package:bowl_in/views/game_screen.dart';
import 'package:bowl_in/views/ingame_screen.dart';
import 'package:bowl_in/views/main_screen.dart';
import 'package:bowl_in/views/rank_screen.dart';
import 'package:bowl_in/views/welcome_screen.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:bowl_in/config/app_router.dart';
import 'model/IManager.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
static IManager controller = LocalData();
const MyApp({super.key});
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
@ -25,7 +25,7 @@ class MyApp extends StatelessWidget {
);
}
// This widget is the root of your application.
// This widget is the root of your application.
}
class MyHomePage extends StatefulWidget {

@ -0,0 +1,97 @@
import 'Player.dart';
final maxScoreInFrame = 30;
abstract class AbstractRound {
int? _firstThrow;
int? _secondThrow;
int? _points;
int _number;
Player _player;
AbstractRound? _previousRound;
// Constructor
AbstractRound(this._firstThrow, this._secondThrow, this._points, this._player, this._number);
// Getters and setters
int? get firstThrow => _firstThrow;
set firstThrow(int? value) {
_firstThrow = value;
}
int? get secondThrow => _secondThrow;
set secondThrow(int? value) {
_secondThrow = value;
}
int? get points => _points;
set points(int? value) {
if((value??0)>=maxScoreInFrame){
_points=maxScoreInFrame;
}else {
_points = value;
}
}
int get number => _number;
set number(int value) {
_number = value;
}
Player get player => _player;
set player(Player value) {
_player = value;
}
AbstractRound? get previousRound => _previousRound;
set previousRound(AbstractRound? value) {
_previousRound = value;
}
bool computeNext(int val);
void computePoints();
bool shotIsStrike();
int getMaxPinsThisShot();
bool isStrike() {
return firstThrow==10;
}
bool isSpare(){
return firstThrow!=10 && (firstThrow ?? 0)+(secondThrow ?? 0)==10;
}
bool isSpareOrStrike() {
return (firstThrow ?? 0)+(secondThrow ?? 0)==10;
}
int getNbStrike();
int getNbSpares();
int getPinsKnockedDown();
void subscribe(AbstractRound nextRound){
nextRound.previousRound=this;
}
void update(int val){
print(" ROUND " + number.toString() + "UPDATE : " + val.toString());
points = (points ?? 0) + val;
previousRound?.update(val);
}
void unsubscribePreviousRound(){
print("UNSUBSCRIBE");
previousRound?.unsubscribePreviousRound();
previousRound=null;
}
}

@ -1,43 +1,17 @@
import 'package:uuid/uuid.dart';
import 'Player.dart';
class Game {
Uuid _id;
DateTime _time;
int _pointsCurrentUser;
bool _isFinished;
List<String> _playerImages = [];
final int _id;
final DateTime _date;
final int _pointsCurrentUser;
final List<Player> _players;
// Constructor
Game(this._id, this._time, this._pointsCurrentUser, this._isFinished, this._playerImages);
// Getters and setters
Uuid get id => _id;
set id(Uuid value) {
_id = value;
}
DateTime get time => _time;
set time(DateTime value) {
_time = value;
}
Game(this._id, this._date, this._pointsCurrentUser,
this._players);
int get id => _id;
DateTime get date => _date;
int get pointsCurrentUser => _pointsCurrentUser;
set pointsCurrentUser(int value) {
_pointsCurrentUser = value;
}
bool get isFinished => _isFinished;
set isFinished(bool value) {
_isFinished = value;
}
List<String> get playerImages => _playerImages;
set playerImages(List<String> value) {
_playerImages = value;
}
List<Player> get players => _players;
}

@ -1,82 +1,82 @@
import 'package:uuid/uuid.dart';
import 'package:bowl_in/model/AbstractRound.dart';
import 'package:bowl_in/model/Game.dart';
import 'package:bowl_in/model/LastRound.dart';
import 'Player.dart';
import 'Round.dart';
import 'User.dart';
class GameDetail {
Uuid _id;
DateTime _time;
Uuid _winner;
int _nbPoints;
bool _isFinished;
Round _currentRound;
Player _host;
List<Round> _rounds = [];
List<Player> _players = [];
int _id;
final DateTime _time;
Player? _winner;
final int _host;
final List<AbstractRound> _rounds = [];
final List<Player> _players;
final Map<Player, int> _points = {};
// Constructor
GameDetail(
this._id,
this._time,
this._winner,
this._nbPoints,
this._isFinished,
this._currentRound,
this._host,
this._rounds,
this._players);
GameDetail(this._id, this._time, this._winner, this._host, this._players) {
for (int i = 1; i <= 9; i++) {
players.forEach((element) {
this.rounds.add(Round(null, null, 0, element, i));
});
}
players.forEach((element) {
this.rounds.add(LastRound(null, null, 0, element, 10, null));
});
}
// Getters and setters
Uuid get id => _id;
int get id => _id;
set id(Uuid value) {
set id(int value) {
_id = value;
}
DateTime get time => _time;
set time(DateTime value) {
_time = value;
}
Uuid get winner => _winner;
Player? get winner => _winner;
set winner(Uuid value) {
set winner(Player? value) {
_winner = value;
}
int get nbPoints => _nbPoints;
int get host => _host;
set nbPoints(int value) {
_nbPoints = value;
}
bool get isFinished => _isFinished;
List<AbstractRound> get rounds => _rounds;
set isFinished(bool value) {
_isFinished = value;
}
List<Player> get players => _players;
Round get currentRound => _currentRound;
Map<Player, int> get points => _points;
set currentRound(Round value) {
_currentRound = value;
void addGameToUsers() {
for (var p in players) {
if (p is User) {
p.games.add(Game(this.id, this.time, points[p] ?? 0, players));
p.stat.updateStats(this, p);
}
}
}
Player get host => _host;
set host(Player value) {
_host = value;
void computeWinner() {
print(getRank().entries.first.key.name);
this.winner = getRank().entries.first.key;
}
List<Round> get rounds => _rounds;
set rounds(List<Round> value) {
_rounds = value;
void computeScores() {
print("====COMPUTE POINTS====");
for (var element in rounds) {
points[element.player] =
(points[element.player] ?? 0) + (element.points ?? 0);
print(element.points);
}
computeWinner();
addGameToUsers();
}
List<Player> get players => _players;
set players(List<Player> value) {
_players = value;
Map<Player, int> getRank() {
var sortedByValueMap = Map.fromEntries(points.entries.toList()
..sort((e1, e2) => e2.value.compareTo(e1.value)));
return sortedByValueMap;
}
}

@ -0,0 +1,65 @@
import 'package:bowl_in/model/AbstractRound.dart';
import 'package:bowl_in/model/IManager.dart';
import 'package:flutter/cupertino.dart';
import 'GameDetail.dart';
import 'package:go_router/go_router.dart';
import 'Round.dart';
class GamePlayer {
late GameDetail _game;
final IManager _parent;
int currentRoundIndex = 0;
GamePlayer(this._parent);
GameDetail get game => _game;
set game(GameDetail value) {
currentRoundIndex = 0;
_game = value;
}
AbstractRound? get currentRound {
if (currentRoundIndex < game.rounds.length){
return game.rounds[currentRoundIndex];
}
return null;
}
void onNext(bool isRoundFinished, BuildContext? context) {
if (isRoundFinished) {
print("++");
currentRoundIndex++;
}
if (currentRoundIndex >= game.rounds.length) {
print("FINISHED");
game.id=_parent.gameMgr.getNextId();
_parent.gameMgr.addGame(game);
game.computeScores();
_parent.userMgr.saveUser(_parent.userCurrent);
_parent.gameMgr.saveGame(_game);
context?.go("/scoreboard", extra: game);
} else {
print("IN GAME : " + currentRoundIndex.toString());
if (game.rounds[currentRoundIndex] is Round) {
print("ROUND");
} else {
print("LAST ROUND");
}
context?.pushReplacement("/in-game",
extra: game.rounds[currentRoundIndex]);
}
}
void onSpareOrStrike() {
if (currentRoundIndex < game.rounds.length - game.players.length) {
print("ON SPAREORSTRIKE");
game.rounds[currentRoundIndex]
.subscribe(game.rounds[currentRoundIndex + game.players.length]);
}
}
}

@ -1,8 +1,18 @@
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'dart:math';
import 'Player.dart';
const _images = [
"./assets/images/image_user_cyan.png",
"./assets/images/image_user_red.png",
"./assets/images/image_user_yellow.png",
"./assets/images/image_user_pink.png",
"./assets/images/image_user_orange.png",
"./assets/images/image_user_green.png",
"./assets/images/image_user_purple.png",
];
class Guest extends Player {
// Constructor
Guest(Uuid id, String image, String name) : super(id, image, name);
Guest(String name) : super(name, _images[Random().nextInt(_images.length)]);
}

@ -1,5 +1,5 @@
abstract class IAuthManager {
// Methods
bool verifiedUser(String name, String password);
bool verifiedUser(String mail, String password);
}

@ -1,12 +1,14 @@
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'GameDetail.dart';
import 'Player.dart';
abstract class IGameManager {
// Methods
GameDetail getGameById(Uuid id);
List<GameDetail> getGamesByPlayerId(Uuid id);
GameDetail getGameById(int id);
saveGame(GameDetail gameDetail);
List<GameDetail> getGamesByPlayerId(int id);
List<GameDetail> getGamesByPlayer(Player user);
List<GameDetail> getGamesByPlayers(List<Player> users);
List<Player> getPlayersByIdGame(int id);
Map<Player, int> getRankByIdGame(int id);
int getNextId();
addGame(GameDetail gd);
}

@ -1,21 +1,40 @@
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/model/GamePlayer.dart';
import 'User.dart';
import 'Game.dart';
import 'IUserManager.dart';
import 'IGameManager.dart';
import 'Game.dart';
abstract class IManager {
late User _userCurrent;
late Game _gameCurrent;
IUserManager _userMgr;
IGameManager _gameMgr;
late GameDetail _gameCurrent;
late final GamePlayer _gamePlayer = GamePlayer(this);
late final IUserManager _userMgr;
late final IGameManager _gameMgr;
// Constructor
IManager(this._userCurrent, this._gameCurrent);
// Getters and setters
// Getters and settersz
User get userCurrent => _userCurrent;
Game get gameCurrent => _gameCurrent;
set userCurrent(User user) {
_userCurrent = user;
}
GamePlayer get gamePlayer => _gamePlayer;
GameDetail get gameCurrent => _gameCurrent;
set gameCurrent(GameDetail value) {
_gameCurrent = value;
}
IUserManager get userMgr => _userMgr;
IGameManager get gameMgr => _gameMgr;
set gameMgr(IGameManager value) {
_gameMgr = value;
}
set userMgr(IUserManager value) {
_userMgr = value;
}
}

@ -1,12 +1,17 @@
import 'package:uuid/uuid.dart';
import 'Player.dart';
import 'User.dart';
import 'IAuthManager.dart';
abstract class IUserManager {
IAuthManager _authMgr;
// Constructor
IUserManager(this._authMgr);
// Methods
IAuthManager get authMgr => _authMgr;
List<User> getUsersByName(String name);
User getUserById(Uuid id);
List<Player> getUsersByName(String name);
Player getUserById(int id);
saveUser(User user);
List<User> getRankingWithFriends();
}

@ -0,0 +1,112 @@
import 'package:bowl_in/model/AbstractRound.dart';
class LastRound extends AbstractRound {
int? _thirdThrow;
LastRound(super.firstThrow, super.secondThrow, super.points, super.player,
super.number, this._thirdThrow);
int? get thirdThrow => _thirdThrow;
set thirdThrow(int? value) {
_thirdThrow = value;
}
@override
bool computeNext(int val) {
if (firstThrow == null) {
firstThrow = val;
if (previousRound?.isSpare() ?? false) {
previousRound?.update(val);
}
return false;
} else if (secondThrow == null) {
secondThrow = val;
if ((firstThrow ?? 0) + (secondThrow ?? 0) < 10) {
computePoints();
return true;
}
return false;
} else if ((firstThrow ?? 0) + (secondThrow ?? 0) >= 10) {
thirdThrow = val;
}
computePoints();
return true;
}
@override
void computePoints() {
points = (firstThrow ?? 0) + (secondThrow ?? 0) + (thirdThrow ?? 0);
print("Compute points : " + points.toString());
if (previousRound?.isStrike() ?? false) {
update(points ?? 0);
}
unsubscribePreviousRound();
}
@override
bool shotIsStrike() {
if (firstThrow == null) {
return true;
} else if (secondThrow == null) {
return firstThrow == 10;
} else {
return secondThrow == 10;
}
}
@override
int getNbSpares() {
int nb = 0;
if (firstThrow != 10) {
if ((firstThrow ?? 0) + (secondThrow ?? 0) == 10) {
nb += 1;
}
} else {
if ((thirdThrow ?? 0) + (secondThrow ?? 0) == 10) {
nb += 1;
}
}
return nb;
}
@override
int getNbStrike() {
int nb = 0;
if (firstThrow == 10) {
nb += 1;
if (secondThrow == 10) {
nb += 1;
if (thirdThrow == 10) {
nb += 1;
}
}
} else {
if (thirdThrow == 10) {
nb += 1;
}
}
return nb;
}
@override
int getPinsKnockedDown() {
return (firstThrow ?? 0) + (secondThrow ?? 0) + (thirdThrow ?? 0);
}
@override
int getMaxPinsThisShot() {
if (firstThrow == null) {
return 10;
} else if (firstThrow == 10 && secondThrow == null) {
return 10;
} else if ( secondThrow == null ){
return 10 - ( firstThrow ?? 0 );
} else if ( ( firstThrow ?? 0 ) + ( secondThrow ?? 0 ) == 10 || secondThrow == 10 ){
return 10;
} else {
return 10 - ( secondThrow ?? 0 );
}
}
}

@ -0,0 +1,16 @@
import 'package:bowl_in/model/IAuthManager.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart';
class AuthManager extends IAuthManager {
final LocalData parent;
// Constructor
AuthManager(this.parent);
@override
bool verifiedUser(String mail, String password) {
// TODO: implement verifiedUser
throw UnimplementedError();
}
}

@ -0,0 +1,88 @@
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/model/IGameManager.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:bowl_in/model/Player.dart';
import '../User.dart';
class GameManager extends IGameManager {
final LocalData parent;
// Constructor
GameManager(this.parent){
_initGame();
}
// Methods
_initGame() async {
parent.gameDetails = await parent.database.readGameDetail();
}
GameDetail getGameById(int id) {
for (var element in parent.gameDetails) {
if (element.id == id) {
return element;
}
}
throw Exception("Game not found.");
}
saveGame(GameDetail gameDetail) async {
await parent.database.createGameDetail(gameDetail);
}
@override
List<GameDetail> getGamesByPlayerId(int id) {
return parent.gameDetails.where((element) =>
element.players.any((player) => player is User && player.id == id)
).toList();
}
@override
List<GameDetail> getGamesByPlayer(Player user) {
return parent.gameDetails
.where((element) =>
element.players.any((player) => player is User && user is User && player.id == user.id))
.toList();
}
@override
List<GameDetail> getGamesByPlayers(List<Player> users) {
List<GameDetail> games = [];
for (var element in parent.gameDetails) {
if (element.players.toSet().containsAll(users.toSet())) {
games.add(element);
}
}
return games;
}
@override
List<Player> getPlayersByIdGame(int id) {
final gameDetails = parent.gameDetails.firstWhere(
(element) => element.id == id,
orElse: () => throw Exception("Game not found.")
);
return gameDetails.players;
}
@override
Map<Player, int> getRankByIdGame(int id) {
for (var game in parent.gameDetails) {
if (game.id == id) {
return game.getRank();
}
}
throw Exception("Game not found.");
}
@override
addGame(GameDetail gd) {
parent.gameDetails.add(gd);
}
@override
int getNextId() {
return parent.gameDetails.length;
}
}

@ -0,0 +1,23 @@
import 'package:bowl_in/database/sqlflite/BowlInDatabase.dart';
import 'package:bowl_in/model/IManager.dart';
import '../GameDetail.dart';
import 'GameManager.dart';
import 'UserManager.dart';
class LocalData extends IManager {
final BowlInDatabase database = BowlInDatabase();
LocalData() {
userMgr = UserManager(this);
gameMgr = GameManager(this);
}
List<GameDetail> _gameDetails = [];
List<GameDetail> get gameDetails => _gameDetails;
set gameDetails(List<GameDetail> gameDetails) {
_gameDetails = gameDetails;
}
}

@ -0,0 +1,56 @@
import 'package:bowl_in/model/IUserManager.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:bowl_in/model/Player.dart';
import 'package:bowl_in/model/User.dart';
import 'AuthManager.dart';
class UserManager extends IUserManager {
final LocalData parent;
// Constructor
UserManager(this.parent) : super(AuthManager(parent)) {
_initUser();
}
_initUser() async {
//await parent.database.deleteGameDetail();
//await parent.database.deleteUser(0);
//User crUser = User(0, "Lucas", "./assets/images/image_user_red.png", "", [], []);
//await saveUser(crUser);
var user = await parent.database.readUser(0);
if (user == null) {
User user2 =
User(0, "Unknown", "./assets/images/image_user_pink.png", "", [], []);
parent.userCurrent = user2;
} else {
parent.userCurrent = user;
}
}
@override
saveUser(User user) async {
var result = await parent.database.readUser(0);
if (result == null) {
await parent.database.createUser(user);
} else {
await parent.database.updateUser(user);
}
}
@override
List<User> getRankingWithFriends() {
List<User> sortedPlayers = List.from(parent.userCurrent.friends);
sortedPlayers.sort((a, b) => b.stat.highscore.compareTo(a.stat.highscore));
return sortedPlayers;
}
@override
Player getUserById(int id) {
throw UnimplementedError();
}
@override
List<Player> getUsersByName(String name) {
throw UnimplementedError();
}
}

@ -1,15 +1,10 @@
import 'package:uuid/uuid.dart';
class Player {
final Uuid _id;
String _name;
String _image;
// Constructor
Player(this._id, this._name, this._image);
Player(this._name, this._image);
// Getters and setters
Uuid get id => _id;
String get name => _name;
@ -22,4 +17,7 @@ class Player {
set image(String value) {
_image = value;
}
}

@ -1,36 +1,69 @@
import 'Player.dart';
import 'package:bowl_in/model/AbstractRound.dart';
class Round {
int _firstThrow;
int _secondThrow;
int _points;
Player _player;
class Round extends AbstractRound {
Round(super.firstThrow, super.secondThrow, super.points, super.player,
super.number);
// Constructor
Round(this._firstThrow, this._secondThrow, this._points, this._player);
// Getters and setters
int get firstThrow => _firstThrow;
set firstThrow(int value) {
_firstThrow = value;
@override
bool computeNext(int val) {
if (firstThrow == null) {
firstThrow = val;
if (previousRound?.isSpare() ?? false) {
previousRound?.update(val);
unsubscribePreviousRound();
}
if (val == 10) {
computePoints();
return true;
}
return false;
} else if (firstThrow != 10 && secondThrow == null) {
secondThrow = val;
}
computePoints();
return true;
}
int get secondThrow => _secondThrow;
@override
void computePoints() {
points = (firstThrow ?? 0) + (secondThrow ?? 0);
if (previousRound?.isStrike() ?? false) {
previousRound?.update(points ?? 0);
}
}
set secondThrow(int value) {
_secondThrow = value;
@override
bool shotIsStrike() {
return firstThrow == null;
}
int get points => _points;
@override
int getNbSpares() {
if (isSpare()) {
return 1;
}
return 0;
}
set points(int value) {
_points = value;
@override
int getNbStrike() {
if (isStrike()) {
return 1;
}
return 0;
}
Player get player => _player;
@override
int getPinsKnockedDown() {
return (firstThrow ?? 0) + (secondThrow ?? 0);
}
set player(Player value) {
_player = value;
@override
int getMaxPinsThisShot() {
if (firstThrow == null) {
return 10;
} else {
return 10 - (firstThrow ?? 0);
}
}
}

@ -1,18 +1,19 @@
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/model/Player.dart';
class Stat {
int _nbVictory;
int _nbDefeat;
int _nbGames;
int _highscore;
int _nbStrikes;
int _nbSpares;
int _nbScore;
int _avgScore;
double _avgPinsPerRound;
int _nbVictory = 0;
int _nbGames = 0;
int _highscore = 0;
int _nbStrikes = 0;
int _nbSpares = 0;
int _nbScore = 0;
double _avgScore = 0;
double _avgPinsPerRound = 0;
// Constructor
Stat(
this._nbVictory,
this._nbDefeat,
this._nbGames,
this._highscore,
this._nbStrikes,
@ -22,6 +23,9 @@ class Stat {
this._avgPinsPerRound,
);
Stat.empty();
// Getters and setters
int get nbVictory => _nbVictory;
@ -29,12 +33,6 @@ class Stat {
_nbVictory = value;
}
int get nbDefeat => _nbDefeat;
set nbDefeat(int value) {
_nbDefeat = value;
}
int get nbGames => _nbGames;
set nbGames(int value) {
@ -65,9 +63,9 @@ class Stat {
_nbScore = value;
}
int get avgScore => _avgScore;
double get avgScore => _avgScore;
set avgScore(int value) {
set avgScore(double value) {
_avgScore = value;
}
@ -76,4 +74,27 @@ class Stat {
set avgPinsPerRound(double value) {
_avgPinsPerRound = value;
}
void updateStats(GameDetail gd, Player p) {
nbGames += 1;
if (gd.winner == p) {
nbVictory += 1;
}
if ((gd.points[p] ?? 0) > highscore) {
highscore = gd.points[p] ?? 0;
}
double totalpins = 0;
for (var r in gd.rounds) {
if (p == r.player) {
nbStrikes += r.getNbStrike();
nbSpares += r.getNbSpares();
totalpins = totalpins + r.getPinsKnockedDown();
}
}
avgPinsPerRound =
((avgPinsPerRound * (nbGames - 1)) + (totalpins / 10)) / nbGames;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save