diff --git a/frontend/app/views/about/about-view.css b/frontend/app/views/example/about/about-view.css similarity index 100% rename from frontend/app/views/about/about-view.css rename to frontend/app/views/example/about/about-view.css diff --git a/frontend/app/views/addressform/address-form-view.css b/frontend/app/views/example/addressform/address-form-view.css similarity index 100% rename from frontend/app/views/addressform/address-form-view.css rename to frontend/app/views/example/addressform/address-form-view.css diff --git a/frontend/app/views/cardlist/card-list-view.css b/frontend/app/views/example/cardlist/card-list-view.css similarity index 100% rename from frontend/app/views/cardlist/card-list-view.css rename to frontend/app/views/example/cardlist/card-list-view.css diff --git a/frontend/app/views/creditcardform/credit-card-form-view.css b/frontend/app/views/example/creditcardform/credit-card-form-view.css similarity index 100% rename from frontend/app/views/creditcardform/credit-card-form-view.css rename to frontend/app/views/example/creditcardform/credit-card-form-view.css diff --git a/frontend/app/views/helloworld/hello-world-view.css b/frontend/app/views/example/helloworld/hello-world-view.css similarity index 100% rename from frontend/app/views/helloworld/hello-world-view.css rename to frontend/app/views/example/helloworld/hello-world-view.css diff --git a/frontend/app/views/map/map-view.css b/frontend/app/views/example/map/map-view.css similarity index 100% rename from frontend/app/views/map/map-view.css rename to frontend/app/views/example/map/map-view.css diff --git a/frontend/app/views/masterdetail/master-detail-view.css b/frontend/app/views/example/masterdetail/master-detail-view.css similarity index 100% rename from frontend/app/views/masterdetail/master-detail-view.css rename to frontend/app/views/example/masterdetail/master-detail-view.css diff --git a/frontend/app/views/personform/person-form-view.css b/frontend/app/views/example/personform/person-form-view.css similarity index 100% rename from frontend/app/views/personform/person-form-view.css rename to frontend/app/views/example/personform/person-form-view.css diff --git a/frontend/app/views/main/main-view.css b/frontend/app/views/main/main-view.css index 14c6eed..a355ce4 100644 --- a/frontend/app/views/main/main-view.css +++ b/frontend/app/views/main/main-view.css @@ -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 { height: var(--lumo-size-xl); box-shadow: var(--lumo-box-shadow-s); diff --git a/frontend/app/views/match/match-view.css b/frontend/app/views/match/match-view.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/app/views/results/results-view.css b/frontend/app/views/matchday/matchday-view.css similarity index 60% rename from frontend/app/views/results/results-view.css rename to frontend/app/views/matchday/matchday-view.css index 42ea6ed..e0585be 100644 --- a/frontend/app/views/results/results-view.css +++ b/frontend/app/views/matchday/matchday-view.css @@ -1,13 +1,9 @@ -.about-view { - display: block; -} - -.column_header { +.matchday-view .column_header { font-weight: bold; font-size: large; } -.matchday_header { +.matchday-view .matchday_header { font-weight: bolder; font-size: x-large; text-align: center; diff --git a/frontend/app/views/table/table-view.css b/frontend/app/views/table/table-view.css index 8143403..d045ea9 100644 --- a/frontend/app/views/table/table-view.css +++ b/frontend/app/views/table/table-view.css @@ -1,8 +1,4 @@ -.about-view { - display: block; -} - -.important_table_column_header { +.table-view .important-table-column-header { font-weight: bold; font-size: large; -} +} \ No newline at end of file diff --git a/frontend/styles/shared-styles.js b/frontend/styles/shared-styles.js index 4bc9f36..445e8ef 100644 --- a/frontend/styles/shared-styles.js +++ b/frontend/styles/shared-styles.js @@ -8,38 +8,44 @@ $_documentContainer.innerHTML = ` - - `; document.head.appendChild($_documentContainer.content); diff --git a/src/main/java/app/components/label/ValidationLabel.java b/src/main/java/app/components/label/ValidationLabel.java new file mode 100644 index 0000000..4992c52 --- /dev/null +++ b/src/main/java/app/components/label/ValidationLabel.java @@ -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; + } +} diff --git a/src/main/java/app/components/navigation/NavigationHeader.java b/src/main/java/app/components/navigation/NavigationHeader.java new file mode 100644 index 0000000..7d92066 --- /dev/null +++ b/src/main/java/app/components/navigation/NavigationHeader.java @@ -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()); + } + } +} diff --git a/src/main/java/app/components/navigation/SeasonAndMatchdayNavigation.java b/src/main/java/app/components/navigation/SeasonAndMatchdayNavigation.java deleted file mode 100644 index 8171b2f..0000000 --- a/src/main/java/app/components/navigation/SeasonAndMatchdayNavigation.java +++ /dev/null @@ -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()); - } -} diff --git a/src/main/java/app/components/navigation/button/ButtonUtils.java b/src/main/java/app/components/navigation/button/ButtonUtils.java new file mode 100644 index 0000000..3f03970 --- /dev/null +++ b/src/main/java/app/components/navigation/button/ButtonUtils.java @@ -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(); + } +} diff --git a/src/main/java/app/components/navigation/button/NextMatchdayButton.java b/src/main/java/app/components/navigation/button/NextMatchdayButton.java new file mode 100644 index 0000000..7b6d280 --- /dev/null +++ b/src/main/java/app/components/navigation/button/NextMatchdayButton.java @@ -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 nextMatchday = getNextMatchday(); + setEnabled(nextMatchday.isPresent()); + addClickListener(event -> nextMatchday.ifPresent(matchday -> navigation.getMatchdaySelect().setValue(matchday))); + } + + private Optional 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(); + } +} diff --git a/src/main/java/app/components/navigation/button/PrevMatchdayButton.java b/src/main/java/app/components/navigation/button/PrevMatchdayButton.java new file mode 100644 index 0000000..df1af78 --- /dev/null +++ b/src/main/java/app/components/navigation/button/PrevMatchdayButton.java @@ -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 prevMatchday = getPrevMatchday(); + setEnabled(prevMatchday.isPresent()); + addClickListener(event -> prevMatchday.ifPresent(matchday -> navigation.getMatchdaySelect().setValue(matchday))); + } + + private Optional getPrevMatchday() { + int index = ButtonUtils.getMatchdayIndex(navigation); + if (index > 0) return Optional.ofNullable(navigation.getMatchdayList().get(index - 1)); + return Optional.empty(); + } +} diff --git a/src/main/java/app/data/service/ChessComService.java b/src/main/java/app/data/service/ChessComService.java index 80ce226..8c8ea25 100644 --- a/src/main/java/app/data/service/ChessComService.java +++ b/src/main/java/app/data/service/ChessComService.java @@ -10,13 +10,12 @@ import app.data.entity.Player; import app.utils.ChessComUtils; import app.utils.HttpUtils; import com.google.gson.Gson; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; @Service public class ChessComService { @@ -117,26 +116,4 @@ public class ChessComService { } 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 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, Stream>) -// chessComArchive -> chessComArchive.stream() -// .flatMap(archive -> archive.getGames().stream())) -// .filter(chessComGame -> chessComGame.getUrl().equals(game.getGameInfo().getUrl())) -// .findFirst(); -// } } diff --git a/src/main/java/app/navigation/Navigation.java b/src/main/java/app/navigation/Navigation.java index eb21db6..b2aa912 100644 --- a/src/main/java/app/navigation/Navigation.java +++ b/src/main/java/app/navigation/Navigation.java @@ -1,37 +1,34 @@ package app.navigation; +import app.components.label.ValidationLabel; import app.data.entity.Match; import app.data.entity.Matchday; import app.data.entity.Season; import app.data.service.MatchService; import app.data.service.MatchdayService; 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.router.BeforeEvent; import com.vaadin.flow.router.HasUrlParameter; import com.vaadin.flow.router.WildcardParameter; 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.List; import java.util.Map; import java.util.Optional; +@SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class Navigation implements HasUrlParameter { - // 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 runnablesToBeRunAfterSeasonSelection = new ArrayList<>(); - private final List runnablesToBeRunAfterMatchdaySelection = new ArrayList<>(); - private final List runnablesToBeRunAfterMatchSelection = new ArrayList<>(); + private String route; + private boolean onlyMatchdaysWithActivity; + + private final List runnablesToBeRunAfterSelection = new ArrayList<>(); private final SeasonService seasonService; private final MatchdayService matchdayService; @@ -45,113 +42,148 @@ public class Navigation implements HasUrlParameter { private final Select matchdaySelect = new Select<>(); private final Select 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 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.matchdayService = matchdayService; this.matchService = matchService; - this.onlyMatchdaysWithActivity = onlyMatchdaysWithActivity; fillSeasonSelectWithData(); + seasonSelect.addValueChangeListener(seasonSelectValueChangeListener()); matchdaySelect.addValueChangeListener(matchdaySelectValueChangeListener()); 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() { + 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); - 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, 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, 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, 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() { seasonList.clear(); seasonList.addAll(seasonService.getAllSeasonsSorted()); @@ -172,212 +204,82 @@ public class Navigation implements HasUrlParameter { matchSelect.setItems(matchList); } - private boolean isMatchDayParamValid(@NonNull String matchdayParam) { - return matchdayList.stream().anyMatch(matchday -> matchdayParam.equals(matchday.toString())); - } - @Override public void setParameter(BeforeEvent event, @WildcardParameter String param) { - Map map = NavigationUtils.getParameterMap(param); - setParameter(map.get(UrlParameterType.SEASON), map.get(UrlParameterType.MATCHDAY), map.get(UrlParameterType.MATCH)); + Map> 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 seasonParam, Optional matchdayParam, Optional matchParam) { + if (!seasonEnabled) return; + Optional 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 = getMatchdayFromParam(matchdayParam); + if (matchday.isPresent()) matchdaySelect.setValue(matchday.get()); + else autoselectMatchday(); - private void matchFound(Match match) { - matchSelect.setValue(match); + if (!matchEnabled) return; + Optional 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 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 getSeasonFromParam(Optional 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 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 getMatchdayFromParam(Optional 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 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 getMatchFromParam(Optional 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 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 getSeasonList() { + return seasonList; } - public void addRunnableToBeRunAfterMatchSelection(Runnable runnable) { - runnablesToBeRunAfterMatchSelection.add(runnable); + public List getMatchdayList() { + return matchdayList; } - private void configureButtons() { - prevMatchdayButton.setEnabled(isMatchDayParamValid(getPrevMatchdayParam())); - prevMatchdayButton.addClickListener(getButtonClickListener(getPrevMatchdayParam())); - - nextMatchdayButton.setEnabled(isMatchDayParamValid(getNextMatchdayParam())); - nextMatchdayButton.addClickListener(getButtonClickListener(getNextMatchdayParam())); + public List getMatchList() { + return matchList; } - private ComponentEventListener> getButtonClickListener(String matchdayParam) { - return buttonClickEvent -> matchdayList.stream() - .filter(matchday -> matchdayParam.equals(matchday.toString())) - .findFirst().ifPresent(matchdaySelect::setValue); + public Select getSeasonSelect() { + return seasonSelect; } - private String getPrevMatchdayParam() { - try { - return String.valueOf(Integer.parseInt(matchdayParam) - 1); - } catch (NumberFormatException e) { - return ""; - } + public Select getMatchdaySelect() { + return matchdaySelect; } - private String getNextMatchdayParam() { - try { - return String.valueOf(Integer.parseInt(matchdayParam) + 1); - } catch (NumberFormatException e) { - return ""; - } + public Select getMatchSelect() { + return matchSelect; } public Optional getSelectedMatchday() { @@ -391,32 +293,4 @@ public class Navigation implements HasUrlParameter { public Optional getSelectedMatch() { return matchSelect.getOptionalValue(); } - - public Button getPrevMatchdayButton() { - return prevMatchdayButton; - } - - public Button getNextMatchdayButton() { - return nextMatchdayButton; - } - - public Label getInvalidUrlLabel() { - return invalidUrlLabel; - } - - public Select getSeasonSelect() { - return seasonSelect; - } - - public Select getMatchdaySelect() { - return matchdaySelect; - } - - public Select getMatchSelect() { - return matchSelect; - } - - public void selectMatch(Match match) { - matchSelect.setValue(match); - } } diff --git a/src/main/java/app/navigation/NavigationUtils.java b/src/main/java/app/navigation/NavigationUtils.java index 2698e93..e706123 100644 --- a/src/main/java/app/navigation/NavigationUtils.java +++ b/src/main/java/app/navigation/NavigationUtils.java @@ -5,22 +5,28 @@ import org.springframework.lang.NonNull; import java.util.HashMap; import java.util.Map; +import java.util.Optional; public class NavigationUtils { - public static Map getParameterMap(@WildcardParameter String param) { - Map map = new HashMap<>(); + + @NonNull + public static Map> getParameterMap(@WildcardParameter String param) { + Map> map = new HashMap<>(); String[] params = param.split("/"); switch (params.length) { case 3: - map.put(UrlParameterType.MATCH, params[2]); + map.put(UrlParameterType.MATCH, Optional.of(params[2])); case 2: - map.put(UrlParameterType.MATCHDAY, params[1]); + map.put(UrlParameterType.MATCHDAY, Optional.of(params[1])); case 1: - map.put(UrlParameterType.SEASON, params[0]); + map.put(UrlParameterType.SEASON, Optional.of(params[0])); default: break; } + map.putIfAbsent(UrlParameterType.MATCH, Optional.empty()); + map.putIfAbsent(UrlParameterType.MATCHDAY, Optional.empty()); + map.putIfAbsent(UrlParameterType.SEASON, Optional.empty()); return map; } diff --git a/src/main/java/app/views/about/AboutView.java b/src/main/java/app/views/example/about/AboutView.java similarity index 94% rename from src/main/java/app/views/about/AboutView.java rename to src/main/java/app/views/example/about/AboutView.java index 2b44756..557f422 100644 --- a/src/main/java/app/views/about/AboutView.java +++ b/src/main/java/app/views/example/about/AboutView.java @@ -1,4 +1,4 @@ -package app.views.about; +package app.views.example.about; import app.data.service.GameService; 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.Route; -@CssImport("app/views/about/about-view.css") +@CssImport("app/views/example/about/about-view.css") @Route(value = "about", layout = MainView.class) @PageTitle("About") public class AboutView extends Div { diff --git a/src/main/java/app/views/addressform/AddressFormView.java b/src/main/java/app/views/example/addressform/AddressFormView.java similarity index 96% rename from src/main/java/app/views/addressform/AddressFormView.java rename to src/main/java/app/views/example/addressform/AddressFormView.java index a53f562..0fcdad2 100644 --- a/src/main/java/app/views/addressform/AddressFormView.java +++ b/src/main/java/app/views/example/addressform/AddressFormView.java @@ -1,4 +1,4 @@ -package app.views.addressform; +package app.views.example.addressform; import app.data.entity.SampleAddress; 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.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) @PageTitle("Address Form") public class AddressFormView extends Div { diff --git a/src/main/java/app/views/cardlist/CardListView.java b/src/main/java/app/views/example/cardlist/CardListView.java similarity index 98% rename from src/main/java/app/views/cardlist/CardListView.java rename to src/main/java/app/views/example/cardlist/CardListView.java index d3134c7..0952c8e 100644 --- a/src/main/java/app/views/cardlist/CardListView.java +++ b/src/main/java/app/views/example/cardlist/CardListView.java @@ -1,4 +1,4 @@ -package app.views.cardlist; +package app.views.example.cardlist; import app.views.main.MainView; import com.vaadin.flow.component.dependency.CssImport; @@ -18,7 +18,7 @@ import com.vaadin.flow.router.Route; import java.util.Arrays; 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) @PageTitle("Card List") public class CardListView extends Div implements AfterNavigationObserver { diff --git a/src/main/java/app/views/cardlist/Person.java b/src/main/java/app/views/example/cardlist/Person.java similarity index 96% rename from src/main/java/app/views/cardlist/Person.java rename to src/main/java/app/views/example/cardlist/Person.java index 9e1a9f8..8418663 100644 --- a/src/main/java/app/views/cardlist/Person.java +++ b/src/main/java/app/views/example/cardlist/Person.java @@ -1,4 +1,4 @@ -package app.views.cardlist; +package app.views.example.cardlist; public class Person { diff --git a/src/main/java/app/views/creditcardform/CreditCardFormView.java b/src/main/java/app/views/example/creditcardform/CreditCardFormView.java similarity index 96% rename from src/main/java/app/views/creditcardform/CreditCardFormView.java rename to src/main/java/app/views/example/creditcardform/CreditCardFormView.java index 2b4b1ae..bdf191e 100644 --- a/src/main/java/app/views/creditcardform/CreditCardFormView.java +++ b/src/main/java/app/views/example/creditcardform/CreditCardFormView.java @@ -1,4 +1,4 @@ -package app.views.creditcardform; +package app.views.example.creditcardform; import app.views.main.MainView; 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.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) @PageTitle("Credit Card Form") public class CreditCardFormView extends Div { diff --git a/src/main/java/app/views/helloworld/HelloWorldView.java b/src/main/java/app/views/example/helloworld/HelloWorldView.java similarity index 90% rename from src/main/java/app/views/helloworld/HelloWorldView.java rename to src/main/java/app/views/example/helloworld/HelloWorldView.java index 92179c7..1c5b4a0 100644 --- a/src/main/java/app/views/helloworld/HelloWorldView.java +++ b/src/main/java/app/views/example/helloworld/HelloWorldView.java @@ -1,4 +1,4 @@ -package app.views.helloworld; +package app.views.example.helloworld; import app.views.main.MainView; 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.Route; -@CssImport("app/views/helloworld/hello-world-view.css") +@CssImport("app/views/example/helloworld/hello-world-view.css") @Route(value = "hello", layout = MainView.class) @PageTitle("Hello World") public class HelloWorldView extends HorizontalLayout { diff --git a/src/main/java/app/views/map/MapView.java b/src/main/java/app/views/example/map/MapView.java similarity index 94% rename from src/main/java/app/views/map/MapView.java rename to src/main/java/app/views/example/map/MapView.java index d20136c..e488d0f 100644 --- a/src/main/java/app/views/map/MapView.java +++ b/src/main/java/app/views/example/map/MapView.java @@ -1,4 +1,4 @@ -package app.views.map; +package app.views.example.map; import app.components.leafletmap.LeafletMap; import app.views.main.MainView; diff --git a/src/main/java/app/views/masterdetail/MasterDetailView.java b/src/main/java/app/views/example/masterdetail/MasterDetailView.java similarity index 98% rename from src/main/java/app/views/masterdetail/MasterDetailView.java rename to src/main/java/app/views/example/masterdetail/MasterDetailView.java index d47d32d..2e3430b 100644 --- a/src/main/java/app/views/masterdetail/MasterDetailView.java +++ b/src/main/java/app/views/example/masterdetail/MasterDetailView.java @@ -1,4 +1,4 @@ -package app.views.masterdetail; +package app.views.example.masterdetail; import app.data.entity.SamplePerson; import app.data.service.SamplePersonService; @@ -29,7 +29,7 @@ import java.util.ArrayList; import java.util.List; 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) @PageTitle("Master-Detail") public class MasterDetailView extends Div { diff --git a/src/main/java/app/views/personform/PersonFormView.java b/src/main/java/app/views/example/personform/PersonFormView.java similarity index 97% rename from src/main/java/app/views/personform/PersonFormView.java rename to src/main/java/app/views/example/personform/PersonFormView.java index 50a863f..95e0bf3 100644 --- a/src/main/java/app/views/personform/PersonFormView.java +++ b/src/main/java/app/views/example/personform/PersonFormView.java @@ -1,4 +1,4 @@ -package app.views.personform; +package app.views.example.personform; import app.data.entity.SamplePerson; 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.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) @PageTitle("Person Form") public class PersonFormView extends Div { diff --git a/src/main/java/app/views/main/MainView.java b/src/main/java/app/views/main/MainView.java index e2d9693..dc3891b 100644 --- a/src/main/java/app/views/main/MainView.java +++ b/src/main/java/app/views/main/MainView.java @@ -1,7 +1,7 @@ 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 com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentUtil; @@ -40,8 +40,7 @@ public class MainView extends AppLayout { // TODO: View for each match // TODO: View for adding match data // 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 H1 viewTitle; @@ -51,6 +50,7 @@ public class MainView extends AppLayout { addToNavbar(true, createHeaderContent()); menu = createMenu(); addToDrawer(createDrawerContent(menu)); + } private Component createHeaderContent() { @@ -103,7 +103,9 @@ public class MainView extends AppLayout { // createTab("Credit Card Form", CreditCardFormView.class), // createTab("Map", MapView.class), createTab("Table", TableView.class), - createTab("Results", ResultsView.class)}; + createTab("Matchday", MatchdayView.class), + createTab("Match", MatchView.class) + }; } private static Tab createTab(String text, Class navigationTarget) { diff --git a/src/main/java/app/views/match/MatchView.java b/src/main/java/app/views/match/MatchView.java new file mode 100644 index 0000000..221036a --- /dev/null +++ b/src/main/java/app/views/match/MatchView.java @@ -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 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); + } + } +} diff --git a/src/main/java/app/views/results/MatchdayView.java b/src/main/java/app/views/matchday/MatchdayView.java similarity index 67% rename from src/main/java/app/views/results/MatchdayView.java rename to src/main/java/app/views/matchday/MatchdayView.java index ebc871d..5e1d6dd 100644 --- a/src/main/java/app/views/results/MatchdayView.java +++ b/src/main/java/app/views/matchday/MatchdayView.java @@ -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.entity.Matchday; import app.data.service.MatchService; +import app.data.service.MatchdayService; +import app.data.service.SeasonService; import app.navigation.Navigation; import app.utils.StringUtils; 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.dependency.CssImport; import com.vaadin.flow.component.grid.ColumnTextAlign; import com.vaadin.flow.component.grid.Grid; 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.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.data.selection.SelectionListener; 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 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 Navigation navigation; - private final VerticalLayout matchdayLayout = new VerticalLayout(); private final Label matchdayHeader = new Label(); private final Grid grid = new Grid<>(); @@ -34,14 +43,20 @@ public class MatchdayView extends VerticalLayout { private final Button prevButton; 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; - 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(); } @@ -54,7 +69,7 @@ public class MatchdayView extends VerticalLayout { setWidthFull(); setHeightFull(); setAlignItems(FlexComponent.Alignment.CENTER); - add(new SeasonAndMatchdayNavigation(navigation), matchdayLayout); + add(new NavigationHeader(navigation), matchdayLayout); // TODO add background color for content matchdayHeader.addClassName("matchday_header"); // TODO: add dates @@ -66,6 +81,7 @@ public class MatchdayView extends VerticalLayout { matchdayLayout.add(matchdayHeaderLayout, grid); matchdayLayout.setAlignItems(FlexComponent.Alignment.CENTER); matchdayLayout.setWidth(""); + matchdayLayout.addClassName("wrapper"); Label headerPlayer1 = new Label("Player 1"); headerPlayer1.addClassName("column_header"); @@ -95,10 +111,10 @@ public class MatchdayView extends VerticalLayout { grid.addThemeVariants(GridVariant.LUMO_NO_BORDER, GridVariant.LUMO_NO_ROW_BORDERS, GridVariant.LUMO_ROW_STRIPES); - grid.addSelectionListener((SelectionListener, CalculatedMatch>) selectionEvent -> { - Optional calculatedMatch = selectionEvent.getFirstSelectedItem(); - calculatedMatch.ifPresent(match -> navigation.selectMatch(match.getMatch())); - }); +// grid.addSelectionListener((SelectionListener, CalculatedMatch>) selectionEvent -> { +// Optional calculatedMatch = selectionEvent.getFirstSelectedItem(); +// calculatedMatch.ifPresent(match -> navigation.selectMatch(match.getMatch())); +// }); } private String getResultString(CalculatedMatch match) { @@ -110,6 +126,7 @@ public class MatchdayView extends VerticalLayout { // CONTENT // ///////////// + @Override protected void configureContent() { Optional selectedMatchday = navigation.getSelectedMatchday(); selectedMatchday.ifPresent(matchday -> { @@ -117,4 +134,9 @@ public class MatchdayView extends VerticalLayout { grid.setItems(matchService.getCalculatedMatches(matchday)); }); } + + @Override + public String getRoute() { + return "matchday"; + } } diff --git a/src/main/java/app/views/navigation/NavigationViewBase.java b/src/main/java/app/views/navigation/NavigationViewBase.java new file mode 100644 index 0000000..89bd82b --- /dev/null +++ b/src/main/java/app/views/navigation/NavigationViewBase.java @@ -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 { + + 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); + } +} diff --git a/src/main/java/app/views/results/MatchView.java b/src/main/java/app/views/results/MatchView.java deleted file mode 100644 index 8926693..0000000 --- a/src/main/java/app/views/results/MatchView.java +++ /dev/null @@ -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 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); - } - -} diff --git a/src/main/java/app/views/results/ResultsView.java b/src/main/java/app/views/results/ResultsView.java deleted file mode 100644 index 7839042..0000000 --- a/src/main/java/app/views/results/ResultsView.java +++ /dev/null @@ -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 { - - 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); - } -} diff --git a/src/main/java/app/views/table/TableView.java b/src/main/java/app/views/table/TableView.java index ad30ca9..f09f4d3 100644 --- a/src/main/java/app/views/table/TableView.java +++ b/src/main/java/app/views/table/TableView.java @@ -1,6 +1,7 @@ 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.service.MatchService; import app.data.service.MatchdayService; @@ -10,14 +11,15 @@ import app.utils.StringUtils; import app.utils.VaadinUtils; 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.grid.ColumnTextAlign; import com.vaadin.flow.component.grid.Grid; 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.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.function.ValueProvider; import com.vaadin.flow.router.*; import org.springframework.beans.factory.annotation.Autowired; @@ -26,27 +28,28 @@ import java.util.NoSuchElementException; @CssImport("app/views/table/table-view.css") @Route(value = "table", layout = MainView.class) +@RouteAlias(value = "", layout = MainView.class) @PageTitle("Schachliga DACH - Table") -public class TableView extends VerticalLayout implements HasUrlParameter { +public class TableView extends NavigationViewBase { private final PlayerService playerService; - private final Navigation navigation; - private final Label invalidUrlLabel; - private final Grid 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.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("content"); configureLayout(); } @@ -55,11 +58,10 @@ public class TableView extends VerticalLayout implements HasUrlParameter //////////// 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(); } @@ -69,15 +71,15 @@ public class TableView extends VerticalLayout implements HasUrlParameter // TODO: add diff to last matchday Label headerPlace = new Label("Place"); - headerPlace.addClassName("important_table_column_header"); + headerPlace.addClassName("important-table-column-header"); Label headerPlayer = new Label("Player"); - headerPlayer.addClassName("important_table_column_header"); + headerPlayer.addClassName("important-table-column-header"); Label headerMatchesPlayed = new Label("Played"); Label headerMatchPoints = new Label("Points"); - headerMatchPoints.addClassName("important_table_column_header"); + headerMatchPoints.addClassName("important-table-column-header"); Label headerWon = new Label("W"); @@ -92,6 +94,7 @@ public class TableView extends VerticalLayout implements HasUrlParameter grid.addColumn(VaadinUtils.getBoldStringRenderer(PlayerForTable::getPlaceString)) .setHeader(headerPlace) .setTextAlign(ColumnTextAlign.CENTER) +// .setClassNameGenerator(playerForTable -> "leftmost-column-cell") .setWidth("5em"); grid.addColumn(VaadinUtils.getPlayerRenderer(PlayerForTable::getPlayer)) @@ -149,16 +152,18 @@ public class TableView extends VerticalLayout implements HasUrlParameter // CONTENT // ///////////// + @Override + public String getRoute() { + return "table"; + } + + @Override protected void configureContent() { try { grid.setItems(playerService.getPlayersForTable(navigation.getSelectedMatchday().orElseThrow())); } 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); - } }