2 Commits
Author SHA1 Message Date
reyhne 347b3fc4c9 Merge pull request 'HW 07' (#1) from develop into main
Reviewed-on: Arshida_0/HW-07-JavaFX-Arshida#1
2026-07-16 18:02:33 +00:00
Arshida_0 768227a468 HW 07 2026-05-29 19:28:55 +04:30
25 changed files with 616 additions and 37 deletions
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+7 -1
View File
@@ -25,7 +25,13 @@
<version>21</version>
</dependency>
<dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>21</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
+199
View File
@@ -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<Track> tracks = new ArrayList<>();
private static List<Track> playlist = new ArrayList<>();
public static List<Track> getTracks() { return tracks; }
public static List<Track> 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();
}
}
}
}
}
+3 -1
View File
@@ -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);
}
}
+10 -3
View File
@@ -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();
}
@@ -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.
}
}
+65
View File
@@ -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); }
}
@@ -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);
}
}
+39 -1
View File
@@ -1,8 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/fxml" alignment="CENTER" spacing="10">
<?import javafx.scene.control.ListView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.HBox?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="sbu.javafx.AppController"
alignment="CENTER" spacing="20">
<!-- TODO: Add your code here! -->
<padding>
<Insets top="20" right="20" bottom="20" left="10"/>
</padding>
<HBox alignment="CENTER" spacing="150" prefHeight="30">
<Button fx:id="themeToggle" onAction="#toggleTheme" text="☽" prefHeight="20" prefWidth="70" styleClass="top-btn" style="-fx-font-size: 20px;"/>
<Label text="Music Player" styleClass="title" prefWidth="200" alignment="CENTER"/>
<Button fx:id="playlistOrTracks" onAction="#openPlaylistWindow" text="Playlist"
styleClass="top-btn"
style="-fx-font-size: 14px;"
prefWidth="100" prefHeight="20"/>
</HBox>
<ScrollPane fitToWidth="true" prefHeight="500" styleClass="scroll-pane">
<VBox fx:id="tracksContainer" spacing="5" alignment="CENTER" styleClass="tracks-vbox"/>
</ScrollPane>
<HBox alignment="CENTER" prefWidth="650" prefHeight="30" spacing="20">
<padding>
<Insets top="20" right="20" bottom="20" left="20"/>
</padding>
<Label fx:id="playingTrackName" prefWidth="250" styleClass="playing-track" style="-fx-font-weight: bold; -fx-font-size: 23"/>
<Label fx:id="playingTrackArtistName" prefWidth="250" styleClass="playing-track" style="-fx-font-size: 19"/>
<Label fx:id="playingTrackDuration" prefWidth="50" styleClass="playing-track" style="-fx-font-size: 19"/>
</HBox>
</VBox>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<HBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="sbu.javafx.TrackController"
prefHeight="40" prefWidth="650" styleClass="track-box">
<padding>
<Insets top="12" right="12" bottom="12" left="12"/>
</padding>
<VBox alignment="CENTER_LEFT" prefWidth="410" spacing="1">
<Label fx:id="displayTrackName" prefHeight="30" styleClass="track-name"/>
<Label fx:id="displayArtistName" prefHeight="10" styleClass="artist-name"/>
</VBox>
<Label fx:id="displayDuration" prefHeight="40" styleClass="duration"/>
<HBox spacing="10" alignment="CENTER_RIGHT">
<Button fx:id="playButton" onAction="#handlePlayAction" text="▶" styleClass="p-and-a-btn" prefWidth="50"/>
<Button fx:id="addButton" onAction="#addToPlaylist" text="" styleClass="p-and-a-btn" prefWidth="50"/>
</HBox>
</HBox>
Binary file not shown.
+95
View File
@@ -0,0 +1,95 @@
.root {
-fx-background-color: #100518;
-fx-font-family: "DejaVu Sans", "Segoe UI", sans-serif;
}
.title {
-fx-font-size: 22px;
-fx-font-weight: bold;
-fx-text-fill: white;
}
.top-btn {
-fx-background-color: transparent;
-fx-text-fill: white;
-fx-font-weight: bold;
-fx-padding: 8 16;
-fx-background-radius: 6;
-fx-cursor: hand;
}
.top-btn:hover {
-fx-background-color: #1E0A2B;
}
.playing-track {
-fx-text-fill: white;
-fx-alignment: LEFT_CENTER;
}
.track-box {
-fx-background-color: #1E0A2B;
-fx-padding: 20 20;
-fx-spacing: 10;
-fx-alignment: CENTER;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-color: transparent;
-fx-border-width: 2;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 8, 0, 0, 4);
-fx-cursor: hand;
}
.track-box:hover {
-fx-border-color: #D400FF;
-fx-effect: dropshadow(gaussian, rgba(76, 175, 80, 0.5), 16, 0, 0, 6);
}
.track-box:hover .track-name {
-fx-font-weight: bold;
}
.track-name {
-fx-font-size: 20px;
-fx-font-weight: normal;
-fx-text-fill: white;
}
.artist-name {
-fx-font-size: 14px;
-fx-font-weight: normal;
-fx-text-fill: #D400FF;
}
.tracks-vbox {
-fx-background-color: #100518;
-fx-border-color: #100518;
-fx-border-width: 1;
-fx-padding: 10 10;
}
.p-and-a-btn {
-fx-background-color: transparent;
-fx-text-fill: white;
-fx-font-size: 20px;
-fx-font-weight: bold;
-fx-padding: 10 10;
-fx-background-radius: 4;
-fx-cursor: hand;
}
.p-and-a-btn:hover {
-fx-scale-x: 1.3;
-fx-scale-y: 1.3;
}
.duration {
-fx-font-size: 14px;
-fx-font-weight: normal;
-fx-text-fill: #D400FF;
}
.scroll-pane {
-fx-background-color: #100518;
-fx-border-color: #100518;
}
+95
View File
@@ -0,0 +1,95 @@
.root {
-fx-background-color: #FFF0F5;
-fx-font-family: "DejaVu Sans", "Segoe UI", sans-serif;
}
.title {
-fx-font-size: 22px;
-fx-font-weight: bold;
-fx-text-fill: #6B1FA3;
}
.top-btn {
-fx-background-color: transparent;
-fx-text-fill: #6B1FA3;
-fx-font-weight: bold;
-fx-padding: 8 16;
-fx-background-radius: 6;
-fx-cursor: hand;
}
.top-btn:hover {
-fx-background-color: #FCFAFF;
}
.playing-track {
-fx-text-fill: #6B1FA3;
-fx-alignment: LEFT_CENTER;
}
.track-box {
-fx-background-color: #FCFAFF;
-fx-padding: 20 20;
-fx-spacing: 10;
-fx-alignment: CENTER;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-color: transparent;
-fx-border-width: 2;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 8, 0, 0, 4);
-fx-cursor: hand;
}
.track-box:hover {
-fx-border-color: #A020F0;
-fx-effect: dropshadow(gaussian, rgba(76, 175, 80, 0.5), 16, 0, 0, 6);
}
.track-box:hover .track-name {
-fx-font-weight: bold;
}
.track-name {
-fx-font-size: 20px;
-fx-font-weight: normal;
-fx-text-fill: #6B1FA3;
}
.artist-name {
-fx-font-size: 14px;
-fx-font-weight: normal;
-fx-text-fill: #A020F0;
}
.tracks-vbox {
-fx-background-color: #FFF0F5;
-fx-border-color: #FFF0F5;
-fx-border-width: 1;
-fx-padding: 10 10;
}
.p-and-a-btn {
-fx-background-color: transparent;
-fx-text-fill: #6B1FA3;
-fx-font-size: 20px;
-fx-font-weight: bold;
-fx-padding: 10 10;
-fx-background-radius: 4;
-fx-cursor: hand;
}
.p-and-a-btn:hover {
-fx-scale-x: 1.3;
-fx-scale-y: 1.3;
}
.duration {
-fx-font-size: 14px;
-fx-font-weight: normal;
-fx-text-fill: #A020F0;
}
.scroll-pane {
-fx-background-color: #FFF0F5;
-fx-border-color: #FFF0F5;
}