From 76bb3ded81347ee52dde13ede120d63a6794c480 Mon Sep 17 00:00:00 2001 From: Anton Micke Date: Thu, 13 Feb 2025 14:51:07 +0100 Subject: [PATCH] Tuning --- .../org/kickerelo/kickerelo/MainView.java | 79 ------------------- .../kickerelo/layout/KickerAppLayout.java | 8 +- .../repository/Ergebnis1vs1Repository.java | 3 - .../repository/Ergebnis2vs2Repository.java | 2 - .../repository/SpielerRepository.java | 1 - .../service/EloCalculationService.java | 19 ++++- .../kickerelo/service/KickerEloService.java | 42 +++++++++- .../kickerelo/kickerelo/views/AdminView.java | 6 +- .../kickerelo/kickerelo/views/Chart1vs1.java | 20 ++++- .../kickerelo/kickerelo/views/Chart2vs2.java | 19 ++++- .../kickerelo/views/PlayerListView.java | 3 +- src/main/resources/application.properties | 7 +- 12 files changed, 100 insertions(+), 109 deletions(-) delete mode 100644 src/main/java/org/kickerelo/kickerelo/MainView.java diff --git a/src/main/java/org/kickerelo/kickerelo/MainView.java b/src/main/java/org/kickerelo/kickerelo/MainView.java deleted file mode 100644 index 0e030f1..0000000 --- a/src/main/java/org/kickerelo/kickerelo/MainView.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.kickerelo.kickerelo; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.combobox.ComboBox; -import com.vaadin.flow.component.notification.Notification; -import com.vaadin.flow.component.notification.NotificationVariant; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.IntegerField; -import com.vaadin.flow.component.textfield.TextField; -import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.exception.NoSuchPlayerException; -import org.kickerelo.kickerelo.service.KickerEloService; - -/** - * A sample Vaadin view class. - *

- * To implement a Vaadin view just extend any Vaadin component and use @Route - * annotation to announce it in a URL as a Spring managed bean. - *

- * A new instance of this class is created for every new user and every browser - * tab/window. - *

- * The main view contains a text field for getting the user name and a button - * that shows a greeting message in a notification. - */ -@Route -public class MainView extends VerticalLayout { - - /** - * Construct a new Vaadin view. - */ - - public MainView(KickerEloService eloService) { - - - TextField spielername = new TextField("Spielername"); - spielername.addClassName("bordered"); - - // Button click listeners can be defined as lambda expressions - Button button = new Button("Spieler hinzufügen", e -> { - eloService.addSpieler(spielername.getValue()); - Notification.show("Spieler gespeichert").addThemeVariants(NotificationVariant.LUMO_SUCCESS); - }); - - button.addThemeVariants(ButtonVariant.LUMO_PRIMARY); - - ComboBox winnerSelect = new ComboBox<>("Gewinner"); - winnerSelect.setItems(eloService.getSpielerNamen()); - winnerSelect.setPlaceholder("Spieler auswählen"); - - ComboBox loserSelect = new ComboBox<>("Verlierer"); - loserSelect.setItems(eloService.getSpielerNamen()); - loserSelect.setPlaceholder("Spieler auswählen"); - - IntegerField loserGoals = new IntegerField("Tore des Verlierers"); - loserGoals.setMin(0); - loserGoals.setMax(9); - loserGoals.setValue(0); - loserGoals.setStepButtonsVisible(true); - - Button saveButton = new Button("Speichern", e -> { - try { - eloService.enterResult1vs1(winnerSelect.getValue(), loserSelect.getValue(), loserGoals.getValue().shortValue()); - Notification.show("Gespeichert").addThemeVariants(NotificationVariant.LUMO_SUCCESS); - } catch (NoSuchPlayerException err) { - Notification.show("Konnte nicht gespeichert werden").addThemeVariants(NotificationVariant.LUMO_ERROR); - } - }); - - - - // Use custom CSS classes to apply styling. This is defined in - // styles.css. - addClassName("centered-content"); - - add(spielername, button, winnerSelect, loserSelect, loserGoals, saveButton); - } -} \ No newline at end of file diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index 675edad..8751077 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -4,14 +4,10 @@ import com.vaadin.flow.component.applayout.AppLayout; import com.vaadin.flow.component.applayout.DrawerToggle; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.html.H1; -import com.vaadin.flow.component.orderedlayout.Scroller; -import com.vaadin.flow.component.sidenav.SideNav; import com.vaadin.flow.component.tabs.Tab; import com.vaadin.flow.component.tabs.Tabs; import com.vaadin.flow.router.Layout; -import com.vaadin.flow.router.Route; import com.vaadin.flow.router.RouterLink; -import com.vaadin.flow.theme.lumo.LumoUtility; import org.kickerelo.kickerelo.views.*; @Layout @@ -33,9 +29,7 @@ public class KickerAppLayout extends AppLayout { RouterLink graph2vs2 = new RouterLink("Graph 2 vs 2", Graph2vs2View.class); RouterLink admin = new RouterLink("Verwaltung", AdminView.class); - - - Tabs tabs = new Tabs(new Tab(enter1vs1), new Tab(enter2vs2), new Tab(playerList), new Tab(graph1vs1), new Tab(graph2vs2), new Tab(admin)); + Tabs tabs = new Tabs(new Tab(playerList), new Tab(enter1vs1), new Tab(enter2vs2), new Tab(graph1vs1), new Tab(graph2vs2), new Tab(admin)); tabs.setOrientation(Tabs.Orientation.VERTICAL); addToDrawer(tabs); } diff --git a/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis1vs1Repository.java b/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis1vs1Repository.java index ecbaea3..6332e2d 100644 --- a/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis1vs1Repository.java +++ b/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis1vs1Repository.java @@ -1,8 +1,5 @@ package org.kickerelo.kickerelo.repository; -import java.util.List; -import java.util.stream.Stream; - import org.kickerelo.kickerelo.data.Ergebnis1vs1; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis2vs2Repository.java b/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis2vs2Repository.java index 9f2e0f7..3e9c3f9 100644 --- a/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis2vs2Repository.java +++ b/src/main/java/org/kickerelo/kickerelo/repository/Ergebnis2vs2Repository.java @@ -4,8 +4,6 @@ import org.kickerelo.kickerelo.data.Ergebnis2vs2; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.stream.Stream; - @Repository public interface Ergebnis2vs2Repository extends JpaRepository { } diff --git a/src/main/java/org/kickerelo/kickerelo/repository/SpielerRepository.java b/src/main/java/org/kickerelo/kickerelo/repository/SpielerRepository.java index 44e340a..833de58 100644 --- a/src/main/java/org/kickerelo/kickerelo/repository/SpielerRepository.java +++ b/src/main/java/org/kickerelo/kickerelo/repository/SpielerRepository.java @@ -4,7 +4,6 @@ import org.kickerelo.kickerelo.data.Spieler; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.Optional; @Repository diff --git a/src/main/java/org/kickerelo/kickerelo/service/EloCalculationService.java b/src/main/java/org/kickerelo/kickerelo/service/EloCalculationService.java index 3a5c1ed..4e201a7 100644 --- a/src/main/java/org/kickerelo/kickerelo/service/EloCalculationService.java +++ b/src/main/java/org/kickerelo/kickerelo/service/EloCalculationService.java @@ -4,17 +4,34 @@ import org.kickerelo.kickerelo.data.Spieler; import org.springframework.stereotype.Service; - +/** + * This contains the math for calculating ELO only. + */ @Service public class EloCalculationService { + // Default ELOs for a player with 0 games final float initialElo1vs1 = 1500; final float initialElo2vs2 = 1500; + /** + * Updates the 1 vs 1 ELOs of the players according to the result of the game. + * @param gewinner The entity representing the winning player + * @param verlierer The entity representing the losing player + * @param toreVerlierer The number of goals of the losing player + */ public void updateElo1vs1(Spieler gewinner, Spieler verlierer, short toreVerlierer) { gewinner.setElo1vs1(gewinner.getElo1vs1() + 10 - toreVerlierer); verlierer.setElo1vs1(verlierer.getElo1vs1() - 10 + toreVerlierer); } + /** + * Updates the 2 vs 2 ELOs of the players according to the result of the game + * @param gewinnerVorn The winning offensive player + * @param gewinnerHinten The winning defensive player + * @param verliererVorn The losing offensive player + * @param verliererHinten The losing defensive player + * @param toreVerlierer The number of goals of the losing teams + */ public void updateElo2vs2(Spieler gewinnerVorn, Spieler gewinnerHinten, Spieler verliererVorn, Spieler verliererHinten, short toreVerlierer) { gewinnerVorn.setElo2vs2(gewinnerVorn.getElo2vs2() + 10 - toreVerlierer); gewinnerHinten.setElo2vs2(gewinnerHinten.getElo2vs2() + 10 - toreVerlierer); diff --git a/src/main/java/org/kickerelo/kickerelo/service/KickerEloService.java b/src/main/java/org/kickerelo/kickerelo/service/KickerEloService.java index 9cdc2da..b6308e7 100644 --- a/src/main/java/org/kickerelo/kickerelo/service/KickerEloService.java +++ b/src/main/java/org/kickerelo/kickerelo/service/KickerEloService.java @@ -20,6 +20,9 @@ import java.util.HashMap; import java.util.List; import java.util.stream.Stream; +/** + * Provides all functions for the application + */ @Service public class KickerEloService { @Autowired @@ -31,16 +34,29 @@ public class KickerEloService { @Autowired private EloCalculationService eloCalculationService; + /** + * @return List of all player names sorted alphabetically + */ public List getSpielerNamen() { return spielerRepository.findAll().stream().map(Spieler::getName).sorted().toList(); } + /** + * @return List of all player entities sorted by 1 vs 1 ELO + */ public List getSpielerEntities() { return spielerRepository.findAll().stream().sorted(new Spieler1vs1EloComparator()).toList(); } + /** + * Enter a result of a 1 vs 1 game + * @param gewinnerName The name of the winning player + * @param verliererName The name of the losing player + * @param toreVerlierer The number of goals of the loser + */ public void enterResult1vs1(String gewinnerName, String verliererName, short toreVerlierer) { + // Check if the inputs are valid if (gewinnerName == null || verliererName == null) { throw new PlayerNameNotSetException("Alle Namen müssen gesetzt sein"); } @@ -60,7 +76,6 @@ public class KickerEloService { Ergebnis1vs1 ergebnis = new Ergebnis1vs1(gewinner, verlierer, toreVerlierer); - ergebnis1vs1Repository.save(ergebnis); eloCalculationService.updateElo1vs1(gewinner, verlierer, toreVerlierer); @@ -69,10 +84,18 @@ public class KickerEloService { } + /** + * Enter the result of a 2 vs 2 game + * @param gewinnerNameVorn Name of the winning offensive player + * @param gewinnerNameHinten Name of the winning defensive player + * @param verliererNameVorn Name of the losing offensive player + * @param verliererNameHinten Name of the losing defensive player + * @param toreVerlierer Number of goals of the losing team + */ public void enterResult2vs2(String gewinnerNameVorn, String gewinnerNameHinten, String verliererNameVorn, String verliererNameHinten, short toreVerlierer) { - + // Check if the inputs are valid if (gewinnerNameVorn == null || gewinnerNameHinten == null || verliererNameVorn == null || verliererNameHinten == null) { throw new PlayerNameNotSetException("Alle Namen müssen gesetzt sein"); @@ -104,7 +127,6 @@ public class KickerEloService { .orElseThrow(() -> new NoSuchPlayerException(verliererNameHinten)); Ergebnis2vs2 ergebnis = new Ergebnis2vs2(gewinnerVorn, gewinnerHinten, verliererVorn, verliererHinten, toreVerlierer); - ergebnis2vs2Repository.save(ergebnis); eloCalculationService.updateElo2vs2(gewinnerVorn, gewinnerHinten, verliererVorn, verliererHinten, toreVerlierer); @@ -114,13 +136,21 @@ public class KickerEloService { spielerRepository.save(verliererHinten); } + /** + * Add a new player to the system + * @param name Name of the new player + */ public void addSpieler(String name) { + // Check if the player name is valid if (name == null || name.isBlank()) { throw new PlayerNameNotSetException("Leerer Name"); } if (getSpielerNamen().contains(name)) { throw new DuplicatePlayerException("players must not be identical"); } + if (name.length() > 30) { + throw new InvalidDataException("Zu lang"); + } Spieler spieler = new Spieler(); spieler.setName(name); spieler.setElo1vs1(eloCalculationService.getInitialElo1vs1()); @@ -128,6 +158,9 @@ public class KickerEloService { spielerRepository.save(spieler); } + /** + * Recalculate and overwrite all 1 vs 1 ELOs. + */ public void recalculateAll1vs1() { HashMap players = new HashMap<>(); for (Spieler spieler : spielerRepository.findAll()) { @@ -143,6 +176,9 @@ public class KickerEloService { spielerRepository.saveAll(players.values()); } + /** + * Recalculate and overwrite all 2 vs 2 ELOs. + */ public void recalculateAll2vs2() { HashMap players = new HashMap<>(); for (Spieler spieler : spielerRepository.findAll()) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 421beb2..5098cbb 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -8,6 +8,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.Route; import org.kickerelo.kickerelo.exception.DuplicatePlayerException; +import org.kickerelo.kickerelo.exception.InvalidDataException; import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; import org.kickerelo.kickerelo.service.KickerEloService; @@ -26,10 +27,11 @@ public class AdminView extends VerticalLayout { } catch (PlayerNameNotSetException err) { Notification.show("Spielername darf nicht leer sein").addThemeVariants(NotificationVariant.LUMO_ERROR); return; - } - catch (DuplicatePlayerException err) { + } catch (DuplicatePlayerException err) { Notification.show("Spieler existiert bereits").addThemeVariants(NotificationVariant.LUMO_ERROR); return; + } catch (InvalidDataException err) { + Notification.show("Name zu lang").addThemeVariants(NotificationVariant.LUMO_ERROR); } Notification.show("Spieler gespeichert").addThemeVariants(NotificationVariant.LUMO_SUCCESS); }); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java index d2b772b..48e7df3 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java @@ -1,16 +1,23 @@ package org.kickerelo.kickerelo.views; import com.github.appreciated.apexcharts.ApexChartsBuilder; +import com.github.appreciated.apexcharts.config.Theme; import com.github.appreciated.apexcharts.config.builder.ChartBuilder; import com.github.appreciated.apexcharts.config.builder.XAxisBuilder; import com.github.appreciated.apexcharts.config.builder.YAxisBuilder; import com.github.appreciated.apexcharts.config.chart.Type; import com.github.appreciated.apexcharts.config.chart.builder.ZoomBuilder; import com.github.appreciated.apexcharts.config.chart.zoom.ZoomType; +import com.github.appreciated.apexcharts.config.theme.Mode; +import com.github.appreciated.apexcharts.config.theme.Monochrome; import com.github.appreciated.apexcharts.config.xaxis.Labels; import com.github.appreciated.apexcharts.config.xaxis.labels.Style; import com.github.appreciated.apexcharts.config.yaxis.Title; import com.github.appreciated.apexcharts.helper.Series; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.theme.lumo.Lumo; import org.kickerelo.kickerelo.data.Spieler; import org.kickerelo.kickerelo.util.Spieler1vs1EloComparator; @@ -19,13 +26,17 @@ import java.util.List; public class Chart1vs1 extends ApexChartsBuilder { public Chart1vs1(List l) { - Style style = new Style(); - style.setColors(List.of("#80C3FC")); + Theme theme = new Theme(); + Monochrome monochrome = new Monochrome(); + monochrome.setEnabled(true); + theme.setMode(Mode.DARK); + theme.setMonochrome(monochrome); Labels labels = new Labels(); labels.setRotate(270d); labels.setShow(true); labels.setRotateAlways(false); - labels.setStyle(style); + + withChart(ChartBuilder.get().withType(Type.SCATTER) .withZoom(ZoomBuilder.get().withEnabled(true).withType(ZoomType.XY).build()).build()) .withSeries(new Series<>("ELO", @@ -33,6 +44,7 @@ public class Chart1vs1 extends ApexChartsBuilder { )) .withXaxis(XAxisBuilder.get().withCategories(l.stream().sorted(new Spieler1vs1EloComparator()) .map(Spieler::getName).toList()).withLabels(labels).build()) - .withYaxis(YAxisBuilder.get().build()); + .withYaxis(YAxisBuilder.get().build()) + .withTheme(theme); } } diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java index 8de13b8..696e0cd 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java @@ -1,12 +1,16 @@ package org.kickerelo.kickerelo.views; import com.github.appreciated.apexcharts.ApexChartsBuilder; +import com.github.appreciated.apexcharts.config.Theme; import com.github.appreciated.apexcharts.config.builder.ChartBuilder; import com.github.appreciated.apexcharts.config.builder.XAxisBuilder; import com.github.appreciated.apexcharts.config.builder.YAxisBuilder; import com.github.appreciated.apexcharts.config.chart.Type; import com.github.appreciated.apexcharts.config.chart.builder.ZoomBuilder; import com.github.appreciated.apexcharts.config.chart.zoom.ZoomType; +import com.github.appreciated.apexcharts.config.theme.Mode; +import com.github.appreciated.apexcharts.config.theme.Monochrome; +import com.github.appreciated.apexcharts.config.xaxis.Labels; import com.github.appreciated.apexcharts.helper.Series; import org.kickerelo.kickerelo.data.Spieler; import org.kickerelo.kickerelo.util.Spieler2vs2EloComparator; @@ -15,12 +19,23 @@ import java.util.List; public class Chart2vs2 extends ApexChartsBuilder { public Chart2vs2(List l) { + Theme theme = new Theme(); + Monochrome monochrome = new Monochrome(); + monochrome.setEnabled(true); + theme.setMode(Mode.DARK); + theme.setMonochrome(monochrome); + Labels labels = new Labels(); + labels.setRotate(270d); + labels.setShow(true); + labels.setRotateAlways(false); + withChart(ChartBuilder.get().withType(Type.SCATTER) .withZoom(ZoomBuilder.get().withEnabled(true).withType(ZoomType.XY).build()).build()) .withSeries(new Series<>("ELO", l.stream().sorted(new Spieler2vs2EloComparator()).map(Spieler::getElo2vs2).toArray() )) - .withXaxis(XAxisBuilder.get().withCategories(l.stream().sorted(new Spieler2vs2EloComparator()).map(Spieler::getName).toList()).build()) - .withYaxis(YAxisBuilder.get().build()); + .withXaxis(XAxisBuilder.get().withCategories(l.stream().sorted(new Spieler2vs2EloComparator()).map(Spieler::getName).toList()).withLabels(labels).build()) + .withYaxis(YAxisBuilder.get().build()) + .withTheme(theme); } } diff --git a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java index 1fd8d79..4be1c89 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java @@ -11,9 +11,10 @@ import org.kickerelo.kickerelo.service.KickerEloService; import java.util.List; -@Route("playerlist") +@Route("") public class PlayerListView extends VerticalLayout { public PlayerListView(KickerEloService eloService) { + setSizeFull(); H2 subheading = new H2("Spielerliste"); List players = eloService.getSpielerEntities(); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 743bb0a..902fa33 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,10 +6,9 @@ spring.mustache.check-template-location = false vaadin.launch-browser=true spring.datasource.url=jdbc:mariadb://localhost:3306/kickerelo -spring.datasource.username= -spring.datasource.password= +spring.datasource.username=root +spring.datasource.password=root spring.datasource.driver-class-name=org.mariadb.jdbc.Driver spring.jpa.hibernate.ddl-auto=validate -spring.jpa.show-sql=true -spring.jpa.format-sql=true +spring.jpa.show-sql=false spring.jpa.open-in-view=false \ No newline at end of file