Compare commits

..

22 Commits

Author SHA1 Message Date
David D'ALMEIDA 1ea49a0781 Merge branch 'Api_Game_Endpoints' of https://codefirst.iut.uca.fr/git/BowlDev/Bowl_in into Api_Game_Endpoints
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA a67b5b2ba6 lets finish this API Step1:
2 years ago
David D'ALMEIDA a168b375c1 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 83d01a27b9 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA f47e34d4e1 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA b70d0c81e9 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 2ce1ad47a1 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build was killed Details
2 years ago
David D'ALMEIDA b9085b3e40 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build was killed Details
2 years ago
David D'ALMEIDA 6645d97ad7 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA f003c8770c Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 1573c81cd4 push for docker
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 563dfe98d5 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA e1c6895a69 orm fixe
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 0c2b386056 fix merge error
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA dfb8bc70bc Merge branch 'Api_next-step2' of https://codefirst.iut.uca.fr/git/BowlDev/Bowl_in into Api_next-step2
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 7ffadcb29c push just for merge puspose
2 years ago
Arthur VALIN bcd6335175 Merge remote-tracking branch 'origin/Api_next-step2' into Api_next-step2
continuous-integration/drone/push Build is failing Details
2 years ago
Arthur VALIN 65804fb524 Adding UserStatsEntity and OneToOne Lazy relationship
2 years ago
David D'ALMEIDA 59efe2c595 Merge branch 'Api_next-step2' of https://codefirst.iut.uca.fr/git/BowlDev/Bowl_in into Api_next-step2
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA bc08312ea3 push
2 years ago
Arthur VALIN 887f507cba Adding https configuration
continuous-integration/drone/push Build is failing Details
2 years ago
David D'ALMEIDA 88c52db3e2 keyclock
continuous-integration/drone/push Build is failing Details
2 years ago

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

@ -0,0 +1,27 @@
<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.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 688 KiB

@ -5,27 +5,20 @@
</div> </div>
<div align = center> <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; ![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; ![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; ![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) &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> </div>
## Présentation ## 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)
**Nom de l'application** : Bowl'in :bowling: **Nom de l'application** : Bowl'in :bowling:
@ -33,7 +26,7 @@
**Récapitulation du Projet**: 👇 **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. :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.
@ -50,83 +43,13 @@ La racine de notre gitlab est composé de deux dossier essentielles au projet:
:warning: Code de l'application en cours! :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 ## Technicien en charge de l'application
- Emre KARTAL : emre.kartal@etu.uca.fr - Emre KARTAL
- Lucas DELANIER : lucas.delanier@etu.uca.fr - Lucas DELANIER
- Arthur VALIN : arthur.valin@etu.uca.fr - Arthur VALIN
- David D'ALMEIDA : david.d_almeida@etu.uca.fr - David D'ALMEIDA
- Louison PARANT : louison.parant@etu.uca.fr - Louison PARANT
## 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> <div align = center>
© PM2 © PM2

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

@ -76,6 +76,8 @@
# #
### ###
FROM registry.access.redhat.com/ubi8/openjdk-11:1.14 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 # 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/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/ COPY --chown=185 target/quarkus-app/*.jar /deployments/

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

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

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

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

@ -5,35 +5,27 @@ import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.acme.Api.DTO.ParticipeDto; import org.acme.Api.DTO.ParticipeDto;
import org.acme.Api.DTO.RoundDto; import org.acme.Api.DTO.RoundDto;
import org.acme.Hibernates.entities.ParticipeEntity; import org.acme.Hibernates.entities.ParticipeEntity;
import org.acme.Hibernates.entities.RoundEntity; import org.acme.Hibernates.entities.RoundEntity;
import io.smallrye.mutiny.Uni;
public class Extensions { public class Extensions {
public static Uni<List<RoundDto>> toRoundDtoList(Uni<List<RoundEntity>> uni) { public static List<RoundDto> toRoundDtoList(List<RoundEntity> entities) {
return uni.map(roundEntities -> roundEntities.stream() List<RoundDto> dtos = new ArrayList<>();
.map(RoundMappeur::toDto) for (RoundEntity entity : entities) {
.collect(Collectors.toList())); dtos.add(RoundMappeur.toDto(entity));
}
return dtos;
} }
public static Uni<List<ParticipeDto>> toParticipeDtoList(Uni<List<ParticipeEntity>> uni) { public static List<ParticipeDto> toParticipeDtoList(List<ParticipeEntity> entities) {
return uni List<ParticipeDto> dtos = new ArrayList<>();
.onItem().transformToUni(participes -> { for (ParticipeEntity entity : entities) {
List<ParticipeDto> dtos = new ArrayList<>(); dtos.add(ParticipeMappeur.toDto(entity));
for (ParticipeEntity entity : participes) { }
dtos.add(ParticipeMappeur.toDto(entity)); return dtos;
}
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) { public static LocalDate toLocalDate(Date date) {

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

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

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

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

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

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

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

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

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

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

@ -51,9 +51,9 @@
-- (4, 2, 3, 7); -- (4, 2, 3, 7);
INSERT INTO users (name, password) VALUES ('Alice', 'password123'); INSERT INTO users (name, password) VALUES ('Alice', 'password123');
INSERT INTO users (name, Password) VALUES INSERT INTO users (Id, name, Password) VALUES
('Bob', 'password2'), (2, 'Bob', 'password2'),
('Charlie', 'password3'); (3, 'Charlie', 'password3');
INSERT INTO games (isFinished, nbPoints, time, winner, host_id) VALUES (false, 0, CURRENT_TIMESTAMP, 0, 1); 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 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); 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" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bowlin_project"> package="com.example.bowlin_project">
<application <application
android:label="Bowl'In" android:label="bowlin_project"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

@ -3,4 +3,10 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" /> <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> </layer-list>

@ -3,4 +3,10 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" /> <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> </layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

@ -1,10 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <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"> <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> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </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"> <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item> <item name="android:windowBackground">?android:colorBackground</item>
</style> </style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

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

@ -1,10 +0,0 @@
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';
}

@ -1,10 +0,0 @@
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';
}

@ -1,10 +0,0 @@
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';
}

@ -1,10 +0,0 @@
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';
}

@ -1,16 +0,0 @@
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';
}

@ -1,12 +0,0 @@
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';
}

@ -1,26 +0,0 @@
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);
}
}

@ -1,24 +0,0 @@
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
);
}
}

@ -1,21 +0,0 @@
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]
);
}
}

@ -1,32 +0,0 @@
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]
);
}
}

@ -1,26 +0,0 @@
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
);
}
}

@ -1,336 +0,0 @@
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/model/LocalManager/LocalData.dart'; 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:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:bowl_in/config/app_router.dart'; import 'package:bowl_in/config/app_router.dart';
import 'model/IManager.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
static IManager controller = LocalData();
const MyApp({super.key}); const MyApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); 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 { class MyHomePage extends StatefulWidget {

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

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

@ -1,65 +0,0 @@
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,18 +1,8 @@
import 'dart:math'; import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'Player.dart'; 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 { class Guest extends Player {
// Constructor // Constructor
Guest(String name) : super(name, _images[Random().nextInt(_images.length)]); Guest(Uuid id, String image, String name) : super(id, image, name);
} }

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

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

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

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

@ -1,112 +0,0 @@
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 );
}
}
}

@ -1,16 +0,0 @@
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();
}
}

@ -1,88 +0,0 @@
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;
}
}

@ -1,23 +0,0 @@
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;
}
}

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

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

@ -1,19 +1,18 @@
import 'package:bowl_in/model/GameDetail.dart';
import 'package:bowl_in/model/Player.dart';
class Stat { class Stat {
int _nbVictory = 0; int _nbVictory;
int _nbGames = 0; int _nbDefeat;
int _highscore = 0; int _nbGames;
int _nbStrikes = 0; int _highscore;
int _nbSpares = 0; int _nbStrikes;
int _nbScore = 0; int _nbSpares;
double _avgScore = 0; int _nbScore;
double _avgPinsPerRound = 0; int _avgScore;
double _avgPinsPerRound;
// Constructor // Constructor
Stat( Stat(
this._nbVictory, this._nbVictory,
this._nbDefeat,
this._nbGames, this._nbGames,
this._highscore, this._highscore,
this._nbStrikes, this._nbStrikes,
@ -23,9 +22,6 @@ class Stat {
this._avgPinsPerRound, this._avgPinsPerRound,
); );
Stat.empty();
// Getters and setters // Getters and setters
int get nbVictory => _nbVictory; int get nbVictory => _nbVictory;
@ -33,6 +29,12 @@ class Stat {
_nbVictory = value; _nbVictory = value;
} }
int get nbDefeat => _nbDefeat;
set nbDefeat(int value) {
_nbDefeat = value;
}
int get nbGames => _nbGames; int get nbGames => _nbGames;
set nbGames(int value) { set nbGames(int value) {
@ -63,9 +65,9 @@ class Stat {
_nbScore = value; _nbScore = value;
} }
double get avgScore => _avgScore; int get avgScore => _avgScore;
set avgScore(double value) { set avgScore(int value) {
_avgScore = value; _avgScore = value;
} }
@ -74,27 +76,4 @@ class Stat {
set avgPinsPerRound(double value) { set avgPinsPerRound(double value) {
_avgPinsPerRound = 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