mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Merge remote-tracking branch 'origin/OtherGames' into OtherGames
This commit is contained in:
115
app/src/main/java/org/toop/app/view/displays/SongDisplay.java
Normal file
115
app/src/main/java/org/toop/app/view/displays/SongDisplay.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package org.toop.app.view.displays;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ProgressBar;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.toop.framework.audio.AudioEventListener;
|
||||||
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import org.toop.framework.eventbus.GlobalEventBus;
|
||||||
|
|
||||||
|
public class SongDisplay extends VBox {
|
||||||
|
|
||||||
|
private final Text songTitle;
|
||||||
|
private final ProgressBar progressBar;
|
||||||
|
private final Text progressText;
|
||||||
|
|
||||||
|
public SongDisplay() {
|
||||||
|
new EventFlow()
|
||||||
|
.listen(this::updateTheSong);
|
||||||
|
|
||||||
|
setAlignment(Pos.CENTER);
|
||||||
|
getStyleClass().add("song-display");
|
||||||
|
|
||||||
|
// TODO ADD GOOD SONG TITLES WITH ARTISTS DISPLAYED
|
||||||
|
songTitle = new Text("song playing");
|
||||||
|
songTitle.getStyleClass().add("song-title");
|
||||||
|
|
||||||
|
progressBar = new ProgressBar(0);
|
||||||
|
progressBar.getStyleClass().add("progress-bar");
|
||||||
|
|
||||||
|
progressText = new Text("0:00/0:00");
|
||||||
|
progressText.getStyleClass().add("progress-text");
|
||||||
|
|
||||||
|
// TODO ADD BETTER CSS FOR THE SKIPBUTTON WHERE ITS AT A NICER POSITION
|
||||||
|
|
||||||
|
Button skipButton = new Button(">>");
|
||||||
|
Button pauseButton = new Button("⏸");
|
||||||
|
Button previousButton = new Button("<<");
|
||||||
|
|
||||||
|
skipButton.getStyleClass().setAll("skip-button");
|
||||||
|
pauseButton.getStyleClass().setAll("pause-button");
|
||||||
|
previousButton.getStyleClass().setAll("previous-button");
|
||||||
|
|
||||||
|
skipButton.setOnAction( event -> {
|
||||||
|
GlobalEventBus.post(new AudioEvents.SkipMusic());
|
||||||
|
});
|
||||||
|
|
||||||
|
pauseButton.setOnAction(event -> {
|
||||||
|
GlobalEventBus.post(new AudioEvents.PauseMusic());
|
||||||
|
if (pauseButton.getText().equals("⏸")) {
|
||||||
|
pauseButton.setText("▶");
|
||||||
|
}
|
||||||
|
else if (pauseButton.getText().equals("▶")) {
|
||||||
|
pauseButton.setText("⏸");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
previousButton.setOnAction( event -> {
|
||||||
|
GlobalEventBus.post(new AudioEvents.PreviousMusic());
|
||||||
|
});
|
||||||
|
|
||||||
|
HBox control = new HBox(10, previousButton, pauseButton, skipButton);
|
||||||
|
control.setAlignment(Pos.CENTER);
|
||||||
|
control.getStyleClass().add("controls");
|
||||||
|
|
||||||
|
getChildren().addAll(songTitle, progressBar, progressText, control);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTheSong(AudioEvents.PlayingMusic event) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
String text = event.name();
|
||||||
|
text = text.substring(0, text.length() - 4);
|
||||||
|
songTitle.setText(text);
|
||||||
|
double currentPos = event.currentPosition();
|
||||||
|
double duration = event.duration();
|
||||||
|
if (currentPos / duration > 0.05) {
|
||||||
|
double progress = currentPos / duration;
|
||||||
|
progressBar.setProgress(progress);
|
||||||
|
}
|
||||||
|
else if (currentPos / duration < 0.05) {
|
||||||
|
progressBar.setProgress(0.05);
|
||||||
|
}
|
||||||
|
progressText.setText(getTimeString(event.currentPosition(), event.duration()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTimeString(long position, long duration) {
|
||||||
|
long positionMinutes = position / 60;
|
||||||
|
long durationMinutes = duration / 60;
|
||||||
|
long positionSeconds = position % 60;
|
||||||
|
long durationSeconds = duration % 60;
|
||||||
|
String positionSecondsStr = String.valueOf(positionSeconds);
|
||||||
|
String durationSecondsStr = String.valueOf(durationSeconds);
|
||||||
|
|
||||||
|
if (positionSeconds < 10) {
|
||||||
|
positionSecondsStr = "0" + positionSeconds;
|
||||||
|
}
|
||||||
|
if (durationSeconds < 10) {
|
||||||
|
durationSecondsStr = "0" + durationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
String time = positionMinutes + ":" + positionSecondsStr + " / " + durationMinutes + ":" + durationSecondsStr;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import org.toop.app.GameInformation;
|
|||||||
import org.toop.app.Server;
|
import org.toop.app.Server;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -95,6 +96,14 @@ public final class ChallengeView extends View {
|
|||||||
nodes.add(vbox(computerDifficultyText, computerDifficultySlider));
|
nodes.add(vbox(computerDifficultyText, computerDifficultySlider));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit(hboxFill(
|
fit(hboxFill(
|
||||||
vboxFill(
|
vboxFill(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.toop.app.view.views;
|
|||||||
import org.toop.app.App;
|
import org.toop.app.App;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.animation.KeyFrame;
|
import javafx.animation.KeyFrame;
|
||||||
@@ -46,6 +47,14 @@ public final class CreditsView extends View {
|
|||||||
final Text openglHeader = header();
|
final Text openglHeader = header();
|
||||||
openglHeader.setText(AppContext.getString("opengl") + ": Omar");
|
openglHeader.setText(AppContext.getString("opengl") + ": Omar");
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit("credits-fit", vboxFill("credits-container", "credits-container",
|
fit("credits-fit", vboxFill("credits-container", "credits-container",
|
||||||
vbox("credits-spacer-top", ""),
|
vbox("credits-spacer-top", ""),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.toop.app.view.views;
|
|||||||
|
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -85,6 +86,14 @@ public final class GameView extends View {
|
|||||||
forfeitButton = null;
|
forfeitButton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
if (onMessage != null) {
|
if (onMessage != null) {
|
||||||
chatListView = new ListView<Text>();
|
chatListView = new ListView<Text>();
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.toop.app.game.ReversiGame;
|
|||||||
import org.toop.app.game.TicTacToeGame;
|
import org.toop.app.game.TicTacToeGame;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -51,6 +52,14 @@ public final class LocalMultiplayerView extends View {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit(vboxFill(
|
fit(vboxFill(
|
||||||
hbox(
|
hbox(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.toop.app.view.views;
|
|||||||
import org.toop.app.GameInformation;
|
import org.toop.app.GameInformation;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -39,6 +40,14 @@ public final class LocalView extends View {
|
|||||||
backButton.setText(AppContext.getString("back"));
|
backButton.setText(AppContext.getString("back"));
|
||||||
backButton.setOnAction(_ -> { ViewStack.push(new MainView()); });
|
backButton.setOnAction(_ -> { ViewStack.push(new MainView()); });
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.BOTTOM_LEFT,
|
add(Pos.BOTTOM_LEFT,
|
||||||
vboxFill(
|
vboxFill(
|
||||||
backButton
|
backButton
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import org.toop.app.App;
|
|||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
||||||
@@ -35,6 +35,13 @@ public final class MainView extends View {
|
|||||||
quitButton.setText(AppContext.getString("quit"));
|
quitButton.setText(AppContext.getString("quit"));
|
||||||
quitButton.setOnAction(_ -> { App.startQuit(); });
|
quitButton.setOnAction(_ -> { App.startQuit(); });
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit(vboxFill(
|
fit(vboxFill(
|
||||||
localButton,
|
localButton,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.toop.app.view.views;
|
|||||||
import org.toop.app.Server;
|
import org.toop.app.Server;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -44,6 +45,13 @@ public class OnlineView extends View {
|
|||||||
new Server(serverIPInput.getText(), serverPortInput.getText(), playerNameInput.getText());
|
new Server(serverIPInput.getText(), serverPortInput.getText(), playerNameInput.getText());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit(vboxFill(
|
fit(vboxFill(
|
||||||
serverInformationHeader,
|
serverInformationHeader,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.toop.app.view.views;
|
|||||||
import org.toop.app.App;
|
import org.toop.app.App;
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.framework.audio.VolumeControl;
|
import org.toop.framework.audio.VolumeControl;
|
||||||
import org.toop.framework.audio.events.AudioEvents;
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
@@ -99,6 +100,14 @@ public final class OptionsView extends View {
|
|||||||
backButton.setText(AppContext.getString("back"));
|
backButton.setText(AppContext.getString("back"));
|
||||||
backButton.setOnAction(_ -> { ViewStack.pop(); });
|
backButton.setOnAction(_ -> { ViewStack.pop(); });
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.BOTTOM_LEFT,
|
add(Pos.BOTTOM_LEFT,
|
||||||
vboxFill(
|
vboxFill(
|
||||||
backButton
|
backButton
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.toop.app.view.views;
|
|||||||
|
|
||||||
import org.toop.app.view.View;
|
import org.toop.app.view.View;
|
||||||
import org.toop.app.view.ViewStack;
|
import org.toop.app.view.ViewStack;
|
||||||
|
import org.toop.app.view.displays.SongDisplay;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@@ -53,6 +54,14 @@ public final class ServerView extends View {
|
|||||||
|
|
||||||
listView = new ListView<Button>();
|
listView = new ListView<Button>();
|
||||||
|
|
||||||
|
final SongDisplay songdisplay = new SongDisplay();
|
||||||
|
|
||||||
|
|
||||||
|
add(Pos.BOTTOM_RIGHT,
|
||||||
|
fit(vboxFill(
|
||||||
|
songdisplay
|
||||||
|
)));
|
||||||
|
|
||||||
add(Pos.CENTER,
|
add(Pos.CENTER,
|
||||||
fit(vboxFill(
|
fit(vboxFill(
|
||||||
vbox(
|
vbox(
|
||||||
|
|||||||
@@ -12,6 +12,71 @@
|
|||||||
-fx-effect: dropshadow(gaussian, #224455cc, 8, 0, 0, 2);
|
-fx-effect: dropshadow(gaussian, #224455cc, 8, 0, 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-display {
|
||||||
|
-fx-padding: 8 12 8 12;
|
||||||
|
-fx-spacing: 6px;
|
||||||
|
-fx-alignment: center;
|
||||||
|
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 6, 0.5, 0, 2);
|
||||||
|
-fx-min-width: 220px;
|
||||||
|
-fx-max-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-title {
|
||||||
|
-fx-font-size: 14px;
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
-fx-pref-width: 200px;
|
||||||
|
-fx-accent: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .track {
|
||||||
|
-fx-background-radius: 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .bar {
|
||||||
|
-fx-background-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
-fx-font-size: 11px;
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
-fx-background-color: linear-gradient(to bottom, #1f5e20, #2e7d2e);
|
-fx-background-color: linear-gradient(to bottom, #1f5e20, #2e7d2e);
|
||||||
-fx-background-radius: 8;
|
-fx-background-radius: 8;
|
||||||
|
|||||||
@@ -12,6 +12,71 @@
|
|||||||
-fx-effect: dropshadow(gaussian, #1f6a22ff, 10, 0, 0, 3);
|
-fx-effect: dropshadow(gaussian, #1f6a22ff, 10, 0, 0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-display {
|
||||||
|
-fx-padding: 8 12 8 12;
|
||||||
|
-fx-spacing: 6px;
|
||||||
|
-fx-alignment: center;
|
||||||
|
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 6, 0.5, 0, 2);
|
||||||
|
-fx-min-width: 220px;
|
||||||
|
-fx-max-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-title {
|
||||||
|
-fx-font-size: 14px;
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
-fx-pref-width: 200px;
|
||||||
|
-fx-accent: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .track {
|
||||||
|
-fx-background-radius: 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .bar {
|
||||||
|
-fx-background-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
-fx-font-size: 11px;
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button .text {
|
||||||
|
-fx-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
-fx-background-color: linear-gradient(to bottom, #1b7a1b, #2da32d);
|
-fx-background-color: linear-gradient(to bottom, #1b7a1b, #2da32d);
|
||||||
-fx-background-radius: 8;
|
-fx-background-radius: 8;
|
||||||
|
|||||||
@@ -12,6 +12,72 @@
|
|||||||
-fx-effect: dropshadow(gaussian, #a0c4b088, 6, 0, 0, 2);
|
-fx-effect: dropshadow(gaussian, #a0c4b088, 6, 0, 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-display {
|
||||||
|
-fx-padding: 8 12 8 12;
|
||||||
|
-fx-spacing: 6px;
|
||||||
|
-fx-alignment: center;
|
||||||
|
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 6, 0.5, 0, 2);
|
||||||
|
-fx-min-width: 220px;
|
||||||
|
-fx-max-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-title {
|
||||||
|
-fx-font-size: 14px;
|
||||||
|
-fx-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
-fx-inner-background-color: black;
|
||||||
|
-fx-pref-width: 200px;
|
||||||
|
-fx-accent: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .track {
|
||||||
|
-fx-background-radius: 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .bar {
|
||||||
|
-fx-background-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
-fx-font-size: 11px;
|
||||||
|
-fx-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-button .text {
|
||||||
|
-fx-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pause-button .text {
|
||||||
|
-fx-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-button .text {
|
||||||
|
-fx-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
-fx-background-color: linear-gradient(to bottom, #7ac27a, #90d090);
|
-fx-background-color: linear-gradient(to bottom, #7ac27a, #90d090);
|
||||||
-fx-background-radius: 8;
|
-fx-background-radius: 8;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.toop.framework.audio.interfaces.MusicManager;
|
|||||||
import org.toop.framework.audio.interfaces.SoundEffectManager;
|
import org.toop.framework.audio.interfaces.SoundEffectManager;
|
||||||
import org.toop.framework.audio.interfaces.VolumeManager;
|
import org.toop.framework.audio.interfaces.VolumeManager;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
|
import org.toop.framework.eventbus.GlobalEventBus;
|
||||||
import org.toop.framework.resource.types.AudioResource;
|
import org.toop.framework.resource.types.AudioResource;
|
||||||
|
|
||||||
public class AudioEventListener<T extends AudioResource, K extends AudioResource> {
|
public class AudioEventListener<T extends AudioResource, K extends AudioResource> {
|
||||||
@@ -26,6 +27,9 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
|||||||
new EventFlow()
|
new EventFlow()
|
||||||
.listen(this::handleStopMusicManager)
|
.listen(this::handleStopMusicManager)
|
||||||
.listen(this::handlePlaySound)
|
.listen(this::handlePlaySound)
|
||||||
|
.listen(this::handleSkipSong)
|
||||||
|
.listen(this::handlePauseSong)
|
||||||
|
.listen(this::handlePreviousSong)
|
||||||
.listen(this::handleStopSound)
|
.listen(this::handleStopSound)
|
||||||
.listen(this::handleMusicStart)
|
.listen(this::handleMusicStart)
|
||||||
.listen(this::handleVolumeChange)
|
.listen(this::handleVolumeChange)
|
||||||
@@ -44,6 +48,19 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
|||||||
this.soundEffectManager.play(event.fileName(), event.loop());
|
this.soundEffectManager.play(event.fileName(), event.loop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleSkipSong(AudioEvents.SkipMusic event) {
|
||||||
|
this.musicManager.skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePauseSong(AudioEvents.PauseMusic event) {
|
||||||
|
this.musicManager.pause();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePreviousSong(AudioEvents.PreviousMusic event) {
|
||||||
|
this.musicManager.previous();
|
||||||
|
}
|
||||||
|
|
||||||
private void handleStopSound(AudioEvents.StopEffect event) {
|
private void handleStopSound(AudioEvents.StopEffect event) {
|
||||||
this.soundEffectManager.stop(event.fileName());
|
this.soundEffectManager.stop(event.fileName());
|
||||||
}
|
}
|
||||||
@@ -57,12 +74,9 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleGetVolume(AudioEvents.GetVolume event) {
|
private void handleGetVolume(AudioEvents.GetVolume event) {
|
||||||
new EventFlow()
|
GlobalEventBus.postAsync(new AudioEvents.GetVolumeResponse(
|
||||||
.addPostEvent(
|
|
||||||
new AudioEvents.GetVolumeResponse(
|
|
||||||
audioVolumeManager.getVolume(event.controlType()),
|
audioVolumeManager.getVolume(event.controlType()),
|
||||||
event.identifier()))
|
event.identifier()));
|
||||||
.asyncPostEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,18 @@ package org.toop.framework.audio;
|
|||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
import org.toop.framework.dispatch.interfaces.Dispatcher;
|
import org.toop.framework.dispatch.interfaces.Dispatcher;
|
||||||
import org.toop.framework.dispatch.JavaFXDispatcher;
|
import org.toop.framework.dispatch.JavaFXDispatcher;
|
||||||
import org.toop.annotations.TestsOnly;
|
import org.toop.annotations.TestsOnly;
|
||||||
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
|
import org.toop.framework.eventbus.GlobalEventBus;
|
||||||
import org.toop.framework.resource.types.AudioResource;
|
import org.toop.framework.resource.types.AudioResource;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MusicManager<T extends AudioResource> implements org.toop.framework.audio.interfaces.MusicManager<T> {
|
public class MusicManager<T extends AudioResource> implements org.toop.framework.audio.interfaces.MusicManager<T> {
|
||||||
private static final Logger logger = LogManager.getLogger(MusicManager.class);
|
private static final Logger logger = LogManager.getLogger(MusicManager.class);
|
||||||
@@ -17,6 +23,9 @@ public class MusicManager<T extends AudioResource> implements org.toop.framework
|
|||||||
private final List<T> resources;
|
private final List<T> resources;
|
||||||
private int playingIndex = 0;
|
private int playingIndex = 0;
|
||||||
private boolean playing = false;
|
private boolean playing = false;
|
||||||
|
private long pausedPosition = 0;
|
||||||
|
private ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
|
|
||||||
public MusicManager(List<T> resources, boolean shuffleMusic) {
|
public MusicManager(List<T> resources, boolean shuffleMusic) {
|
||||||
this.dispatcher = new JavaFXDispatcher();
|
this.dispatcher = new JavaFXDispatcher();
|
||||||
@@ -66,6 +75,15 @@ public class MusicManager<T extends AudioResource> implements org.toop.framework
|
|||||||
playCurrentTrack();
|
playCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void skip() {
|
||||||
|
if (backgroundMusic.isEmpty()) return;
|
||||||
|
stop();
|
||||||
|
scheduler.shutdownNow();
|
||||||
|
playingIndex = playingIndex + 1;
|
||||||
|
playing = true;
|
||||||
|
playCurrentTrack();
|
||||||
|
}
|
||||||
|
|
||||||
// Used in testing
|
// Used in testing
|
||||||
void play(int index) {
|
void play(int index) {
|
||||||
if (playing) {
|
if (playing) {
|
||||||
@@ -96,17 +114,29 @@ public class MusicManager<T extends AudioResource> implements org.toop.framework
|
|||||||
current.play();
|
current.play();
|
||||||
|
|
||||||
setTrackRunnable(current);
|
setTrackRunnable(current);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTrackRunnable(T track) {
|
private void setTrackRunnable(T track) {
|
||||||
|
|
||||||
|
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
Runnable currentMusicTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GlobalEventBus.post(new AudioEvents.PlayingMusic(track.getName(), track.currentPosition(), track.duration()));
|
||||||
|
scheduler.schedule(this, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
track.setOnEnd(() -> {
|
track.setOnEnd(() -> {
|
||||||
|
scheduler.shutdownNow();
|
||||||
playingIndex++;
|
playingIndex++;
|
||||||
playCurrentTrack();
|
playCurrentTrack();
|
||||||
});
|
});
|
||||||
|
|
||||||
track.setOnError(() -> {
|
track.setOnError(() -> {
|
||||||
|
scheduler.shutdownNow();
|
||||||
logger.error("Error playing track: {}", track);
|
logger.error("Error playing track: {}", track);
|
||||||
backgroundMusic.remove(track);
|
backgroundMusic.remove(track);
|
||||||
|
|
||||||
@@ -116,6 +146,8 @@ public class MusicManager<T extends AudioResource> implements org.toop.framework
|
|||||||
playing = false;
|
playing = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scheduler.schedule(currentMusicTask, 1, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,4 +157,29 @@ public class MusicManager<T extends AudioResource> implements org.toop.framework
|
|||||||
playing = false;
|
playing = false;
|
||||||
dispatcher.run(() -> backgroundMusic.forEach(T::stop));
|
dispatcher.run(() -> backgroundMusic.forEach(T::stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pause() {
|
||||||
|
T current = backgroundMusic.get(playingIndex);
|
||||||
|
if (this.playing) {
|
||||||
|
current.pause();
|
||||||
|
playing = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.playing = true;
|
||||||
|
dispatcher.run(() -> {
|
||||||
|
current.play();
|
||||||
|
setTrackRunnable(current);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void previous() {
|
||||||
|
if (backgroundMusic.isEmpty()) return;
|
||||||
|
if (playingIndex == 0) return;
|
||||||
|
stop();
|
||||||
|
scheduler.shutdownNow();
|
||||||
|
playingIndex = playingIndex - 1;
|
||||||
|
playing = true;
|
||||||
|
playCurrentTrack();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ public class AudioEvents extends EventsBase {
|
|||||||
/** Start background music. */
|
/** Start background music. */
|
||||||
public record StartBackgroundMusic() implements GenericEvent {}
|
public record StartBackgroundMusic() implements GenericEvent {}
|
||||||
|
|
||||||
|
/** Gives back the name of the song, the position its currently at (in seconds) and how long it takes (in seconds) */
|
||||||
|
public record PlayingMusic(String name, long currentPosition, long duration) implements GenericEvent {}
|
||||||
|
|
||||||
|
/** Skips the song to the last second of the song resulting in a skip effect */
|
||||||
|
public record SkipMusic() implements GenericEvent {}
|
||||||
|
|
||||||
|
public record PreviousMusic() implements GenericEvent {}
|
||||||
|
|
||||||
|
public record PauseMusic() implements GenericEvent {}
|
||||||
|
|
||||||
/** Change volume, choose type with {@link VolumeControl}. */
|
/** Change volume, choose type with {@link VolumeControl}. */
|
||||||
public record ChangeVolume(double newVolume, VolumeControl controlType) implements GenericEvent {}
|
public record ChangeVolume(double newVolume, VolumeControl controlType) implements GenericEvent {}
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,7 @@ import org.toop.framework.resource.types.AudioResource;
|
|||||||
public interface MusicManager<T extends AudioResource> extends AudioManager<T> {
|
public interface MusicManager<T extends AudioResource> extends AudioManager<T> {
|
||||||
void play();
|
void play();
|
||||||
void stop();
|
void stop();
|
||||||
|
void skip();
|
||||||
|
void previous();
|
||||||
|
void pause();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,8 +78,29 @@ public class MusicAsset extends BaseResource implements LoadableResource, AudioR
|
|||||||
getMediaPlayer().play();
|
getMediaPlayer().play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pause() {
|
||||||
|
getMediaPlayer().pause();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
getMediaPlayer().stop();
|
getMediaPlayer().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long duration() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
return (long) this.mediaPlayer.getTotalDuration().toSeconds(); // Why is this a double? TODO: Fix cast
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentPosition() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
return (long) this.mediaPlayer.getCurrentTime().toSeconds(); // Same here. TODO: Fix cast
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ public class SoundEffectAsset extends BaseResource implements LoadableResource,
|
|||||||
return AudioSystem.getAudioInputStream(decodedFormat, audioInputStream);
|
return AudioSystem.getAudioInputStream(decodedFormat, audioInputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
try {
|
try {
|
||||||
@@ -144,4 +142,25 @@ public class SoundEffectAsset extends BaseResource implements LoadableResource,
|
|||||||
if (this.clip.isRunning()) this.clip.stop();
|
if (this.clip.isRunning()) this.clip.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// had to be implemented for mediaplayer.pause() to work so:
|
||||||
|
// TODO: get this removed, somehow OR get a clip.pause which I have no idea why you would ever use
|
||||||
|
public void pause() {
|
||||||
|
this.clip.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long duration() {
|
||||||
|
if (clip != null) {
|
||||||
|
return (long) (clip.getMicrosecondLength() / 1_000_000.0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentPosition() {
|
||||||
|
if (clip != null) {
|
||||||
|
return (long) (clip.getMicrosecondPosition() / 1_000_000.0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ public interface AudioResource {
|
|||||||
void updateVolume(double volume);
|
void updateVolume(double volume);
|
||||||
void play();
|
void play();
|
||||||
void stop();
|
void stop();
|
||||||
|
long duration();
|
||||||
|
long currentPosition();
|
||||||
void setOnEnd(Runnable run);
|
void setOnEnd(Runnable run);
|
||||||
void setOnError(Runnable run);
|
void setOnError(Runnable run);
|
||||||
|
void pause();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ class MockAudioResource extends BaseResource implements AudioResource {
|
|||||||
stopped = true;
|
stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long duration() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentPosition() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnEnd(Runnable callback) {
|
public void setOnEnd(Runnable callback) {
|
||||||
onEnd = callback;
|
onEnd = callback;
|
||||||
|
|||||||
@@ -39,6 +39,16 @@ class MockSoundEffectResource extends BaseResource implements AudioResource {
|
|||||||
stopped = true;
|
stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long duration() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentPosition() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnEnd(Runnable callback) {}
|
public void setOnEnd(Runnable callback) {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user