@ -4,69 +4,62 @@ import com.example.application.data.entity.Matchday;
import com.example.application.data.entity.Season ;
import com.example.application.data.entity.Season ;
import com.example.application.data.service.MatchdayService ;
import com.example.application.data.service.MatchdayService ;
import com.example.application.data.service.SeasonService ;
import com.example.application.data.service.SeasonService ;
import com.vaadin.flow.component.AbstractField ;
import com.vaadin.flow.component.Component ;
import com.vaadin.flow.component.HasValue ;
import com.vaadin.flow.component.UI ;
import com.vaadin.flow.component.html.Div ;
import com.vaadin.flow.component.* ;
import com.vaadin.flow.component.button.Button ;
import com.vaadin.flow.component.html.Label ;
import com.vaadin.flow.component.html.Label ;
import com.vaadin.flow.component.icon.Icon ;
import com.vaadin.flow.component.icon.VaadinIcon ;
import com.vaadin.flow.component.orderedlayout.FlexComponent ;
import com.vaadin.flow.component.orderedlayout.FlexComponent ;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout ;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout ;
import com.vaadin.flow.component.orderedlayout.VerticalLayout ;
import com.vaadin.flow.component.select.Select ;
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.beans.factory.annotation.Autowired ;
import org.springframework.lang.NonNull ;
import org.springframework.lang.NonNull ;
import org.springframework.lang.Nullable ;
import org.springframework.lang.Nullable ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.List ;
import java.util.List ;
import java.util.Optional ;
public abstract class SeasonAndMatchdayNavigationView extends Div implements HasUrlParameter < String > {
public class SeasonAndMatchdayNavigation {
/ / TODO : show dropdown menus also for invalid URLs ( with content that fits the situation )
/ / TODO : show dropdown menus also for invalid URLs ( with content that fits the situation )
protected final SeasonService seasonService ;
protected final MatchdayService matchdayService ;
protected String seasonParam ;
protected String matchdayParam ;
private final SeasonService seasonService ;
private final MatchdayService matchdayService ;
private final Label invalidUrlLabel = new Label ( ) ;
private final Label invalidUrlLabel = new Label ( ) ;
protected final VerticalLayout outer = new VerticalLayout ( ) ;
protected final HorizontalLayout selectionLayout = new HorizontalLayout ( ) ;
protected final List < Season > seasonList = new ArrayList < > ( ) ;
protected final Select < Season > seasonSelect = new Select < > ( ) ;
private final HorizontalLayout selectionLayout = new HorizontalLayout ( ) ;
protected final List < Matchday > matchdayList = new ArrayList < > ( ) ;
protected final Select < Matchday > matchdaySelect = new Select < > ( ) ;
protected Component contentLayout ;
private final List < Season > seasonList = new ArrayList < > ( ) ;
private final Select < Season > seasonSelect = new Select < > ( ) ;
public SeasonAndMatchdayNavigationView ( @Autowired SeasonService seasonService , @Autowired MatchdayService matchdayService ) {
this . seasonService = seasonService ;
this . matchdayService = matchdayService ;
private final List < Matchday > matchdayList = new ArrayList < > ( ) ;
private final Select < Matchday > matchdaySelect = new Select < > ( ) ;
private final String route ;
private final boolean onlyMatchdaysWithActivity ;
private Runnable runnableToBeRunAfterSelection ;
private final Button prevButton = new Button ( new Icon ( VaadinIcon . ARROW_LEFT ) ) ;
private final Button nextButton = new Button ( new Icon ( VaadinIcon . ARROW_RIGHT ) ) ;
addClassName ( "results-view" ) ;
private String seasonParam ;
private String matchdayParam ;
configureOuterLayout ( ) ;
configureSelectionLayout ( ) ;
configureContentLayout ( ) ;
public SeasonAndMatchdayNavigation ( String route ,
@Autowired SeasonService seasonService ,
@Autowired MatchdayService matchdayService ) {
this ( route , seasonService , matchdayService , false ) ;
}
}
protected abstract String route ( ) ;
protected abstract void configureContentLayout ( ) ;
protected abstract void configureContent ( ) ;
protected abstract boolean showOnlyMatchdaysWithActivity ( ) ;
public SeasonAndMatchdayNavigation ( String route ,
@Autowired SeasonService seasonService ,
@Autowired MatchdayService matchdayService ,
boolean onlyMatchdaysWithActivity ) {
this . route = route ;
this . seasonService = seasonService ;
this . matchdayService = matchdayService ;
this . onlyMatchdaysWithActivity = onlyMatchdaysWithActivity ;
private void configureOuterLayout ( ) {
add ( outer ) ;
outer . setAlignItems ( FlexComponent . Alignment . CENTER ) ;
configureSelectionLayout ( ) ;
}
}
private void configureSelectionLayout ( ) {
private void configureSelectionLayout ( ) {
@ -83,19 +76,19 @@ public abstract class SeasonAndMatchdayNavigationView extends Div implements Has
}
}
private HasValue . ValueChangeListener < ? super AbstractField . ComponentValueChangeEvent < Select < Matchday > , Matchday > > matchdaySelectValueChangeListener ( ) {
private HasValue . ValueChangeListener < ? super AbstractField . ComponentValueChangeEvent < Select < Matchday > , Matchday > > matchdaySelectValueChangeListener ( ) {
return matchdayChangeEvent - > getUI ( ) . ifPresent ( ui - > {
return matchdayChangeEvent - > {
Season season = seasonSelect . getValue ( ) ;
Season season = seasonSelect . getValue ( ) ;
Matchday matchday = matchdayChangeEvent . getValue ( ) ;
Matchday matchday = matchdayChangeEvent . getValue ( ) ;
if ( season ! = null & & matchday ! = null ) {
if ( season ! = null & & matchday ! = null ) {
String seasonParam = season . toString ( ) ;
String seasonParam = season . toString ( ) ;
String matchdayParam = matchday . toString ( ) ;
String matchdayParam = matchday . toString ( ) ;
navigate ( ui , seasonParam , matchdayParam ) ;
navigate ( seasonParam , matchdayParam ) ;
}
}
} ) ;
} ;
}
}
private HasValue . ValueChangeListener < ? super AbstractField . ComponentValueChangeEvent < Select < Season > , Season > > seasonSelectValueChangeListener ( ) {
private HasValue . ValueChangeListener < ? super AbstractField . ComponentValueChangeEvent < Select < Season > , Season > > seasonSelectValueChangeListener ( ) {
return seasonChangeEvent - > getUI ( ) . ifPresent ( ui - > {
return seasonChangeEvent - > {
Season newSeason = seasonChangeEvent . getValue ( ) ;
Season newSeason = seasonChangeEvent . getValue ( ) ;
if ( newSeason ! = null ) {
if ( newSeason ! = null ) {
String seasonParam = newSeason . toString ( ) ;
String seasonParam = newSeason . toString ( ) ;
@ -109,9 +102,9 @@ public abstract class SeasonAndMatchdayNavigationView extends Div implements Has
}
}
matchdayParam = matchdayInNewSeason = = null ? "1" : matchdayParam ;
matchdayParam = matchdayInNewSeason = = null ? "1" : matchdayParam ;
navigate ( ui , seasonParam , matchdayParam ) ;
navigate ( seasonParam , matchdayParam ) ;
}
}
} ) ;
} ;
}
}
private void fillSeasonSelectWithData ( ) {
private void fillSeasonSelectWithData ( ) {
@ -122,73 +115,62 @@ public abstract class SeasonAndMatchdayNavigationView extends Div implements Has
private void fillMatchdaySelectWithData ( ) {
private void fillMatchdaySelectWithData ( ) {
matchdayList . clear ( ) ;
matchdayList . clear ( ) ;
List < Matchday > matchdaysToAdd = sh owO nlyMatchdaysWithActivity( ) ?
List < Matchday > matchdaysToAdd = onlyMatchdaysWithActivity ?
matchdayService . getMatchdaysWithActivityForSeasonSorted ( seasonSelect . getValue ( ) ) : matchdayService . getMatchdaysForSeasonSorted ( seasonSelect . getValue ( ) ) ;
matchdayService . getMatchdaysWithActivityForSeasonSorted ( seasonSelect . getValue ( ) ) : matchdayService . getMatchdaysForSeasonSorted ( seasonSelect . getValue ( ) ) ;
matchdayList . addAll ( matchdaysToAdd ) ;
matchdayList . addAll ( matchdaysToAdd ) ;
matchdaySelect . setItems ( matchdayList ) ;
matchdaySelect . setItems ( matchdayList ) ;
}
}
protected boolean isMatchDayParamValid ( @NonNull String matchdayParam ) {
private boolean isMatchDayParamValid ( @NonNull String matchdayParam ) {
return matchdayList . stream ( ) . anyMatch ( matchday - > matchdayParam . equals ( matchday . toString ( ) ) ) ;
return matchdayList . stream ( ) . anyMatch ( matchday - > matchdayParam . equals ( matchday . toString ( ) ) ) ;
}
}
protected void navigate ( UI ui , String seasonParam , String matchdayParam ) {
ui . navigate ( String . format ( "%s/%s/%s/" , route ( ) , seasonParam , matchdayParam ) ) ;
private void navigate ( String seasonParam , String matchdayParam ) {
UI . getCurrent ( ) . navigate ( String . format ( "%s/%s/%s/" , route , seasonParam , matchdayParam ) ) ;
/ / setParameter ( seasonParam , matchdayParam ) ;
}
}
@Override
public void setParameter ( BeforeEvent beforeEvent , @WildcardParameter String param ) {
outer . removeAll ( ) ;
public void setParameter ( String seasonParam , String matchdayParam ) {
/ / TODO : handle corner case where first matchday has no active games yet : still show first matchday
/ / TODO : handle corner case where first matchday has no active games yet : still show first matchday
if ( param . equals ( "" ) ) {
Season latestSeason = seasonService . getLatestSeason ( ) ;
if ( latestSeason ! = null ) {
Matchday latestMatchday = matchdayService . getLastMatchdayWithActivityForSeason ( latestSeason ) ;
if ( latestMatchday ! = null ) {
String seasonParam = latestSeason . toString ( ) ;
String matchdayParam = latestMatchday . toString ( ) ;
navigate ( UI . getCurrent ( ) , seasonParam , matchdayParam ) ;
setParameter ( beforeEvent , String . format ( "%s/%s/" , seasonParam , matchdayParam ) ) ; / / TODO : check why this line seems to be necessary
if ( seasonParam = = null | | seasonParam . equals ( "" ) | | matchdayParam = = null | | matchdayParam . equals ( "" ) ) {
Optional < Season > latestSeason = seasonService . getLatestSeason ( ) ;
if ( latestSeason . isPresent ( ) ) {
Optional < Matchday > latestMatchday = matchdayService . getLastMatchdayWithActivityForSeason ( latestSeason . get ( ) ) ;
if ( latestMatchday . isPresent ( ) ) {
seasonParam = latestSeason . get ( ) . toString ( ) ;
matchdayParam = latestMatchday . get ( ) . toString ( ) ;
navigate ( seasonParam , matchdayParam ) ;
setParameter ( seasonParam , matchdayParam ) ;
}
}
}
}
return ;
return ;
}
}
if ( ! param . matches ( "^[0-9]*/[0-9]*/?$" ) ) {
invalidUrlLabel . setText ( "Invalid URL! Please provide params in the form season/matchday/" ) ;
outer . add ( invalidUrlLabel ) ;
return ;
}
String [ ] params = param . split ( "/" ) ;
seasonParam = params [ 0 ] ;
matchdayParam = params [ 1 ] ;
Season season = getSeasonFromParam ( seasonParam ) ;
Season season = getSeasonFromParam ( seasonParam ) ;
if ( season = = null ) {
if ( season = = null ) {
invalidUrlLabel . setText ( String . format ( "Invalid URL! Season \"%s\" does not exist in the database!" , seasonParam ) ) ;
invalidUrlLabel . setText ( String . format ( "Invalid URL! Season \"%s\" does not exist in the database!" , seasonParam ) ) ;
outer . add ( invalidUrlLabel ) ;
return ;
return ;
}
}
seasonSelect . setValue ( season ) ;
seasonSelect . setValue ( season ) ;
this . seasonParam = seasonParam ;
fillMatchdaySelectWithData ( ) ;
fillMatchdaySelectWithData ( ) ;
Matchday matchday = getMatchdayFromParam ( matchdayParam ) ;
Matchday matchday = getMatchdayFromParam ( matchdayParam ) ;
if ( matchday = = null ) {
if ( matchday = = null ) {
String messageExtra = sh owO nlyMatchdaysWithActivity( ) ? " or has no games played yet" : "" ;
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 ) ) ;
invalidUrlLabel . setText ( String . format ( "Invalid URL! Matchday \"%s\" in Season \"%s\" does not exist in the database%s!" , matchdayParam , seasonParam , messageExtra ) ) ;
outer . add ( invalidUrlLabel ) ;
return ;
return ;
}
}
matchdaySelect . setValue ( matchday ) ;
matchdaySelect . setValue ( matchday ) ;
this . matchdayParam = matchdayParam ;
configureButtons ( ) ;
outer . add ( selectionLayout ) ;
outer . add ( contentLayout ) ;
configureContent ( ) ;
if ( ( runnableToBeRunAfterSelection ) ! = null ) {
runnableToBeRunAfterSelection . run ( ) ;
}
}
}
@Nullable
@Nullable
@ -216,4 +198,61 @@ public abstract class SeasonAndMatchdayNavigationView extends Div implements Has
}
}
return null ;
return null ;
}
}
public void setRunnableToBeRunAfterSelection ( Runnable runnableToBeRunAfterSelection ) {
this . runnableToBeRunAfterSelection = runnableToBeRunAfterSelection ;
}
private void configureButtons ( ) {
prevButton . setEnabled ( isMatchDayParamValid ( getPrevMatchdayParam ( ) ) ) ;
prevButton . addClickListener ( getButtonClickListener ( getPrevMatchdayParam ( ) ) ) ;
nextButton . setEnabled ( isMatchDayParamValid ( getNextMatchdayParam ( ) ) ) ;
nextButton . addClickListener ( getButtonClickListener ( getNextMatchdayParam ( ) ) ) ;
}
private ComponentEventListener < ClickEvent < Button > > getButtonClickListener ( String matchdayParam ) {
return buttonClickEvent - > navigate ( seasonParam , matchdayParam ) ;
}
private String getPrevMatchdayParam ( ) {
try {
return String . valueOf ( Integer . parseInt ( matchdayParam ) - 1 ) ;
} catch ( NumberFormatException e ) {
return "" ;
}
}
private String getNextMatchdayParam ( ) {
try {
return String . valueOf ( Integer . parseInt ( matchdayParam ) + 1 ) ;
} catch ( NumberFormatException e ) {
return "" ;
}
}
public Optional < Matchday > getSelectedMatchday ( ) {
return matchdaySelect . getOptionalValue ( ) ;
}
public Optional < Season > getSelectedSeason ( ) {
return seasonSelect . getOptionalValue ( ) ;
}
public HorizontalLayout getSelectionLayout ( ) {
return selectionLayout ;
}
public Button getPrevButton ( ) {
return prevButton ;
}
public Button getNextButton ( ) {
return nextButton ;
}
public Label getInvalidUrlLabel ( ) {
return invalidUrlLabel ;
}
}
}