Browse Source

EditMatch game timeControl categories

master
GAM 4 years ago
parent
commit
cdbef4af2e
5 changed files with 215 additions and 70 deletions
  1. +40
    -35
      frontend/app/views/main/main-view.css
  2. +19
    -10
      src/main/java/app/data/service/ChessComService.java
  3. +29
    -0
      src/main/java/app/utils/MatchUtils.java
  4. +65
    -0
      src/main/java/app/utils/TimeControl.java
  5. +62
    -25
      src/main/java/app/views/match/components/EditMatchCard.java

+ 40
- 35
frontend/app/views/main/main-view.css View File

@ -1,33 +1,32 @@
/*/////////*/
/* GENERAL */
/*/////////*/
.content {
background-color: var(--lumo-contrast-10pct);
min-height: 100%;
background-color: var(--lumo-contrast-10pct);
min-height: 100%;
}
.grid-card {
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: 0 var(--lumo-space-m) var(--lumo-space-m);
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: 0 var(--lumo-space-m) var(--lumo-space-m);
}
.card {
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: var(--lumo-space-m);
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: var(--lumo-space-m);
}
.bold-label {
font-weight: bold;
font-weight: bold;
}
.nickname-label {
margin-left: var(--lumo-space-xs);
margin-left: var(--lumo-space-xs);
}
/*//////////////////*/
@ -35,47 +34,53 @@
/*//////////////////*/
#header {
height: var(--lumo-size-xl);
box-shadow: var(--lumo-box-shadow-s);
height: var(--lumo-size-xl);
box-shadow: var(--lumo-box-shadow-s);
}
#header vaadin-avatar {
margin-left: auto;
margin-right: var(--lumo-space-m);
margin-left: auto;
margin-right: var(--lumo-space-m);
}
vaadin-app-layout[dir='rtl'] #header vaadin-avatar {
margin-left: var(--lumo-space-m);
margin-right: auto;
margin-left: var(--lumo-space-m);
margin-right: auto;
}
#header h1 {
font-size: var(--lumo-font-size-l);
margin: 0;
font-size: var(--lumo-font-size-l);
margin: 0;
}
#logo {
box-sizing: border-box;
box-shadow: inset 0 -1px var(--lumo-contrast-10pct);
padding: var(--lumo-space-s) var(--lumo-space-m);
box-sizing: border-box;
box-shadow: inset 0 -1px var(--lumo-contrast-10pct);
padding: var(--lumo-space-s) var(--lumo-space-m);
}
#logo img {
height: calc(var(--lumo-size-l) * 1.5);
height: calc(var(--lumo-size-l) * 1.5);
}
#logo h1 {
font-size: var(--lumo-font-size-xl);
font-weight: 600;
margin: 0 var(--lumo-space-s);
font-size: var(--lumo-font-size-xl);
font-weight: 600;
margin: 0 var(--lumo-space-s);
}
vaadin-tab {
font-size: var(--lumo-font-size-s);
height: var(--lumo-size-l);
font-weight: 600;
color: var(--lumo-body-text-color);
font-size: var(--lumo-font-size-s);
height: var(--lumo-size-l);
font-weight: 600;
color: var(--lumo-body-text-color);
}
vaadin-tab:hover {
background-color: var(--lumo-contrast-5pct);
background-color: var(--lumo-contrast-5pct);
}
vaadin-tab[selected] {
background-color: var(--lumo-primary-color-10pct);
color: var(--lumo-primary-text-color);
background-color: var(--lumo-primary-color-10pct);
color: var(--lumo-primary-text-color);
}

+ 19
- 10
src/main/java/app/data/service/ChessComService.java View File

@ -8,6 +8,8 @@ import app.data.entity.GameInfo;
import app.data.entity.Match;
import app.data.entity.Player;
import app.utils.ChessComUtils;
import app.utils.MatchUtils;
import app.utils.TimeControl;
import app.utils.HttpUtils;
import com.google.gson.Gson;
import org.springframework.lang.NonNull;
@ -16,6 +18,8 @@ import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
import static app.utils.TimeControl.*;
@Service
public class ChessComService {
// TODO: make everything nullsafe
@ -29,8 +33,8 @@ public class ChessComService {
}
@NonNull
public List<Game> getLatestGamesBetweenPlayers(@NonNull Match match, int amountOfGames, int maxAmountOfMonths) {
List<Game> games = new ArrayList<>();
public Map<TimeControl, List<Game>> getLatestGamesBetweenPlayers(@NonNull Match match, int maxAmountOfMonths) {
Map<TimeControl, List<Game>> map = MatchUtils.createEmptyGamesMap();
for (String archiveUrl : getLatestArchiveUrls(match.getPlayer1(), maxAmountOfMonths)) {
List<ChessComGame> chessComGames = getChessComGames(archiveUrl).stream()
.sorted(Comparator.comparingLong(ChessComGame::getEndTime).reversed())
@ -38,19 +42,24 @@ public class ChessComService {
.filter(ChessComUtils::hasValidTimeControl)
.collect(Collectors.toList());
chessComGames.forEach(chessComGame -> chessComGameCache.put(chessComGame.getUrl(), chessComGame));
games.addAll(chessComGames.stream()
List<Game> games = chessComGames.stream()
.map(chessComGame -> getGame(chessComGame, match))
.collect(Collectors.toList()));
if (games.size() >= amountOfGames) {
.collect(Collectors.toList());
map.get(TEN_MINUTES).addAll(games.stream().filter(game -> game.getGameInfo().getTimeControl().equals("600")).collect(Collectors.toList()));
map.get(FIVE_MINUTES).addAll(games.stream().filter(game -> game.getGameInfo().getTimeControl().equals("300")).collect(Collectors.toList()));
map.get(THREE_MINUTES).addAll(games.stream().filter(game -> game.getGameInfo().getTimeControl().equals("180")).collect(Collectors.toList()));
if (map.get(TEN_MINUTES).size() >= 2 && map.get(FIVE_MINUTES).size() >= 2 && map.get(THREE_MINUTES).size() >= 2) {
break;
}
}
games.sort(Comparator.comparingLong(game -> game.getGameInfo().getEndTime()));
if (games.size() > amountOfGames) {
games = games.subList(games.size() - amountOfGames, games.size());
for (TimeControl key : map.keySet()) {
map.get(key).sort(Comparator.comparingLong(game -> game.getGameInfo().getEndTime()));
int size = map.get(key).size();
if (size > 2) map.put(key, map.get(key).subList(size - 2, size));
}
return games;
} // TODO: find exactly two games of each time control
return map;
}
private List<ChessComGame> getChessComGames(String archiveUrl) {
List<ChessComGame> list = new ArrayList<>();


+ 29
- 0
src/main/java/app/utils/MatchUtils.java View File

@ -0,0 +1,29 @@
package app.utils;
import app.data.entity.Game;
import app.data.entity.Match;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MatchUtils {
public static Map<TimeControl, List<Game>> getGamesMap(Match match) {
Map<TimeControl, List<Game>> map = createEmptyGamesMap();
for (Game game : match.getGames()) {
TimeControl timeControl = TimeControl.fromSecondsString(game.getGameInfo().getTimeControl());
map.get(timeControl).add(game);
}
return map;
}
public static Map<TimeControl, List<Game>> createEmptyGamesMap() {
Map<TimeControl, List<Game>> map = new HashMap<>();
for (TimeControl key : TimeControl.values()) {
map.put(key, new ArrayList<>());
}
return map;
}
}

+ 65
- 0
src/main/java/app/utils/TimeControl.java View File

@ -0,0 +1,65 @@
package app.utils;
import java.sql.Time;
public enum TimeControl {
TEN_MINUTES,
FIVE_MINUTES,
THREE_MINUTES;
public static TimeControl fromSecondsString(String secondsString) {
switch (secondsString) {
case "600":
return TEN_MINUTES;
case "300":
return FIVE_MINUTES;
case "180":
return THREE_MINUTES;
default:
throw new UnsupportedOperationException(String.format("%s cannot be converted to a TimeControl!", secondsString));
}
}
public String toSecondsString() {
switch (this) {
case TEN_MINUTES:
return "600";
case FIVE_MINUTES:
return "300";
case THREE_MINUTES:
return "180";
default:
throw new UnsupportedOperationException(String.format("Cannot convert %s to a secondsString!", this.toString()));
}
}
public static String toSecondsString(TimeControl timeControl) {
return timeControl.toSecondsString();
}
public static TimeControl fromPresentationString(String presentationString) {
switch (presentationString) {
case "10 min":
return TEN_MINUTES;
case "5 min":
return FIVE_MINUTES;
case "3 min":
return THREE_MINUTES;
default:
throw new UnsupportedOperationException(String.format("%s cannot be converted to a TimeControl!", presentationString));
}
}
public String toPresentationString() {
switch (this) {
case TEN_MINUTES:
return "10 min";
case FIVE_MINUTES:
return "5 min";
case THREE_MINUTES:
return "3 min";
default:
throw new UnsupportedOperationException(String.format("Cannot convert %s to a presentationString!", this.toString()));
}
}
}

+ 62
- 25
src/main/java/app/views/match/components/EditMatchCard.java View File

@ -7,23 +7,27 @@ import app.data.service.MatchService;
import app.gameimage.GameImageService;
import app.navigation.Navigation;
import app.utils.ChessComUtils;
import app.utils.MatchUtils;
import app.utils.TimeControl;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.formlayout.FormLayout.ResponsiveStep;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.shared.Registration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import static app.utils.TimeControl.*;
import static com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY;
import static com.vaadin.flow.component.formlayout.FormLayout.ResponsiveStep.LabelsPosition.ASIDE;
public class EditMatchCard extends VerticalLayout {
@ -32,7 +36,10 @@ public class EditMatchCard extends VerticalLayout {
private final ChessComService chessComService;
private final GameImageService gameImageService;
private final ArrayList<TextField> textFields = new ArrayList<>();
private final VerticalLayout formLayout = new VerticalLayout();
private final List<TextField> tenMinuteTextFields = new ArrayList<>();
private final List<TextField> fiveMinuteTextFields = new ArrayList<>();
private final List<TextField> threeMinuteTextFields = new ArrayList<>();
// TODO: autocorrect "/live/game" to "/game/live/"
private final Button submitButton = new Button("Submit", new Icon(VaadinIcon.CHECK));
// TODO: disable when no 6 values in form, and make sure you don't freeze forever when there are wrong entries
@ -40,7 +47,7 @@ public class EditMatchCard extends VerticalLayout {
private Registration editSubmitButtonRegistration;
private final Button editCancelButton = new Button("Cancel", new Icon(VaadinIcon.CLOSE));
private Registration editCancelButtonRegistration;
private final Button chessComButton = new Button("Autofill with the latest 6 games between the players", new Icon(VaadinIcon.MAGIC));
private final Button chessComButton = new Button("Autofill with the latest games between the players", new Icon(VaadinIcon.MAGIC));
private Registration chessComButtonButtonRegistration;
private Match match;
@ -59,7 +66,7 @@ public class EditMatchCard extends VerticalLayout {
////////////
private void defineLayout() {
setAlignItems(FlexComponent.Alignment.CENTER);
setAlignItems(Alignment.CENTER);
setWidth("");
addClassName("card");
add(chessComButton);
@ -70,25 +77,48 @@ public class EditMatchCard extends VerticalLayout {
}
private void defineTextFields() {
for (int i = 0; i < 6; i++) {
add(formLayout);
// formLayout.setSpacing(false);
formLayout.setPadding(false);
// List<ResponsiveStep> responsiveSteps = new ArrayList<>();
// for (int i = 0; i < 6; i++) {
// responsiveSteps.add(new ResponsiveStep("40em", 1, ASIDE));
// }
// formLayout.setResponsiveSteps(responsiveSteps);
defineTextFields(tenMinuteTextFields, TEN_MINUTES, 1);
defineTextFields(fiveMinuteTextFields, FIVE_MINUTES, 3);
defineTextFields(threeMinuteTextFields, THREE_MINUTES, 5);
}
private void defineTextFields(List<TextField> list, TimeControl timeControl, int startGameNumber) {
for (int i = 0; i < 2; i++) {
TextField textField = new TextField();
textField.setWidth("23em");
HorizontalLayout horizontalLayout = new HorizontalLayout(new Label(String.format("Game %d:", i + 1)), textField);
horizontalLayout.setAlignItems(FlexComponent.Alignment.CENTER);
horizontalLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
add(horizontalLayout);
textFields.add(textField);
textField.setPlaceholder("Please enter URL");
Label gameLabel = new Label(String.format("Game %d", startGameNumber + i));
gameLabel.addClassName("bold-label");
Label timeControlLabel = new Label(String.format("(%s):", timeControl.toPresentationString()));
timeControlLabel.addClassName("nickname-label");
HorizontalLayout labelLayout = new HorizontalLayout(gameLabel, timeControlLabel);
labelLayout.setSpacing(false);
labelLayout.setAlignItems(Alignment.CENTER);
labelLayout.setJustifyContentMode(JustifyContentMode.START);
HorizontalLayout row = new HorizontalLayout(labelLayout, textField);
row.setWidthFull();
row.setJustifyContentMode(JustifyContentMode.BETWEEN);
formLayout.add(row);
list.add(textField);
}
}
private void defineSubmitButton() {
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
submitButton.addThemeVariants(LUMO_PRIMARY);
}
private void addSubmitAndCancelButtons() {
HorizontalLayout buttonLayout = new HorizontalLayout();
buttonLayout.setAlignItems(FlexComponent.Alignment.CENTER);
buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
buttonLayout.setAlignItems(Alignment.CENTER);
buttonLayout.setJustifyContentMode(JustifyContentMode.CENTER);
buttonLayout.add(submitButton, editCancelButton);
add(buttonLayout);
}
@ -99,10 +129,9 @@ public class EditMatchCard extends VerticalLayout {
void configureContent(Match match) {
this.match = match;
List<Game> games = new ArrayList<>(match.getGames());
clearTextFields();
fillTextFieldsWithURLs(games);
fillTextFieldsWithURLs(MatchUtils.getGamesMap(match));
configureChessComButton();
configureEditSubmitButton();
@ -110,12 +139,20 @@ public class EditMatchCard extends VerticalLayout {
}
private void clearTextFields() {
textFields.forEach(textField -> textField.setValue(""));
for (List<TextField> list : Set.of(tenMinuteTextFields, fiveMinuteTextFields, threeMinuteTextFields)) {
list.forEach(textField -> textField.setValue(""));
}
}
private void fillTextFieldsWithURLs(List<Game> games) {
for (int i = 0; i < Math.min(games.size(), 6); i++)
textFields.get(i).setValue(ChessComUtils.getGameURL(games.get(i)));
private void fillTextFieldsWithURLs(Map<TimeControl, List<Game>> games) {
for (int i = 0; i < 2; i++) {
if (games.get(TEN_MINUTES).size() > i)
tenMinuteTextFields.get(i).setValue(ChessComUtils.getGameURL(games.get(TEN_MINUTES).get(i)));
if (games.get(FIVE_MINUTES).size() > i)
fiveMinuteTextFields.get(i).setValue(ChessComUtils.getGameURL(games.get(FIVE_MINUTES).get(i)));
if (games.get(THREE_MINUTES).size() > i)
threeMinuteTextFields.get(i).setValue(ChessComUtils.getGameURL(games.get(THREE_MINUTES).get(i)));
}
}
private void configureChessComButton() {
@ -125,7 +162,7 @@ public class EditMatchCard extends VerticalLayout {
private ComponentEventListener<ClickEvent<Button>> createChessComButtonClickListener() {
return event -> {
List<Game> gamesBetweenPlayers = chessComService.getLatestGamesBetweenPlayers(match, 6, 2);
Map<TimeControl, List<Game>> gamesBetweenPlayers = chessComService.getLatestGamesBetweenPlayers(match, 2);
fillTextFieldsWithURLs(gamesBetweenPlayers);
};
}
@ -147,7 +184,7 @@ public class EditMatchCard extends VerticalLayout {
}
private void addGamesToMatchFromFieldValues() {
for (TextField textField : textFields) {
for (TextField textField : tenMinuteTextFields) {
Optional<Game> game = chessComService.getGame(textField.getValue(), match); // TODO: handle this when Optional is empty!
game.ifPresent(value -> match.getGames().add(value));
}


Loading…
Cancel
Save