From dc60e5954f07ebada6cb292e9322b9c9c5b80d02 Mon Sep 17 00:00:00 2001 From: Mobina Date: Thu, 28 May 2026 14:54:11 +0330 Subject: [PATCH] =?UTF-8?q?=D8=B5=D9=81=D8=AD=D9=87=20=D8=A7=D8=B5=D9=84?= =?UTF-8?q?=DB=8C=20=D8=A8=D8=AF=D9=88=D9=86=20=D8=A7=D8=B9=D9=85=D8=A7?= =?UTF-8?q?=D9=84=20=D9=BE=D9=84=DB=8C=20=D9=84=DB=8C=D8=B3=D8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/vcs.xml | 6 + src/main/java/sbu/javafx/Launcher.java | 7 +- src/main/java/sbu/javafx/Main.java | 39 +++++ src/main/java/sbu/javafx/MusicController.java | 163 +++++++++++++++++- src/main/java/sbu/javafx/Song.java | 18 ++ src/main/resources/css/dark.css | 47 +++++ src/main/resources/css/light.css | 46 +++++ src/main/resources/image/forward.png | Bin 0 -> 1470 bytes src/main/resources/image/pause.png | Bin 0 -> 1085 bytes src/main/resources/image/play.png | Bin 0 -> 1387 bytes src/main/resources/image/rewind.png | Bin 0 -> 1484 bytes src/main/resources/sbu/javafx/App-view.fxml | 74 +++++++- 12 files changed, 393 insertions(+), 7 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 src/main/java/sbu/javafx/Main.java create mode 100644 src/main/java/sbu/javafx/Song.java create mode 100644 src/main/resources/css/dark.css create mode 100644 src/main/resources/css/light.css create mode 100644 src/main/resources/image/forward.png create mode 100644 src/main/resources/image/pause.png create mode 100644 src/main/resources/image/play.png create mode 100644 src/main/resources/image/rewind.png 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/src/main/java/sbu/javafx/Launcher.java b/src/main/java/sbu/javafx/Launcher.java index c288d10..f4f7a99 100644 --- a/src/main/java/sbu/javafx/Launcher.java +++ b/src/main/java/sbu/javafx/Launcher.java @@ -2,7 +2,10 @@ package sbu.javafx; import javafx.application.Application; -public class Launcher{ +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(Main.class); + } } diff --git a/src/main/java/sbu/javafx/Main.java b/src/main/java/sbu/javafx/Main.java new file mode 100644 index 0000000..1385424 --- /dev/null +++ b/src/main/java/sbu/javafx/Main.java @@ -0,0 +1,39 @@ +package sbu.javafx; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class Main extends Application { + @Override + public void start(Stage primaryStage) throws Exception { + + FXMLLoader loader = new FXMLLoader(getClass().getResource("/sbu/javafx/App-view.fxml")); + Parent root = loader.load(); + + MusicController controller = loader.getController(); + + controller.musicsListView.getItems().addAll( + new Song("Blinding Lights", "The Weeknd"), + new Song("Flowers", "Miley Cyrus"), + new Song("As It Was", "Harry Styles") + ); + + controller.setupListView(controller.musicsListView); + + Scene scene = new Scene(root, 600, 500); + scene.getStylesheets().add( + getClass().getResource("/css/light.css").toExternalForm() + ); + + primaryStage.setTitle("Music Player"); + primaryStage.setScene(scene); + primaryStage.show(); + } + + public static void main(String[] args) { + launch(args); + } +} \ No newline at end of file diff --git a/src/main/java/sbu/javafx/MusicController.java b/src/main/java/sbu/javafx/MusicController.java index 5da27a9..b97a82c 100644 --- a/src/main/java/sbu/javafx/MusicController.java +++ b/src/main/java/sbu/javafx/MusicController.java @@ -2,30 +2,189 @@ package sbu.javafx; import javafx.fxml.FXML; import javafx.event.ActionEvent; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.*; +import javafx.scene.Scene; import javafx.scene.layout.VBox; + public class MusicController { + @FXML + public ListView playlistListView; + @FXML + public ListView musicsListView; + @FXML + private VBox root; + @FXML + Label nowPlayingLabel; + @FXML + Button playPauseBtn; + @FXML + Button openPlaylistBtn; + @FXML + Button themeToggleBtn; + private boolean isDarkMode=true; + private boolean isPlaying=false; + private Song currentSong = null; + ImageView playIcon; + ImageView pauseIcon; + // TODO: Define your UI components using the @FXML annotation. + @FXML + public void initialize() { + Image playImg = new Image(getClass().getResourceAsStream("/image/play.png")); + Image pauseImg = new Image(getClass().getResourceAsStream("/image/pause.png")); + + playIcon = new ImageView(playImg); + pauseIcon = new ImageView(pauseImg); + + playIcon.setFitWidth(35); + playIcon.setFitHeight(35); + pauseIcon.setFitWidth(35); + pauseIcon.setFitHeight(35); + + playPauseBtn.setGraphic(playIcon); + + } + + public void setupListView(ListView listView) { + + listView.setCellFactory(param -> new ListCell() { + @Override + protected void updateItem(Song song, boolean empty) { + super.updateItem(song, empty); + + if (empty || song == null) { + setText(null); + setGraphic(null); + return; + } + + Label nameLabel = new Label(song.getName()); + nameLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;"); + + Label singerLabel = new Label(song.getSinger()); + singerLabel.setStyle("-fx-text-fill: gray; -fx-font-size: 12px;"); + + VBox songInfo = new VBox(3); + songInfo.setAlignment(Pos.CENTER_LEFT); + + songInfo.getChildren().addAll(nameLabel, singerLabel); + + Button addToPlaylistBtn = new Button("Add to playlist"); + addToPlaylistBtn.getStyleClass().add("playlist-button"); + addToPlaylistBtn.setOnAction(e -> { + addToPlaylist(e, song); + }); + + Button playBtn = new Button("Play"); + playBtn.getStyleClass().add("play-button"); + playBtn.setOnAction(e -> { + play(e, song); + }); + + HBox row = new HBox(10); + row.setPadding(new Insets(10)); + row.setAlignment(Pos.CENTER_LEFT); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + row.getChildren().addAll(songInfo, spacer, playBtn, addToPlaylistBtn); + + setGraphic(row); + } + }); + } + + @FXML + public void toggleTheme(ActionEvent event) { + if (isDarkMode) { + themeToggleBtn.setText("Light"); + changeTheme(); + isDarkMode = false; + } else { + themeToggleBtn.setText("Dark"); + changeTheme(); + isDarkMode = true; + } + } + + public void changeTheme(){ + + + Scene scene = root.getScene(); + + scene.getStylesheets().clear(); + + if(isDarkMode){ + scene.getStylesheets().add( + getClass().getResource("/css/dark.css").toExternalForm() + ); + + }else{ + scene.getStylesheets().add( + getClass().getResource("/css/light.css").toExternalForm() + ); + } + + isDarkMode=!isDarkMode; + } + //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. } + public void play(ActionEvent event, Song song){ + currentSong=song; + nowPlayingLabel.setText(song.getName()); + if (!isPlaying) + playPause(event); + //کد پخش + } + + @FXML + public void playPause(ActionEvent a){ + if(isPlaying){ + playPauseBtn.setGraphic(playIcon); + isPlaying=false; + //کد توقف اینجاست چون برای هر توقفی دکمه ی پاز رو میزنیم ولی برای پلی ممکنه از بین آهنگ ها بزنیم + } + else{ + playPauseBtn.setGraphic(pauseIcon); + isPlaying=true; + } + } + //TODO: Logic to add a specific song to the user's playlist. - public void addToPlaylist(String songName) { + public void addToPlaylist(ActionEvent event, Song song) { //Add the song to a list or update a ListView. + playlistListView.getItems().add(song); } // 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. + musicsListView.setVisible(false); + if(playlistListView!=null) + playlistListView.setVisible(true); + else + throw new RuntimeException("Playlist is empty"); } + } diff --git a/src/main/java/sbu/javafx/Song.java b/src/main/java/sbu/javafx/Song.java new file mode 100644 index 0000000..d24ae61 --- /dev/null +++ b/src/main/java/sbu/javafx/Song.java @@ -0,0 +1,18 @@ +package sbu.javafx; + +public class Song { + private String name; + private String singer; + public Song(String name, String singer) + { + this.name=name; + this.singer=singer; + } + + public String getName() { + return name; + } + public String getSinger() { + return singer; + } +} diff --git a/src/main/resources/css/dark.css b/src/main/resources/css/dark.css new file mode 100644 index 0000000..e23df1d --- /dev/null +++ b/src/main/resources/css/dark.css @@ -0,0 +1,47 @@ +.root{ + -fx-background-color: #0f172a; +} + +.label{ + -fx-text-fill: #f8fafc; +} + +.button{ + -fx-background-color: #334155;; + -fx-text-fill: white; + -fx-background-radius: 14px; + -fx-cursor: hand; +} + +.button:hover{ + -fx-background-color: #475569; +} + +.list-view{ + -fx-background-color: #111827; + -fx-control-inner-background: #111827; + -fx-background-radius: 16px; +} + +.list-cell{ + -fx-background-color: transparent; + -fx-text-fill: white; +} + +.list-cell:selected{ + -fx-background-color: #2563eb; +} + +.button.circle-button{ + + -fx-background-color: #dbeafe; + + -fx-background-radius: 100em; + -fx-background-insets: 0; + + -fx-padding: 0; + + -fx-pref-width: 34px; + -fx-pref-height: 34px; + +} \ No newline at end of file diff --git a/src/main/resources/css/light.css b/src/main/resources/css/light.css new file mode 100644 index 0000000..961717f --- /dev/null +++ b/src/main/resources/css/light.css @@ -0,0 +1,46 @@ +.root{ + -fx-background-color: #f8fafc; +} + +.label{ + -fx-text-fill: #1e293b; +} + +.button{ + -fx-background-color: #dbeafe; + -fx-text-fill: #1e3a8a; + -fx-background-radius: 14px; + -fx-cursor: hand; +} + +.button:hover{ + -fx-background-color: #bfdbfe; +} + +.list-view{ + -fx-background-color: #ffffff; + -fx-control-inner-background: #ffffff; + -fx-background-radius: 16px; +} + +.list-cell{ + -fx-background-color: transparent; +} + +.list-cell:selected { + -fx-background-color: #93c5fd; +} + +.button.circle-button{ + + -fx-background-color: #dbeafe; + + -fx-background-radius: 100em; + -fx-background-insets: 0; + + -fx-padding: 0; + + -fx-pref-width: 35px; + -fx-pref-height: 35px; + +} \ No newline at end of file diff --git a/src/main/resources/image/forward.png b/src/main/resources/image/forward.png new file mode 100644 index 0000000000000000000000000000000000000000..2b0e588f65ec3d6844b50b2da135d1c1cacede36 GIT binary patch literal 1470 zcmV;v1ws0WP)He*whAAUpTgSfOUEk3@}$v|2w2 z)%Z%I=qHUa(KH18px+1~HZf_GJ+s)vfDsAWow-|UTMAp;E!0R;XiE_ka0{*3zIJ!a z+4lCayIuC)JNHrQFF8rKy?Z*p-=3K{bLOm~{10dGP}|q{su5aC7&NJjh6#sW!r-FH zXi{a6oim!m-{IeK&)~BWT8r;hRwFbW?k9|XsxtbU%4tUBR9LhOVQ^YybZ;d)xLNTt zv{>^xjnf9gX^#!UC5X60w9hr- z1qKOChicb}S9P`Cr84?uZUOU*yb%qMC7d1z>MiSCAz#T3ZdN(OJttmh{aYD*z)|vq zho2yfj{AUYQ6rq*)FPo8N62eB>>!LzdQI}y2Gc5|FUcj(pq_9@drz+1NPslq@PZuj zkx-4wVajV#Rw6-*(5GZ%bmQKWu^b6E0#VpxiF{CRSwEl3dQQZa2#ogOwryGf758}` z5RfAR>^DVT)1lfINscUIkPWc#wlYIsukdN2V>1e9AD&xo{pmAk^m?$)8N6AVe5`q$ ztEW1*qkz-%B~OqVrwv{Y(s2=3c;|`&s2omuJwO+%t0?&g+rsymb@p)dkk}RbNmNA- z*&bM>9?tpN-rnlC2t~_l1Z#LE9UZxRULY=|CdBT9Zfj62!~Hp5*QQhA!?V9SDgfbh zPqFZin|1WZL{cn8g%R^p+0Tuq6CLbyge|6Tra0#F%)s_h(xI7#K}WhgjD{8?0I#GR6u`jgv8$rK=SN!t7{LGC5G#L*m0So_ zMn~Ncz*yMAqvu3*-hOXZ07NF6%}ueIGNxET1aKHx8UZ)l62QQplmCkM679AGFmQc( zQhe0kX)*$6a_J&C>$U*KBDp&ewJm^wPk!$(!Khq&ifX~jIvM2y|e+ndL zrj~tTb_AH1oe`f8#Dr#b3aBnFf-B_)Rt2z{8{{v7y>1AA&%d%lc4$_Bk<_?&+fH_v zw+)7!6aYh1Rw6W&nLBIPJ%TS!gqSm_u$d4oHx+)a>w8Ja7S}R)s4AI6oFWXls z0sfv!i4P>#2m(Cx{DJ^g$6N1_eH^ZmbQ~_0HA+7YBdlD5DwX)6!AT__Dx-VNIy!uLaG@mj?tDgP)xH`&yHFA{oz|L-00vFcilRGX$E6iT z(bu+ixz(RyhFq0mAP)BU`MxZUz$Qc=4A4;{I(=CweKkfetl6tE1a@G0Jy54i)8Tbx zEnklZ%WbXIcxd}=)gXag=WXzaVg`iM13nnIB!hjX$Qw;kxnBL%Pd;I(NeY1p1Gb-f zPr{-xI!5$wHY#?Y>EXv#M~iI1CqEs~;YmdX0y=$h)wRm9P@S?yo293uH%l*@4i+oO zt{9_Z0S-aMNd%&>$&W3xxMSH~@Jw!z`+bruWpJP0cl1Sf>!g zvjd}V;7QB1aOW@>;Gx&*TU+l?{DPpaS6~w&VYJ&p@?ChI_x$^UWoD3j@b<+{{*Zew z`e4vx`HK%;V@n5Yz#2SWL=X<3avD=P9nO7udae|ong4lsUNFFC@jYAhmb<+kzjC|d YKj>9fBeOrw zg?~X1q|`r9M0C}SCAnvcE=0H8`L?zNH)5MMb8mE|)ha5Dj-2T$+S*JrlgvzRKR6K5 z+{=7l&z(815n>6|g}T?=qzT%z#Oqo@MiIQy1bI#HQAzyG#-I5+?{5+^-fs!oc&$hx zbkDl2itvUee60w7X+pOW^VUl2(}W$0np;Gi@$!yXu4MY0CU{mU;j$*-sYBLTw^uZX zSP>`diXzBWjrbhTfMJK=a^ym2JGEC64%UkJT#vv3O;&5oiRWqkN+t33~*-w^f(C4F{FPFHw{IzXM>kkk?r_stLYF zO|rbfPbKkGsN|KMKB)+c(UbG-3B^LzIvxsnCyNKPgdb6ps>BmC!QtQ$os939_hDmB zPik{Tp)*2 z54O*&;m>|BF+Lo~6AA>Ed}MYID61=e&HEGJ;m%nB9`5wDhW8G56owYeAeEQT2Rm9cF~p21|wj@Lc>0P1s?I0DR9gyC|ATZJ8qgBa9ip#FoVw zJcL;90u&^i7G+vv!^XD87(9Vlugy_Sa6!bjJ)Wz6d))VEtS{oO@RuUk<%|3@ zc>J_(1dz}vDjJfK-mJcxXp=Zl(U25_0|p*HO)&XSd9pT%AaHElpNtXNe+_=BEF20% zei{y?Pb6+s*0zobBZs9W{0Mzm`tRcqUIjUP^7yGh>3yP_aC%akV>v=Au`loqZ*g

kNkbXa+oTwwR86+Nc_NSc@M7PRs7;Z)EMpFu!d{!+=x(w-HPC) zk}%@EJndy^T#n}#sbOSFux|b>ugTqCwL0qS7xj)m^|T|v?F1O{00000NkvXXu0mjf DW5WAu literal 0 HcmV?d00001 diff --git a/src/main/resources/image/play.png b/src/main/resources/image/play.png new file mode 100644 index 0000000000000000000000000000000000000000..d61293bb7f2ce5f75aef967bb845905e9d917bcd GIT binary patch literal 1387 zcmV-x1(f=UP)j7Myhb?mhB)jB+jf=VE8-mXQVyeD5zjKtMu>nt+J&G|YZKvYxMIY!42Db_ zYAa5>rn~I{%GoE*0;Y|;>kW`0f;ETj)|C|@U(FA#r2^vGiD%on4V*pdDS0BSrwM0M zJ|LUZh+vauG*agYdDDh%gtObaNiJ`Yq@2B=mOO_>A|R!oT%n!-DI#FI8uHOd9ThOE zn^Y;DU`E+9Dk8cm{bWk^gj=BwSW^=Du-&?HA(Yilq%09Q8^&$BXaOkh^FAP;Mg%xe z6nWEzT3-Y?s*FP>#H}X^bbY%@RiIPXby)5>!)0yfm%f+^n71td_BrfTG2phIqjF+y zRw5?nlk)vb1G3t-Gz$T*=O;hdvO-l>_wm&sc{k2Zj>{MOzt!gjf?dsk*X$Ehm7B zfy8gJq4!utMaWrRBUr=JAOK=6otCX*=VVRC7ZnkJ2(~Ym`^R+&;NtqslzcO8doKcq zf$Y+?D64v_L;x2j$A6YvPapBn10c1&3sx<0|44)CLCO&TF+D#gKe!z8EOx;9hOsCB zH2F;c7Z;}!a@XMZ>ILBN&f@&%%<`)MZtQUE*HO8->nnBBfV0S=2jG#Ej|Ffsp1keE z4yNjbkaBh-2m-hmoVY2sml-<{0b@%&;8u_XKqS*CC&4P+16X3|A~+v30T3A}<+I(T zZI{T|2)Y1>`re}o1Q5ZS0*HfS7t~Av8n8uhY-UQn5f@4q!B`Lkm`$f-%jl1?rsH$v z+o0ul0Wd#!uKOF00wM0-Q26HTjC}j-DW%Vr9STQTz25|w&!nYw(DILa0ud(mAC&Y86!wA*KV5JD4G}g~+&~Mxg%GrKh0=Sjprz%t_#x>73 zMbQgW3AxjQd_SKdS0fjQ!XCfn1i;fGFDpJpm&Fm-gy^*Zn809hW6PW?Vn76I_Q8WIGWe({ z@@|uq)2knR@3>WI4=TvYjI)W5fUw~uLLIQik1e#gW0k$&6}d$o@JXEm!6(XZOs4x002ovPDHLkV1h5bkUjta literal 0 HcmV?d00001 diff --git a/src/main/resources/image/rewind.png b/src/main/resources/image/rewind.png new file mode 100644 index 0000000000000000000000000000000000000000..c09cd59c5729447196cba5a55fdaecc023a36f7b GIT binary patch literal 1484 zcmV;-1vC1IP)zV^q*ag>xG3T2oQ3o&R#6fR>* z5}3l|eI*I`JNdWtGxFIeDUoB1#V96+ClMuIVM>0-jHEClLQzwQ!Z}Pyc@aId#t5>Q z@rvapBfAhIXI%i!tB68Vh{Db==gW*h0jIDRQ|R*wc$QMqix|A`I}tc)J%=diC>Zc8 zg?5v}=7Iw+Zm50)Q}SIpfcXYK;|(y07&#c`l`9GYzK9-LgBi5>4m?}C*HQA6r{EE@ zUPP4K4glDkiWnI(qmeD1fHyg8LzImA4RT?HB&OsIz2GTqM+_$X2WQt4U;;6CO%M2J zWD906<~Jx6PcWlotB#EBw*O$1Jz+2ugVjpl!@P3ER4VH`5LYBn(jm8P#{^)x&j$d2 z9unYyBk(4N&4EaAbSZ_&5VbbibbY=opoxx4FCZQA+_LbuPhqd$ll4yFz5L+g70U~H zsw=b?F!D#<6Qs$=F25(~ISJI-F)sm_L9^czEPyuT1pjoc^@P{|d{bSu*cty#6miS7 zt>Rc!+SaqND#v4Ume-K1;du!D)2`Fvdh)K2@xM~v*t z<^FA60N>VlOf=rSCT5EKtYYisGe<@ApUbmsT^LR{w?&~PyL8Q5Rd2KO8D1s!_q2&* zYGT%eRR~zmE%EK8RxvVuFUyt+0rIrCwjNf_aQ{fDPVjrqMMdwOp{&WO5b$ zF|REp4`4*d`i3!00F>zfzV-AGar|1}ypwf8K={-z!Wy_JQj?Q;Z7CB#;q&SBPl@FQ zxQy!M7n;Rz4i|MwfXRsX;(VjHnH;rcOO*gbNo3js&!76)mW$dUU_%`U35oKHI9zYT^gW$N`fnT0)Ql9Kw0zPby3FrQ!hX9G$P$A&!i!Is+_@uMm zwJkjaF#AhDM(J-Z#cfCYd<5XBh@ZGO=I;`~3PCWl=c~Bz+#qOo&-XG2wz|psdPW9a z5s=ZhT26{ihg+(yZO~FBAd~mYT>Z|(xGMrONtIj{gEp6io-Kt^{ju*6ge2(iek{}E7JQ~j9k<8Z$0&gpS@dWm^-9G2qM zHCSoWad9^Bw<`iN`bxvEf?prd-~rHV%oR*YxfcY?OrJ9)vG4o4T-lNtWTqr`{Y`3-6WRXn|RD*=2rVrJzd5tq_B-;iZIPusVn>v~tIC9q=4(kp}{jET!Z=zv{$^hmArD zW?=f;Sq5#kTVTDCusl0ZvPYh@3g+$%dO|Gn?)K{Hhm4>|nDb?_2@z4!=ppz9d7k(E zeLLF(duym#6QS;!{&U_fHW9 m@>w}%9j|=U@A(@Ky8H{FtW%K@QQ{T=0000 - - + + + - + + + + + + + + + + + + + + + + +