From 5104d09b2431c38f2ddc90512997302cff81302a Mon Sep 17 00:00:00 2001 From: "aksenov.vitalii" Date: Sun, 20 Mar 2016 21:47:21 +0300 Subject: [PATCH] Breaking news widget works --- icpc-live-v2.iml | 3 + src/main/java/ru/ifmo/acm/backend/Main.java | 10 +++ .../player/widgets/BreakingNewsWidget.java | 65 +++++++++++++++---- .../backend/player/widgets/TeamWidget.java | 7 ++ .../acm/backend/player/widgets/Widget.java | 16 ++++- .../acm/datapassing/BreakingNewsData.java | 26 +++++--- .../ifmo/acm/datapassing/StandingsData.java | 11 +--- .../ru/ifmo/acm/events/PCMS/PCMSRunInfo.java | 4 ++ src/main/java/ru/ifmo/acm/events/RunInfo.java | 1 + .../ru/ifmo/acm/events/WF/WFEventsLoader.java | 3 +- .../mainscreen/MainScreenStandingsView.java | 18 +++-- src/main/resources/mainscreen.properties | 7 +- 12 files changed, 130 insertions(+), 41 deletions(-) diff --git a/icpc-live-v2.iml b/icpc-live-v2.iml index fa82e70d..39156f56 100644 --- a/icpc-live-v2.iml +++ b/icpc-live-v2.iml @@ -27,6 +27,9 @@ + + + diff --git a/src/main/java/ru/ifmo/acm/backend/Main.java b/src/main/java/ru/ifmo/acm/backend/Main.java index 862a676d..b012147b 100644 --- a/src/main/java/ru/ifmo/acm/backend/Main.java +++ b/src/main/java/ru/ifmo/acm/backend/Main.java @@ -59,6 +59,16 @@ private void run() throws InterruptedException, InvocationTargetException, IOExc generator.addWidget(new QueueWidget(100)); generator.addWidget(new BigStandingsWidget(64, 64, Widget.BASE_WIDTH - 128, Widget.BASE_HEIGHT - 128, updateWait, true)); + generator.addWidget(new BreakingNewsWidget( + updateWait, + (int)(Widget.BASE_WIDTH * 0.65), + (int)(Widget.BASE_HEIGHT * 0.6), + (int)(Widget.BASE_WIDTH * 0.3), + (int)(Widget.BASE_HEIGHT * 0.2), + 16. / 9, + Integer.parseInt(properties.getProperty("sleep.time")), + Integer.parseInt(properties.getProperty("breakingnews.time")) + )); new TickPlayer("Main screen", generator, frameRate).frame.setLocation(0, 0); } diff --git a/src/main/java/ru/ifmo/acm/backend/player/widgets/BreakingNewsWidget.java b/src/main/java/ru/ifmo/acm/backend/player/widgets/BreakingNewsWidget.java index b997e26c..f1ad22fc 100644 --- a/src/main/java/ru/ifmo/acm/backend/player/widgets/BreakingNewsWidget.java +++ b/src/main/java/ru/ifmo/acm/backend/player/widgets/BreakingNewsWidget.java @@ -19,12 +19,13 @@ public class BreakingNewsWidget extends VideoWidget { private final int PLATE_WIDTH; private final int GAP; - public BreakingNewsWidget(int x, int y, int width, int height, double aspectRatio, int sleepTime, int duration) { + public BreakingNewsWidget(long updateWait, int x, int y, int width, int height, double aspectRatio, int sleepTime, int duration) { super(x, y, width, (int) (height / aspectRatio), sleepTime, 0); + this.updateWait = updateWait; wVideo = width; - hVideo = (int) (height / aspectRatio); + hVideo = (int) (width / aspectRatio); - PLATE_WIDTH = (int) (1.5 * width); + PLATE_WIDTH = (int) (1.2 * width); GAP = (int) (0.05 * hVideo); this.x = x; @@ -52,13 +53,19 @@ protected void updateImpl(Data data) { } if (isVisible()) return; - setVisible(true); int teamId = data.breakingNewsData.teamId; int problemId = data.breakingNewsData.problemId; - team = Preparation.eventsLoader.getContestData().getParticipant(teamId).getSmallTeamInfo(); + System.err.println("Get request for " + teamId + " " + problemId); + + team = Preparation.eventsLoader.getContestData().getParticipant(teamId); java.util.List runs = team.getRuns()[problemId]; + + if (runs.size() == 0) { + System.err.println("Team " + teamId + " has no submit for problem " + problemId); + return; + } run = runs.get(runs.size() - 1); for (RunInfo run1 : runs) { if (run1.isAccepted()) { @@ -70,9 +77,11 @@ protected void updateImpl(Data data) { if (data.breakingNewsData.isLive) { url = TeamWidget.getUrl(team, data.breakingNewsData.infoType); } else { - url = run.toString(); + url = TeamWidget.getUrl(run); } + System.err.println("Change to " + url); + change(url); isLive = data.breakingNewsData.isLive; @@ -89,37 +98,69 @@ protected void updateImpl(Data data) { } caption += " problem " + (char) ('A' + problemId); + System.err.println("Caption: " + caption); + currentShow = run.getTeamInfoBefore(); timer = 0; + rankState = 0; + visibilityState = 0; + setVisible(true); } lastUpdate = System.currentTimeMillis(); } + private double localVisibility; + private int rankState; @Override public void paintImpl(Graphics2D g, int width, int height) { update(); - if (visibilityState == 0) { + int dt = updateVisibilityState(); + + if (visibilityState == 0 && !isVisible()) { stop(); return; } - int dt = updateVisibilityState(); - timer += dt; + if (!ready.get()) { + return; + } - if (timer > duration / 2) { + timer += dt; + System.err.println(localVisibility + " " + visibilityState + " " + isVisible()); + if (rankState == 0) { + setVisibilityState(0); + rankState = 1; + } + if (timer > duration / 2 - 1000 && rankState == 1) { + rankState = 2; + localVisibility = 1; + } + if (rankState == 2) { + localVisibility -= dt * V; + localVisibility = Math.max(localVisibility, 0); + if (localVisibility == 0) { + rankState = 3; + } + } + if (rankState == 3) { + localVisibility += dt * V; + localVisibility = Math.min(localVisibility, 1); currentShow = team; + if (localVisibility == 1) { + rankState = 4; + } } - if (run == null || URL.get() == null) { + if (run == null || URL.get() != null) { int hh = (int) (hVideo * opacity); g.drawImage(image.get(), x, y + (hVideo - hh) / 2, wVideo, hh, null); } int y = this.y + hVideo + GAP; int x = this.x + (wVideo - PLATE_WIDTH) / 2; - drawTeamPane(g, currentShow, x, y + hVideo, PLATE_WIDTH, visibilityState); + drawTeamPane(g, currentShow, x, y, PLATE_WIDTH, rankState == 2 || rankState == 3 ? localVisibility : visibilityState); drawTextInRect(g, caption, (int) (x - 0.005 * PLATE_WIDTH), y, -1, PLATE_WIDTH / 10, POSITION_RIGHT, ACCENT_COLOR, Color.white, visibilityState); } diff --git a/src/main/java/ru/ifmo/acm/backend/player/widgets/TeamWidget.java b/src/main/java/ru/ifmo/acm/backend/player/widgets/TeamWidget.java index 7c15e0fc..835ea68e 100644 --- a/src/main/java/ru/ifmo/acm/backend/player/widgets/TeamWidget.java +++ b/src/main/java/ru/ifmo/acm/backend/player/widgets/TeamWidget.java @@ -27,6 +27,9 @@ public class TeamWidget extends VideoWidget { String url = properties.getProperty("info." + types[i], ""); urlTemplates.put(types[i], url); } + if (properties.get("info.record") != null) { + urlTemplates.put("record", properties.getProperty("info.record")); + } } catch (Exception e) { e.printStackTrace(); } @@ -195,4 +198,8 @@ public static String getUrl(TeamInfo team, String infoType) { } return null; } + + public static String getUrl(RunInfo run) { + return String.format(urlTemplates.get("record"), run.getId()); + } } diff --git a/src/main/java/ru/ifmo/acm/backend/player/widgets/Widget.java b/src/main/java/ru/ifmo/acm/backend/player/widgets/Widget.java index e0613545..3608cdc6 100644 --- a/src/main/java/ru/ifmo/acm/backend/player/widgets/Widget.java +++ b/src/main/java/ru/ifmo/acm/backend/player/widgets/Widget.java @@ -75,7 +75,7 @@ public void paint(Graphics2D g, int width, int height, double scale) { } } - private static final double V = 0.001; + protected static final double V = 0.001; protected int updateVisibilityState() { long time = System.currentTimeMillis(); @@ -98,6 +98,14 @@ public void setVisibilityState(double visibilityState) { textOpacity = f(visibilityState * 2 - 1); } + public double getOpacity(double visibilityState) { + return f(visibilityState * 2); + } + + public double getTextOpacity(double visibilityState) { + return f(visibilityState * 2 - 1); + } + protected double f(double x) { if (x < 0) return 0; if (x > 1) return 1; @@ -146,8 +154,10 @@ void drawRect(Graphics2D g, int x, int y, int width, int height, Color color, do static final int POSITION_RIGHT = 1; static final int POSITION_CENTER = 2; - void drawTextInRect(Graphics2D g, String text, int x, int y, int width, int height, int position, Color color, Color textColor, double state) { - setVisibilityState(state); + void drawTextInRect(Graphics2D g, String text, int x, int y, int width, int height, int position, Color color, Color textColor, double visibilityState) { + //setVisibilityState(state); + double opacity = getOpacity(visibilityState); + double textOpacity = getTextOpacity(visibilityState); if (text == null) { text = "NULL"; } diff --git a/src/main/java/ru/ifmo/acm/datapassing/BreakingNewsData.java b/src/main/java/ru/ifmo/acm/datapassing/BreakingNewsData.java index 67cc0eea..b3f61329 100644 --- a/src/main/java/ru/ifmo/acm/datapassing/BreakingNewsData.java +++ b/src/main/java/ru/ifmo/acm/datapassing/BreakingNewsData.java @@ -11,6 +11,10 @@ public BreakingNewsData initialize() { BreakingNewsData data = MainScreenData.getMainScreenData().breakingNewsData; this.timestamp = data.timestamp; this.isVisible = data.isVisible; + this.isLive = data.isLive; + this.teamId = data.teamId; + this.problemId = data.problemId; + this.infoType = data.infoType; return this; } @@ -19,16 +23,17 @@ public void recache() { } public synchronized boolean setNewsVisible(boolean visible, String type, boolean isLive, String info) { + if (visible && isVisible) { + return false; + } + this.isVisible = visible; if (visible) { String[] zz = info.split(" "); - int teamId = Integer.parseInt(zz[0]); + int teamId = Integer.parseInt(zz[0]) - 1; int problemId = zz[1].charAt(0) - 'A'; - if (timestamp + MainScreenData.getProperties().sleepTime > System.currentTimeMillis() && isVisible) { - return false; - } TeamInfo teamInfo = MainScreenData.getProperties().contestInfo.getParticipant(teamId); this.teamId = teamId; this.problemId = problemId; @@ -47,7 +52,8 @@ public void update() { synchronized (breakingNewsLock) { //System.err.println(PCMSEventsLoader.getInstance().getContestData().getTeamsNumber()); if (System.currentTimeMillis() > timestamp + - MainScreenData.getProperties().breakingNewsTimeToShow) { + MainScreenData.getProperties().breakingNewsTimeToShow + + MainScreenData.getProperties().sleepTime) { isVisible = false; change = true; } @@ -62,12 +68,14 @@ public String toString() { public String getStatus() { if (isVisible) { - String status = "Breaking news (%s) are shown for team %d and problem %c for %d seconds"; + String status = "Breaking news (%s) are shown for team %s and problem %c for %d seconds"; - long time = (timestamp + MainScreenData.getProperties().breakingNewsTimeToShow - System.currentTimeMillis()) / 1000; - String type = isLive ? "Live" : infoType; + long time = (timestamp + MainScreenData.getProperties().breakingNewsTimeToShow + + MainScreenData.getProperties().sleepTime + - System.currentTimeMillis()) / 1000; + String type = isLive ? infoType : "record"; - return String.format(status, type, teamId, (char)('A' + problemId), time); + return String.format(status, type, teamName, (char) ('A' + problemId), time); } else { return "Breaking news aren't shown"; } diff --git a/src/main/java/ru/ifmo/acm/datapassing/StandingsData.java b/src/main/java/ru/ifmo/acm/datapassing/StandingsData.java index b17e1815..9eaac54c 100644 --- a/src/main/java/ru/ifmo/acm/datapassing/StandingsData.java +++ b/src/main/java/ru/ifmo/acm/datapassing/StandingsData.java @@ -4,6 +4,7 @@ import ru.ifmo.acm.backend.player.widgets.StandingsWidget; import ru.ifmo.acm.events.EventsLoader; import ru.ifmo.acm.mainscreen.MainScreenData; +import ru.ifmo.acm.mainscreen.MainScreenProperties; public class StandingsData implements CachedData { @Override @@ -31,10 +32,6 @@ public String toString() { (isBig() ? " big standings are shown" : " compact standings are shown"); } - public long getLatency() { - return latency; - } - public void recache() { Data.cache.refresh(StandingsData.class); } @@ -53,8 +50,8 @@ public void setStandingsVisible(boolean visible, StandingsType type, boolean isB public static long getTotalTime(boolean isBig, StandingsType type) { return isBig ? - BigStandingsWidget.totalTime(type, EventsLoader.getInstance().getContestData().getTeamsNumber()) + latency : - StandingsWidget.totalTime(type, EventsLoader.getInstance().getContestData().getTeamsNumber()) + latency; + BigStandingsWidget.totalTime(type, EventsLoader.getInstance().getContestData().getTeamsNumber()) + MainScreenData.getProperties().latency : + StandingsWidget.totalTime(type, EventsLoader.getInstance().getContestData().getTeamsNumber()) + MainScreenData.getProperties().latency; } public void update() { @@ -98,8 +95,6 @@ public void setBig(boolean big) { public boolean isBig; public OptimismLevel optimismLevel = OptimismLevel.NORMAL; - public static long latency; - final private Object standingsLock = new Object(); public enum StandingsType { diff --git a/src/main/java/ru/ifmo/acm/events/PCMS/PCMSRunInfo.java b/src/main/java/ru/ifmo/acm/events/PCMS/PCMSRunInfo.java index 33407f71..9ba8d7cd 100644 --- a/src/main/java/ru/ifmo/acm/events/PCMS/PCMSRunInfo.java +++ b/src/main/java/ru/ifmo/acm/events/PCMS/PCMSRunInfo.java @@ -24,6 +24,10 @@ public class PCMSRunInfo implements RunInfo { this.firstToSolve = firstToSolve; } + public int getId() { + throw new AssertionError("PCMSRunInfo doesn't have id"); + } + public boolean isAccepted() { return "AC".equals(result); } diff --git a/src/main/java/ru/ifmo/acm/events/RunInfo.java b/src/main/java/ru/ifmo/acm/events/RunInfo.java index 4ac91d29..16e47e7c 100644 --- a/src/main/java/ru/ifmo/acm/events/RunInfo.java +++ b/src/main/java/ru/ifmo/acm/events/RunInfo.java @@ -1,6 +1,7 @@ package ru.ifmo.acm.events; public interface RunInfo { + int getId(); boolean isAccepted(); boolean isJudged(); String getResult(); diff --git a/src/main/java/ru/ifmo/acm/events/WF/WFEventsLoader.java b/src/main/java/ru/ifmo/acm/events/WF/WFEventsLoader.java index 3354a9cf..15311925 100644 --- a/src/main/java/ru/ifmo/acm/events/WF/WFEventsLoader.java +++ b/src/main/java/ru/ifmo/acm/events/WF/WFEventsLoader.java @@ -77,7 +77,8 @@ private List problemsInfoRead() throws IOException { problem.name = val; break; case "rgb": - problem.color = Color.decode(val.substring(1, 8)); + //System.err.println(val + " " + val.length()); + problem.color = Color.decode(val); break; } } diff --git a/src/main/java/ru/ifmo/acm/mainscreen/MainScreenStandingsView.java b/src/main/java/ru/ifmo/acm/mainscreen/MainScreenStandingsView.java index 0c088c36..8ba4e200 100644 --- a/src/main/java/ru/ifmo/acm/mainscreen/MainScreenStandingsView.java +++ b/src/main/java/ru/ifmo/acm/mainscreen/MainScreenStandingsView.java @@ -64,17 +64,20 @@ public Component getBreakingNewsController() { isLive = new CheckBox("Is live"); isLive.addValueChangeListener(event -> { - types.setValue(isLive.getValue() ? null: TeamWidget.types[0]); - for (String type : TeamWidget.types) { - types.setItemEnabled(type, isLive.isEmpty()); - } + //types.setValue(isLive.getValue() ? null: TeamWidget.types[0]); +// for (String type : TeamWidget.types) { +// types.setItemEnabled(type, !isLive.getValue()); +// } + types.setEnabled(isLive.getValue()); breakingNewsStatus.setValue(getBreakingNewsStatus()); }); + isLive.setValue(false); types = new OptionGroup(); types.addItems(TeamWidget.types); types.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); types.setValue(TeamWidget.types[0]); + types.setEnabled(false); team = new TextField("Team: "); team.setSizeFull(); @@ -85,7 +88,12 @@ public Component getBreakingNewsController() { Notification.show("Team field requires team id and problem id"); } else { if (!mainScreenData.breakingNewsData.setNewsVisible(true, (String) types.getValue(), isLive.getValue(), team.getValue())) { - Notification.show("You need to wait 30 seconds first", Notification.Type.WARNING_MESSAGE); + Notification.show( + String.format("You need to wait while current breaking news is shown"), + Notification.Type.WARNING_MESSAGE + ); + } else { + team.clear(); } breakingNewsStatus.setValue(getBreakingNewsStatus()); } diff --git a/src/main/resources/mainscreen.properties b/src/main/resources/mainscreen.properties index a5b10a6e..7107ac6b 100644 --- a/src/main/resources/mainscreen.properties +++ b/src/main/resources/mainscreen.properties @@ -3,13 +3,14 @@ backup.advertisements=advertisements.txt advertisement.time=5000 person.time=5000 latency.time=2000 -breakingnews.time=5000 +breakingnews.time=20000 data.update=1000 data.host=localhost data.port=25675 info.types=screen;camera info.screen=http://10.25.94.24:9080/video/screen/%d info.camera=http://10.25.94.24:9080/video/camera/%d +info.record=pics/logo.png sleep.time=3000 camera.number=2 @@ -17,6 +18,6 @@ camera.url.1=null camera.name.1=studio camera.url.2=null camera.name.2=commentators -width=1920 -height=1080 +width=920 +height=560 rate=25 \ No newline at end of file