diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index e45147d..a9873af 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,13 @@ 21 - + + org.openjfx + javafx-media + 21 + + + org.junit.jupiter junit-jupiter-api ${junit.version} diff --git a/src/main/java/sbu/javafx/AppController.java b/src/main/java/sbu/javafx/AppController.java new file mode 100644 index 0000000..65f49a4 --- /dev/null +++ b/src/main/java/sbu/javafx/AppController.java @@ -0,0 +1,199 @@ +package sbu.javafx; + +import javafx.beans.Observable; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class AppController { + + @FXML private Button playlistOrTracks; + @FXML private Button themeToggle; + + @FXML private Label playingTrackName; + @FXML private Label playingTrackArtistName; + @FXML private Label playingTrackDuration; + + @FXML private VBox tracksContainer; + + private static boolean isDark = true; + private static boolean isPlaylist; + private static Track playingTrack = new Track("___", "___", "00:00", ""); + + private static List tracks = new ArrayList<>(); + private static List playlist = new ArrayList<>(); + + public static List getTracks() { return tracks; } + + public static List getPlaylist() { return playlist; } + + public static boolean isPlaylist() { return isPlaylist; } + + public static void setPlayingTrack(Track pTrack) { + + //updating playingTrack box + playingTrack.getTrackNameProperty().set(pTrack.getTrackName()); + playingTrack.getArtistNameProperty().set(pTrack.getArtistName()); + playingTrack.getDurationProperty().set(pTrack.getDuration()); + + if (isPlaylist) { + //updating all play & add buttons + for (Track t : playlist) { + if (t.getTrackName().equals(pTrack.getTrackName()) && + t.getArtistName().equals(pTrack.getArtistName())) { + t.setPlayButton("⏸"); + t.play(); + } else { + t.setPlayButton("▶"); + t.stop(); + } + } + } + else { + //updating all play & add buttons + //updating each media action + for (Track t : tracks) { + if (t.getTrackName().equals(pTrack.getTrackName()) && + t.getArtistName().equals(pTrack.getArtistName())) { + t.setPlayButton("⏸"); + t.play(); + } else { + t.setPlayButton("▶"); + t.stop(); + } + } + } + } + + public static void addOrRemove(Track track) { + + boolean isInPlaylist = false; + for (Track t : playlist) { + if (t.getTrackName().equals(track.getTrackName()) && + t.getArtistName().equals(track.getArtistName())) { + + isInPlaylist = true; + break; + } + } + if (isInPlaylist) playlist.remove(track); + else playlist.add(track); + + + for (Track t : tracks) { + t.setAddButton("+"); + for (Track p : playlist) { + if (t.equals(p)) { + t.setAddButton("-"); + } + } + } + } + + @FXML + public void toggleTheme() { + isDark = !isDark; + + themeToggle.getScene().getStylesheets().clear(); + if (!isDark) { + //Switch to Light mode + themeToggle.getScene().getStylesheets().add(getClass().getResource("light.css").toExternalForm()); + themeToggle.setText("☀"); + } + else { + //Switch to Dark mode + themeToggle.getScene().getStylesheets().add(getClass().getResource("dark.css").toExternalForm()); + themeToggle.setText("☽"); + } + } + + // TODO:This method should open a new window or change the current scene to display the "Playlist" page. + + @FXML + public void openPlaylistWindow() { + //Create a new stage and show the playlist UI. + isPlaylist = !isPlaylist; + try { + Stage stage = (Stage) playingTrackName.getScene().getWindow(); + FXMLLoader fxmlLoader = new FXMLLoader(MusicApp.class.getResource("App-view.fxml")); + Scene newScene = new Scene(fxmlLoader.load(), 700, 700); + if (isDark) newScene.getStylesheets().add(getClass().getResource("dark.css").toExternalForm()); + else newScene.getStylesheets().add(getClass().getResource("light.css").toExternalForm()); + + stage.setScene(newScene); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + @FXML + public void initialize() { + + playingTrackName.textProperty().bind(playingTrack.getTrackNameProperty()); + playingTrackArtistName.textProperty().bind(playingTrack.getArtistNameProperty()); + playingTrackDuration.textProperty().bind(playingTrack.getDurationProperty()); + + tracks.add(new Track("End of Beginning", "Djo", "02:39", "End of Beginning.mp3")); + tracks.add(new Track("Heathens", "Twenty One Pilots", "03:20", "Heathens.mp3")); + tracks.add(new Track("Mask Off (Instrumental)", "Future", "03:30", "Mask Off (Instrumental).mp3")); + tracks.add(new Track("California Dreamin'", "The Mamas & the Papas", "02:45", "California Dreamin'.mp3")); + tracks.add(new Track("Let Me Down slowly", "Alec Benjamin", "02:49", "Let Me Down Slowly.mp3")); + tracks.add(new Track("Attention", "Charlie Puth", "03:51", "Attention.mp3")); + tracks.add(new Track("Talking to the Moon", "Bruno Mars", "03:35", "Talking to the Moon.mp3")); + tracks.add(new Track("Believer", "Imagine Dragons", "03:23", "Believer.mp3")); + tracks.add(new Track("Yumeji's Theme", "Shigeru Umebayashi", "02:30", "Yujime's Theme.mp3")); + tracks.add(new Track("In This Shirt", "The Irrepressibles", "05:35", "In This Shirt.mp3")); + tracks.add(new Track("GOSSIP", "Måneskin (ft. Tom Morello)", "02:48", "GOSSIP.mp3")); + tracks.add(new Track("They Don't Care About Us", "Michael Jackson", "04:44", "They Don't Care About Us.mp3")); + + if (isPlaylist) { + playlistOrTracks.setText("Tracks"); + for (Track t : playlist) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("Track-boxes.fxml")); + + HBox trackBox = loader.load(); + + TrackController controller = loader.getController(); + controller.setTrack(t); + + tracksContainer.getChildren().add(trackBox); + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + else { + playlistOrTracks.setText("Playlist"); + for (Track t : tracks) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("Track-boxes.fxml")); + + HBox trackBox = loader.load(); + + TrackController controller = loader.getController(); + controller.setTrack(t); + + tracksContainer.getChildren().add(trackBox); + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/sbu/javafx/Launcher.java b/src/main/java/sbu/javafx/Launcher.java index c288d10..b66ae9b 100644 --- a/src/main/java/sbu/javafx/Launcher.java +++ b/src/main/java/sbu/javafx/Launcher.java @@ -4,5 +4,7 @@ import javafx.application.Application; public class Launcher{ public static void main(String[] args) { - // TODO: Launch the JavaFX application by calling Application.launch(Main.class) } + // TODO: Launch the JavaFX application by calling Application.launch(Main.class) + Application.launch(MusicApp.class); + } } diff --git a/src/main/java/sbu/javafx/MusicApp.java b/src/main/java/sbu/javafx/MusicApp.java index a50badc..0e12613 100644 --- a/src/main/java/sbu/javafx/MusicApp.java +++ b/src/main/java/sbu/javafx/MusicApp.java @@ -5,18 +5,25 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; +import javax.swing.*; +import java.awt.*; +import javafx.scene.image.Image; import java.io.IOException; public class MusicApp extends Application { @Override - public void start(Stage stage) throws IOException - { + public void start(Stage stage) throws IOException { FXMLLoader fxmlLoader = new FXMLLoader(MusicApp.class.getResource("App-view.fxml")); - Scene scene = new Scene(fxmlLoader.load()); + Scene scene = new Scene(fxmlLoader.load(), 700, 700); + scene.getStylesheets().add(getClass().getResource("dark.css").toExternalForm()); stage.setTitle("Music Player"); stage.setScene(scene); + //TODO: add icon to the stage + Image icon = new Image(getClass().getResourceAsStream("MusicAppIcon.png")); + stage.getIcons().add(icon); + stage.show(); } diff --git a/src/main/java/sbu/javafx/MusicController.java b/src/main/java/sbu/javafx/MusicController.java deleted file mode 100644 index 5da27a9..0000000 --- a/src/main/java/sbu/javafx/MusicController.java +++ /dev/null @@ -1,31 +0,0 @@ -package sbu.javafx; - -import javafx.fxml.FXML; -import javafx.event.ActionEvent; -import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.VBox; - -public class MusicController { - - // TODO: Define your UI components using the @FXML annotation. - - //TODO: Implement the logic to play a song. This method should update the UI to show which song is currently playing. - - @FXML - public void handlePlayAction() { - //Update labels, change button icons, etc. - } - - //TODO: Logic to add a specific song to the user's playlist. - - public void addToPlaylist(String songName) { - //Add the song to a list or update a ListView. - } - - // TODO:This method should open a new window or change the current scene to display the "Playlist" page. - - public void openPlaylistWindow() { - //Create a new stage and show the playlist UI. - } -} diff --git a/src/main/java/sbu/javafx/Track.java b/src/main/java/sbu/javafx/Track.java new file mode 100644 index 0000000..459887f --- /dev/null +++ b/src/main/java/sbu/javafx/Track.java @@ -0,0 +1,65 @@ +package sbu.javafx; + +import javafx.beans.property.*; + +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; + +public class Track { + + private final StringProperty trackName = new SimpleStringProperty(); + private final StringProperty artistName = new SimpleStringProperty(); + private final StringProperty duration = new SimpleStringProperty(); + private final StringProperty playButton = new SimpleStringProperty(); + private final StringProperty addButton = new SimpleStringProperty(); + private String fileName; + private MediaPlayer player; + + public Track (String trackName, String artistName, String duration, String fileName) { + this.trackName.set(trackName); + this.artistName.set(artistName); + this.duration.set(duration); + this.playButton.set("▶"); + this.addButton.set("+"); + if (fileName.isEmpty()) this.fileName = "Yujime's Theme.mp3"; + else this.fileName = fileName; + + String audioFilePath = getClass().getResource(this.fileName).toExternalForm(); + Media media = new Media(audioFilePath); + player = new MediaPlayer(media); + } + + public void play() { + if (player != null) { + player.play(); + } + } + + public void stop() { + if (player != null) { + player.stop(); + } + } + + public StringProperty getTrackNameProperty() { return trackName; } + + public StringProperty getArtistNameProperty() { return artistName; } + + public StringProperty getDurationProperty() { return duration; } + + public String getTrackName() { return trackName.get(); } + + public String getArtistName() { return artistName.get(); } + + public String getDuration() { return duration.get(); } + + public String getFilePath() { return fileName; } + + public StringProperty getPlayButton() { return playButton; } + + public StringProperty getAddButton() { return addButton; } + + public void setPlayButton(String s) { playButton.set(s); } + + public void setAddButton(String s) { addButton.set(s); } +} diff --git a/src/main/java/sbu/javafx/TrackController.java b/src/main/java/sbu/javafx/TrackController.java new file mode 100644 index 0000000..0db4204 --- /dev/null +++ b/src/main/java/sbu/javafx/TrackController.java @@ -0,0 +1,66 @@ +package sbu.javafx; + +import javafx.fxml.FXML; +import javafx.scene.control.*; + +import javax.print.attribute.standard.Media; +import java.nio.MappedByteBuffer; + +public class TrackController { + + // TODO: Define your UI components using the @FXML annotation. + + @FXML private Label displayTrackName; + @FXML private Label displayArtistName; + @FXML private Label displayDuration; + @FXML private Button playButton; + @FXML private Button addButton; + + private Track currentTrack; + + private static Track playingTrack = new Track("___", "___", "00:00", ""); + + public void setTrack(Track track) { + this.currentTrack = track; + + this.displayTrackName.textProperty().bind(track.getTrackNameProperty()); + this.displayArtistName.textProperty().bind(track.getArtistNameProperty()); + this.displayDuration.textProperty().bind(track.getDurationProperty()); + + this.playButton.textProperty().bind(track.getPlayButton()); + this.addButton.textProperty().bind(track.getAddButton()); + } + + @FXML + public void initialize() { + // + } + + //TODO: Implement the logic to play a song. This method should update the UI to show which song is currently playing. + + @FXML + public void handlePlayAction() { + //Update labels, change button icons, etc. + + //changing playingTrack + if (playingTrack.getTrackName().equals(currentTrack.getTrackName()) && + playingTrack.getArtistName().equals(currentTrack.getArtistName())) { + playingTrack = new Track("___", "___", "00:00", ""); + } + else { + playingTrack = currentTrack; + } + + //parsing playingTrack to AppController + AppController.setPlayingTrack(playingTrack); + } + + //TODO: Logic to add a specific song to the user's playlist. + + @FXML + public void addToPlaylist() { + //Add the song to a list or update a ListView. + + AppController.addOrRemove(currentTrack); + } +} diff --git a/src/main/resources/sbu/javafx/App-view.fxml b/src/main/resources/sbu/javafx/App-view.fxml index 306c8d3..d2863ea 100644 --- a/src/main/resources/sbu/javafx/App-view.fxml +++ b/src/main/resources/sbu/javafx/App-view.fxml @@ -1,8 +1,46 @@ - + + + + + + + + + + + + +