diff --git a/db/db_init.sql b/db/db_init.sql index 2f49630..4ca7207 100644 --- a/db/db_init.sql +++ b/db/db_init.sql @@ -106,7 +106,7 @@ INSERT INTO "player_info" (url) VALUES ('https://www.chess.com/member/maddinglad INSERT INTO "player" (name, nickname, info) VALUES ('Maddin', 'maddingladi', (SELECT id from player_info WHERE url='https://www.chess.com/member/maddingladi') ); INSERT INTO "player_info" (url) VALUES ('https://www.chess.com/member/magnus-brother'); -INSERT INTO "player" (name, nickname, info) VALUES ('Tariq', 'Magnus-brother', (SELECT id from player_info WHERE url='https://www.chess.com/member/magnus-brother') ); +INSERT INTO "player" (name, nickname, info) VALUES ('Tariq', 'Magnus-Brother', (SELECT id from player_info WHERE url='https://www.chess.com/member/magnus-brother') ); INSERT INTO "player_info" (url) VALUES ('https://www.chess.com/member/mama-lolo'); INSERT INTO "player" (name, nickname, info) VALUES ('Malte', 'Mama-Lolo', (SELECT id from player_info WHERE url='https://www.chess.com/member/mama-lolo') ); diff --git a/src/main/java/app/gameimage/GameImageService.java b/src/main/java/app/gameimage/GameImageService.java index c8b1fad..6116e1c 100644 --- a/src/main/java/app/gameimage/GameImageService.java +++ b/src/main/java/app/gameimage/GameImageService.java @@ -3,12 +3,18 @@ package app.gameimage; import app.data.chesscom.ChessComGame; import app.data.entity.Game; import app.data.service.ChessComService; +import com.vaadin.flow.component.html.Image; +import com.vaadin.flow.server.StreamResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.ByteArrayInputStream; import java.io.File; import java.util.Optional; +import static app.gameimage.GameImageGenerator.*; +import static app.gameimage.GameImageUtils.*; + @Service public class GameImageService { @@ -20,29 +26,24 @@ public class GameImageService { public boolean hasImage(Game game) { - String path = GameImageUtils.IMAGE_DEST_PATH_SERVER + getGameNumber(game) + GameImageUtils.EXTENSION; + String path = IMAGE_DEST_DIR + getGameId(game) + EXTENSION; File f = new File(path); return f.isFile(); } - public boolean createImageIfNotPresent(Game game) { - if (hasImage(game)) return true; - Optional optionalFen = getFen(game); - - if (optionalFen.isPresent()) { - GameImageUtils.writeImage(GameImageGenerator.generateImage(optionalFen.get()), getGameNumber(game)); - return true; - } - return false; + public void createImageIfNotPresent(Game game) { + if (hasImage(game)) return; + getFen(game).ifPresent(fen -> GameImageUtils.writeImage(generateImage(fen), getGameId(game))); } - private String getGameNumber(Game game) { - String[] url = game.getGameInfo().getChessComId().split("/"); - return url[url.length - 1]; + public Image getImage(Game game, String alt) { + StreamResource resource = new StreamResource(getImageFilename(game), () -> new ByteArrayInputStream(getImageBytes(game))); + return new Image(resource, alt); } private Optional getFen(Game game) { if (game.getGameInfo().getFen() != null) return Optional.of(game.getGameInfo().getFen()); return chessComService.getChessComGame(game).map(ChessComGame::getFen); } + } diff --git a/src/main/java/app/gameimage/GameImageUtils.java b/src/main/java/app/gameimage/GameImageUtils.java index 586ba09..e76ee17 100644 --- a/src/main/java/app/gameimage/GameImageUtils.java +++ b/src/main/java/app/gameimage/GameImageUtils.java @@ -1,24 +1,30 @@ package app.gameimage; +import app.data.entity.Game; +import com.vaadin.flow.component.html.Image; +import com.vaadin.flow.server.StreamResource; +import org.apache.commons.io.FileUtils; + import javax.imageio.ImageIO; import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; public class GameImageUtils { - public static final String IMAGE_PATH_CLIENT = "images/games/"; - public static final String EXTENSION = ".png"; + static final String EXTENSION = ".png"; - static final String IMAGE_SOURCE_PATH_SERVER = "src/main/resources/META-INF/resources/images/chess-sources/"; - static final String IMAGE_DEST_PATH_SERVER = "src/main/resources/META-INF/resources/images/games/"; + static final String IMAGE_SOURCE_DIR = "src/main/resources/META-INF/resources/images/chess-sources/"; + static final String IMAGE_DEST_DIR = "src/main/resources/META-INF/resources/images/games/"; private static final String EXTENSION_WITHOUT_DOT = "png"; - private GameImageUtils() {} + private GameImageUtils() { + } public static BufferedImage readImage(String fileNameWithoutExtension) { BufferedImage img = null; try { - String path = IMAGE_SOURCE_PATH_SERVER + fileNameWithoutExtension + EXTENSION; + String path = IMAGE_SOURCE_DIR + fileNameWithoutExtension + EXTENSION; img = ImageIO.read(new File(path)); } catch (IOException e) { e.printStackTrace(); @@ -28,11 +34,33 @@ public class GameImageUtils { public static void writeImage(BufferedImage img, String fileNameWithoutExtension) { try { - String path = IMAGE_DEST_PATH_SERVER + fileNameWithoutExtension + EXTENSION; + String path = IMAGE_DEST_DIR + fileNameWithoutExtension + EXTENSION; File outputFile = new File(path); ImageIO.write(img, EXTENSION_WITHOUT_DOT, outputFile); } catch (IOException e) { e.printStackTrace(); } } + + private static String getImagePath(Game game) { + return IMAGE_DEST_DIR + getImageFilename(game); + } + + static String getImageFilename(Game game) { + return getGameId(game) + EXTENSION; + } + + static String getGameId(Game game) { + String[] urlParts = game.getGameInfo().getChessComId().split("/"); + return urlParts[urlParts.length - 1]; + } + + static byte[] getImageBytes(Game game) { + try { + return FileUtils.readFileToByteArray(new File(getImagePath(game))); + } catch (IOException e) { + return new byte[0]; + } + } + } diff --git a/src/main/java/app/views/match/components/GameComponent.java b/src/main/java/app/views/match/components/GameComponent.java index 5381c7a..46cf601 100644 --- a/src/main/java/app/views/match/components/GameComponent.java +++ b/src/main/java/app/views/match/components/GameComponent.java @@ -30,19 +30,19 @@ public class GameComponent extends Div { addClassName("wrapper"); addClassName("game-card"); - configureInner(); + defineInner(); } - private void configureInner() { + private void defineInner() { add(inner); inner.add(left, right); inner.setAlignItems(FlexComponent.Alignment.CENTER); - configureLeft(); - configureRight(); + defineLeft(); + defineRight(); } - private void configureLeft() { + private void defineLeft() { Label header = GameComponentUtils.getHeader(game); Div timeControlDiv = GameComponentUtils.getTimeControlDiv(game); Div blackDiv = GameComponentUtils.getPlayerDiv(game, false); @@ -58,11 +58,11 @@ public class GameComponent extends Div { } - private void configureRight() { + private void defineRight() { right.addClassName("game-image-div"); gameImageService.createImageIfNotPresent(game); - Image image = new Image(GameComponentUtils.getImagePath(game), "Could not load game image."); + Image image = gameImageService.getImage(game, "Could not load game image."); right.add(image); image.setWidthFull(); image.setHeightFull(); diff --git a/src/main/java/app/views/match/components/MatchComponent.java b/src/main/java/app/views/match/components/MatchComponent.java index 60bd496..7921956 100644 --- a/src/main/java/app/views/match/components/MatchComponent.java +++ b/src/main/java/app/views/match/components/MatchComponent.java @@ -50,7 +50,9 @@ public class MatchComponent extends Div implements ContentConfigurable { private final FlexLayout editLayoutWrapper = new FlexLayout(); private final VerticalLayout editLayout = new VerticalLayout(); private final ArrayList editTextFields = new ArrayList<>(); + // TODO: autocorrect "/live/game" to "/game/live/" private final Button editSubmitButton = new Button("Submit", new Icon(VaadinIcon.CHECK)); + // TODO: disable when no 6 values in form, and make sure you don't freeze forever when there are wrong entries private Registration editSubmitButtonRegistration; private final Button editCancelButton = new Button("Cancel", new Icon(VaadinIcon.CLOSE)); private Registration editCancelButtonRegistration; @@ -72,13 +74,13 @@ public class MatchComponent extends Div implements ContentConfigurable { add(headerLayout); - configureHeaderLayout(); - configureGamesLayout(); - configureNoGamesLayout(); - configureEditLayout(); + defineHeaderLayout(); + defineGamesLayout(); + defineNoGamesLayout(); + defineEditLayout(); } - private void configureNoGamesLayout() { + private void defineNoGamesLayout() { Label label = new Label("No games for this match in the database."); Button button = new Button("Add games", new Icon(VaadinIcon.PLUS)); button.addThemeVariants(ButtonVariant.LUMO_PRIMARY); @@ -90,7 +92,7 @@ public class MatchComponent extends Div implements ContentConfigurable { noGamesLayout.setAlignItems(FlexComponent.Alignment.CENTER); } - private void configureHeaderLayout() { + private void defineHeaderLayout() { headerLayout.add(headerPlayersLayout, headerResultLabel); headerPlayersLayout.addClassName("match-header-players"); @@ -99,12 +101,12 @@ public class MatchComponent extends Div implements ContentConfigurable { headerResultLabel.addClassName("bold-header"); } - private void configureGamesLayout() { + private void defineGamesLayout() { gamesLayout.setFlexWrap(FlexLayout.FlexWrap.WRAP); gamesLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); } - private void configureEditLayout() { + private void defineEditLayout() { editLayoutWrapper.add(editLayout); editLayoutWrapper.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); diff --git a/src/main/java/app/views/match/components/utils/GameComponentUtils.java b/src/main/java/app/views/match/components/utils/GameComponentUtils.java index 0305d42..ee4a00a 100644 --- a/src/main/java/app/views/match/components/utils/GameComponentUtils.java +++ b/src/main/java/app/views/match/components/utils/GameComponentUtils.java @@ -8,14 +8,21 @@ import app.utils.EntityComponentUtils; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.Image; import com.vaadin.flow.component.html.Label; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.server.StreamResource; +import org.apache.commons.io.FileUtils; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class GameComponentUtils { private GameComponentUtils() { @@ -28,10 +35,6 @@ public class GameComponentUtils { return games.indexOf(game) + 1; } - public static String getImagePath(Game game) { - String[] urlParts = game.getGameInfo().getChessComId().split("/"); - return GameImageUtils.IMAGE_PATH_CLIENT + urlParts[urlParts.length - 1] + GameImageUtils.EXTENSION; - } public static Player getWhitePlayer(Game game) { return game.getPlayer1IsWhite() ? game.getMatch().getPlayer1() : game.getMatch().getPlayer2(); diff --git a/src/main/java/app/views/matchday/components/MatchdayComponent.java b/src/main/java/app/views/matchday/components/MatchdayComponent.java index 4fd7d25..05d1522 100644 --- a/src/main/java/app/views/matchday/components/MatchdayComponent.java +++ b/src/main/java/app/views/matchday/components/MatchdayComponent.java @@ -39,11 +39,11 @@ public class MatchdayComponent extends Div implements ContentConfigurable { add(inner); inner.add(header, grid); - configureHeader(); - configureGrid(); + defineHeader(); + defineGrid(); } - private void configureHeader() { + private void defineHeader() { header.add(new PrevMatchdayButton(this.navigation), headerLabel, new NextMatchdayButton(this.navigation)); header.setWidthFull(); @@ -51,7 +51,7 @@ public class MatchdayComponent extends Div implements ContentConfigurable { } - private void configureGrid() { + private void defineGrid() { Label headerPlayer1 = new Label("Player 1"); headerPlayer1.addClassName("column_header"); Label headerPlayer2 = new Label("Player 2"); diff --git a/src/main/java/app/views/navigation/NavigationViewBase.java b/src/main/java/app/views/navigation/NavigationViewBase.java index a79b195..8167c27 100644 --- a/src/main/java/app/views/navigation/NavigationViewBase.java +++ b/src/main/java/app/views/navigation/NavigationViewBase.java @@ -25,10 +25,10 @@ public abstract class NavigationViewBase extends VerticalLayout implements HasUr this.navigationHeader = new NavigationHeader(navigation); - configure(); + define(); } - private void configure() { + private void define() { add(navigationHeader); addClassName("content"); setAlignItems(FlexComponent.Alignment.CENTER); diff --git a/src/main/java/app/views/table/components/TableComponent.java b/src/main/java/app/views/table/components/TableComponent.java index 447a255..68e00a3 100644 --- a/src/main/java/app/views/table/components/TableComponent.java +++ b/src/main/java/app/views/table/components/TableComponent.java @@ -31,10 +31,10 @@ public class TableComponent extends Div implements ContentConfigurable { addClassName("grid-wrapper"); add(grid); - configureGrid(); + defineGrid(); } - private void configureGrid() { + private void defineGrid() { // TODO: add diff to last matchday // TODO: rounded corners for rows?