Browse Source

nice structure :)

master
GAM 4 years ago
parent
commit
c62d48b4cd
38 changed files with 587 additions and 572 deletions
  1. +0
    -0
      frontend/app/views/example/about/about-view.css
  2. +0
    -0
      frontend/app/views/example/addressform/address-form-view.css
  3. +0
    -0
      frontend/app/views/example/cardlist/card-list-view.css
  4. +0
    -0
      frontend/app/views/example/creditcardform/credit-card-form-view.css
  5. +0
    -0
      frontend/app/views/example/helloworld/hello-world-view.css
  6. +0
    -0
      frontend/app/views/example/map/map-view.css
  7. +0
    -0
      frontend/app/views/example/masterdetail/master-detail-view.css
  8. +0
    -0
      frontend/app/views/example/personform/person-form-view.css
  9. +28
    -0
      frontend/app/views/main/main-view.css
  10. +0
    -0
      frontend/app/views/match/match-view.css
  11. +2
    -6
      frontend/app/views/matchday/matchday-view.css
  12. +2
    -6
      frontend/app/views/table/table-view.css
  13. +32
    -26
      frontend/styles/shared-styles.js
  14. +16
    -0
      src/main/java/app/components/label/ValidationLabel.java
  15. +40
    -0
      src/main/java/app/components/navigation/NavigationHeader.java
  16. +0
    -16
      src/main/java/app/components/navigation/SeasonAndMatchdayNavigation.java
  17. +14
    -0
      src/main/java/app/components/navigation/button/ButtonUtils.java
  18. +38
    -0
      src/main/java/app/components/navigation/button/NextMatchdayButton.java
  19. +37
    -0
      src/main/java/app/components/navigation/button/PrevMatchdayButton.java
  20. +1
    -24
      src/main/java/app/data/service/ChessComService.java
  21. +161
    -287
      src/main/java/app/navigation/Navigation.java
  22. +11
    -5
      src/main/java/app/navigation/NavigationUtils.java
  23. +2
    -2
      src/main/java/app/views/example/about/AboutView.java
  24. +2
    -2
      src/main/java/app/views/example/addressform/AddressFormView.java
  25. +2
    -2
      src/main/java/app/views/example/cardlist/CardListView.java
  26. +1
    -1
      src/main/java/app/views/example/cardlist/Person.java
  27. +2
    -2
      src/main/java/app/views/example/creditcardform/CreditCardFormView.java
  28. +2
    -2
      src/main/java/app/views/example/helloworld/HelloWorldView.java
  29. +1
    -1
      src/main/java/app/views/example/map/MapView.java
  30. +2
    -2
      src/main/java/app/views/example/masterdetail/MasterDetailView.java
  31. +2
    -2
      src/main/java/app/views/example/personform/PersonFormView.java
  32. +7
    -5
      src/main/java/app/views/main/MainView.java
  33. +58
    -0
      src/main/java/app/views/match/MatchView.java
  34. +39
    -17
      src/main/java/app/views/matchday/MatchdayView.java
  35. +54
    -0
      src/main/java/app/views/navigation/NavigationViewBase.java
  36. +0
    -66
      src/main/java/app/views/results/MatchView.java
  37. +0
    -72
      src/main/java/app/views/results/ResultsView.java
  38. +31
    -26
      src/main/java/app/views/table/TableView.java

frontend/app/views/about/about-view.css → frontend/app/views/example/about/about-view.css View File


frontend/app/views/addressform/address-form-view.css → frontend/app/views/example/addressform/address-form-view.css View File


frontend/app/views/cardlist/card-list-view.css → frontend/app/views/example/cardlist/card-list-view.css View File


frontend/app/views/creditcardform/credit-card-form-view.css → frontend/app/views/example/creditcardform/credit-card-form-view.css View File


frontend/app/views/helloworld/hello-world-view.css → frontend/app/views/example/helloworld/hello-world-view.css View File


frontend/app/views/map/map-view.css → frontend/app/views/example/map/map-view.css View File


frontend/app/views/masterdetail/master-detail-view.css → frontend/app/views/example/masterdetail/master-detail-view.css View File


frontend/app/views/personform/person-form-view.css → frontend/app/views/example/personform/person-form-view.css View File


+ 28
- 0
frontend/app/views/main/main-view.css View File

@ -1,3 +1,31 @@
/*/////////*/
/* GENERAL */
/*/////////*/
.content {
background-color: var(--lumo-contrast-10pct);
min-height: 100%;
}
.grid-wrapper {
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);
}
.wrapper {
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: var(--lumo-space-m);
}
/*//////////////////*/
/* APP-LAYOUT-STUFF */
/*//////////////////*/
#header { #header {
height: var(--lumo-size-xl); height: var(--lumo-size-xl);
box-shadow: var(--lumo-box-shadow-s); box-shadow: var(--lumo-box-shadow-s);


+ 0
- 0
frontend/app/views/match/match-view.css View File


frontend/app/views/results/results-view.css → frontend/app/views/matchday/matchday-view.css View File

@ -1,13 +1,9 @@
.about-view {
display: block;
}
.column_header {
.matchday-view .column_header {
font-weight: bold; font-weight: bold;
font-size: large; font-size: large;
} }
.matchday_header {
.matchday-view .matchday_header {
font-weight: bolder; font-weight: bolder;
font-size: x-large; font-size: x-large;
text-align: center; text-align: center;

+ 2
- 6
frontend/app/views/table/table-view.css View File

@ -1,8 +1,4 @@
.about-view {
display: block;
}
.important_table_column_header {
.table-view .important-table-column-header {
font-weight: bold; font-weight: bold;
font-size: large; font-size: large;
}
}

+ 32
- 26
frontend/styles/shared-styles.js View File

@ -8,38 +8,44 @@ $_documentContainer.innerHTML = `
<style include='lumo-badge'> <style include='lumo-badge'>
html { html {
--lumo-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; --lumo-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
} }
[theme~="dark"] { [theme~="dark"] {
--lumo-base-color: #312e2b;
--lumo-shade-5pct: rgba(38, 33, 27, 0.05);
--lumo-shade-10pct: rgba(38, 33, 27, 0.1);
--lumo-shade-20pct: rgba(38, 33, 27, 0.2);
--lumo-shade-30pct: rgba(38, 33, 27, 0.3);
--lumo-shade-40pct: rgba(38, 33, 27, 0.4);
--lumo-shade-50pct: rgba(38, 33, 27, 0.5);
--lumo-shade-60pct: rgba(38, 33, 27, 0.6);
--lumo-shade-70pct: rgba(38, 33, 27, 0.7);
--lumo-shade-80pct: rgba(38, 33, 27, 0.8);
--lumo-shade-90pct: rgba(38, 33, 27, 0.9);
--lumo-shade: 26211b;
--lumo-primary-text-color: #7fa650;
--lumo-primary-color-50pct: rgba(127, 166, 80, 0.5);
--lumo-primary-color-10pct: rgba(127, 166, 80, 0.1);
--lumo-primary-color: #7fa650;
--lumo-error-text-color: rgb(179, 52, 48);
--lumo-error-color-50pct: rgba(179, 52, 48, 0.5);
--lumo-error-color-10pct: rgba(179, 52, 48, 0.1);
--lumo-error-color: #b33430;
--lumo-success-text-color: rgb(118, 150, 86);
--lumo-success-color-50pct: rgba(118, 150, 86, 0.5);
--lumo-success-color-10pct: rgba(118, 150, 86, 0.1);
--lumo-success-color: #769656;
--lumo-base-color: #22201e;
--lumo-shade-5pct: rgba(27, 25, 23, 0.05);
--lumo-shade-10pct: rgba(27, 25, 23, 0.1);
--lumo-shade-20pct: rgba(27, 25, 23, 0.2);
--lumo-shade-30pct: rgba(27, 25, 23, 0.3);
--lumo-shade-40pct: rgba(27, 25, 23, 0.4);
--lumo-shade-50pct: rgba(27, 25, 23, 0.5);
--lumo-shade-60pct: rgba(27, 25, 23, 0.6);
--lumo-shade-70pct: rgba(27, 25, 23, 0.7);
--lumo-shade-80pct: rgba(27, 25, 23, 0.8);
--lumo-shade-90pct: rgba(27, 25, 23, 0.9);
--lumo-shade: #1b1917;
--lumo-tint-5pct: rgba(177, 177, 177, 0.05);
--lumo-tint-10pct: rgba(177, 177, 177, 0.1);
--lumo-tint-20pct: rgba(177, 177, 177, 0.2);
--lumo-tint-30pct: rgba(177, 177, 177, 0.3);
--lumo-tint-40pct: rgba(177, 177, 177, 0.4);
--lumo-tint-50pct: rgba(177, 177, 177, 0.5);
--lumo-tint-60pct: rgba(177, 177, 177, 0.6);
--lumo-tint-70pct: rgba(177, 177, 177, 0.7);
--lumo-tint-80pct: rgba(177, 177, 177, 0.8);
--lumo-tint-90pct: rgba(177, 177, 177, 0.9);
--lumo-tint: #b1b1b1;
--lumo-primary-text-color: #7fa650;
--lumo-primary-color-50pct: rgba(127, 166, 80, 0.5);
--lumo-primary-color-10pct: rgba(127, 166, 80, 0.1);
--lumo-primary-color: #7fa650;
--lumo-success-color-50pct: rgba(108, 157, 65, 0.5);
--lumo-success-color-10pct: rgba(108, 157, 65, 0.1);
--lumo-success-color: #6c9d41;
--lumo-success-text-color: #6c9d41;
} }
</style> </style>
</custom-style> </custom-style>
`; `;
document.head.appendChild($_documentContainer.content); document.head.appendChild($_documentContainer.content);

+ 16
- 0
src/main/java/app/components/label/ValidationLabel.java View File

@ -0,0 +1,16 @@
package app.components.label;
import com.vaadin.flow.component.html.Label;
public class ValidationLabel extends Label {
private boolean valid = true;
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
}

+ 40
- 0
src/main/java/app/components/navigation/NavigationHeader.java View File

@ -0,0 +1,40 @@
package app.components.navigation;
import app.navigation.Navigation;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
public class NavigationHeader extends HorizontalLayout {
private final Navigation navigation;
private final Label seasonLabel = new Label("Season:");
private final Label matchdayLabel = new Label("Matchday:");
private final Label matchLabel = new Label("Match:");
public NavigationHeader(Navigation navigation) {
this.navigation = navigation;
configureLayout();
configureChildren();
}
private void configureLayout() {
setWidthFull();
setAlignItems(FlexComponent.Alignment.CENTER);
setJustifyContentMode(FlexComponent.JustifyContentMode.END);
}
private void configureChildren() {
removeAll();
if (navigation.isSeasonEnabled()) {
add(seasonLabel, navigation.getSeasonSelect());
}
if (navigation.isMatchdayEnabled()) {
add(matchdayLabel, navigation.getMatchdaySelect());
}
if (navigation.isMatchEnabled()) {
add(matchLabel, navigation.getMatchSelect());
}
}
}

+ 0
- 16
src/main/java/app/components/navigation/SeasonAndMatchdayNavigation.java View File

@ -1,16 +0,0 @@
package app.components.navigation;
import app.navigation.Navigation;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
public class SeasonAndMatchdayNavigation extends HorizontalLayout {
public SeasonAndMatchdayNavigation(Navigation navigation) {
setWidthFull();
setAlignItems(FlexComponent.Alignment.CENTER);
setJustifyContentMode(FlexComponent.JustifyContentMode.END);
add(new Label("Season:"), navigation.getSeasonSelect(), new Label("Matchday:"), navigation.getMatchdaySelect());
}
}

+ 14
- 0
src/main/java/app/components/navigation/button/ButtonUtils.java View File

@ -0,0 +1,14 @@
package app.components.navigation.button;
import app.navigation.Navigation;
import java.util.concurrent.atomic.AtomicInteger;
class ButtonUtils {
static int getMatchdayIndex(Navigation navigation) {
AtomicInteger index = new AtomicInteger();
navigation.getSelectedMatchday().ifPresent(matchday -> index.set(navigation.getMatchdayList().indexOf(matchday)));
return index.get();
}
}

+ 38
- 0
src/main/java/app/components/navigation/button/NextMatchdayButton.java View File

@ -0,0 +1,38 @@
package app.components.navigation.button;
import app.data.entity.Matchday;
import app.navigation.Navigation;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import java.util.Optional;
public class NextMatchdayButton extends Button {
private final Navigation navigation;
public NextMatchdayButton(Navigation navigation) {
this.navigation = navigation;
if (!navigation.isMatchdayEnabled())
throw new IllegalStateException("Cannot instantiate NextMatchdayButton when Matchdays are not enabled!");
setIcon(new Icon(VaadinIcon.ARROW_RIGHT));
navigation.addRunnableToBeRunAfterSelection(this::configure);
}
private void configure() {
Optional<Matchday> nextMatchday = getNextMatchday();
setEnabled(nextMatchday.isPresent());
addClickListener(event -> nextMatchday.ifPresent(matchday -> navigation.getMatchdaySelect().setValue(matchday)));
}
private Optional<Matchday> getNextMatchday() {
int index = ButtonUtils.getMatchdayIndex(navigation);
if (index >= 0 && index < navigation.getMatchdayList().size() - 1)
return Optional.ofNullable(navigation.getMatchdayList().get(index + 1));
return Optional.empty();
}
}

+ 37
- 0
src/main/java/app/components/navigation/button/PrevMatchdayButton.java View File

@ -0,0 +1,37 @@
package app.components.navigation.button;
import app.data.entity.Matchday;
import app.navigation.Navigation;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import java.util.Optional;
public class PrevMatchdayButton extends Button {
private final Navigation navigation;
public PrevMatchdayButton(Navigation navigation) {
this.navigation = navigation;
if (!navigation.isMatchdayEnabled())
throw new IllegalStateException("Cannot instantiate PrevMatchdayButton when Matchdays are not enabled!");
setIcon(new Icon(VaadinIcon.ARROW_LEFT));
navigation.addRunnableToBeRunAfterSelection(this::configure);
}
private void configure() {
Optional<Matchday> prevMatchday = getPrevMatchday();
setEnabled(prevMatchday.isPresent());
addClickListener(event -> prevMatchday.ifPresent(matchday -> navigation.getMatchdaySelect().setValue(matchday)));
}
private Optional<Matchday> getPrevMatchday() {
int index = ButtonUtils.getMatchdayIndex(navigation);
if (index > 0) return Optional.ofNullable(navigation.getMatchdayList().get(index - 1));
return Optional.empty();
}
}

+ 1
- 24
src/main/java/app/data/service/ChessComService.java View File

@ -10,13 +10,12 @@ import app.data.entity.Player;
import app.utils.ChessComUtils; import app.utils.ChessComUtils;
import app.utils.HttpUtils; import app.utils.HttpUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service @Service
public class ChessComService { public class ChessComService {
@ -117,26 +116,4 @@ public class ChessComService {
} }
return Optional.empty(); return Optional.empty();
} }
// return getArchiveUrls(player).stream()
// .map(this::getChessComArchive)
// .flatMap(chessComArchive -> chessComArchive.orElseThrow().getGames().stream())
// .filter(chessComGame -> chessComGame.getUrl().equals(game.getGameInfo().getUrl()))
// .findFirst();
// .forEach(g -> g
// .filter(chessComGame -> chessComGame.getUrl().equals(game.getGameInfo().getUrl())))
// .findFirst();
// }
// private Optional<ChessComGame> getChessComGame(@NonNull Game game, Player player) {
// if (!(game.getMatch().getPlayer1().equals(player) || game.getMatch().getPlayer2().equals(player))) {
// throw new IllegalArgumentException("Player must be participating in Game!");
// }
// return getArchiveUrls(player).stream()
// .map(this::getChessComArchive)
// .flatMap((Function<Optional<ChessComArchive>, Stream<ChessComGame>>)
// chessComArchive -> chessComArchive.stream()
// .flatMap(archive -> archive.getGames().stream()))
// .filter(chessComGame -> chessComGame.getUrl().equals(game.getGameInfo().getUrl()))
// .findFirst();
// }
} }

+ 161
- 287
src/main/java/app/navigation/Navigation.java View File

@ -1,37 +1,34 @@
package app.navigation; package app.navigation;
import app.components.label.ValidationLabel;
import app.data.entity.Match; import app.data.entity.Match;
import app.data.entity.Matchday; import app.data.entity.Matchday;
import app.data.entity.Season; import app.data.entity.Season;
import app.data.service.MatchService; import app.data.service.MatchService;
import app.data.service.MatchdayService; import app.data.service.MatchdayService;
import app.data.service.SeasonService; import app.data.service.SeasonService;
import com.vaadin.flow.component.*;
import com.vaadin.flow.component.button.Button;
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.AbstractField;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.select.Select; import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.router.BeforeEvent; import com.vaadin.flow.router.BeforeEvent;
import com.vaadin.flow.router.HasUrlParameter; import com.vaadin.flow.router.HasUrlParameter;
import com.vaadin.flow.router.WildcardParameter; import com.vaadin.flow.router.WildcardParameter;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class Navigation implements HasUrlParameter<String> { public class Navigation implements HasUrlParameter<String> {
// TODO: show dropdown menus also for invalid URLs (with content that fits the situation)
private final String route;
private final boolean onlyMatchdaysWithActivity;
private final List<Runnable> runnablesToBeRunAfterSeasonSelection = new ArrayList<>();
private final List<Runnable> runnablesToBeRunAfterMatchdaySelection = new ArrayList<>();
private final List<Runnable> runnablesToBeRunAfterMatchSelection = new ArrayList<>();
private String route;
private boolean onlyMatchdaysWithActivity;
private final List<Runnable> runnablesToBeRunAfterSelection = new ArrayList<>();
private final SeasonService seasonService; private final SeasonService seasonService;
private final MatchdayService matchdayService; private final MatchdayService matchdayService;
@ -45,113 +42,148 @@ public class Navigation implements HasUrlParameter<String> {
private final Select<Matchday> matchdaySelect = new Select<>(); private final Select<Matchday> matchdaySelect = new Select<>();
private final Select<Match> matchSelect = new Select<>(); private final Select<Match> matchSelect = new Select<>();
private String seasonParam;
private String matchdayParam;
private String matchParam;
private boolean autoselectSeason = false;
private boolean autoselectMatchday = false;
private boolean autoselectMatch = false;
private boolean seasonEnabled = false;
private boolean matchdayEnabled = false;
private boolean matchEnabled = false;
private final Label invalidUrlLabel = new Label();
private final Button prevMatchdayButton = new Button(new Icon(VaadinIcon.ARROW_LEFT));
private final Button nextMatchdayButton = new Button(new Icon(VaadinIcon.ARROW_RIGHT));
private final ValidationLabel validationLabel = new ValidationLabel();
public Navigation(String route,
@Autowired SeasonService seasonService,
public Navigation(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService, @Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) { @Autowired MatchService matchService) {
this(route, seasonService, matchdayService, matchService, false);
}
public Navigation(String route,
@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService,
boolean onlyMatchdaysWithActivity) {
this.route = route;
this.seasonService = seasonService; this.seasonService = seasonService;
this.matchdayService = matchdayService; this.matchdayService = matchdayService;
this.matchService = matchService; this.matchService = matchService;
this.onlyMatchdaysWithActivity = onlyMatchdaysWithActivity;
fillSeasonSelectWithData(); fillSeasonSelectWithData();
seasonSelect.addValueChangeListener(seasonSelectValueChangeListener()); seasonSelect.addValueChangeListener(seasonSelectValueChangeListener());
matchdaySelect.addValueChangeListener(matchdaySelectValueChangeListener()); matchdaySelect.addValueChangeListener(matchdaySelectValueChangeListener());
matchSelect.addValueChangeListener(matchSelectValueChangeListener()); matchSelect.addValueChangeListener(matchSelectValueChangeListener());
} }
public void setAutoselectSeason(boolean autoselectSeason) {
this.autoselectSeason = autoselectSeason;
public void setRoute(String route) {
this.route = route;
}
public void setOnlyMatchdaysWithActivity(boolean onlyMatchdaysWithActivity) {
this.onlyMatchdaysWithActivity = onlyMatchdaysWithActivity;
}
public void setSeasonEnabled(boolean seasonEnabled) {
this.seasonEnabled = seasonEnabled;
}
public void setMatchdayEnabled(boolean matchdayEnabled) {
this.matchdayEnabled = matchdayEnabled;
}
public void setMatchEnabled(boolean matchEnabled) {
this.matchEnabled = matchEnabled;
}
public void addRunnableToBeRunAfterSelection(Runnable runnable) {
runnablesToBeRunAfterSelection.add(runnable);
}
public boolean isSeasonEnabled() {
return seasonEnabled;
} }
public void setAutoselectMatchday(boolean autoselectMatchday) {
this.autoselectMatchday = autoselectMatchday;
public boolean isMatchdayEnabled() {
return matchdayEnabled;
} }
public void setAutoselectMatch(boolean autoselectMatch) {
this.autoselectMatch = autoselectMatch;
public boolean isMatchEnabled() {
return matchEnabled;
}
private String getRoute() {
if (route != null) return route;
throw new IllegalStateException("Route must be set!");
} }
private void updateUrl() { private void updateUrl() {
String seasonParam = null;
String matchdayParam = null;
String matchParam = null;
if (seasonEnabled) seasonParam = seasonSelect.getValue().toString();
if (matchdayEnabled) matchdayParam = matchdaySelect.getValue().toString();
if (matchEnabled) matchParam = matchdaySelect.getValue().toString();
String params = NavigationUtils.getWildcardParam(seasonParam, matchdayParam, matchParam); String params = NavigationUtils.getWildcardParam(seasonParam, matchdayParam, matchParam);
UI.getCurrent().getPage().getHistory().pushState(null, String.format("%s/%s", route, params));
UI.getCurrent().getPage().getHistory().pushState(null, String.format("%s/%s", getRoute(), params));
} }
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Season>, Season>> seasonSelectValueChangeListener() { private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Season>, Season>> seasonSelectValueChangeListener() {
return seasonChangeEvent -> {
Season newSeason = seasonChangeEvent.getValue();
if (newSeason != null) {
String seasonParam = newSeason.toString();
String matchdayParam = null;
Matchday matchdayInNewSeason = null;
Matchday matchdayInOldSeason = matchdaySelect.getValue();
if (matchdayInOldSeason != null) {
matchdayParam = matchdayInOldSeason.toString();
matchdayInNewSeason = getMatchdayFromParam(matchdayParam, newSeason);
}
matchdayParam = matchdayInNewSeason == null ? "1" : matchdayParam;
this.seasonParam = seasonParam;
this.matchdayParam = matchdayParam;
this.matchParam = null;
return event -> {
if (!seasonEnabled) throw new IllegalStateException("Cannot select season when it is not enabled!");
if (matchdayEnabled) {
fillMatchdaySelectWithData(event.getValue());
autoselectMatchday();
return;
} }
runnablesToBeRunAfterSeasonSelection.forEach(Runnable::run);
updateUrl();
doPostSelectionStuff();
}; };
} }
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Matchday>, Matchday>> matchdaySelectValueChangeListener() { private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Matchday>, Matchday>> matchdaySelectValueChangeListener() {
return matchdayChangeEvent -> {
Matchday matchday = matchdayChangeEvent.getValue();
if (matchday == null) {
matchParam = null;
} else {
matchdayParam = matchday.toString();
fillMatchSelectWithData(matchday);
return event -> {
if (!matchdayEnabled) throw new IllegalStateException("Cannot select matchday when it is not enabled!");
if (matchEnabled) {
fillMatchSelectWithData(event.getValue());
autoselectMatch();
return;
} }
configureButtons();
matchSelect.setValue(null);
runnablesToBeRunAfterMatchdaySelection.forEach(Runnable::run);
updateUrl();
doPostSelectionStuff();
}; };
} }
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Match>, Match>> matchSelectValueChangeListener() { private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Match>, Match>> matchSelectValueChangeListener() {
return matchChangeEvent -> {
Match match = matchChangeEvent.getValue();
if (match == null) {
matchParam = null;
} else {
matchParam = match.toString();
}
runnablesToBeRunAfterMatchSelection.forEach(Runnable::run);
updateUrl();
return event -> {
if (!matchEnabled) throw new IllegalStateException("Cannot select match when it is not enabled!");
doPostSelectionStuff();
}; };
} }
private void doPostSelectionStuff() {
validationLabel.setValid(true);
updateUrl();
runnablesToBeRunAfterSelection.forEach(Runnable::run);
}
private void autoselectSeason() {
if (!seasonEnabled) throw new IllegalStateException("This method should not be called when season is not enabled!");
if (seasonList.isEmpty()) {
validationLabel.setText("No Seasons in List!");
validationLabel.setValid(false);
return;
}
seasonSelect.setValue(seasonList.get(seasonList.size() - 1));
}
private void autoselectMatchday() { // TODO: add date stuff and choose depending on date instead!
if (!matchdayEnabled) throw new IllegalStateException("This method should not be called when matchday is not enabled!");
if (matchdayList.isEmpty()) {
validationLabel.setText("No Matchdays in List!");
validationLabel.setValid(false);
return;
}
Matchday matchdayToSelect = matchdayList.get(0);
for (Matchday matchday : matchdayList) if (matchdayService.hasActivity(matchday)) matchdayToSelect = matchday;
matchdaySelect.setValue(matchdayToSelect);
}
private void autoselectMatch() {
if (!matchEnabled) throw new IllegalStateException("This method should not be called when match is not enabled!");
if (matchList.isEmpty()) {
validationLabel.setText("No Matches in List!");
validationLabel.setValid(false);
return;
}
matchSelect.setValue(matchList.get(0));
}
private void fillSeasonSelectWithData() { private void fillSeasonSelectWithData() {
seasonList.clear(); seasonList.clear();
seasonList.addAll(seasonService.getAllSeasonsSorted()); seasonList.addAll(seasonService.getAllSeasonsSorted());
@ -172,212 +204,82 @@ public class Navigation implements HasUrlParameter<String> {
matchSelect.setItems(matchList); matchSelect.setItems(matchList);
} }
private boolean isMatchDayParamValid(@NonNull String matchdayParam) {
return matchdayList.stream().anyMatch(matchday -> matchdayParam.equals(matchday.toString()));
}
@Override @Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) { public void setParameter(BeforeEvent event, @WildcardParameter String param) {
Map<UrlParameterType, String> map = NavigationUtils.getParameterMap(param);
setParameter(map.get(UrlParameterType.SEASON), map.get(UrlParameterType.MATCHDAY), map.get(UrlParameterType.MATCH));
Map<UrlParameterType, Optional<String>> map = NavigationUtils.getParameterMap(param);
navigate(map.get(UrlParameterType.SEASON), map.get(UrlParameterType.MATCHDAY), map.get(UrlParameterType.MATCH));
} }
private boolean paramInvalid(@Nullable String param) {
return param == null || param.equals("");
}
private void navigate(Optional<String> seasonParam, Optional<String> matchdayParam, Optional<String> matchParam) {
if (!seasonEnabled) return;
Optional<Season> season = getSeasonFromParam(seasonParam);
if (season.isPresent()) seasonSelect.setValue(season.get());
else autoselectSeason();
private void noMatchFound(Season season, Matchday matchday) {
invalidUrlLabel.setText(String.format("No Match found in Matchday %s in Season %s!", matchday.toString(), season.toString()));
}
if (!matchdayEnabled) return;
Optional<Matchday> matchday = getMatchdayFromParam(matchdayParam);
if (matchday.isPresent()) matchdaySelect.setValue(matchday.get());
else autoselectMatchday();
private void matchFound(Match match) {
matchSelect.setValue(match);
if (!matchEnabled) return;
Optional<Match> match = getMatchFromParam(matchParam);
if (match.isPresent()) matchSelect.setValue(match.get());
else autoselectMatch();
} }
private void noMatchdayFound(Season season) {
invalidUrlLabel.setText(String.format("No Matchday found in Season %s!", season.toString()));
}
private void autoselectMatch(Season season, Matchday matchday) {
Optional<Match> firstMatch = matchService.getFirstMatch(matchday);
firstMatch.ifPresentOrElse(
this::matchFound,
() -> noMatchFound(season, matchday));
}
private void matchdayFound(Season season, Matchday matchday, String matchParam) {
matchdaySelect.setValue(matchday);
fillMatchSelectWithData(matchday);
if (paramInvalid(matchParam) && autoselectMatch) {
autoselectMatch(season, matchday);
private Optional<Season> getSeasonFromParam(Optional<String> seasonParam) {
if (seasonParam.isEmpty()) {
return Optional.empty();
} }
return seasonList.stream()
.filter(season -> season.toString().equals(seasonParam.get()))
.findFirst();
} }
private void noSeasonFound() {
invalidUrlLabel.setText("No Season found!");
}
private void autoselectMatchday(Season season, String matchParam) {
Optional<Matchday> latestMatchday = matchdayService.getLastMatchdayWithActivityOrElseFirstMatchday(season);
latestMatchday.ifPresentOrElse(
matchday -> matchdayFound(season, matchday, matchParam),
() -> noMatchdayFound(season));
}
private void seasonFound(Season season, String matchdayParam, String matchParam) {
seasonSelect.setValue(season);
fillMatchdaySelectWithData(season);
if (paramInvalid(matchdayParam) && autoselectMatchday) {
autoselectMatchday(season, matchParam);
private Optional<Matchday> getMatchdayFromParam(Optional<String> matchdayParam) {
if (matchdayParam.isEmpty()) {
return Optional.empty();
} }
return matchdayList.stream()
.filter(matchday -> matchday.toString().equals(matchdayParam.get()))
.findFirst();
} }
private void autoselectSeason(String matchdayParam, String matchParam) {
Optional<Season> latestSeason = seasonService.getLatestSeason();
latestSeason.ifPresentOrElse(
season -> seasonFound(season, matchdayParam, matchParam),
this::noSeasonFound);
}
private boolean autoselectIfNecessary(String seasonParam, String matchdayParam, String matchParam) {
if (paramInvalid(seasonParam) && autoselectSeason) {
autoselectSeason(matchdayParam, matchParam);
return true;
}
if (paramInvalid(matchdayParam) && autoselectMatchday) {
autoselectMatchday(seasonSelect.getValue(), matchParam);
return true;
}
if (paramInvalid(matchParam) && autoselectMatch) {
autoselectMatch(seasonSelect.getValue(), matchdaySelect.getValue());
return true;
private Optional<Match> getMatchFromParam(Optional<String> matchParam) {
if (matchParam.isEmpty()) {
return Optional.empty();
} }
return false;
return matchList.stream()
.filter(match -> match.toString().equals(matchParam.get()))
.findFirst();
} }
public void setParameter(String seasonParam, String matchdayParam, String matchParam) {
if (autoselectIfNecessary(seasonParam, matchdayParam, matchParam)) {
return;
}
Season season = getSeasonFromParam(seasonParam);
if (season != null) {
seasonSelect.setValue(season);
this.seasonParam = seasonParam;
fillMatchdaySelectWithData(season);
} else if (autoselectSeason) {
invalidUrlLabel.setText(String.format("Invalid URL! Season \"%s\" does not exist in the database!", seasonParam));
return;
}
Matchday matchday = getMatchdayFromParam(matchdayParam);
if (matchday != null) {
matchdaySelect.setValue(matchday);
this.matchdayParam = matchdayParam;
fillMatchSelectWithData(matchday);
configureButtons();
} else if (autoselectMatchday) {
String messageExtra = onlyMatchdaysWithActivity ? " or has no games played yet" : "";
invalidUrlLabel.setText(String.format("Invalid URL! Matchday \"%s\" in Season \"%s\" does not exist in the database%s!", matchdayParam, seasonParam, messageExtra));
return;
}
Match match = getMatchFromParam(matchParam);
if (match != null) {
matchSelect.setValue(match);
this.matchParam = matchParam;
} else if (autoselectMatch) {
invalidUrlLabel.setText(String.format("Invalid URL: Match \"%s\" in Matchday \"%s\" in Season \"%s\" does not exist in the database!", matchParam, matchdayParam, seasonParam));
}
}
@Nullable
private Season getSeasonFromParam(@Nullable String seasonParam) {
if (seasonParam == null) {
return null;
}
for (Season season : seasonList) {
if (seasonParam.equals(season.toString())) {
return season;
}
}
return null;
}
@Nullable
private Matchday getMatchdayFromParam(@Nullable String matchdayParam) {
return getMatchdayFromParam(matchdayParam, null);
}
@Nullable
private Matchday getMatchdayFromParam(@Nullable String matchdayParam, @Nullable Season season) {
if (matchdayParam == null) {
return null;
}
List<Matchday> matchdayList = season == null ? this.matchdayList : matchdayService.getMatchdaysSorted(season);
for (Matchday matchday : matchdayList) {
if (matchdayParam.equals(matchday.toString())) {
return matchday;
}
}
return null;
}
@Nullable
private Match getMatchFromParam(@Nullable String matchParam) {
if (matchParam == null) {
return null;
}
for (Match match : matchList) {
if (matchParam.equals(match.toString())) {
return match;
}
}
return null;
}
public void addRunnableToBeRunAfterSeasonSelection(Runnable runnable) {
runnablesToBeRunAfterSeasonSelection.add(runnable);
public ValidationLabel getValidationLabel() {
return validationLabel;
} }
public void addRunnableToBeRunAfterMatchdaySelection(Runnable runnable) {
runnablesToBeRunAfterMatchdaySelection.add(runnable);
public List<Season> getSeasonList() {
return seasonList;
} }
public void addRunnableToBeRunAfterMatchSelection(Runnable runnable) {
runnablesToBeRunAfterMatchSelection.add(runnable);
public List<Matchday> getMatchdayList() {
return matchdayList;
} }
private void configureButtons() {
prevMatchdayButton.setEnabled(isMatchDayParamValid(getPrevMatchdayParam()));
prevMatchdayButton.addClickListener(getButtonClickListener(getPrevMatchdayParam()));
nextMatchdayButton.setEnabled(isMatchDayParamValid(getNextMatchdayParam()));
nextMatchdayButton.addClickListener(getButtonClickListener(getNextMatchdayParam()));
public List<Match> getMatchList() {
return matchList;
} }
private ComponentEventListener<ClickEvent<Button>> getButtonClickListener(String matchdayParam) {
return buttonClickEvent -> matchdayList.stream()
.filter(matchday -> matchdayParam.equals(matchday.toString()))
.findFirst().ifPresent(matchdaySelect::setValue);
public Select<Season> getSeasonSelect() {
return seasonSelect;
} }
private String getPrevMatchdayParam() {
try {
return String.valueOf(Integer.parseInt(matchdayParam) - 1);
} catch (NumberFormatException e) {
return "";
}
public Select<Matchday> getMatchdaySelect() {
return matchdaySelect;
} }
private String getNextMatchdayParam() {
try {
return String.valueOf(Integer.parseInt(matchdayParam) + 1);
} catch (NumberFormatException e) {
return "";
}
public Select<Match> getMatchSelect() {
return matchSelect;
} }
public Optional<Matchday> getSelectedMatchday() { public Optional<Matchday> getSelectedMatchday() {
@ -391,32 +293,4 @@ public class Navigation implements HasUrlParameter<String> {
public Optional<Match> getSelectedMatch() { public Optional<Match> getSelectedMatch() {
return matchSelect.getOptionalValue(); return matchSelect.getOptionalValue();
} }
public Button getPrevMatchdayButton() {
return prevMatchdayButton;
}
public Button getNextMatchdayButton() {
return nextMatchdayButton;
}
public Label getInvalidUrlLabel() {
return invalidUrlLabel;
}
public Select<Season> getSeasonSelect() {
return seasonSelect;
}
public Select<Matchday> getMatchdaySelect() {
return matchdaySelect;
}
public Select<Match> getMatchSelect() {
return matchSelect;
}
public void selectMatch(Match match) {
matchSelect.setValue(match);
}
} }

+ 11
- 5
src/main/java/app/navigation/NavigationUtils.java View File

@ -5,22 +5,28 @@ import org.springframework.lang.NonNull;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
public class NavigationUtils { public class NavigationUtils {
public static Map<UrlParameterType, String> getParameterMap(@WildcardParameter String param) {
Map<UrlParameterType, String> map = new HashMap<>();
@NonNull
public static Map<UrlParameterType, Optional<String>> getParameterMap(@WildcardParameter String param) {
Map<UrlParameterType, Optional<String>> map = new HashMap<>();
String[] params = param.split("/"); String[] params = param.split("/");
switch (params.length) { switch (params.length) {
case 3: case 3:
map.put(UrlParameterType.MATCH, params[2]);
map.put(UrlParameterType.MATCH, Optional.of(params[2]));
case 2: case 2:
map.put(UrlParameterType.MATCHDAY, params[1]);
map.put(UrlParameterType.MATCHDAY, Optional.of(params[1]));
case 1: case 1:
map.put(UrlParameterType.SEASON, params[0]);
map.put(UrlParameterType.SEASON, Optional.of(params[0]));
default: default:
break; break;
} }
map.putIfAbsent(UrlParameterType.MATCH, Optional.empty());
map.putIfAbsent(UrlParameterType.MATCHDAY, Optional.empty());
map.putIfAbsent(UrlParameterType.SEASON, Optional.empty());
return map; return map;
} }


src/main/java/app/views/about/AboutView.java → src/main/java/app/views/example/about/AboutView.java View File

@ -1,4 +1,4 @@
package app.views.about;
package app.views.example.about;
import app.data.service.GameService; import app.data.service.GameService;
import app.views.main.MainView; import app.views.main.MainView;
@ -8,7 +8,7 @@ import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
@CssImport("app/views/about/about-view.css")
@CssImport("app/views/example/about/about-view.css")
@Route(value = "about", layout = MainView.class) @Route(value = "about", layout = MainView.class)
@PageTitle("About") @PageTitle("About")
public class AboutView extends Div { public class AboutView extends Div {

src/main/java/app/views/addressform/AddressFormView.java → src/main/java/app/views/example/addressform/AddressFormView.java View File

@ -1,4 +1,4 @@
package app.views.addressform;
package app.views.example.addressform;
import app.data.entity.SampleAddress; import app.data.entity.SampleAddress;
import app.data.service.SampleAddressService; import app.data.service.SampleAddressService;
@ -18,7 +18,7 @@ import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
@CssImport("app/views/addressform/address-form-view.css")
@CssImport("app/views/example/addressform/address-form-view.css")
@Route(value = "address-form", layout = MainView.class) @Route(value = "address-form", layout = MainView.class)
@PageTitle("Address Form") @PageTitle("Address Form")
public class AddressFormView extends Div { public class AddressFormView extends Div {

src/main/java/app/views/cardlist/CardListView.java → src/main/java/app/views/example/cardlist/CardListView.java View File

@ -1,4 +1,4 @@
package app.views.cardlist;
package app.views.example.cardlist;
import app.views.main.MainView; import app.views.main.MainView;
import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.dependency.CssImport;
@ -18,7 +18,7 @@ import com.vaadin.flow.router.Route;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@CssImport("app/views/cardlist/card-list-view.css")
@CssImport("app/views/example/cardlist/card-list-view.css")
@Route(value = "card-list", layout = MainView.class) @Route(value = "card-list", layout = MainView.class)
@PageTitle("Card List") @PageTitle("Card List")
public class CardListView extends Div implements AfterNavigationObserver { public class CardListView extends Div implements AfterNavigationObserver {

src/main/java/app/views/cardlist/Person.java → src/main/java/app/views/example/cardlist/Person.java View File

@ -1,4 +1,4 @@
package app.views.cardlist;
package app.views.example.cardlist;
public class Person { public class Person {

src/main/java/app/views/creditcardform/CreditCardFormView.java → src/main/java/app/views/example/creditcardform/CreditCardFormView.java View File

@ -1,4 +1,4 @@
package app.views.creditcardform;
package app.views.example.creditcardform;
import app.views.main.MainView; import app.views.main.MainView;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
@ -17,7 +17,7 @@ import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
@CssImport("app/views/creditcardform/credit-card-form-view.css")
@CssImport("app/views/example/creditcardform/credit-card-form-view.css")
@Route(value = "credit-card-form", layout = MainView.class) @Route(value = "credit-card-form", layout = MainView.class)
@PageTitle("Credit Card Form") @PageTitle("Credit Card Form")
public class CreditCardFormView extends Div { public class CreditCardFormView extends Div {

src/main/java/app/views/helloworld/HelloWorldView.java → src/main/java/app/views/example/helloworld/HelloWorldView.java View File

@ -1,4 +1,4 @@
package app.views.helloworld;
package app.views.example.helloworld;
import app.views.main.MainView; import app.views.main.MainView;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
@ -9,7 +9,7 @@ import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
@CssImport("app/views/helloworld/hello-world-view.css")
@CssImport("app/views/example/helloworld/hello-world-view.css")
@Route(value = "hello", layout = MainView.class) @Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World") @PageTitle("Hello World")
public class HelloWorldView extends HorizontalLayout { public class HelloWorldView extends HorizontalLayout {

src/main/java/app/views/map/MapView.java → src/main/java/app/views/example/map/MapView.java View File

@ -1,4 +1,4 @@
package app.views.map;
package app.views.example.map;
import app.components.leafletmap.LeafletMap; import app.components.leafletmap.LeafletMap;
import app.views.main.MainView; import app.views.main.MainView;

src/main/java/app/views/masterdetail/MasterDetailView.java → src/main/java/app/views/example/masterdetail/MasterDetailView.java View File

@ -1,4 +1,4 @@
package app.views.masterdetail;
package app.views.example.masterdetail;
import app.data.entity.SamplePerson; import app.data.entity.SamplePerson;
import app.data.service.SamplePersonService; import app.data.service.SamplePersonService;
@ -29,7 +29,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@CssImport("app/views/masterdetail/master-detail-view.css")
@CssImport("app/views/example/masterdetail/master-detail-view.css")
@Route(value = "master-detail", layout = MainView.class) @Route(value = "master-detail", layout = MainView.class)
@PageTitle("Master-Detail") @PageTitle("Master-Detail")
public class MasterDetailView extends Div { public class MasterDetailView extends Div {

src/main/java/app/views/personform/PersonFormView.java → src/main/java/app/views/example/personform/PersonFormView.java View File

@ -1,4 +1,4 @@
package app.views.personform;
package app.views.example.personform;
import app.data.entity.SamplePerson; import app.data.entity.SamplePerson;
import app.data.service.SamplePersonService; import app.data.service.SamplePersonService;
@ -21,7 +21,7 @@ import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
@CssImport("app/views/personform/person-form-view.css")
@CssImport("app/views/example/personform/person-form-view.css")
@Route(value = "person-form", layout = MainView.class) @Route(value = "person-form", layout = MainView.class)
@PageTitle("Person Form") @PageTitle("Person Form")
public class PersonFormView extends Div { public class PersonFormView extends Div {

+ 7
- 5
src/main/java/app/views/main/MainView.java View File

@ -1,7 +1,7 @@
package app.views.main; package app.views.main;
import app.views.cardlist.CardListView;
import app.views.results.ResultsView;
import app.views.match.MatchView;
import app.views.matchday.MatchdayView;
import app.views.table.TableView; import app.views.table.TableView;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.ComponentUtil;
@ -40,8 +40,7 @@ public class MainView extends AppLayout {
// TODO: View for each match // TODO: View for each match
// TODO: View for adding match data // TODO: View for adding match data
// TODO: Handle database connection with environment variables // TODO: Handle database connection with environment variables
// TODO: make it look even more like chess.com (use darker colors etc.)
// TODO: add light theme like on chess.com
// TODO: add light theme
private final Tabs menu; private final Tabs menu;
private H1 viewTitle; private H1 viewTitle;
@ -51,6 +50,7 @@ public class MainView extends AppLayout {
addToNavbar(true, createHeaderContent()); addToNavbar(true, createHeaderContent());
menu = createMenu(); menu = createMenu();
addToDrawer(createDrawerContent(menu)); addToDrawer(createDrawerContent(menu));
} }
private Component createHeaderContent() { private Component createHeaderContent() {
@ -103,7 +103,9 @@ public class MainView extends AppLayout {
// createTab("Credit Card Form", CreditCardFormView.class), // createTab("Credit Card Form", CreditCardFormView.class),
// createTab("Map", MapView.class), // createTab("Map", MapView.class),
createTab("Table", TableView.class), createTab("Table", TableView.class),
createTab("Results", ResultsView.class)};
createTab("Matchday", MatchdayView.class),
createTab("Match", MatchView.class)
};
} }
private static Tab createTab(String text, Class<? extends Component> navigationTarget) { private static Tab createTab(String text, Class<? extends Component> navigationTarget) {


+ 58
- 0
src/main/java/app/views/match/MatchView.java View File

@ -0,0 +1,58 @@
package app.views.match;
import app.data.entity.Game;
import app.data.entity.Match;
import app.data.service.MatchService;
import app.data.service.MatchdayService;
import app.data.service.SeasonService;
import app.image.ImageService;
import app.navigation.Navigation;
import app.views.main.MainView;
import app.views.navigation.NavigationViewBase;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
@CssImport("app/views/match/match-view.css")
@Route(value = "match", layout = MainView.class)
@PageTitle("Schachliga DACH - Results - Matches")
public class MatchView extends NavigationViewBase {
private final List<Image> images = new ArrayList<>();
private final ImageService imageService;
public MatchView(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService,
@Autowired ImageService imageService) {
super(seasonService, matchdayService, matchService, true, true, true);
this.imageService = imageService;
this.navigation.setSeasonEnabled(true);
this.navigation.setMatchdayEnabled(true);
this.navigation.setMatchEnabled(true);
}
@Override
public String getRoute() {
return "match";
}
@Override
protected void configureContent() {
Match match = navigation.getSelectedMatch().orElseThrow();
removeAll();
for (Game game : match.getGames()) {
Image image = new Image(imageService.getVaadinImagePath(game).orElse(""), "image");
image.setWidth("30%");
add(image);
}
}
}

src/main/java/app/views/results/MatchdayView.java → src/main/java/app/views/matchday/MatchdayView.java View File

@ -1,13 +1,20 @@
package app.views.results;
package app.views.matchday;
import app.components.navigation.SeasonAndMatchdayNavigation;
import app.components.navigation.NavigationHeader;
import app.components.navigation.button.NextMatchdayButton;
import app.components.navigation.button.PrevMatchdayButton;
import app.data.bean.CalculatedMatch; import app.data.bean.CalculatedMatch;
import app.data.entity.Matchday; import app.data.entity.Matchday;
import app.data.service.MatchService; import app.data.service.MatchService;
import app.data.service.MatchdayService;
import app.data.service.SeasonService;
import app.navigation.Navigation; import app.navigation.Navigation;
import app.utils.StringUtils; import app.utils.StringUtils;
import app.utils.VaadinUtils; import app.utils.VaadinUtils;
import app.views.main.MainView;
import app.views.navigation.NavigationViewBase;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.grid.ColumnTextAlign; import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant; import com.vaadin.flow.component.grid.GridVariant;
@ -15,18 +22,20 @@ import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.selection.SelectionListener;
import com.vaadin.flow.function.ValueProvider; import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Optional; import java.util.Optional;
public class MatchdayView extends VerticalLayout {
@CssImport("app/views/matchday/matchday-view.css")
@Route(value = "matchday", layout = MainView.class)
@PageTitle("Schachliga DACH - Results - Matchdays")
public class MatchdayView extends NavigationViewBase {
private final MatchService matchService; private final MatchService matchService;
private final Navigation navigation;
private final VerticalLayout matchdayLayout = new VerticalLayout(); private final VerticalLayout matchdayLayout = new VerticalLayout();
private final Label matchdayHeader = new Label(); private final Label matchdayHeader = new Label();
private final Grid<CalculatedMatch> grid = new Grid<>(); private final Grid<CalculatedMatch> grid = new Grid<>();
@ -34,14 +43,20 @@ public class MatchdayView extends VerticalLayout {
private final Button prevButton; private final Button prevButton;
private final Button nextButton; private final Button nextButton;
public MatchdayView(Navigation navigation, @Autowired MatchService matchService) {
this.navigation = navigation;
this.navigation.addRunnableToBeRunAfterSeasonSelection(this::configureContent);
this.navigation.addRunnableToBeRunAfterMatchdaySelection(this::configureContent);
public MatchdayView(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) {
super(seasonService, matchdayService, matchService, true, true, false);
this.matchService = matchService; this.matchService = matchService;
prevButton = navigation.getPrevMatchdayButton();
nextButton = navigation.getNextMatchdayButton();
this.navigation.setSeasonEnabled(true);
this.navigation.setMatchdayEnabled(true);
prevButton = new PrevMatchdayButton(navigation);
nextButton = new NextMatchdayButton(navigation);
addClassName("matchday-view");
addClassName("content");
configureContentLayout(); configureContentLayout();
} }
@ -54,7 +69,7 @@ public class MatchdayView extends VerticalLayout {
setWidthFull(); setWidthFull();
setHeightFull(); setHeightFull();
setAlignItems(FlexComponent.Alignment.CENTER); setAlignItems(FlexComponent.Alignment.CENTER);
add(new SeasonAndMatchdayNavigation(navigation), matchdayLayout);
add(new NavigationHeader(navigation), matchdayLayout);
// TODO add background color for content // TODO add background color for content
matchdayHeader.addClassName("matchday_header"); // TODO: add dates matchdayHeader.addClassName("matchday_header"); // TODO: add dates
@ -66,6 +81,7 @@ public class MatchdayView extends VerticalLayout {
matchdayLayout.add(matchdayHeaderLayout, grid); matchdayLayout.add(matchdayHeaderLayout, grid);
matchdayLayout.setAlignItems(FlexComponent.Alignment.CENTER); matchdayLayout.setAlignItems(FlexComponent.Alignment.CENTER);
matchdayLayout.setWidth(""); matchdayLayout.setWidth("");
matchdayLayout.addClassName("wrapper");
Label headerPlayer1 = new Label("Player 1"); Label headerPlayer1 = new Label("Player 1");
headerPlayer1.addClassName("column_header"); headerPlayer1.addClassName("column_header");
@ -95,10 +111,10 @@ public class MatchdayView extends VerticalLayout {
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER, grid.addThemeVariants(GridVariant.LUMO_NO_BORDER,
GridVariant.LUMO_NO_ROW_BORDERS, GridVariant.LUMO_ROW_STRIPES); GridVariant.LUMO_NO_ROW_BORDERS, GridVariant.LUMO_ROW_STRIPES);
grid.addSelectionListener((SelectionListener<Grid<CalculatedMatch>, CalculatedMatch>) selectionEvent -> {
Optional<CalculatedMatch> calculatedMatch = selectionEvent.getFirstSelectedItem();
calculatedMatch.ifPresent(match -> navigation.selectMatch(match.getMatch()));
});
// grid.addSelectionListener((SelectionListener<Grid<CalculatedMatch>, CalculatedMatch>) selectionEvent -> {
// Optional<CalculatedMatch> calculatedMatch = selectionEvent.getFirstSelectedItem();
// calculatedMatch.ifPresent(match -> navigation.selectMatch(match.getMatch()));
// });
} }
private String getResultString(CalculatedMatch match) { private String getResultString(CalculatedMatch match) {
@ -110,6 +126,7 @@ public class MatchdayView extends VerticalLayout {
// CONTENT // // CONTENT //
///////////// /////////////
@Override
protected void configureContent() { protected void configureContent() {
Optional<Matchday> selectedMatchday = navigation.getSelectedMatchday(); Optional<Matchday> selectedMatchday = navigation.getSelectedMatchday();
selectedMatchday.ifPresent(matchday -> { selectedMatchday.ifPresent(matchday -> {
@ -117,4 +134,9 @@ public class MatchdayView extends VerticalLayout {
grid.setItems(matchService.getCalculatedMatches(matchday)); grid.setItems(matchService.getCalculatedMatches(matchday));
}); });
} }
@Override
public String getRoute() {
return "matchday";
}
} }

+ 54
- 0
src/main/java/app/views/navigation/NavigationViewBase.java View File

@ -0,0 +1,54 @@
package app.views.navigation;
import app.components.navigation.NavigationHeader;
import app.data.service.MatchService;
import app.data.service.MatchdayService;
import app.data.service.SeasonService;
import app.navigation.Navigation;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEvent;
import com.vaadin.flow.router.HasUrlParameter;
import com.vaadin.flow.router.WildcardParameter;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class NavigationViewBase extends VerticalLayout implements HasUrlParameter<String> {
protected final Navigation navigation;
protected final NavigationHeader navigationHeader;
protected NavigationViewBase(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService,
boolean seasonEnabled,
boolean matchdayEnabled,
boolean matchEnabled) {
this.navigation = new Navigation(seasonService, matchdayService, matchService);
this.navigationHeader = new NavigationHeader(navigation);
navigation.setRoute(getRoute());
navigation.setSeasonEnabled(seasonEnabled);
navigation.setMatchdayEnabled(matchdayEnabled);
navigation.setMatchEnabled(matchEnabled);
add(navigationHeader);
setAlignItems(FlexComponent.Alignment.CENTER);
navigation.addRunnableToBeRunAfterSelection(this::configureContent);
}
protected abstract String getRoute();
protected abstract void configureContent();
@Override
public void removeAll() {
super.removeAll();
add(navigationHeader);
}
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
navigation.setParameter(event, param);
}
}

+ 0
- 66
src/main/java/app/views/results/MatchView.java View File

@ -1,66 +0,0 @@
package app.views.results;
import app.data.entity.Game;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Image;
import app.data.entity.Match;
import app.image.ImageService;
import app.navigation.Navigation;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MatchView extends VerticalLayout {
private final ResultsView parent;
private final Navigation navigation;
private final List<Image> images = new ArrayList<>();
private final ImageService imageService;
// private final ChessComService chessComService;
// private final PlayerService playerService;
// public ResultsViewRight(@Autowired ChessComService chessComService, @Autowired PlayerService playerService) {
public MatchView(Navigation navigation, ResultsView resultsView, @Autowired ImageService imageService) {
this.parent = resultsView;
this.navigation = navigation;
this.imageService = imageService;
navigation.addRunnableToBeRunAfterMatchSelection(this::configureContent);
navigation.addRunnableToBeRunAfterMatchSelection(this::configureParentSplit);
// this.chessComService = chessComService;
// this.playerService = playerService;
}
private void configureParentSplit() {
navigation.getSelectedMatch().ifPresentOrElse(
match -> parent.enableSplit(),
parent::disableSplit
);
}
private void configureContent() {
Match match = navigation.getSelectedMatch().orElseThrow();
removeAll();
for (Game game : match.getGames()) {
Image image = new Image(imageService.getVaadinImagePath(game).orElse(""), "image");
// Image img = new Image()
// image.setWidth(200, Unit.PIXELS);
// image.setHeight(200, Unit.PIXELS);
image.setWidth("30%");
// image.setHeight("30%");
add(image);
}
//
// images.addAll(match.getGames().stream()
// .map(game -> new Image(imageService.getImagePath(game).orElse(""), "app/image"))
// .collect(Collectors.toList()));
// images.forEach(this::add);
}
}

+ 0
- 72
src/main/java/app/views/results/ResultsView.java View File

@ -1,72 +0,0 @@
package app.views.results;
import app.views.main.MainView;
import app.data.service.*;
import app.image.ImageService;
import app.navigation.Navigation;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.splitlayout.SplitLayout;
import com.vaadin.flow.router.*;
import org.springframework.beans.factory.annotation.Autowired;
@CssImport("app/views/results/results-view.css")
@Route(value = "results", layout = MainView.class)
@RouteAlias(value = "", layout = MainView.class)
@PageTitle("Schachliga DACH - Results")
public class ResultsView extends Div implements HasUrlParameter<String> {
private final SplitLayout splitLayout = new SplitLayout();
private final Navigation navigation;
private final MatchdayView matchdayView;
private final MatchView matchView;
public ResultsView(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService,
@Autowired ImageService imageService,
@Autowired ChessComService chessComService,
@Autowired PlayerService playerService) {
this.navigation = new Navigation("results", seasonService, matchdayService, matchService);
this.navigation.setAutoselectSeason(true);
this.navigation.setAutoselectMatchday(true);
this.matchdayView = new MatchdayView(navigation, matchService);
this.matchView = new MatchView(navigation, this, imageService);
addClassName("results-view");
configureLayout();
disableSplit();
// enableSplit();
}
public void enableSplit() {
removeAll();
add(splitLayout);
splitLayout.addToPrimary(matchdayView);
splitLayout.addToSecondary(matchView);
splitLayout.setWidthFull();
splitLayout.setHeightFull();
splitLayout.setSplitterPosition(50);
}
public void disableSplit() {
removeAll();
add(matchdayView);
matchdayView.setWidthFull();
matchdayView.setHeightFull();
}
private void configureLayout() {
setWidthFull();
setHeightFull();
}
@Override
public void setParameter(BeforeEvent beforeEvent, @WildcardParameter String param) {
navigation.setParameter(beforeEvent, param);
}
}

+ 31
- 26
src/main/java/app/views/table/TableView.java View File

@ -1,6 +1,7 @@
package app.views.table; package app.views.table;
import app.components.navigation.SeasonAndMatchdayNavigation;
import app.components.label.ValidationLabel;
import app.components.navigation.NavigationHeader;
import app.data.bean.PlayerForTable; import app.data.bean.PlayerForTable;
import app.data.service.MatchService; import app.data.service.MatchService;
import app.data.service.MatchdayService; import app.data.service.MatchdayService;
@ -10,14 +11,15 @@ import app.utils.StringUtils;
import app.utils.VaadinUtils; import app.utils.VaadinUtils;
import app.navigation.Navigation; import app.navigation.Navigation;
import app.views.main.MainView; import app.views.main.MainView;
import app.views.navigation.NavigationViewBase;
import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.grid.ColumnTextAlign; import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant; import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label; import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.function.ValueProvider; import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.router.*; import com.vaadin.flow.router.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -26,27 +28,28 @@ import java.util.NoSuchElementException;
@CssImport("app/views/table/table-view.css") @CssImport("app/views/table/table-view.css")
@Route(value = "table", layout = MainView.class) @Route(value = "table", layout = MainView.class)
@RouteAlias(value = "", layout = MainView.class)
@PageTitle("Schachliga DACH - Table") @PageTitle("Schachliga DACH - Table")
public class TableView extends VerticalLayout implements HasUrlParameter<String> {
public class TableView extends NavigationViewBase {
private final PlayerService playerService; private final PlayerService playerService;
private final Navigation navigation;
private final Label invalidUrlLabel;
private final Grid<PlayerForTable> grid = new Grid<>(); private final Grid<PlayerForTable> grid = new Grid<>();
public TableView(@Autowired SeasonService seasonService, @Autowired MatchdayService matchdayService, @Autowired MatchService matchService, @Autowired PlayerService playerService) {
public TableView(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService,
@Autowired PlayerService playerService) {
super(seasonService, matchdayService, matchService, true, true, false);
this.playerService = playerService; this.playerService = playerService;
this.navigation = new Navigation("table", seasonService, matchdayService, matchService, true);
this.navigation.setAutoselectSeason(true);
this.navigation.setAutoselectMatchday(true);
this.navigation.addRunnableToBeRunAfterSeasonSelection(this::configureContent);
this.navigation.addRunnableToBeRunAfterMatchdaySelection(this::configureContent);
this.invalidUrlLabel = navigation.getInvalidUrlLabel();
// this.navigation = new Navigation("table", seasonService, matchdayService, matchService, true);
this.navigation.setOnlyMatchdaysWithActivity(true);
this.navigation.setSeasonEnabled(true);
this.navigation.setMatchdayEnabled(true);
addClassName("table-view"); addClassName("table-view");
addClassName("content");
configureLayout(); configureLayout();
} }
@ -55,11 +58,10 @@ public class TableView extends VerticalLayout implements HasUrlParameter<String>
//////////// ////////////
private void configureLayout() { private void configureLayout() {
setWidthFull();
setHeightFull();
setAlignItems(FlexComponent.Alignment.CENTER);
Div gridWrapper = new Div(grid);
gridWrapper.addClassName("grid-wrapper");
add(new SeasonAndMatchdayNavigation(navigation), new HorizontalLayout(grid));
add(new NavigationHeader(navigation), new HorizontalLayout(gridWrapper));
configureGrid(); configureGrid();
} }
@ -69,15 +71,15 @@ public class TableView extends VerticalLayout implements HasUrlParameter<String>
// TODO: add diff to last matchday // TODO: add diff to last matchday
Label headerPlace = new Label("Place"); Label headerPlace = new Label("Place");
headerPlace.addClassName("important_table_column_header");
headerPlace.addClassName("important-table-column-header");
Label headerPlayer = new Label("Player"); Label headerPlayer = new Label("Player");
headerPlayer.addClassName("important_table_column_header");
headerPlayer.addClassName("important-table-column-header");
Label headerMatchesPlayed = new Label("Played"); Label headerMatchesPlayed = new Label("Played");
Label headerMatchPoints = new Label("Points"); Label headerMatchPoints = new Label("Points");
headerMatchPoints.addClassName("important_table_column_header");
headerMatchPoints.addClassName("important-table-column-header");
Label headerWon = new Label("W"); Label headerWon = new Label("W");
@ -92,6 +94,7 @@ public class TableView extends VerticalLayout implements HasUrlParameter<String>
grid.addColumn(VaadinUtils.getBoldStringRenderer(PlayerForTable::getPlaceString)) grid.addColumn(VaadinUtils.getBoldStringRenderer(PlayerForTable::getPlaceString))
.setHeader(headerPlace) .setHeader(headerPlace)
.setTextAlign(ColumnTextAlign.CENTER) .setTextAlign(ColumnTextAlign.CENTER)
// .setClassNameGenerator(playerForTable -> "leftmost-column-cell")
.setWidth("5em"); .setWidth("5em");
grid.addColumn(VaadinUtils.getPlayerRenderer(PlayerForTable::getPlayer)) grid.addColumn(VaadinUtils.getPlayerRenderer(PlayerForTable::getPlayer))
@ -149,16 +152,18 @@ public class TableView extends VerticalLayout implements HasUrlParameter<String>
// CONTENT // // CONTENT //
///////////// /////////////
@Override
public String getRoute() {
return "table";
}
@Override
protected void configureContent() { protected void configureContent() {
try { try {
grid.setItems(playerService.getPlayersForTable(navigation.getSelectedMatchday().orElseThrow())); grid.setItems(playerService.getPlayersForTable(navigation.getSelectedMatchday().orElseThrow()));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
invalidUrlLabel.setText("No season and/or matchday selected! Please select them above.");
removeAll();
add(navigation.getValidationLabel());
} }
} }
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
navigation.setParameter(event, param);
}
} }

Loading…
Cancel
Save