Browse Source

match results without games

master
GAM 4 years ago
parent
commit
d5ccedb102
12 changed files with 182 additions and 20 deletions
  1. +2
    -0
      db/db_increment_005.sql
  2. +13
    -0
      src/main/java/app/data/entity/Match.java
  3. +14
    -0
      src/main/java/app/data/service/MatchService.java
  4. +4
    -1
      src/main/java/app/data/service/MatchdayService.java
  5. +4
    -2
      src/main/java/app/data/service/PlayerForTableProvider.java
  6. +21
    -3
      src/main/java/app/navigation/Navigation.java
  7. +3
    -1
      src/main/java/app/navigation/NavigationUtils.java
  8. +21
    -0
      src/main/java/app/utils/StringUtils.java
  9. +59
    -0
      src/main/java/app/views/match/components/EditMatchCard.java
  10. +32
    -7
      src/main/java/app/views/match/components/MatchComponent.java
  11. +4
    -2
      src/main/java/app/views/matchday/components/MatchdayCard.java
  12. +5
    -4
      src/main/java/app/views/player/components/PlayerCard.java

+ 2
- 0
db/db_increment_005.sql View File

@ -0,0 +1,2 @@
ALTER TABLE "match" ADD COLUMN "state" varchar not null default 'NOT_YET_PLAYED';
UPDATE match SET state='PLAYED' WHERE (id IN (SELECT match from game));

+ 13
- 0
src/main/java/app/data/entity/Match.java View File

@ -15,12 +15,25 @@ import java.util.Collection;
catalog = "chessleague")
public class Match extends AbstractEntity implements Navigable {
public enum State {
NOT_YET_PLAYED,
PLAYED,
SIX_ZERO,
ZERO_SIX,
ZERO_ZERO
}
@ManyToOne(cascade = CascadeType.DETACH)
@JoinColumn(name = "matchday",
referencedColumnName = "id",
nullable = false)
private Matchday matchday;
@Basic
@Enumerated(EnumType.STRING)
@Column(name = "state", nullable = false)
private State state;
@ManyToOne(cascade = CascadeType.DETACH)
@JoinColumn(name = "player1",
referencedColumnName = "id",


+ 14
- 0
src/main/java/app/data/service/MatchService.java View File

@ -14,6 +14,8 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static app.data.entity.Match.State.*;
@Service
public class MatchService extends CrudService<Match, Integer> implements NavigableService<Match> {
@ -53,6 +55,12 @@ public class MatchService extends CrudService<Match, Integer> implements Navigab
}
private static double getScore1(Match match) {
if (match.getState().equals(SIX_ZERO)) {
return 6;
}
if (match.getState().equals(ZERO_SIX) || match.getState().equals(ZERO_ZERO)) {
return 0;
}
double score = 0;
for (Game game : match.getGames()) {
score += (double) ((game.getPlayer1IsWhite() ? game.getResult() : -game.getResult()) + 1) / 2;
@ -61,6 +69,12 @@ public class MatchService extends CrudService<Match, Integer> implements Navigab
}
private static double getScore2(Match match) {
if (match.getState().equals(ZERO_SIX)) {
return 6;
}
if (match.getState().equals(SIX_ZERO) || match.getState().equals(ZERO_ZERO)) {
return 0;
}
double score = 0;
for (Game game : match.getGames()) {
score += (double) ((game.getPlayer1IsWhite() ? -game.getResult() : game.getResult()) + 1) / 2;


+ 4
- 1
src/main/java/app/data/service/MatchdayService.java View File

@ -1,6 +1,7 @@
package app.data.service;
import app.data.bean.CalculatedMatch;
import app.data.entity.Match;
import app.data.entity.Matchday;
import app.data.entity.Season;
import app.data.repository.MatchdayRepository;
@ -15,6 +16,8 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static app.data.entity.Match.State.NOT_YET_PLAYED;
@Service
public class MatchdayService extends CrudService<Matchday, Integer> implements NavigableService<Matchday> {
@ -63,7 +66,7 @@ public class MatchdayService extends CrudService<Matchday, Integer> implements N
}
public boolean hasActivity(@NonNull Matchday matchday) {
return matchday.getMatches().stream().mapToInt(match -> match.getGames().size()).sum() != 0;
return matchday.getMatches().stream().anyMatch(match -> !match.getState().equals(NOT_YET_PLAYED));
}
@Override


+ 4
- 2
src/main/java/app/data/service/PlayerForTableProvider.java View File

@ -10,6 +10,8 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static app.data.entity.Match.State.ZERO_ZERO;
class PlayerForTableProvider {
private final PlayerService playerService;
private final MatchdayService matchdayService;
@ -160,7 +162,7 @@ class PlayerForTableProvider {
map.get(WinState.WON).add(match);
continue;
}
if (match.getScore1() < match.getScore2()) {
if (match.getScore1() < match.getScore2() || match.getMatch().getState().equals(ZERO_ZERO)) {
map.get(WinState.LOST).add(match);
continue;
}
@ -174,7 +176,7 @@ class PlayerForTableProvider {
map.get(WinState.WON).add(match);
continue;
}
if (match.getScore2() < match.getScore1()) {
if (match.getScore2() < match.getScore1() || match.getMatch().getState().equals(ZERO_ZERO)) {
map.get(WinState.LOST).add(match);
continue;
}


+ 21
- 3
src/main/java/app/navigation/Navigation.java View File

@ -14,6 +14,7 @@ import org.springframework.lang.Nullable;
import java.util.*;
import static app.navigation.NavigationUtils.ADMIN;
import static app.navigation.NavigationUtils.EDIT;
public abstract class Navigation implements HasUrlParameter<String> {
@ -33,6 +34,8 @@ public abstract class Navigation implements HasUrlParameter<String> {
protected boolean editFlag = false;
protected boolean adminFlag = false;
@SafeVarargs
public Navigation(NavigableService<? extends Navigable>... services) {
for (NavigableService<? extends Navigable> service : services) {
@ -91,7 +94,7 @@ public abstract class Navigation implements HasUrlParameter<String> {
}
}
String wildcardParam = NavigationUtils.getWildcardParam(editFlag, params);
String wildcardParam = NavigationUtils.getWildcardParam(editFlag, adminFlag, params);
UI.getCurrent().getPage().getHistory().pushState(null, String.format("%s/%s", getRoute(), wildcardParam));
}
@ -107,6 +110,18 @@ public abstract class Navigation implements HasUrlParameter<String> {
}
}
public boolean adminFlag() {
return adminFlag;
}
public void setAdminFlag(boolean adminFlag) {
if (adminFlag != this.adminFlag) {
this.adminFlag = adminFlag;
updateUrl();
runnablesToBeRunAfterSelection.forEach(Runnable::run);
}
}
public void addRunnableToBeRunAfterSelection(Runnable runnable) {
runnablesToBeRunAfterSelection.add(runnable);
}
@ -158,7 +173,10 @@ public abstract class Navigation implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
String[] params = param.split("/");
editFlag = params[params.length - 1].equals(EDIT);
List<String> paramsAsList = Arrays.asList(params);
editFlag = paramsAsList.contains(EDIT);
adminFlag = paramsAsList.contains(ADMIN);
for (int i = 0; i < Math.min(params.length, navigableClasses.size()); i++) {
navigateClass(navigableClasses.get(i), params[i]);
@ -180,7 +198,7 @@ public abstract class Navigation implements HasUrlParameter<String> {
for (int i = 0; i < navigableClasses.size(); i++) {
params[i] = getParam(navigableClasses.get(i)).orElse(null);
}
return NavigationUtils.getWildcardParam(editFlag, params);
return NavigationUtils.getWildcardParam(editFlag, adminFlag, params);
}
@SuppressWarnings("unchecked")


+ 3
- 1
src/main/java/app/navigation/NavigationUtils.java View File

@ -8,12 +8,13 @@ import java.util.Optional;
public class NavigationUtils {
public static final String EDIT = "edit";
public static final String ADMIN = "admin";
private NavigationUtils() {
}
@NonNull
public static String getWildcardParam(boolean editFlag, String... params) {
public static String getWildcardParam(boolean editFlag, boolean adminFlag, String... params) {
StringBuilder stringBuilder = new StringBuilder();
for (String param : params) {
if (param == null || param.equals("")) {
@ -22,6 +23,7 @@ public class NavigationUtils {
stringBuilder.append(param).append("/");
}
if (editFlag) stringBuilder.append(EDIT).append("/");
if (adminFlag) stringBuilder.append(ADMIN).append("/");
return stringBuilder.toString();
}


+ 21
- 0
src/main/java/app/utils/StringUtils.java View File

@ -1,10 +1,13 @@
package app.utils;
import app.data.bean.CalculatedMatch;
import org.apache.commons.lang3.RandomStringUtils;
import java.util.HashSet;
import java.util.Set;
import static app.data.entity.Match.State.*;
public class StringUtils {
private StringUtils() {
}
@ -13,6 +16,24 @@ public class StringUtils {
// SPECIAL FORMATTING //
////////////////////////
public static String getResultString(String delimiter, CalculatedMatch match, boolean player1left) {
if (match.getMatch().getState().equals(NOT_YET_PLAYED)) {
return "- : -"; // TODO: care about delimiter
}
if (match.getMatch().getState().equals(SIX_ZERO)) {
return "6 : 0"; // TODO: care about delimiter
}
if (match.getMatch().getState().equals(ZERO_SIX)) {
return "0 : 6"; // TODO: care about delimiter
}
String score1String = match.getScore1().toString().replace(".0", "");
String score2String = match.getScore2().toString().replace(".0", "");
return player1left ?
String.format("%s %s %s", score1String, delimiter, score2String) :
String.format("%s %s %s", score2String, delimiter, score1String);
} // TODO: refactor these 2 methods for less duplication
public static String getResultString(String delimiter, Double first, Double second) {
String firstString = first.toString().replace(".0", "");
String secondString = second.toString().replace(".0", "");


+ 59
- 0
src/main/java/app/views/match/components/EditMatchCard.java View File

@ -2,6 +2,7 @@ package app.views.match.components;
import app.data.entity.Game;
import app.data.entity.Match;
import app.data.entity.Match.State;
import app.data.service.ChessComService;
import app.data.service.MatchService;
import app.gameimage.GameImageService;
@ -23,6 +24,7 @@ import com.vaadin.flow.shared.Registration;
import java.util.*;
import static app.data.entity.Match.State.*;
import static app.utils.TimeControl.*;
import static com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY;
@ -46,6 +48,14 @@ public class EditMatchCard extends VerticalLayout {
private final Button chessComButton = new Button("Autofill with the latest games between the players", new Icon(VaadinIcon.MAGIC));
private Registration chessComButtonButtonRegistration;
HorizontalLayout adminButtonLayout = new HorizontalLayout();
private Registration sixZeroButtonRegistration;
private final Button sixZeroButton = new Button("6 - 0", new Icon(VaadinIcon.CHECK));
private Registration zeroSixButtonRegistration;
private final Button zeroSixButton = new Button("0 - 6", new Icon(VaadinIcon.CHECK));
private Registration zeroZeroButtonRegistration;
private final Button zeroZeroButton = new Button("0 - 0", new Icon(VaadinIcon.CHECK));
private Match match;
public EditMatchCard(MatchNavigation matchNavigation, ChessComService chessComService, GameImageService gameImageService) {
@ -70,6 +80,7 @@ public class EditMatchCard extends VerticalLayout {
defineTextFields();
defineSubmitButton();
addSubmitAndCancelButtons();
addAdminButtons();
}
private void defineTextFields() {
@ -111,6 +122,16 @@ public class EditMatchCard extends VerticalLayout {
add(buttonLayout);
}
private void addAdminButtons() {
sixZeroButton.addThemeVariants(LUMO_PRIMARY);
zeroSixButton.addThemeVariants(LUMO_PRIMARY);
zeroZeroButton.addThemeVariants(LUMO_PRIMARY);
adminButtonLayout.setAlignItems(Alignment.CENTER);
adminButtonLayout.setJustifyContentMode(JustifyContentMode.CENTER);
adminButtonLayout.add(sixZeroButton, zeroSixButton, zeroZeroButton);
}
/////////////
// CONTENT //
/////////////
@ -124,6 +145,8 @@ public class EditMatchCard extends VerticalLayout {
configureChessComButton();
configureEditSubmitButton();
configureEditCancelButton();
configureAdminButtons();
}
private void clearTextFields() {
@ -191,6 +214,42 @@ public class EditMatchCard extends VerticalLayout {
editCancelButtonRegistration = editCancelButton.addClickListener(createEditCancelButtonListener());
}
private void configureAdminButtons() {
if (matchNavigation.adminFlag()) {
configureSixZeroButton();
configureZeroSixButton();
configureZeroZeroButton();
add(adminButtonLayout);
}
else {
remove(adminButtonLayout);
}
}
private void configureSixZeroButton() {
if (sixZeroButtonRegistration != null) sixZeroButtonRegistration.remove();
sixZeroButtonRegistration = sixZeroButton.addClickListener(event -> submitAdminDecision(SIX_ZERO));
}
private void configureZeroSixButton() {
if (zeroSixButtonRegistration != null) zeroSixButtonRegistration.remove();
zeroSixButtonRegistration = zeroSixButton.addClickListener(event -> submitAdminDecision(ZERO_SIX));
}
private void configureZeroZeroButton() {
if (zeroZeroButtonRegistration != null) zeroZeroButtonRegistration.remove();
zeroZeroButtonRegistration = zeroZeroButton.addClickListener(event -> submitAdminDecision(ZERO_ZERO));
}
private void submitAdminDecision(State sixZero) {
match.getGames().clear();
match.setState(sixZero);
matchService.update(match);
matchNavigation.setEditFlag(false);
matchNavigation.setAdminFlag(false);
}
private ComponentEventListener<ClickEvent<Button>> createEditCancelButtonListener() {
return event -> UI.getCurrent().navigate(String.format("matchday/%s", matchNavigation.getWildcardParam().replace("edit/", "")));
}


+ 32
- 7
src/main/java/app/views/match/components/MatchComponent.java View File

@ -36,7 +36,8 @@ public class MatchComponent extends Div implements ContentConfigurable {
private final Label headerResultLabel = new Label();
private final FlexLayout gamesLayout = new FlexLayout();
private final VerticalLayout noGamesLayout = new VerticalLayout();
private final VerticalLayout notPlayedYetLayout = new VerticalLayout();
private final Label resultWithoutGamesLabel = new Label();
private final FlexLayout editLayout = new FlexLayout();
private final EditMatchCard editMatchCard;
@ -84,8 +85,8 @@ public class MatchComponent extends Div implements ContentConfigurable {
}
private void defineNoGamesLayout() {
noGamesLayout.add(createNoGamesLabel(), createAddGamesButton());
noGamesLayout.setAlignItems(FlexComponent.Alignment.CENTER);
notPlayedYetLayout.add(createNoGamesLabel(), createAddGamesButton());
notPlayedYetLayout.setAlignItems(FlexComponent.Alignment.CENTER);
}
private Label createNoGamesLabel() {
@ -97,7 +98,7 @@ public class MatchComponent extends Div implements ContentConfigurable {
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
button.addClickListener(event -> {
matchNavigation.setEditFlag(true);
remove(noGamesLayout);
remove(notPlayedYetLayout);
});
return button;
}
@ -145,7 +146,7 @@ public class MatchComponent extends Div implements ContentConfigurable {
} else {
headerLayout.add(headerResultLabel);
headerResultLabel.setText(String.format("%s",
StringUtils.getResultString("-", calculatedMatch.getScore1(), calculatedMatch.getScore2())));
StringUtils.getResultString("-", calculatedMatch, true)));
}
}
@ -163,11 +164,19 @@ public class MatchComponent extends Div implements ContentConfigurable {
private void configureGamesContent() {
if (match.getGames().isEmpty()) {
remove(gamesLayout);
add(noGamesLayout);
if (match.getState().equals(Match.State.NOT_YET_PLAYED)) {
remove(resultWithoutGamesLabel);
add(notPlayedYetLayout);
} else {
remove(notPlayedYetLayout);
configureResultWithoutGamesLabel();
add(resultWithoutGamesLabel);
}
return;
}
remove(noGamesLayout);
remove(notPlayedYetLayout);
remove(resultWithoutGamesLabel);
add(gamesLayout);
gamesLayout.removeAll();
@ -175,4 +184,20 @@ public class MatchComponent extends Div implements ContentConfigurable {
gamesLayout.add(new GameCard(game, gameImageService));
}
}
private void configureResultWithoutGamesLabel() {
switch (match.getState()) {
case SIX_ZERO:
resultWithoutGamesLabel.setText("This match was set to be valued 6-0 by an administrator decision.");
break;
case ZERO_SIX:
resultWithoutGamesLabel.setText("This match was set to be valued 0-6 by an administrator decision.");
break;
case ZERO_ZERO:
resultWithoutGamesLabel.setText("An administrator decided to give both players 0 points for this match.");
break;
default:
resultWithoutGamesLabel.setText("This text should never appear!");
}
}
}

+ 4
- 2
src/main/java/app/views/matchday/components/MatchdayCard.java View File

@ -26,6 +26,8 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.NoSuchElementException;
import static app.data.entity.Match.State.NOT_YET_PLAYED;
public class MatchdayCard extends Div implements ContentConfigurable {
private final MatchdayNavigation matchdayNavigation;
@ -110,7 +112,7 @@ public class MatchdayCard extends Div implements ContentConfigurable {
String matchParam = EntityStringUtils.getMatchStringForURL(match.getMatch());
String targetWildcardParam = String.format("match/%s%s/", seasonAndMatchdayParam, matchParam);
if (match.getScore1() == 0 && match.getScore2() == 0) {
if (match.getMatch().getState().equals(NOT_YET_PLAYED)) {
button.setIcon(VaadinIcon.PENCIL.create());
button.addClickListener(event -> UI.getCurrent().navigate(targetWildcardParam + "edit"));
return button;
@ -126,7 +128,7 @@ public class MatchdayCard extends Div implements ContentConfigurable {
}
private String getResultString(CalculatedMatch match) {
return StringUtils.getResultString(":", match.getScore1(), match.getScore2());
return StringUtils.getResultString(":", match, true);
}
@Override


+ 5
- 4
src/main/java/app/views/player/components/PlayerCard.java View File

@ -1,6 +1,7 @@
package app.views.player.components;
import app.data.bean.CalculatedMatch;
import app.data.entity.Match;
import app.data.entity.Player;
import app.data.entity.Season;
import app.navigation.player.PlayerNavigation;
@ -24,6 +25,8 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import java.util.NoSuchElementException;
import static app.data.entity.Match.State.NOT_YET_PLAYED;
public class PlayerCard extends Div implements ContentConfigurable {
private final PlayerNavigation playerNavigation;
@ -97,7 +100,7 @@ public class PlayerCard extends Div implements ContentConfigurable {
String targetWildcardParam = String.format("match/%s/%s/%s/", seasonParam, matchdayParam, matchParam);
if (match.getScore1() == 0 && match.getScore2() == 0) {
if (match.getMatch().getState().equals(NOT_YET_PLAYED)) {
button.setIcon(VaadinIcon.PENCIL.create());
button.addClickListener(event -> UI.getCurrent().navigate(targetWildcardParam + "edit"));
return button;
@ -118,9 +121,7 @@ public class PlayerCard extends Div implements ContentConfigurable {
private String getResultString(CalculatedMatch match) {
boolean isPlayer1 = match.getPlayer1().equals(player);
double ownScore = isPlayer1 ? match.getScore1() : match.getScore2();
double opponentScore = isPlayer1 ? match.getScore2() : match.getScore1();
return StringUtils.getResultString(":", ownScore, opponentScore);
return StringUtils.getResultString(":", match, isPlayer1);
}
@Override


Loading…
Cancel
Save