Browse Source

PlayerNavigation

master
GAM 4 years ago
parent
commit
f703100ee2
48 changed files with 1635 additions and 855 deletions
  1. +10
    -18
      LICENSE.md
  2. +20
    -9
      README.md
  3. +4
    -4
      db/db_increment_001.sql
  4. +3
    -3
      db/db_increment_002.sql
  5. +835
    -456
      db/db_init.sql
  6. +28
    -26
      frontend/app/components/leafletmap/leaflet-map.js
  7. +1
    -1
      frontend/app/views/example/about/about-view.css
  8. +7
    -6
      frontend/app/views/example/addressform/address-form-view.css
  9. +32
    -32
      frontend/app/views/example/cardlist/card-list-view.css
  10. +7
    -6
      frontend/app/views/example/creditcardform/credit-card-form-view.css
  11. +2
    -2
      frontend/app/views/example/helloworld/hello-world-view.css
  12. +3
    -3
      frontend/app/views/example/map/map-view.css
  13. +16
    -16
      frontend/app/views/example/masterdetail/master-detail-view.css
  14. +7
    -6
      frontend/app/views/example/personform/person-form-view.css
  15. +5
    -5
      frontend/app/views/matchday/matchday-view.css
  16. +5
    -5
      frontend/app/views/table/table-view.css
  17. +6
    -0
      src/main/java/app/data/service/PlayerService.java
  18. +8
    -0
      src/main/java/app/data/service/SeasonService.java
  19. +0
    -8
      src/main/java/app/navigation/NavigationLevel.java
  20. +5
    -21
      src/main/java/app/navigation/NavigationUtils.java
  21. +0
    -40
      src/main/java/app/navigation/components/NavigationHeader.java
  22. +0
    -14
      src/main/java/app/navigation/components/button/ButtonUtils.java
  23. +0
    -38
      src/main/java/app/navigation/components/button/NextMatchdayButton.java
  24. +0
    -37
      src/main/java/app/navigation/components/button/PrevMatchdayButton.java
  25. +194
    -0
      src/main/java/app/navigation/player/PlayerNavigation.java
  26. +7
    -0
      src/main/java/app/navigation/player/PlayerNavigationLevel.java
  27. +23
    -0
      src/main/java/app/navigation/player/PlayerNavigationService.java
  28. +25
    -0
      src/main/java/app/navigation/player/PlayerNavigationUtils.java
  29. +31
    -0
      src/main/java/app/navigation/player/components/PlayerNavigationHeader.java
  30. +37
    -0
      src/main/java/app/navigation/player/components/button/NextPlayerButton.java
  31. +14
    -0
      src/main/java/app/navigation/player/components/button/PlayerButtonUtils.java
  32. +37
    -0
      src/main/java/app/navigation/player/components/button/PrevPlayerButton.java
  33. +20
    -19
      src/main/java/app/navigation/regular/RegularNavigation.java
  34. +8
    -0
      src/main/java/app/navigation/regular/RegularNavigationLevel.java
  35. +7
    -7
      src/main/java/app/navigation/regular/RegularNavigationService.java
  36. +31
    -0
      src/main/java/app/navigation/regular/RegularNavigationUtils.java
  37. +40
    -0
      src/main/java/app/navigation/regular/components/RegularNavigationHeader.java
  38. +14
    -0
      src/main/java/app/navigation/regular/components/button/MatchdayButtonUtils.java
  39. +37
    -0
      src/main/java/app/navigation/regular/components/button/NextMatchdayButton.java
  40. +36
    -0
      src/main/java/app/navigation/regular/components/button/PrevMatchdayButton.java
  41. +5
    -5
      src/main/java/app/views/match/MatchView.java
  42. +7
    -8
      src/main/java/app/views/match/components/EditMatchCard.java
  43. +11
    -11
      src/main/java/app/views/match/components/MatchComponent.java
  44. +5
    -5
      src/main/java/app/views/matchday/MatchdayView.java
  45. +11
    -13
      src/main/java/app/views/matchday/components/MatchdayCard.java
  46. +16
    -16
      src/main/java/app/views/navigation/NavigationViewBase.java
  47. +6
    -6
      src/main/java/app/views/table/TableView.java
  48. +9
    -9
      src/main/java/app/views/table/components/TableCard.java

+ 10
- 18
LICENSE.md View File

@ -1,24 +1,16 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or
as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright
interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the
detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of
all present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>

+ 20
- 9
README.md View File

@ -3,34 +3,42 @@
This is an example project that can be used as a starting point to create your own Vaadin application with Spring Boot.
It contains all the necessary configuration and some placeholder files to get you started.
The project is a standard Maven project, so you can import it to your IDE of choice. [Read more how to set up a development environment](https://vaadin.com/docs/v14/flow/installing/installing-overview.html) for Vaadin projects (Windows, Linux, macOS).
The project is a standard Maven project, so you can import it to your IDE of
choice. [Read more how to set up a development environment](https://vaadin.com/docs/v14/flow/installing/installing-overview.html)
for Vaadin projects (Windows, Linux, macOS).
This project was created from https://start.vaadin.com.
## Running and debugging the application
### Running the application from the command line.
To run from the command line, use `mvn` and open http://localhost:8080 in your browser.
### Running and debugging the application in Intellij IDEA
- Locate the app.Application.java class in the Project view. It is in the src folder, under the main package's root.
- Right-click on the app.Application class
- Select "Debug 'app.Application.main()'" from the list
After the application has started, you can view it at http://localhost:8080/ in your browser.
You can now also attach breakpoints in code for debugging purposes, by clicking next to a line number in any source file.
After the application has started, you can view it at http://localhost:8080/ in your browser. You can now also attach
breakpoints in code for debugging purposes, by clicking next to a line number in any source file.
### Running and debugging the application in Eclipse
- Locate the app.Application.java class in the Package Explorer. It is in `src/main/java`, under the main package.
- Right-click on the file and select `Debug As` --> `Java app.Application`.
Do not worry if the debugger breaks at a `SilentExitException`. This is a Spring Boot feature and happens on every startup.
Do not worry if the debugger breaks at a `SilentExitException`. This is a Spring Boot feature and happens on every
startup.
After the application has started, you can view it at http://localhost:8080/ in your browser. You can now also attach
breakpoints in code for debugging purposes, by clicking next to a line number in any source file.
After the application has started, you can view it at http://localhost:8080/ in your browser.
You can now also attach breakpoints in code for debugging purposes, by clicking next to a line number in any source file.
## Project structure
- `MainView.java` in `src/main/java` contains the app.navigation setup. It uses [App Layout](https://vaadin.com/components/vaadin-app-layout).
- `MainView.java` in `src/main/java` contains the app.regularNavigation setup. It
uses [App Layout](https://vaadin.com/components/vaadin-app-layout).
- `app.views` package in `src/main/java` contains the server-side Java app.views of your application.
- `app.views` folder in `frontend/` contains the client-side JavaScript app.views of your application.
@ -38,6 +46,9 @@ You can now also attach breakpoints in code for debugging purposes, by clicking
[vaadin.com](https://vaadin.com) has lots of material to help you get you started:
- Follow the tutorials in [vaadin.com/tutorials](https://vaadin.com/tutorials). Especially [vaadin.com/tutorials/getting-started-with-flow](https://vaadin.com/tutorials/getting-started-with-flow) is good for getting a grasp of the basic Vaadin concepts.
- Follow the tutorials in [vaadin.com/tutorials](https://vaadin.com/tutorials).
Especially [vaadin.com/tutorials/getting-started-with-flow](https://vaadin.com/tutorials/getting-started-with-flow) is
good for getting a grasp of the basic Vaadin concepts.
- Read the documentation in [vaadin.com/docs](https://vaadin.com/docs).
- For a bigger Vaadin application example, check out the Full Stack App starter from [vaadin.com/start](https://vaadin.com/start).
- For a bigger Vaadin application example, check out the Full Stack App starter
from [vaadin.com/start](https://vaadin.com/start).

+ 4
- 4
db/db_increment_001.sql View File

@ -1,8 +1,8 @@
ALTER TABLE "game_info"
ADD COLUMN "pgn" varchar,
ADD COLUMN "rated" boolean,
ADD COLUMN "time_class" varchar,
ADD COLUMN "rules" varchar,
ADD COLUMN "pgn" varchar,
ADD COLUMN "rated" boolean,
ADD COLUMN "time_class" varchar,
ADD COLUMN "rules" varchar,
ADD COLUMN "white_rating" int,
ADD COLUMN "black_rating" int,
ADD COLUMN "white_result" varchar,

+ 3
- 3
db/db_increment_002.sql View File

@ -1,5 +1,5 @@
ALTER TABLE "season"
ADD COLUMN "week_of_first_matchday" int not null default 9 CHECK ( week_of_first_matchday > 0 AND week_of_first_matchday <= 53 ),
ADD COLUMN "week_of_first_matchday" int not null default 9 CHECK ( week_of_first_matchday > 0 AND week_of_first_matchday <= 53 ),
ADD COLUMN "first_weekday_of_matchday" int not null default 2 CHECK ( first_weekday_of_matchday > 0 AND first_weekday_of_matchday <= 7 ),
ADD COLUMN "last_weekday_of_matchday" int not null default 1 CHECK ( last_weekday_of_matchday > 0 AND last_weekday_of_matchday <= 7 ),
ADD COLUMN "weekday_of_view_change" int not null default 4 CHECK ( weekday_of_view_change > 0 AND weekday_of_view_change <= 7 );
ADD COLUMN "last_weekday_of_matchday" int not null default 1 CHECK ( last_weekday_of_matchday > 0 AND last_weekday_of_matchday <= 7 ),
ADD COLUMN "weekday_of_view_change" int not null default 4 CHECK ( weekday_of_view_change > 0 AND weekday_of_view_change <= 7 );

+ 835
- 456
db/db_init.sql
File diff suppressed because it is too large
View File


+ 28
- 26
frontend/app/components/leafletmap/leaflet-map.js View File

@ -6,31 +6,33 @@ const openStreetMapLayer = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
const openStreetMapAttribution = `&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors`;
export class LeafletMap extends PolymerElement {
_attachDom(dom) {
// Do not use a shadow root
this.appendChild(dom);
}
render() {
return html``;
}
ready() {
super.ready();
this.map = L.map(this);
let tileLayer = L.tileLayer(openStreetMapLayer, {
attribution: openStreetMapAttribution,
maxZoom: 13,
});
tileLayer.addTo(this.map);
}
async setView(latitude, longitude, zoomLevel) {
this.map.setView([latitude, longitude], zoomLevel);
}
static get is() {
return 'leaflet-map';
}
_attachDom(dom) {
// Do not use a shadow root
this.appendChild(dom);
}
render() {
return html``;
}
ready() {
super.ready();
this.map = L.map(this);
let tileLayer = L.tileLayer(openStreetMapLayer, {
attribution: openStreetMapAttribution,
maxZoom: 13,
});
tileLayer.addTo(this.map);
}
async setView(latitude, longitude, zoomLevel) {
this.map.setView([latitude, longitude], zoomLevel);
}
static get is() {
return 'leaflet-map';
}
}
customElements.define(LeafletMap.is, LeafletMap);

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

@ -1,3 +1,3 @@
.about-view {
display: block;
display: block;
}

+ 7
- 6
frontend/app/views/example/addressform/address-form-view.css View File

@ -1,10 +1,11 @@
.address-form-view {
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
}
.address-form-view .button-layout {
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
}

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

@ -1,70 +1,70 @@
.card-list-view {
display: block;
height: 100%;
display: block;
height: 100%;
}
.card-list-view vaadin-grid {
height: 100%;
line-height: var(--lumo-line-height-m);
height: 100%;
line-height: var(--lumo-line-height-m);
}
.card-list-view vaadin-grid,
.card-list-view vaadin-grid-cell-content {
background-color: var(--lumo-contrast-10pct);
background-color: var(--lumo-contrast-10pct);
}
.card-list-view .card {
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: calc(var(--lumo-space-s) * 1.5) var(--lumo-space-m);
background-color: var(--lumo-base-color);
border-radius: var(--lumo-border-radius);
box-shadow: var(--lumo-box-shadow-xs);
padding: calc(var(--lumo-space-s) * 1.5) var(--lumo-space-m);
}
.card-list-view img {
border-radius: 50%;
flex-shrink: 0;
height: var(--lumo-size-m);
margin-right: calc(var(--lumo-space-s) * 1.5);
width: var(--lumo-size-m);
border-radius: 50%;
flex-shrink: 0;
height: var(--lumo-size-m);
margin-right: calc(var(--lumo-space-s) * 1.5);
width: var(--lumo-size-m);
}
.card-list-view .header {
align-items: baseline;
align-items: baseline;
}
.card-list-view .name {
font-size: var(--lumo-font-size-s);
font-weight: bold;
margin-right: var(--lumo-space-s);
font-size: var(--lumo-font-size-s);
font-weight: bold;
margin-right: var(--lumo-space-s);
}
.card-list-view .date {
color: var(--lumo-tertiary-text-color);
font-size: var(--lumo-font-size-xs);
color: var(--lumo-tertiary-text-color);
font-size: var(--lumo-font-size-xs);
}
.card-list-view .post {
color: var(--lumo-secondary-text-color);
font-size: var(--lumo-font-size-s);
margin-bottom: var(--lumo-space-s);
white-space: normal;
color: var(--lumo-secondary-text-color);
font-size: var(--lumo-font-size-s);
margin-bottom: var(--lumo-space-s);
white-space: normal;
}
.card-list-view .actions {
align-items: center;
align-items: center;
}
.card-list-view iron-icon {
color: var(--lumo-tertiary-text-color);
height: calc(var(--lumo-icon-size-s) * 0.8);
margin-right: var(--lumo-space-s);
width: calc(var(--lumo-icon-size-s) * 0.8);
color: var(--lumo-tertiary-text-color);
height: calc(var(--lumo-icon-size-s) * 0.8);
margin-right: var(--lumo-space-s);
width: calc(var(--lumo-icon-size-s) * 0.8);
}
.card-list-view .likes,
.card-list-view .comments,
.card-list-view .shares {
color: var(--lumo-tertiary-text-color);
font-size: var(--lumo-font-size-xs);
margin-right: var(--lumo-space-l);
color: var(--lumo-tertiary-text-color);
font-size: var(--lumo-font-size-xs);
margin-right: var(--lumo-space-l);
}

+ 7
- 6
frontend/app/views/example/creditcardform/credit-card-form-view.css View File

@ -1,10 +1,11 @@
.credit-card-form-view {
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
}
.credit-card-form-view .button-layout {
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
}

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

@ -1,4 +1,4 @@
.hello-world-view {
display: block;
padding: 1em;
display: block;
padding: 1em;
}

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

@ -1,8 +1,8 @@
.map-view {
display: flex;
height: 100%;
display: flex;
height: 100%;
}
.map-view .map {
flex: 1;
flex: 1;
}

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

@ -1,33 +1,33 @@
.master-detail-view {
display: flex;
height: 100%;
flex-direction: column;
display: flex;
height: 100%;
flex-direction: column;
}
.master-detail-view .grid-wrapper {
flex-grow: 1;
width: 100%;
flex-grow: 1;
width: 100%;
}
.master-detail-view .full-size {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
}
.master-detail-view #editor-layout {
width: 400px;
display: flex;
flex-direction: column;
width: 400px;
display: flex;
flex-direction: column;
}
.master-detail-view #editor {
padding: var(--lumo-space-l);
flex-grow: 1;
padding: var(--lumo-space-l);
flex-grow: 1;
}
.master-detail-view #button-layout {
width: 100%;
flex-wrap: wrap;
background-color: var(--lumo-contrast-5pct);
padding: var(--lumo-space-s) var(--lumo-space-l);
width: 100%;
flex-wrap: wrap;
background-color: var(--lumo-contrast-5pct);
padding: var(--lumo-space-s) var(--lumo-space-l);
}

+ 7
- 6
frontend/app/views/example/personform/person-form-view.css View File

@ -1,10 +1,11 @@
.person-form-view {
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
display: block;
margin: 0 auto;
max-width: 1024px;
padding: 0 var(--lumo-space-l);
}
.person-form-view .button-layout {
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
margin-bottom: var(--lumo-space-l);
margin-top: var(--lumo-space-m);
}

+ 5
- 5
frontend/app/views/matchday/matchday-view.css View File

@ -1,11 +1,11 @@
.matchday-view .column_header {
font-weight: bold;
font-size: large;
font-weight: bold;
font-size: large;
}
.matchday-view .matchday-header-label-layout {
width: 100%;
justify-content: center;
font-size: x-large;
width: 100%;
justify-content: center;
font-size: x-large;
}

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

@ -1,10 +1,10 @@
.table-view .important-table-column-header {
font-weight: bold;
font-size: large;
font-weight: bold;
font-size: large;
}
.table-view .table-header-label-layout {
width: 100%;
justify-content: center;
font-size: x-large;
width: 100%;
justify-content: center;
font-size: x-large;
}

+ 6
- 0
src/main/java/app/data/service/PlayerService.java View File

@ -37,6 +37,12 @@ public class PlayerService extends CrudService<Player, Integer> {
return new PlayerForTableProvider(matchday).getPlayersForTableSorted(true);
}
public List<Player> getAllPlayersSorted() {
return repository.findAll().stream()
.sorted((player1, player2) -> player1.getNickname().compareToIgnoreCase(player2.getNickname()))
.collect(Collectors.toList());
}
private class PlayerForTableProvider {
List<Matchday> matchdays = new ArrayList<>();
List<CalculatedMatch> calculatedMatches = new ArrayList<>();


+ 8
- 0
src/main/java/app/data/service/SeasonService.java View File

@ -1,5 +1,6 @@
package app.data.service;
import app.data.entity.Player;
import app.data.entity.Season;
import app.data.repository.SeasonRepository;
import org.springframework.beans.factory.annotation.Autowired;
@ -46,4 +47,11 @@ public class SeasonService extends CrudService<Season, Integer> {
.findFirst();
}
public List<Season> getAllSeasonsForPlayerSorted(Player player) {
return repository.findAll().stream()
.filter(season -> season.getMatchdays().stream()
.anyMatch(matchday -> matchday.getMatches().stream()
.anyMatch(match -> match.getPlayer1().equals(player) || match.getPlayer2().equals(player))))
.collect(Collectors.toList());
}
}

+ 0
- 8
src/main/java/app/navigation/NavigationLevel.java View File

@ -1,8 +0,0 @@
package app.navigation;
public enum NavigationLevel {
NONE,
SEASON,
MATCHDAY,
MATCH
}

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

@ -4,39 +4,23 @@ import app.utils.EntityStringUtils;
import com.vaadin.flow.router.WildcardParameter;
import org.springframework.lang.NonNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
class NavigationUtils {
private static final String EDIT = "edit";
public class NavigationUtils {
public static final String EDIT = "edit";
private NavigationUtils() {
}
@NonNull
static Map<NavigationLevel, Optional<String>> getParameterMap(@WildcardParameter String param) {
Map<NavigationLevel, Optional<String>> map = new HashMap<>();
String[] params = param.split("/");
if (params.length >= 1 && !params[0].equals(EDIT)) map.put(NavigationLevel.SEASON, Optional.of(params[0]));
if (params.length >= 2 && !params[1].equals(EDIT)) map.put(NavigationLevel.MATCHDAY, Optional.of(params[1]));
if (params.length >= 3 && !params[2].equals(EDIT)) map.put(NavigationLevel.MATCH, Optional.of(params[2]));
map.putIfAbsent(NavigationLevel.MATCH, Optional.empty());
map.putIfAbsent(NavigationLevel.MATCHDAY, Optional.empty());
map.putIfAbsent(NavigationLevel.SEASON, Optional.empty());
return map;
}
static boolean editFlag(@WildcardParameter String param) {
public static boolean editFlag(@WildcardParameter String param) {
String[] params = param.split("/");
return params[params.length - 1].equals(EDIT);
}
@NonNull
static String getWildcardParam(boolean editFlag, String... params) {
public static String getWildcardParam(boolean editFlag, String... params) {
StringBuilder stringBuilder = new StringBuilder();
for (String param : params) {
if (param == null || param.equals("")) {
@ -48,7 +32,7 @@ class NavigationUtils {
return stringBuilder.toString();
}
static <T> Optional<T> getObjectFromParam(List<T> objectList, Optional<String> param) {
public static <T> Optional<T> getObjectFromParam(List<T> objectList, Optional<String> param) {
if (param.isEmpty()) {
return Optional.empty();
}


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

@ -1,40 +0,0 @@
package app.navigation.components;
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.seasonEnabled()) {
add(seasonLabel, navigation.getSeasonSelect());
}
if (navigation.matchdayEnabled()) {
add(matchdayLabel, navigation.getMatchdaySelect());
}
if (navigation.matchEnabled()) {
add(matchLabel, navigation.getMatchSelect());
}
}
}

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

@ -1,14 +0,0 @@
package app.navigation.components.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();
}
}

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

@ -1,38 +0,0 @@
package app.navigation.components.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.matchdayEnabled())
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();
}
}

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

@ -1,37 +0,0 @@
package app.navigation.components.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.matchdayEnabled())
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();
}
}

+ 194
- 0
src/main/java/app/navigation/player/PlayerNavigation.java View File

@ -0,0 +1,194 @@
package app.navigation.player;
import app.components.label.ValidationLabel;
import app.data.entity.Player;
import app.data.entity.Season;
import app.data.service.PlayerService;
import app.data.service.SeasonService;
import app.navigation.NavigationUtils;
import app.utils.EntityStringUtils;
import com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent;
import com.vaadin.flow.component.HasValue.ValueChangeListener;
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class PlayerNavigation implements HasUrlParameter<String> {
private String route;
private final List<Runnable> runnablesToBeRunAfterSelection = new ArrayList<>();
private final PlayerService playerService;
private final SeasonService seasonService;
private final List<Player> playerList = new ArrayList<>();
private final List<Season> seasonList = new ArrayList<>();
private final Select<Player> playerSelect = new Select<>();
private final Select<Season> seasonSelect = new Select<>();
private final ValidationLabel validationLabel = new ValidationLabel();
public PlayerNavigation(@Autowired PlayerService playerService,
@Autowired SeasonService seasonService) {
this.playerService = playerService;
this.seasonService = seasonService;
fillPlayerSelectWithData();
playerSelect.addValueChangeListener(playerSelectValueChangeListener());
seasonSelect.addValueChangeListener(seasonSelectValueChangeListener());
playerSelect.setItemLabelGenerator(EntityStringUtils::getPlayerString);
seasonSelect.setItemLabelGenerator(EntityStringUtils::getSeasonString);
}
public void setRoute(String route) {
this.route = route;
}
public void addRunnableToBeRunAfterSelection(Runnable runnable) {
runnablesToBeRunAfterSelection.add(runnable);
}
private String getRoute() {
if (route != null) return route;
throw new IllegalStateException("Route must be set!");
}
private void updateUrl() {
String playerParam = null;
String seasonParam = null;
if (playerSelect.getOptionalValue().isPresent())
playerParam = EntityStringUtils.getPlayerStringForURL(playerSelect.getValue());
if (seasonSelect.getOptionalValue().isPresent())
seasonParam = EntityStringUtils.getSeasonStringForURL(seasonSelect.getValue());
String params = NavigationUtils.getWildcardParam(false, playerParam, seasonParam);
UI.getCurrent().getPage().getHistory().pushState(null, String.format("%s/%s", getRoute(), params));
}
private ValueChangeListener<ComponentValueChangeEvent<Select<Player>, Player>> playerSelectValueChangeListener() {
return event -> {
fillSeasonSelectWithData(event.getValue());
autoselectSeason();
};
}
private ValueChangeListener<ComponentValueChangeEvent<Select<Season>, Season>> seasonSelectValueChangeListener() {
return event -> doPostSelectionStuff();
}
private void doPostSelectionStuff() {
validationLabel.setValid(true);
updateUrl();
runnablesToBeRunAfterSelection.forEach(Runnable::run);
}
private void autoselectPlayer() {
if (playerList.isEmpty()) {
validationLabel.setText("No Players in List!");
validationLabel.setValid(false);
return;
}
playerSelect.setValue(playerList.get(0));
}
private void autoselectSeason() {
if (seasonList.isEmpty()) {
validationLabel.setText("No Season in List!");
validationLabel.setValid(false);
return;
}
seasonSelect.setValue(seasonList.get(seasonList.size() - 1));
}
private void fillPlayerSelectWithData() {
playerList.clear();
playerList.addAll(playerService.getAllPlayersSorted());
playerSelect.setItems(playerList);
}
private void fillSeasonSelectWithData(Player player) {
seasonList.clear();
seasonList.addAll(seasonService.getAllSeasonsForPlayerSorted(player));
seasonSelect.setItems(seasonList);
}
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
Map<PlayerNavigationLevel, Optional<String>> map = PlayerNavigationUtils.getParameterMap(param);
navigate(map.get(PlayerNavigationLevel.PLAYER), map.get(PlayerNavigationLevel.SEASON));
}
private void navigate(Optional<String> playerParam, Optional<String> seasonParam) {
Optional<Player> player = NavigationUtils.getObjectFromParam(playerList, playerParam);
if (player.isPresent()) playerSelect.setValue(player.get());
else autoselectPlayer();
Optional<Season> season = NavigationUtils.getObjectFromParam(seasonList, seasonParam);
if (season.isPresent()) seasonSelect.setValue(season.get());
else autoselectSeason();
}
public ValidationLabel getValidationLabel() {
return validationLabel;
}
public List<Player> getPlayerList() {
return playerList;
}
public List<Season> getSeasonList() {
return seasonList;
}
public Select<Player> getPlayerSelect() {
return playerSelect;
}
public Select<Season> getSeasonSelect() {
return seasonSelect;
}
public Optional<Player> getSelectedPlayer() {
return playerSelect.getOptionalValue();
}
public Optional<Season> getSelectedSeason() {
return seasonSelect.getOptionalValue();
}
public PlayerService getPlayerService() {
return playerService;
}
public SeasonService getSeasonService() {
return seasonService;
}
public String getWildcardParam() {
return NavigationUtils.getWildcardParam(
false,
getPlayerParam().orElse(null),
getSeasonParam().orElse(null));
}
public Optional<String> getPlayerParam() {
return getSelectedPlayer().map(EntityStringUtils::getPlayerStringForURL);
}
public Optional<String> getSeasonParam() {
return getSelectedSeason().map(EntityStringUtils::getSeasonStringForURL);
}
}

+ 7
- 0
src/main/java/app/navigation/player/PlayerNavigationLevel.java View File

@ -0,0 +1,7 @@
package app.navigation.player;
public enum PlayerNavigationLevel {
NONE,
PLAYER,
SEASON,
}

+ 23
- 0
src/main/java/app/navigation/player/PlayerNavigationService.java View File

@ -0,0 +1,23 @@
package app.navigation.player;
import app.data.service.PlayerService;
import app.data.service.SeasonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PlayerNavigationService {
private final SeasonService seasonService;
private final PlayerService playerService;
public PlayerNavigationService(@Autowired PlayerService playerService,
@Autowired SeasonService seasonService) {
this.playerService = playerService;
this.seasonService = seasonService;
}
public PlayerNavigation getNewNavigation() {
return new PlayerNavigation(playerService, seasonService);
}
}

+ 25
- 0
src/main/java/app/navigation/player/PlayerNavigationUtils.java View File

@ -0,0 +1,25 @@
package app.navigation.player;
import com.vaadin.flow.router.WildcardParameter;
import org.springframework.lang.NonNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
class PlayerNavigationUtils {
private PlayerNavigationUtils() {
}
@NonNull
static Map<PlayerNavigationLevel, Optional<String>> getParameterMap(@WildcardParameter String param) {
Map<PlayerNavigationLevel, Optional<String>> map = new HashMap<>();
String[] params = param.split("/");
if (params.length >= 1) map.put(PlayerNavigationLevel.PLAYER, Optional.of(params[0]));
if (params.length >= 2) map.put(PlayerNavigationLevel.SEASON, Optional.of(params[1]));
map.putIfAbsent(PlayerNavigationLevel.PLAYER, Optional.empty());
map.putIfAbsent(PlayerNavigationLevel.SEASON, Optional.empty());
return map;
}
}

+ 31
- 0
src/main/java/app/navigation/player/components/PlayerNavigationHeader.java View File

@ -0,0 +1,31 @@
package app.navigation.player.components;
import app.navigation.player.PlayerNavigation;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
public class PlayerNavigationHeader extends HorizontalLayout {
private final PlayerNavigation playerNavigation;
private final Label seasonLabel = new Label("Season:");
private final Label playerLabel = new Label("Player:");
public PlayerNavigationHeader(PlayerNavigation playerNavigation) {
this.playerNavigation = playerNavigation;
defineLayout();
configureChildren();
}
private void defineLayout() {
setWidthFull();
setAlignItems(Alignment.CENTER);
setJustifyContentMode(JustifyContentMode.END);
}
private void configureChildren() {
removeAll();
add(playerLabel, playerNavigation.getPlayerSelect());
add(seasonLabel, playerNavigation.getSeasonSelect());
}
}

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

@ -0,0 +1,37 @@
package app.navigation.player.components.button;
import app.data.entity.Player;
import app.navigation.player.PlayerNavigation;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.icon.VaadinIcon;
import java.util.List;
import java.util.Optional;
public class NextPlayerButton extends Button {
private final PlayerNavigation playerNavigation;
public NextPlayerButton(PlayerNavigation playerNavigation) {
this.playerNavigation = playerNavigation;
setIcon(VaadinIcon.ARROW_RIGHT.create());
playerNavigation.addRunnableToBeRunAfterSelection(this::configure);
}
private void configure() {
Optional<Player> nextPlayer = getNextPlayer();
setEnabled(nextPlayer.isPresent());
addClickListener(event -> nextPlayer.ifPresent(player -> playerNavigation.getPlayerSelect().setValue(player)));
}
private Optional<Player> getNextPlayer() {
int index = PlayerButtonUtils.getPlayerIndex(playerNavigation);
if (index < 0) return Optional.empty();
List<Player> playerList = playerNavigation.getPlayerList();
return Optional.ofNullable(playerList.get((index + 1) % playerList.size()));
}
}

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

@ -0,0 +1,14 @@
package app.navigation.player.components.button;
import app.navigation.player.PlayerNavigation;
import java.util.concurrent.atomic.AtomicInteger;
class PlayerButtonUtils {
static int getPlayerIndex(PlayerNavigation playerNavigation) {
AtomicInteger index = new AtomicInteger(-1);
playerNavigation.getSelectedPlayer().ifPresent(player -> index.set(playerNavigation.getPlayerList().indexOf(player)));
return index.get();
}
}

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

@ -0,0 +1,37 @@
package app.navigation.player.components.button;
import app.data.entity.Player;
import app.navigation.player.PlayerNavigation;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.icon.VaadinIcon;
import java.util.List;
import java.util.Optional;
public class PrevPlayerButton extends Button {
private final PlayerNavigation playerNavigation;
public PrevPlayerButton(PlayerNavigation playerNavigation) {
this.playerNavigation = playerNavigation;
setIcon(VaadinIcon.ARROW_LEFT.create());
playerNavigation.addRunnableToBeRunAfterSelection(this::configure);
}
private void configure() {
Optional<Player> prevPlayer = getPrevPlayer();
setEnabled(prevPlayer.isPresent());
addClickListener(event -> prevPlayer.ifPresent(player -> playerNavigation.getPlayerSelect().setValue(player)));
}
private Optional<Player> getPrevPlayer() {
int index = PlayerButtonUtils.getPlayerIndex(playerNavigation);
if (index < 0) return Optional.empty();
List<Player> playerList = playerNavigation.getPlayerList();
return Optional.ofNullable(playerList.get((index - 1) % playerList.size()));
}
}

src/main/java/app/navigation/Navigation.java → src/main/java/app/navigation/regular/RegularNavigation.java View File

@ -1,4 +1,4 @@
package app.navigation;
package app.navigation.regular;
import app.components.label.ValidationLabel;
import app.data.entity.Match;
@ -7,9 +7,10 @@ import app.data.entity.Season;
import app.data.service.MatchService;
import app.data.service.MatchdayService;
import app.data.service.SeasonService;
import app.navigation.NavigationUtils;
import app.utils.EntityStringUtils;
import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent;
import com.vaadin.flow.component.HasValue.ValueChangeListener;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.router.BeforeEvent;
@ -24,7 +25,7 @@ import java.util.Map;
import java.util.Optional;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class Navigation implements HasUrlParameter<String> {
public class RegularNavigation implements HasUrlParameter<String> {
private String route;
private boolean onlyMatchdaysWithActivity;
@ -43,15 +44,15 @@ public class Navigation implements HasUrlParameter<String> {
private final Select<Matchday> matchdaySelect = new Select<>();
private final Select<Match> matchSelect = new Select<>();
private NavigationLevel navigationLevel = NavigationLevel.SEASON;
private RegularNavigationLevel regularNavigationLevel = RegularNavigationLevel.SEASON;
private final ValidationLabel validationLabel = new ValidationLabel();
private boolean editFlag = false;
public Navigation(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) {
public RegularNavigation(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) {
this.seasonService = seasonService;
this.matchdayService = matchdayService;
this.matchService = matchService;
@ -75,8 +76,8 @@ public class Navigation implements HasUrlParameter<String> {
this.onlyMatchdaysWithActivity = onlyMatchdaysWithActivity;
}
public void setNavigationLevel(@NonNull NavigationLevel navigationLevel) {
this.navigationLevel = navigationLevel;
public void setNavigationLevel(@NonNull RegularNavigationLevel regularNavigationLevel) {
this.regularNavigationLevel = regularNavigationLevel;
}
public void addRunnableToBeRunAfterSelection(Runnable runnable) {
@ -84,15 +85,15 @@ public class Navigation implements HasUrlParameter<String> {
}
public boolean seasonEnabled() {
return this.navigationLevel.compareTo(NavigationLevel.SEASON) >= 0;
return this.regularNavigationLevel.compareTo(RegularNavigationLevel.SEASON) >= 0;
}
public boolean matchdayEnabled() {
return this.navigationLevel.compareTo(NavigationLevel.MATCHDAY) >= 0;
return this.regularNavigationLevel.compareTo(RegularNavigationLevel.MATCHDAY) >= 0;
}
public boolean matchEnabled() {
return this.navigationLevel.compareTo(NavigationLevel.MATCH) >= 0;
return this.regularNavigationLevel.compareTo(RegularNavigationLevel.MATCH) >= 0;
}
private String getRoute() {
@ -115,7 +116,7 @@ public class Navigation implements HasUrlParameter<String> {
UI.getCurrent().getPage().getHistory().pushState(null, String.format("%s/%s", getRoute(), params));
}
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Season>, Season>> seasonSelectValueChangeListener() {
private ValueChangeListener<ComponentValueChangeEvent<Select<Season>, Season>> seasonSelectValueChangeListener() {
return event -> {
if (!seasonEnabled()) throw new IllegalStateException("Cannot select season when it is not enabled!");
if (matchdayEnabled()) {
@ -127,7 +128,7 @@ public class Navigation implements HasUrlParameter<String> {
};
}
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Matchday>, Matchday>> matchdaySelectValueChangeListener() {
private ValueChangeListener<ComponentValueChangeEvent<Select<Matchday>, Matchday>> matchdaySelectValueChangeListener() {
return event -> {
if (!matchdayEnabled()) throw new IllegalStateException("Cannot select matchday when it is not enabled!");
if (matchEnabled()) {
@ -139,7 +140,7 @@ public class Navigation implements HasUrlParameter<String> {
};
}
private HasValue.ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<Select<Match>, Match>> matchSelectValueChangeListener() {
private ValueChangeListener<ComponentValueChangeEvent<Select<Match>, Match>> matchSelectValueChangeListener() {
return event -> {
if (!matchEnabled()) throw new IllegalStateException("Cannot select match when it is not enabled!");
doPostSelectionStuff();
@ -163,7 +164,7 @@ public class Navigation implements HasUrlParameter<String> {
seasonSelect.setValue(seasonList.get(seasonList.size() - 1));
}
private void autoselectMatchday() { // TODO: add date stuff and choose depending on date instead!
private void autoselectMatchday() { // TODO: choose depending on date instead!
if (!matchdayEnabled())
throw new IllegalStateException("This method should not be called when matchday is not enabled!");
if (matchdayList.isEmpty()) {
@ -209,9 +210,9 @@ public class Navigation implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
Map<NavigationLevel, Optional<String>> map = NavigationUtils.getParameterMap(param);
Map<RegularNavigationLevel, Optional<String>> map = RegularNavigationUtils.getParameterMap(param);
editFlag = NavigationUtils.editFlag(param);
navigate(map.get(NavigationLevel.SEASON), map.get(NavigationLevel.MATCHDAY), map.get(NavigationLevel.MATCH));
navigate(map.get(RegularNavigationLevel.SEASON), map.get(RegularNavigationLevel.MATCHDAY), map.get(RegularNavigationLevel.MATCH));
}
private void navigate(Optional<String> seasonParam, Optional<String> matchdayParam, Optional<String> matchParam) {

+ 8
- 0
src/main/java/app/navigation/regular/RegularNavigationLevel.java View File

@ -0,0 +1,8 @@
package app.navigation.regular;
public enum RegularNavigationLevel {
NONE,
SEASON,
MATCHDAY,
MATCH
}

src/main/java/app/navigation/NavigationService.java → src/main/java/app/navigation/regular/RegularNavigationService.java View File

@ -1,4 +1,4 @@
package app.navigation;
package app.navigation.regular;
import app.data.service.MatchService;
import app.data.service.MatchdayService;
@ -7,21 +7,21 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class NavigationService {
public class RegularNavigationService {
private final SeasonService seasonService;
private final MatchdayService matchdayService;
private final MatchService matchService;
public NavigationService(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) {
public RegularNavigationService(@Autowired SeasonService seasonService,
@Autowired MatchdayService matchdayService,
@Autowired MatchService matchService) {
this.seasonService = seasonService;
this.matchdayService = matchdayService;
this.matchService = matchService;
}
public Navigation getNewNavigation() {
return new Navigation(seasonService, matchdayService, matchService);
public RegularNavigation getNewNavigation() {
return new RegularNavigation(seasonService, matchdayService, matchService);
}
}

+ 31
- 0
src/main/java/app/navigation/regular/RegularNavigationUtils.java View File

@ -0,0 +1,31 @@
package app.navigation.regular;
import app.navigation.NavigationUtils;
import com.vaadin.flow.router.WildcardParameter;
import org.springframework.lang.NonNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
class RegularNavigationUtils {
private RegularNavigationUtils() {
}
@NonNull
static Map<RegularNavigationLevel, Optional<String>> getParameterMap(@WildcardParameter String param) {
Map<RegularNavigationLevel, Optional<String>> map = new HashMap<>();
String[] params = param.split("/");
if (params.length >= 1 && !params[0].equals(NavigationUtils.EDIT))
map.put(RegularNavigationLevel.SEASON, Optional.of(params[0]));
if (params.length >= 2 && !params[1].equals(NavigationUtils.EDIT))
map.put(RegularNavigationLevel.MATCHDAY, Optional.of(params[1]));
if (params.length >= 3 && !params[2].equals(NavigationUtils.EDIT))
map.put(RegularNavigationLevel.MATCH, Optional.of(params[2]));
map.putIfAbsent(RegularNavigationLevel.MATCH, Optional.empty());
map.putIfAbsent(RegularNavigationLevel.MATCHDAY, Optional.empty());
map.putIfAbsent(RegularNavigationLevel.SEASON, Optional.empty());
return map;
}
}

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

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

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

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

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

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

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

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

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

@ -4,8 +4,8 @@ import app.data.service.ChessComService;
import app.data.service.GameInfoService;
import app.data.service.GameService;
import app.gameimage.GameImageService;
import app.navigation.NavigationLevel;
import app.navigation.NavigationService;
import app.navigation.regular.RegularNavigationLevel;
import app.navigation.regular.RegularNavigationService;
import app.views.main.MainView;
import app.views.match.components.MatchComponent;
import app.views.navigation.NavigationViewBase;
@ -25,9 +25,9 @@ public class MatchView extends NavigationViewBase {
private final GameImageService gameImageService;
private MatchComponent matchComponent;
public MatchView(@Autowired NavigationService navigationService,
public MatchView(@Autowired RegularNavigationService regularNavigationService,
@Autowired ChessComService chessComService, @Autowired GameService gameService, GameInfoService gameInfoService, GameImageService gameImageService) {
super(navigationService, "match", NavigationLevel.MATCH);
super(regularNavigationService, "match", RegularNavigationLevel.MATCH);
this.chessComService = chessComService;
this.gameService = gameService;
this.gameInfoService = gameInfoService;
@ -43,7 +43,7 @@ public class MatchView extends NavigationViewBase {
////////////
private void configureLayout() {
matchComponent = new MatchComponent(navigation, chessComService, gameImageService);
matchComponent = new MatchComponent(regularNavigation, chessComService, gameImageService);
add(matchComponent);
}


+ 7
- 8
src/main/java/app/views/match/components/EditMatchCard.java View File

@ -5,7 +5,7 @@ import app.data.entity.Match;
import app.data.service.ChessComService;
import app.data.service.MatchService;
import app.gameimage.GameImageService;
import app.navigation.Navigation;
import app.navigation.regular.RegularNavigation;
import app.utils.ChessComUtils;
import app.utils.ComponentUtils;
import app.utils.MatchUtils;
@ -14,7 +14,6 @@ import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
@ -29,7 +28,7 @@ import static com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY;
public class EditMatchCard extends VerticalLayout {
private final Navigation navigation;
private final RegularNavigation regularNavigation;
private final MatchService matchService;
private final ChessComService chessComService;
private final GameImageService gameImageService;
@ -49,10 +48,10 @@ public class EditMatchCard extends VerticalLayout {
private Match match;
public EditMatchCard(Navigation navigation, ChessComService chessComService, GameImageService gameImageService) {
this.navigation = navigation;
public EditMatchCard(RegularNavigation regularNavigation, ChessComService chessComService, GameImageService gameImageService) {
this.regularNavigation = regularNavigation;
this.chessComService = chessComService;
this.matchService = navigation.getMatchService();
this.matchService = regularNavigation.getMatchService();
this.gameImageService = gameImageService;
defineLayout();
@ -168,7 +167,7 @@ public class EditMatchCard extends VerticalLayout {
matchService.update(match);
match.getGames().forEach(gameImageService::createImageIfNotPresent);
navigation.setEditFlag(false);
regularNavigation.setEditFlag(false);
};
}
@ -193,6 +192,6 @@ public class EditMatchCard extends VerticalLayout {
}
private ComponentEventListener<ClickEvent<Button>> createEditCancelButtonListener() {
return event -> UI.getCurrent().navigate(String.format("matchday/%s", navigation.getWildcardParam().replace("edit/", "")));
return event -> UI.getCurrent().navigate(String.format("matchday/%s", regularNavigation.getWildcardParam().replace("edit/", "")));
}
}

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

@ -6,7 +6,7 @@ import app.data.entity.Match;
import app.data.service.ChessComService;
import app.data.service.MatchService;
import app.gameimage.GameImageService;
import app.navigation.Navigation;
import app.navigation.regular.RegularNavigation;
import app.utils.ComponentUtils;
import app.utils.StringUtils;
import app.views.navigation.interfaces.ContentConfigurable;
@ -26,7 +26,7 @@ import java.util.NoSuchElementException;
public class MatchComponent extends Div implements ContentConfigurable {
private final Navigation navigation;
private final RegularNavigation regularNavigation;
private final MatchService matchService;
private final GameImageService gameImageService;
@ -43,14 +43,14 @@ public class MatchComponent extends Div implements ContentConfigurable {
private Match match;
private CalculatedMatch calculatedMatch;
public MatchComponent(Navigation navigation,
public MatchComponent(RegularNavigation regularNavigation,
@Autowired ChessComService chessComService,
@Autowired GameImageService gameImageService) {
this.navigation = navigation;
this.matchService = navigation.getMatchService();
this.regularNavigation = regularNavigation;
this.matchService = regularNavigation.getMatchService();
this.gameImageService = gameImageService;
this.editMatchCard = new EditMatchCard(navigation, chessComService, gameImageService);
this.editMatchCard = new EditMatchCard(regularNavigation, chessComService, gameImageService);
defineLayout();
}
@ -95,7 +95,7 @@ public class MatchComponent extends Div implements ContentConfigurable {
Button button = new Button("Add games", new Icon(VaadinIcon.PLUS));
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
button.addClickListener(event -> {
navigation.setEditFlag(true);
regularNavigation.setEditFlag(true);
remove(noGamesLayout);
});
return button;
@ -113,13 +113,13 @@ public class MatchComponent extends Div implements ContentConfigurable {
@Override
public void configureContent() {
try {
match = navigation.getSelectedMatch().orElseThrow();
match = regularNavigation.getSelectedMatch().orElseThrow();
calculatedMatch = matchService.getCalculatedMatch(match);
configureHeaderContent();
configureMainContent();
} catch (NoSuchElementException e) {
gamesLayout.removeAll();
add(navigation.getValidationLabel());
add(regularNavigation.getValidationLabel());
}
}
@ -138,7 +138,7 @@ public class MatchComponent extends Div implements ContentConfigurable {
}
private void configureHeaderResultLabel() {
if (match.getGames().isEmpty() || navigation.editFlag()) {
if (match.getGames().isEmpty() || regularNavigation.editFlag()) {
headerLayout.remove(headerResultLabel);
} else {
headerLayout.add(headerResultLabel);
@ -148,7 +148,7 @@ public class MatchComponent extends Div implements ContentConfigurable {
}
private void configureMainContent() {
if (navigation.editFlag()) {
if (regularNavigation.editFlag()) {
remove(gamesLayout);
add(editLayout);
editMatchCard.configureContent(match);


+ 5
- 5
src/main/java/app/views/matchday/MatchdayView.java View File

@ -1,7 +1,7 @@
package app.views.matchday;
import app.navigation.NavigationLevel;
import app.navigation.NavigationService;
import app.navigation.regular.RegularNavigationLevel;
import app.navigation.regular.RegularNavigationService;
import app.views.main.MainView;
import app.views.matchday.components.MatchdayCard;
import app.views.navigation.NavigationViewBase;
@ -17,8 +17,8 @@ public class MatchdayView extends NavigationViewBase {
private MatchdayCard matchdayCard;
public MatchdayView(@Autowired NavigationService navigationService) {
super(navigationService, "matchday", NavigationLevel.MATCHDAY);
public MatchdayView(@Autowired RegularNavigationService regularNavigationService) {
super(regularNavigationService, "matchday", RegularNavigationLevel.MATCHDAY);
addClassName("matchday-view");
@ -30,7 +30,7 @@ public class MatchdayView extends NavigationViewBase {
////////////
private void configureLayout() {
matchdayCard = new MatchdayCard(navigation);
matchdayCard = new MatchdayCard(regularNavigation);
add(matchdayCard);
}


+ 11
- 13
src/main/java/app/views/matchday/components/MatchdayCard.java View File

@ -2,9 +2,9 @@ package app.views.matchday.components;
import app.data.bean.CalculatedMatch;
import app.data.entity.Matchday;
import app.navigation.Navigation;
import app.navigation.components.button.NextMatchdayButton;
import app.navigation.components.button.PrevMatchdayButton;
import app.navigation.regular.RegularNavigation;
import app.navigation.regular.components.button.NextMatchdayButton;
import app.navigation.regular.components.button.PrevMatchdayButton;
import app.utils.ComponentUtils;
import app.utils.EntityStringUtils;
import app.utils.StringUtils;
@ -24,13 +24,11 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.TimeZone;
public class MatchdayCard extends Div implements ContentConfigurable {
private final Navigation navigation;
private final RegularNavigation regularNavigation;
private final Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.");
@ -40,8 +38,8 @@ public class MatchdayCard extends Div implements ContentConfigurable {
private final Grid<CalculatedMatch> grid = new Grid<>();
public MatchdayCard(Navigation navigation) {
this.navigation = navigation;
public MatchdayCard(RegularNavigation regularNavigation) {
this.regularNavigation = regularNavigation;
addClassName("card");
add(new VerticalLayout(header, grid));
@ -57,7 +55,7 @@ public class MatchdayCard extends Div implements ContentConfigurable {
}
private void defineHeader() {
header.add(new PrevMatchdayButton(this.navigation), headerLabelLayout, new NextMatchdayButton(this.navigation));
header.add(new PrevMatchdayButton(this.regularNavigation), headerLabelLayout, new NextMatchdayButton(this.regularNavigation));
header.setWidthFull();
headerLabelLayout.addClassName("matchday-header-label-layout");
@ -109,7 +107,7 @@ public class MatchdayCard extends Div implements ContentConfigurable {
Button button = new Button();
button.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
String seasonAndMatchdayParam = navigation.getWildcardParam();
String seasonAndMatchdayParam = regularNavigation.getWildcardParam();
String matchParam = EntityStringUtils.getMatchStringForURL(match.getMatch());
String targetWildcardParam = String.format("match/%s%s/", seasonAndMatchdayParam, matchParam);
@ -131,12 +129,12 @@ public class MatchdayCard extends Div implements ContentConfigurable {
@Override
public void configureContent() {
try {
Matchday matchday = navigation.getSelectedMatchday().orElseThrow();
Matchday matchday = regularNavigation.getSelectedMatchday().orElseThrow();
configureHeaderLabels(matchday);
grid.setItems(navigation.getMatchService().getCalculatedMatches(matchday));
grid.setItems(regularNavigation.getMatchService().getCalculatedMatches(matchday));
} catch (NoSuchElementException e) {
removeAll();
add(navigation.getValidationLabel());
add(regularNavigation.getValidationLabel());
}
}


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

@ -1,9 +1,9 @@
package app.views.navigation;
import app.navigation.Navigation;
import app.navigation.NavigationLevel;
import app.navigation.NavigationService;
import app.navigation.components.NavigationHeader;
import app.navigation.regular.RegularNavigation;
import app.navigation.regular.RegularNavigationLevel;
import app.navigation.regular.RegularNavigationService;
import app.navigation.regular.components.RegularNavigationHeader;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEvent;
@ -13,27 +13,27 @@ 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 final RegularNavigation regularNavigation;
protected final RegularNavigationHeader regularNavigationHeader;
protected NavigationViewBase(@Autowired NavigationService navigationService,
protected NavigationViewBase(@Autowired RegularNavigationService regularNavigationService,
String route,
NavigationLevel navigationLevel) {
this.navigation = navigationService.getNewNavigation();
navigation.setRoute(route);
navigation.setNavigationLevel(navigationLevel);
RegularNavigationLevel regularNavigationLevel) {
this.regularNavigation = regularNavigationService.getNewNavigation();
regularNavigation.setRoute(route);
regularNavigation.setNavigationLevel(regularNavigationLevel);
this.navigationHeader = new NavigationHeader(navigation);
this.regularNavigationHeader = new RegularNavigationHeader(regularNavigation);
define();
}
private void define() {
add(navigationHeader);
add(regularNavigationHeader);
addClassName("content");
setAlignItems(FlexComponent.Alignment.CENTER);
navigation.addRunnableToBeRunAfterSelection(this::configureContent);
regularNavigation.addRunnableToBeRunAfterSelection(this::configureContent);
}
/////////////
@ -49,11 +49,11 @@ public abstract class NavigationViewBase extends VerticalLayout implements HasUr
@Override
public void removeAll() {
super.removeAll();
add(navigationHeader);
add(regularNavigationHeader);
}
@Override
public void setParameter(BeforeEvent event, @WildcardParameter String param) {
navigation.setParameter(event, param);
regularNavigation.setParameter(event, param);
}
}

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

@ -1,8 +1,8 @@
package app.views.table;
import app.data.service.PlayerService;
import app.navigation.NavigationLevel;
import app.navigation.NavigationService;
import app.navigation.regular.RegularNavigationLevel;
import app.navigation.regular.RegularNavigationService;
import app.views.main.MainView;
import app.views.navigation.NavigationViewBase;
import app.views.table.components.TableCard;
@ -22,12 +22,12 @@ public class TableView extends NavigationViewBase {
private TableCard tableCard;
public TableView(@Autowired NavigationService navigationService,
public TableView(@Autowired RegularNavigationService regularNavigationService,
@Autowired PlayerService playerService) {
super(navigationService, "table", NavigationLevel.MATCHDAY);
super(regularNavigationService, "table", RegularNavigationLevel.MATCHDAY);
this.playerService = playerService;
this.navigation.setOnlyMatchdaysWithActivity(true);
this.regularNavigation.setOnlyMatchdaysWithActivity(true);
addClassName("table-view");
@ -39,7 +39,7 @@ public class TableView extends NavigationViewBase {
////////////
private void defineLayout() {
tableCard = new TableCard(navigation, playerService);
tableCard = new TableCard(regularNavigation, playerService);
add(tableCard);
}


+ 9
- 9
src/main/java/app/views/table/components/TableCard.java View File

@ -3,9 +3,9 @@ package app.views.table.components;
import app.data.bean.PlayerForTable;
import app.data.entity.Matchday;
import app.data.service.PlayerService;
import app.navigation.Navigation;
import app.navigation.components.button.NextMatchdayButton;
import app.navigation.components.button.PrevMatchdayButton;
import app.navigation.regular.RegularNavigation;
import app.navigation.regular.components.button.NextMatchdayButton;
import app.navigation.regular.components.button.PrevMatchdayButton;
import app.utils.ComponentUtils;
import app.utils.EntityStringUtils;
import app.utils.StringUtils;
@ -27,7 +27,7 @@ import java.util.NoSuchElementException;
public class TableCard extends Div implements ContentConfigurable {
private final Navigation navigation;
private final RegularNavigation regularNavigation;
private final PlayerService playerService;
@ -35,8 +35,8 @@ public class TableCard extends Div implements ContentConfigurable {
private final HorizontalLayout headerLabelLayout = new HorizontalLayout();
private final Grid<PlayerForTable> grid = new Grid<>();
public TableCard(Navigation navigation, @Autowired PlayerService playerService) {
this.navigation = navigation;
public TableCard(RegularNavigation regularNavigation, @Autowired PlayerService playerService) {
this.regularNavigation = regularNavigation;
this.playerService = playerService;
addClassName("card");
@ -47,7 +47,7 @@ public class TableCard extends Div implements ContentConfigurable {
}
private void defineHeader() {
header.add(new PrevMatchdayButton(this.navigation), headerLabelLayout, new NextMatchdayButton(this.navigation));
header.add(new PrevMatchdayButton(this.regularNavigation), headerLabelLayout, new NextMatchdayButton(this.regularNavigation));
header.setWidthFull();
headerLabelLayout.addClassName("table-header-label-layout");
@ -161,7 +161,7 @@ public class TableCard extends Div implements ContentConfigurable {
@Override
public void configureContent() {
try {
Matchday matchday = navigation.getSelectedMatchday().orElseThrow();
Matchday matchday = regularNavigation.getSelectedMatchday().orElseThrow();
String mainText = "Table";
String matchdayText = String.format("Matchday %s", EntityStringUtils.getMatchdayString(matchday));
@ -169,7 +169,7 @@ public class TableCard extends Div implements ContentConfigurable {
grid.setItems(playerService.getPlayersForTable(matchday));
} catch (NoSuchElementException e) {
removeAll();
add(navigation.getValidationLabel());
add(regularNavigation.getValidationLabel());
}
}
}

Loading…
Cancel
Save