IT WORRRKSSSSS.
parent
0cf2a744fa
commit
e07f095a82
1000
.idea/workspace.xml
1000
.idea/workspace.xml
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 473 B |
Binary file not shown.
After Width: | Height: | Size: 581 B |
Binary file not shown.
After Width: | Height: | Size: 654 B |
|
@ -1,7 +1,10 @@
|
|||
package io.makerforce.undefined;
|
||||
|
||||
import io.makerforce.undefined.util.LibraryManager;
|
||||
import io.makerforce.undefined.view.InterfaceController;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
|
@ -10,12 +13,10 @@ import javafx.stage.Stage;
|
|||
import javafx.stage.StageStyle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Main extends Application {
|
||||
|
||||
ChangeListener<LibraryManager.LibraryManagerState> ch = null; // Because it doesn't work in there
|
||||
private Stage mainStage;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -30,27 +31,60 @@ public class Main extends Application {
|
|||
initStage.initStyle(StageStyle.UNDECORATED);
|
||||
initStage.setScene(splashScene);
|
||||
initStage.toFront();
|
||||
initStage.setAlwaysOnTop(true);
|
||||
initStage.show();
|
||||
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
executor.schedule(() -> Platform.runLater(() -> {
|
||||
initStage.close();
|
||||
ch = (state, oldValue, newValue) -> {
|
||||
InterfaceController.getLibraryManager().stateProperty().removeListener(ch);
|
||||
//ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
//executor.schedule(() -> Platform.runLater(() -> {
|
||||
Platform.runLater(() -> {
|
||||
Parent root = null;
|
||||
try {
|
||||
root = FXMLLoader.load(Main.this.getClass().getResource("view/interface.fxml"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(284);
|
||||
}
|
||||
mainStage = new Stage(StageStyle.DECORATED);
|
||||
mainStage.setTitle("Undefined");
|
||||
mainStage.setScene(new Scene(root, 640, 480));
|
||||
mainStage.setMinHeight(((BorderPane) root).getMinHeight());
|
||||
mainStage.setMinWidth(((BorderPane) root).getMinWidth());
|
||||
mainStage.setOnCloseRequest((event) -> {
|
||||
LibraryManager.unScheduleAll();
|
||||
});
|
||||
mainStage.show();
|
||||
//executor.shutdown();
|
||||
InterfaceController.getLibraryManager().stateProperty().set(LibraryManager.UPDATING);
|
||||
InterfaceController.getLibraryManager().stateProperty().set(LibraryManager.READY);
|
||||
|
||||
Parent root = null;
|
||||
Thread initStageClose = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
initStage.close();
|
||||
});
|
||||
});
|
||||
initStageClose.start();
|
||||
});
|
||||
//}), 1500, TimeUnit.MILLISECONDS);
|
||||
};
|
||||
InterfaceController.getLibraryManager().stateProperty().addListener(ch);
|
||||
|
||||
Thread init = new Thread(() -> {
|
||||
try {
|
||||
root = FXMLLoader.load(getClass().getResource("view/interface.fxml"));
|
||||
} catch (IOException e) {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(284);
|
||||
}
|
||||
mainStage = new Stage(StageStyle.DECORATED);
|
||||
mainStage.setTitle("Undefined");
|
||||
mainStage.setScene(new Scene(root, 640, 480));
|
||||
mainStage.setMinHeight(((BorderPane) root).getMinHeight());
|
||||
mainStage.setMinWidth(((BorderPane) root).getMinWidth());
|
||||
mainStage.show();
|
||||
executor.shutdown();
|
||||
}), 1500, TimeUnit.MILLISECONDS);
|
||||
InterfaceController.getLibraryManager().update(); // IT DOES REAL WORK MIND YOU. SO COOL. SADLY, SCHEDULING UPDATES DONT WORK YET
|
||||
});
|
||||
init.start();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import io.makerforce.undefined.util.Util;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -26,8 +25,4 @@ public class Album extends ItemList<Track> {
|
|||
}
|
||||
}
|
||||
|
||||
public ObservableList<Track> getTracks() {
|
||||
return this.getItems();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import io.makerforce.undefined.util.Util;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public class Artist extends ItemList<Album> {
|
||||
|
||||
public ItemList<Track> tracks = new ItemList<>();
|
||||
|
||||
public Artist() {
|
||||
super();
|
||||
}
|
||||
|
@ -21,11 +22,12 @@ public class Artist extends ItemList<Album> {
|
|||
o.getJSONObject("albums").keySet().forEach((key) -> {
|
||||
Album a = new Album(o.getJSONObject("albums").getJSONObject(key), key, artistName, endPoint);
|
||||
super.getItems().add(a);
|
||||
tracks.getItems().addAll(a.getItems());
|
||||
});
|
||||
}
|
||||
|
||||
public ObservableList<Album> getAlbums() {
|
||||
return this.getItems();
|
||||
public ItemList<Track> getTracks() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public interface Item {
|
||||
|
||||
public URL getPicture();
|
||||
ObjectProperty<URL> pictureProperty();
|
||||
|
||||
public String getTitle();
|
||||
StringProperty titleProperty();
|
||||
|
||||
public String getSubtitle();
|
||||
StringProperty subtitleProperty();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
|
@ -7,16 +11,16 @@ import java.net.URL;
|
|||
|
||||
public class ItemList<T> implements Item {
|
||||
|
||||
private URL picture;
|
||||
private String title;
|
||||
private String subtitle;
|
||||
private ObjectProperty<URL> picture = new SimpleObjectProperty<>();
|
||||
private StringProperty title = new SimpleStringProperty();
|
||||
private StringProperty subtitle = new SimpleStringProperty();
|
||||
|
||||
private ObservableList<T> items = FXCollections.observableArrayList();
|
||||
|
||||
public ItemList(URL picture, String title, String subtitle) {
|
||||
this.picture = picture;
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
this.picture.set(picture);
|
||||
this.title.set(title);
|
||||
this.subtitle.set(subtitle);
|
||||
}
|
||||
|
||||
public ItemList(URL picture, String title) {
|
||||
|
@ -27,15 +31,15 @@ public class ItemList<T> implements Item {
|
|||
this(null, "", "");
|
||||
}
|
||||
|
||||
public URL getPicture() {
|
||||
public ObjectProperty<URL> pictureProperty() {
|
||||
return picture;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
public StringProperty titleProperty() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
public StringProperty subtitleProperty() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public class Library extends ItemList<Artist> {
|
||||
|
||||
public ItemList<Album> albums = new ItemList<>();
|
||||
public ItemList<Track> tracks = new ItemList<>();
|
||||
|
||||
public Library() {
|
||||
super();
|
||||
}
|
||||
|
@ -16,11 +18,17 @@ public class Library extends ItemList<Artist> {
|
|||
o.getJSONObject("artists").keySet().forEach((key) -> {
|
||||
Artist a = new Artist(o.getJSONObject("artists").getJSONObject(key), key, endPoint);
|
||||
super.getItems().add(a);
|
||||
albums.getItems().addAll(a.getItems());
|
||||
tracks.getItems().addAll(a.getTracks().getItems());
|
||||
});
|
||||
}
|
||||
|
||||
public ObservableList<Artist> getArtists() {
|
||||
return this.getItems();
|
||||
public ItemList<Album> getAlbums() {
|
||||
return albums;
|
||||
}
|
||||
|
||||
public ItemList<Track> getTracks() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package io.makerforce.undefined.model;
|
||||
|
||||
import io.makerforce.undefined.util.Util;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -8,15 +11,15 @@ import java.net.URL;
|
|||
|
||||
public class Track implements Item {
|
||||
|
||||
private URL file;
|
||||
private URL picture;
|
||||
private String title;
|
||||
private String artist;
|
||||
private String album;
|
||||
private String year;
|
||||
private int trackNumber; // track.no OR number
|
||||
private int totalTracks;
|
||||
private String[] genre;
|
||||
private ObjectProperty<URL> file = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<URL> picture = new SimpleObjectProperty<>();
|
||||
private StringProperty title = new SimpleStringProperty();
|
||||
private StringProperty artist = new SimpleStringProperty();
|
||||
private StringProperty album = new SimpleStringProperty();
|
||||
private StringProperty year = new SimpleStringProperty();
|
||||
private IntegerProperty trackNumber = new SimpleIntegerProperty(); // track.no OR number
|
||||
private IntegerProperty totalTracks = new SimpleIntegerProperty();
|
||||
private ObservableList<String> genre = FXCollections.observableArrayList();
|
||||
|
||||
public Track() {
|
||||
|
||||
|
@ -29,72 +32,71 @@ public class Track implements Item {
|
|||
|
||||
public Track(JSONObject track, String albumName, String artistName, URL endPoint) {
|
||||
this();
|
||||
title = Util.getNotEmpty(
|
||||
title.set(Util.getNotEmpty(
|
||||
track.getString("title"),
|
||||
(track.has("filetitle") ? track.getString("filetitle") : "")
|
||||
);
|
||||
file = Util.toURLOrNull(endPoint + track.getString("file"));
|
||||
picture = Util.toURLOrNull(endPoint + track.getString("picture"));
|
||||
artist = Util.getNotEmpty(
|
||||
));
|
||||
file.set(Util.toURLOrNull(endPoint + track.getString("file")));
|
||||
picture.set(Util.toURLOrNull(endPoint + track.getString("picture")));
|
||||
artist.set(Util.getNotEmpty(
|
||||
(track.getJSONArray("artist").length() > 0 ? track.getJSONArray("artist").getString(0) : ""),
|
||||
artistName
|
||||
);
|
||||
album = Util.getNotEmpty(
|
||||
));
|
||||
album.set(Util.getNotEmpty(
|
||||
track.getString("album"),
|
||||
albumName
|
||||
);
|
||||
year = track.getString("year");
|
||||
trackNumber = track.getInt("number"); // track.getJSONObject("track").getInt("no");
|
||||
totalTracks = track.getJSONObject("track").getInt("of");
|
||||
));
|
||||
year.set(track.getString("year"));
|
||||
trackNumber.set(track.getInt("number")); // track.getJSONObject("track").getInt("no");
|
||||
totalTracks.set(track.getJSONObject("track").getInt("of"));
|
||||
JSONArray genres = track.getJSONArray("genre");
|
||||
genre = new String[genres.length()];
|
||||
for (int i = 0; i < genres.length(); i++) {
|
||||
genre[i] = genres.getString(i);
|
||||
genre.add(genres.getString(i));
|
||||
}
|
||||
}
|
||||
|
||||
public URL getPicture() {
|
||||
public ObjectProperty<URL> pictureProperty() {
|
||||
return picture;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
public StringProperty titleProperty() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
public StringProperty subtitleProperty() {
|
||||
return artist;
|
||||
}
|
||||
|
||||
public URL getFile() {
|
||||
public ObjectProperty<URL> fileProperty() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public String getArtist() {
|
||||
public StringProperty artistProperty() {
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getAlbum() {
|
||||
public StringProperty albumProperty() {
|
||||
return album;
|
||||
}
|
||||
|
||||
public String getYear() {
|
||||
public StringProperty yearProperty() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public int getTrackNumber() {
|
||||
public IntegerProperty trackNumberProperty() {
|
||||
return trackNumber;
|
||||
}
|
||||
|
||||
public int getTotalTracks() {
|
||||
public IntegerProperty totalTracksProperty() {
|
||||
return totalTracks;
|
||||
}
|
||||
|
||||
public String[] getGenre() {
|
||||
public ObservableList<String> getGenre() {
|
||||
return genre;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return title + " (" + artist + ", " + album + ")";
|
||||
return title.get() + " (" + artist.get() + ", " + album.get() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.makerforce.undefined.util;
|
||||
|
||||
import io.makerforce.undefined.model.Library;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -11,6 +12,7 @@ import java.net.HttpURLConnection;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -21,16 +23,13 @@ public class LibraryManager {
|
|||
public static final LibraryManagerState ERROR = new LibraryManagerState("error");
|
||||
public static final LibraryManagerState READY = new LibraryManagerState("ready");
|
||||
|
||||
public static final String DEFAULT_ENDPOINT = "http://ambrose.makerforce.io:8080/";
|
||||
|
||||
public static final String DEFAULT_ENDPOINT = "http://ambrose.makerforce.io:8080";
|
||||
private static ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
|
||||
private SimpleObjectProperty<LibraryManagerState> state = new SimpleObjectProperty<>();
|
||||
|
||||
private URL endPoint;
|
||||
|
||||
private Library l;
|
||||
|
||||
private ScheduledExecutorService scheduledExecutorService = null;
|
||||
private boolean hasScheduled = false;
|
||||
private ScheduledFuture<?> future;
|
||||
//private static ArrayList<ScheduledFuture> futures = new ArrayList<>();
|
||||
|
||||
public LibraryManager() {
|
||||
state.set(EMPTY);
|
||||
|
@ -53,6 +52,13 @@ public class LibraryManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static void unScheduleAll() {
|
||||
//futures.forEach((future) -> {
|
||||
// future.cancel(true);
|
||||
//});
|
||||
scheduledExecutorService.shutdownNow();
|
||||
}
|
||||
|
||||
public Library getLibrary() {
|
||||
return l;
|
||||
}
|
||||
|
@ -62,53 +68,67 @@ public class LibraryManager {
|
|||
}
|
||||
|
||||
public void update() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
state.set(UPDATING);
|
||||
try {
|
||||
state.set(UPDATING);
|
||||
|
||||
HttpURLConnection con = (HttpURLConnection) endPoint.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
con.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
con.setRequestProperty("X-Undefined-Client", "JavaFX/0.0.2");
|
||||
HttpURLConnection con = (HttpURLConnection) endPoint.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
con.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
con.setRequestProperty("X-Undefined-Client", "JavaFX/0.0.2");
|
||||
|
||||
int responseCode = con.getResponseCode();
|
||||
System.out.println("Response Code: " + responseCode);
|
||||
int responseCode = con.getResponseCode();
|
||||
System.out.println("Response Code: " + responseCode);
|
||||
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuilder response = new StringBuilder();
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuilder response = new StringBuilder();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
|
||||
JSONObject obj = new JSONObject(response.toString());
|
||||
l = new Library(obj, endPoint);
|
||||
|
||||
state.set(READY);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
state.set(ERROR);
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
}).run();
|
||||
in.close();
|
||||
|
||||
JSONObject obj = new JSONObject(response.toString());
|
||||
l = new Library(obj, endPoint);
|
||||
|
||||
state.set(READY);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
state.set(ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public void schedule() {
|
||||
if (scheduledExecutorService == null) {
|
||||
scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
|
||||
scheduledExecutorService.scheduleAtFixedRate(() -> {
|
||||
this.update();
|
||||
}, 0, 60, TimeUnit.SECONDS);
|
||||
//this.update();
|
||||
if (future == null) {
|
||||
future = scheduledExecutorService.scheduleWithFixedDelay(() -> {
|
||||
//this.update(); // DISABLED BECAUSE: Will stop playback if it's playing due to bad implementation. And anyway the server-side stuff won't change.
|
||||
state.set(UPDATING);
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
state.set(READY);
|
||||
}, 0, 60, TimeUnit.SECONDS); // Poke every minute (although nothing will change on the remote server)
|
||||
//futures.add(future);
|
||||
} else {
|
||||
throw new Error("Updates are already scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleRate() {
|
||||
future.getDelay(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void unSchedule() {
|
||||
scheduledExecutorService.shutdownNow();
|
||||
scheduledExecutorService = null;
|
||||
future.cancel(true);
|
||||
//futures.remove(future);
|
||||
}
|
||||
|
||||
public ObjectProperty<LibraryManagerState> stateProperty() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public static final class LibraryManagerState {
|
||||
|
|
|
@ -4,10 +4,12 @@ import io.makerforce.undefined.model.Track;
|
|||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PlayManager {
|
||||
|
@ -21,7 +23,7 @@ public class PlayManager {
|
|||
|
||||
private ArrayList<Track> queue = new ArrayList<>();
|
||||
|
||||
private IntegerProperty currentTrack = new SimpleIntegerProperty(0);
|
||||
private IntegerProperty currentTrack = new SimpleIntegerProperty(-1);
|
||||
|
||||
private MediaPlayer player;
|
||||
|
||||
|
@ -30,7 +32,12 @@ public class PlayManager {
|
|||
private DoubleProperty currentPercent = new SimpleDoubleProperty();
|
||||
private ObjectProperty<Duration> timeLeft = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<Duration> currentTime = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<Duration> totalTime = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<Duration> totalTime = new SimpleObjectProperty<>(new Duration(0));
|
||||
|
||||
private ObjectProperty<URL> currentPicture = new SimpleObjectProperty<>();
|
||||
private StringProperty currentTitle = new SimpleStringProperty();
|
||||
private StringProperty currentArtist = new SimpleStringProperty();
|
||||
|
||||
private ChangeListener<Duration> currentTimeChange = new ChangeListener<Duration>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration c) {
|
||||
|
@ -45,53 +52,116 @@ public class PlayManager {
|
|||
}
|
||||
|
||||
private void load(Track track) {
|
||||
player = new MediaPlayer(new Media(track.getFile().toString()));
|
||||
player = new MediaPlayer(new Media(track.fileProperty().get().toString()));
|
||||
// To player
|
||||
player.muteProperty().bind(muted);
|
||||
player.volumeProperty().bind(volume);
|
||||
// From player
|
||||
player.currentTimeProperty().addListener(currentTimeChange);
|
||||
totalTime.set(player.totalDurationProperty().get());
|
||||
totalTime.bind(player.totalDurationProperty());
|
||||
currentPicture.bind(track.pictureProperty());
|
||||
currentTitle.bind(track.titleProperty());
|
||||
currentArtist.bind(track.artistProperty());
|
||||
}
|
||||
|
||||
public void play() {
|
||||
if (state.equals(PAUSED) || state.equals(STOPPED)) {
|
||||
player.play();
|
||||
state.set(PLAYING);
|
||||
} else if (state.equals(ENDED)) {
|
||||
if (currentTrack.get() == -1) {
|
||||
next();
|
||||
} else if (player == null) {
|
||||
|
||||
} else {
|
||||
if (state.get() == PAUSED || state.get() == STOPPED) {
|
||||
player.play();
|
||||
state.set(PLAYING);
|
||||
state.get();
|
||||
} else if (state.get() == ENDED) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (state.equals(PLAYING)) {
|
||||
player.pause();
|
||||
if (player == null) {
|
||||
|
||||
} else {
|
||||
if (state.get() == PLAYING) {
|
||||
player.pause();
|
||||
state.set(PAUSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (player == null) {
|
||||
|
||||
} else {
|
||||
player.stop();
|
||||
state.set(PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
public void previous() {
|
||||
if (currentTime.get().toSeconds() < 1) {
|
||||
player.stop();
|
||||
if (currentTrack.get() - 1 > 0) {
|
||||
currentTrack.subtract(1);
|
||||
load(queue.get(currentTrack.get()));
|
||||
}
|
||||
if (player == null) {
|
||||
|
||||
} else {
|
||||
player.seek(new Duration(0));
|
||||
if (currentTime.get().toSeconds() < 2) {
|
||||
stop();
|
||||
if (currentTrack.get() - 1 > 0) {
|
||||
currentTrack.set(currentTrack.get() - 1);
|
||||
load(queue.get(currentTrack.get()));
|
||||
play();
|
||||
}
|
||||
} else {
|
||||
player.seek(new Duration(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void next() {
|
||||
player.stop();
|
||||
if (currentTrack.get() + 1 < queue.size()) {
|
||||
currentTrack.add(1);
|
||||
load(queue.get(currentTrack.get()));
|
||||
if (player != null) {
|
||||
stop();
|
||||
}
|
||||
if (currentTrack.get() + 1 < queue.size()) {
|
||||
currentTrack.set(currentTrack.get() + 1);
|
||||
load(queue.get(currentTrack.get()));
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
public void seek(Duration t) {
|
||||
player.seek(t);
|
||||
}
|
||||
|
||||
public void setIndex(int selectedIndex) {
|
||||
currentTrack.set(selectedIndex - 1);
|
||||
next();
|
||||
}
|
||||
|
||||
public void addToQueue(Track track) {
|
||||
queue.add(track);
|
||||
}
|
||||
|
||||
public void addAllToQueue(ObservableList<Track> tracks) {
|
||||
queue.addAll(tracks);
|
||||
}
|
||||
|
||||
public void clearQueue() {
|
||||
if (player != null) {
|
||||
stop();
|
||||
}
|
||||
queue.clear();
|
||||
currentTrack.set(-1);
|
||||
}
|
||||
|
||||
// Was for creating a new PlayManager, but decided to just reset the queue
|
||||
/*
|
||||
public void destroy() {
|
||||
queue.clear();
|
||||
player.stop();
|
||||
player.dispose();
|
||||
}
|
||||
*/
|
||||
|
||||
public BooleanProperty muteProperty() {
|
||||
return muted;
|
||||
}
|
||||
|
@ -120,6 +190,18 @@ public class PlayManager {
|
|||
return totalTime;
|
||||
}
|
||||
|
||||
public ObjectProperty<URL> currentPictureProperty() {
|
||||
return currentPicture;
|
||||
}
|
||||
|
||||
public StringProperty currentTitleProperty() {
|
||||
return currentTitle;
|
||||
}
|
||||
|
||||
public StringProperty currentArtistProperty() {
|
||||
return currentArtist;
|
||||
}
|
||||
|
||||
public static final class PlayManagerState {
|
||||
|
||||
private final String text;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package io.makerforce.undefined.util;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.util.Duration;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
@ -47,11 +50,20 @@ public class Util {
|
|||
|
||||
public static String getNotEmpty(String... strings) {
|
||||
for (String s : strings) {
|
||||
if (!s.isEmpty()) {
|
||||
if (s != null && !s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static ObjectProperty<Image> getImageFromURLProperty(ObjectProperty<URL> urlObjectProperty) {
|
||||
ObjectProperty<Image> i = new SimpleObjectProperty<>();
|
||||
urlObjectProperty.addListener(u -> {
|
||||
if (u != null) {
|
||||
i.set(new Image(urlObjectProperty.get().toString()));
|
||||
}
|
||||
});
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.makerforce.undefined.view;
|
||||
|
||||
import io.makerforce.undefined.model.Item;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
|
@ -51,4 +52,8 @@ public class CoverItemController extends AnchorPane {
|
|||
this(null, "", "", "");
|
||||
}
|
||||
|
||||
public CoverItemController(Item i) {
|
||||
this(new Image(String.valueOf(i.pictureProperty().get())), i.titleProperty().get(), i.subtitleProperty().get());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.makerforce.undefined.view;
|
||||
|
||||
import io.makerforce.undefined.model.Item;
|
||||
import io.makerforce.undefined.model.ItemList;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
|
@ -21,4 +22,16 @@ public class CoverListController extends FlowPane {
|
|||
}
|
||||
}
|
||||
|
||||
public void setItemList(ItemList list) {
|
||||
itemList = list;
|
||||
list.getItems().forEach(i -> {
|
||||
this.getChildren().add(new CoverItemController((Item) i));
|
||||
});/*
|
||||
this.getChildren().addAll(
|
||||
(Collection<CoverItemController>)
|
||||
list.getItems().stream().map(i -> new CoverItemController((Item) i))
|
||||
.collect(Collectors.toList()));
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.makerforce.undefined.view;
|
||||
|
||||
import io.makerforce.undefined.model.Track;
|
||||
import io.makerforce.undefined.util.LibraryManager;
|
||||
import io.makerforce.undefined.util.PlayManager;
|
||||
import io.makerforce.undefined.util.Util;
|
||||
|
@ -11,22 +10,22 @@ import javafx.fxml.FXML;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Duration;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InterfaceController {
|
||||
|
||||
//private MediaPlayer player;
|
||||
private static PlayManager player = new PlayManager();
|
||||
private static LibraryManager libraryManager = new LibraryManager();
|
||||
@FXML
|
||||
private VBox leftPane;
|
||||
|
||||
@FXML
|
||||
private VBox currentDetails;
|
||||
@FXML
|
||||
|
@ -35,23 +34,19 @@ public class InterfaceController {
|
|||
private Label currentTitle;
|
||||
@FXML
|
||||
private Label currentArtist;
|
||||
|
||||
@FXML
|
||||
private ListView<String> showList;
|
||||
private ObservableList<String> showListItems = FXCollections.observableArrayList("Albums", "Artists", "Songs");
|
||||
|
||||
private ObservableList<String> showListItems = FXCollections.observableArrayList("Artists", "Albums", "Songs");
|
||||
@FXML
|
||||
private ScrollPane scrollPane;
|
||||
@FXML
|
||||
private FlowPane flowPane;
|
||||
//@FXML
|
||||
private TrackListController trackList;
|
||||
//@FXML
|
||||
private CoverListController coverList;
|
||||
|
||||
private CoverListController albumList;
|
||||
//@FXML
|
||||
private CoverListController artistList;
|
||||
private Image playIcon = new Image("/icons/play3.48.png");
|
||||
private Image pauseIcon = new Image("/icons/pause2.48.png");
|
||||
|
||||
@FXML
|
||||
private Button pausePlayButton;
|
||||
@FXML
|
||||
|
@ -66,48 +61,44 @@ public class InterfaceController {
|
|||
private Label playbackTimeLabel;
|
||||
@FXML
|
||||
private Label playbackLeftLabel;
|
||||
|
||||
@FXML
|
||||
private ToggleButton muteToggle;
|
||||
@FXML
|
||||
private ImageView muteToggleIcon;
|
||||
@FXML
|
||||
private Slider volumeSlider;
|
||||
|
||||
private Image cloudUpdatingIcon = new Image("/icons/cloud-download.32.png");
|
||||
private Image cloudReadyIcon = new Image("/icons/cloud-check.32.png");
|
||||
private Image cloudErrorIcon = new Image("/icons/warning.32.png");
|
||||
@FXML
|
||||
private ImageView statusIcon;
|
||||
|
||||
//private MediaPlayer player;
|
||||
private PlayManager player = new PlayManager();
|
||||
|
||||
|
||||
public InterfaceController() {
|
||||
|
||||
}
|
||||
|
||||
public static PlayManager getPlayManager() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public static LibraryManager getLibraryManager() {
|
||||
return libraryManager;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
|
||||
trackList = new TrackListController();
|
||||
coverList = new CoverListController();
|
||||
albumList = new CoverListController();
|
||||
artistList = new CoverListController();
|
||||
|
||||
// Temporary stuff
|
||||
/*
|
||||
currentImage.setImage(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"));
|
||||
currentArtist.setText("Alan Walker");
|
||||
currentTitle.setText("Fade");
|
||||
|
||||
trackList = new TrackListController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Spectre/1"), "Spectre", "Alan Walker");
|
||||
coverList = new CoverListController();
|
||||
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Spectre/1"), "Spectre", "Alan Walker"));
|
||||
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Fade", "Alan Walker"));
|
||||
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Alan Walker"));
|
||||
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Alan Walker"));
|
||||
*/
|
||||
/*
|
||||
try {
|
||||
player.addToQueue(new Track(new JSONObject(""), "", "", new URL(LibraryManager.DEFAULT_ENDPOINT)));
|
||||
player.addToQueue(new Track(new JSONObject("{\"title\":\"Fade\",\"artist\":[\"Alan Walker\"],\"albumartist\":[\"Various Artists\"],\"album\":\"Fade\",\"year\":\"2014\",\"track\":{\"no\":7,\"of\":0},\"genre\":[\"Dance & House\"],\"disk\":{\"no\":1,\"of\":0},\"picture\":\"/art/Alan%20Walker/Fade/1\",\"duration\":0,\"number\":1,\"file\":\"/tracks/Alan%20Walker/Fade/Fade.mp3\"}"), "", "", new URL(LibraryManager.DEFAULT_ENDPOINT)));
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
// UI Bindings
|
||||
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
@ -126,22 +117,56 @@ public class InterfaceController {
|
|||
showList.selectionModelProperty().get().selectedIndexProperty().addListener(observable2 -> {
|
||||
int sel = showList.selectionModelProperty().get().getSelectedIndex();
|
||||
if (sel == 0) {
|
||||
scrollPane.setContent(flowPane);
|
||||
scrollPane.setContent(artistList);
|
||||
// artists
|
||||
} else if (sel == 1) {
|
||||
scrollPane.setContent(flowPane);
|
||||
scrollPane.setContent(albumList);
|
||||
// albums
|
||||
} else if (sel == 2) {
|
||||
scrollPane.setContent(trackList);
|
||||
}
|
||||
});
|
||||
|
||||
// Library bindings
|
||||
|
||||
libraryManager.stateProperty().addListener(observable -> {
|
||||
if (libraryManager.stateProperty().get() == LibraryManager.UPDATING) {
|
||||
statusIcon.setImage(cloudUpdatingIcon);
|
||||
} else if (libraryManager.stateProperty().get() == LibraryManager.READY) { // HMM tells me that not on FX thread...
|
||||
Platform.runLater(() -> {
|
||||
trackList.setItemList(libraryManager.getLibrary().getTracks());
|
||||
albumList.setItemList(libraryManager.getLibrary().getAlbums());
|
||||
artistList.setItemList(libraryManager.getLibrary());
|
||||
statusIcon.setImage(cloudReadyIcon);
|
||||
});
|
||||
clearStatusIcon();
|
||||
} else if (libraryManager.stateProperty().get() == LibraryManager.ERROR) {
|
||||
statusIcon.setImage(cloudErrorIcon);
|
||||
//clearStatusIcon();
|
||||
Timer t = new Timer();
|
||||
t.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
libraryManager.update();
|
||||
t.cancel(); // Here's the solution to the problem of unable to shut down.
|
||||
}
|
||||
}, 1000); // Quick hack to trigger more frequent updates.
|
||||
}
|
||||
});
|
||||
//libraryManager.schedule();
|
||||
|
||||
// Player bindings
|
||||
|
||||
// To player
|
||||
player.muteProperty().bind(muteToggle.selectedProperty());
|
||||
player.volumeProperty().bind(volumeSlider.valueProperty());
|
||||
|
||||
// Player events
|
||||
// From player
|
||||
currentImage.imageProperty().bind(Util.getImageFromURLProperty(player.currentPictureProperty()));
|
||||
currentTitle.textProperty().bind(player.currentTitleProperty());
|
||||
currentArtist.textProperty().bind(player.currentArtistProperty());
|
||||
|
||||
// Playback status
|
||||
// Playback status (From player)
|
||||
player.stateProperty().addListener((observable, old, state) -> {
|
||||
if (state == PlayManager.PLAYING) {
|
||||
pausePlayButtonIcon.setImage(pauseIcon);
|
||||
|
@ -150,23 +175,23 @@ public class InterfaceController {
|
|||
}
|
||||
});
|
||||
|
||||
// Update slider position when music plays.
|
||||
// Update slider position when music plays. (From player)
|
||||
playbackSlider.valueProperty().bind(player.currentPercent());
|
||||
|
||||
// Update labels.
|
||||
playbackSlider.valueProperty().addListener((observable1, oldValue1, v) -> {
|
||||
// Update labels. (From slider)
|
||||
playbackSlider.valueProperty().addListener((observable, old, v) -> {
|
||||
Duration d = new Duration(v.doubleValue() * player.totalTimeProperty().get().toMillis());
|
||||
playbackTimeLabel.setText(Util.durationToString(d));
|
||||
playbackLeftLabel.setText(Util.durationToString(d.subtract(player.totalTimeProperty().get())));
|
||||
});
|
||||
|
||||
// Seek when slider is released.
|
||||
playbackSlider.valueChangingProperty().addListener((observable, oldValue, c) -> {
|
||||
// Seek when slider is released. (To player)
|
||||
playbackSlider.valueChangingProperty().addListener((observable, old, c) -> {
|
||||
if (c) {
|
||||
playbackSlider.valueProperty().unbind();
|
||||
} else {
|
||||
playbackSlider.valueProperty().bind(player.currentPercent());
|
||||
//player.seek(new Duration(playbackSlider.getValue() * player.totalTimeProperty().get().toMillis()));
|
||||
player.seek(new Duration(playbackSlider.getValue() * player.totalTimeProperty().get().toMillis()));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -186,13 +211,30 @@ public class InterfaceController {
|
|||
@FXML
|
||||
private void nextTrack() {
|
||||
|
||||
player.next();
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void previousTrack() {
|
||||
|
||||
player.previous();
|
||||
|
||||
}
|
||||
|
||||
private void clearStatusIcon(int milliseconds) {
|
||||
Timer t = new Timer();
|
||||
t.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusIcon.setImage(null);
|
||||
t.cancel(); // Here's the solution to the problem of unable to shut down.
|
||||
}
|
||||
}, milliseconds);
|
||||
}
|
||||
|
||||
private void clearStatusIcon() {
|
||||
clearStatusIcon(4000);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package io.makerforce.undefined.view;
|
||||
|
||||
import io.makerforce.undefined.model.ItemList;
|
||||
import io.makerforce.undefined.model.Track;
|
||||
import javafx.beans.value.ObservableIntegerValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
|
@ -24,6 +28,19 @@ public class TrackListController extends VBox {
|
|||
@FXML
|
||||
private ImageView imageView;
|
||||
|
||||
@FXML
|
||||
private TableColumn<Track, Integer> trackNumberTableColumn;
|
||||
@FXML
|
||||
private TableColumn<Track, String> trackTitleTableColumn;
|
||||
@FXML
|
||||
private TableColumn<Track, String> trackArtistTableColumn;
|
||||
@FXML
|
||||
private TableColumn<Track, String> trackAlbumTableColumn;
|
||||
@FXML
|
||||
private TableColumn<Track, String> trackLengthTableColumn;
|
||||
|
||||
private ItemList itemList;
|
||||
|
||||
public TrackListController(Image image, String title, String subtitle) {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tracklist.fxml"));
|
||||
fxmlLoader.setRoot(this);
|
||||
|
@ -37,6 +54,17 @@ public class TrackListController extends VBox {
|
|||
titleLabel.setText(title);
|
||||
subtitleLabel.setText(subtitle);
|
||||
coverContainer.setManaged(!(subtitle.isEmpty() && title.isEmpty()));
|
||||
trackNumberTableColumn.setCellValueFactory(track -> track.getValue().trackNumberProperty().asObject());
|
||||
trackTitleTableColumn.setCellValueFactory(track -> track.getValue().titleProperty());
|
||||
trackArtistTableColumn.setCellValueFactory(track -> track.getValue().artistProperty());
|
||||
trackAlbumTableColumn.setCellValueFactory(track -> track.getValue().albumProperty());
|
||||
tableView.getSelectionModel().selectedIndexProperty().addListener((selectedIndex) -> {
|
||||
InterfaceController.getPlayManager().clearQueue();
|
||||
InterfaceController.getPlayManager().addAllToQueue(itemList.getItems());
|
||||
InterfaceController.getPlayManager().setIndex(((ObservableIntegerValue) selectedIndex).get());
|
||||
//InterfaceController.getPlayManager().play();
|
||||
System.out.println(((ObservableIntegerValue) selectedIndex).get());
|
||||
});
|
||||
}
|
||||
|
||||
public TrackListController(Image image, String title) {
|
||||
|
@ -47,4 +75,9 @@ public class TrackListController extends VBox {
|
|||
this(null, "", "");
|
||||
}
|
||||
|
||||
public void setItemList(ItemList list) {
|
||||
itemList = list;
|
||||
tableView.setItems(list.getItems());
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0"
|
||||
minWidth="600.0" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40"
|
||||
minWidth="600.0" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/null"
|
||||
fx:controller="io.makerforce.undefined.view.InterfaceController">
|
||||
<bottom>
|
||||
<HBox alignment="CENTER_LEFT" spacing="7.0" BorderPane.alignment="CENTER_LEFT">
|
||||
|
@ -66,17 +66,21 @@
|
|||
</Button>
|
||||
</children>
|
||||
<HBox.margin>
|
||||
<Insets left="7.0" right="7.0"/>
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets left="7.0" right="7.0"/>
|
||||
</padding>
|
||||
</HBox>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Separator minWidth="-Infinity" orientation="VERTICAL" prefWidth="2.0"/>
|
||||
<HBox alignment="CENTER" spacing="7.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label fx:id="playbackTimeLabel" minWidth="42.0" prefHeight="24.0" text="--:--"/>
|
||||
<StackPane HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<ProgressBar fx:id="bufferProgress" minHeight="-Infinity" prefHeight="8.0"
|
||||
prefWidth="1000.0" progress="0.0" StackPane.alignment="BOTTOM_CENTER">
|
||||
prefWidth="1000.0" progress="0.0" visible="false"
|
||||
StackPane.alignment="BOTTOM_CENTER">
|
||||
<StackPane.margin>
|
||||
<Insets bottom="-5.0" left="4.0" right="6.0"/>
|
||||
</StackPane.margin>
|
||||
|
@ -91,8 +95,11 @@
|
|||
<HBox.margin>
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets left="7.0" right="7.0"/>
|
||||
</padding>
|
||||
</HBox>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Separator minWidth="-Infinity" orientation="VERTICAL" prefWidth="2.0"/>
|
||||
<HBox alignment="CENTER" spacing="7.0">
|
||||
<children>
|
||||
<ToggleButton fx:id="muteToggle" mnemonicParsing="false">
|
||||
|
@ -111,16 +118,26 @@
|
|||
<Font size="1.0"/>
|
||||
</font>
|
||||
</ToggleButton>
|
||||
<Slider fx:id="volumeSlider" max="1.0" min="0.0" prefHeight="16.0" prefWidth="64.0"
|
||||
<Slider fx:id="volumeSlider" max="1.0" min="0.0" minWidth="-Infinity" prefWidth="64.0"
|
||||
value="1.0"/>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets left="7.0" right="7.0"/>
|
||||
</padding>
|
||||
</HBox>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Separator minWidth="-Infinity" orientation="VERTICAL" prefWidth="2.0"/>
|
||||
<HBox alignment="CENTER" prefWidth="16.0">
|
||||
<children>
|
||||
<ImageView fx:id="statusIcon" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true"
|
||||
preserveRatio="true"/>
|
||||
<ImageView fx:id="statusIcon" fitHeight="16.0" fitWidth="16.0" opacity="0.75"
|
||||
pickOnBounds="true" preserveRatio="true">
|
||||
<HBox.margin>
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
</ImageView>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="3.5" left="3.5" right="3.5" top="3.5"/>
|
||||
</padding>
|
||||
</HBox>
|
||||
</children>
|
||||
<padding>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<fx:root xmlns:fx="http://javafx.com/fxml/1" type="VBox" xmlns="http://javafx.com/javafx/8.0.40">
|
||||
<fx:root xmlns:fx="http://javafx.com/fxml/1" type="VBox" xmlns="http://javafx.com/javafx/null">
|
||||
<children>
|
||||
<HBox fx:id="coverContainer" alignment="CENTER">
|
||||
<children>
|
||||
|
@ -29,11 +29,16 @@
|
|||
</HBox>
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn editable="false" prefWidth="28.0" resizable="false" sortable="false" text="#"/>
|
||||
<TableColumn editable="false" prefWidth="200.0" sortable="false" text="Title"/>
|
||||
<TableColumn editable="false" prefWidth="90.0" sortable="false" text="Artist"/>
|
||||
<TableColumn editable="false" prefWidth="90.0" sortable="false" text="Album"/>
|
||||
<TableColumn editable="false" prefWidth="70.0" sortable="false" text="Length"/>
|
||||
<TableColumn fx:id="trackNumberTableColumn" editable="false" prefWidth="28.0" resizable="false"
|
||||
sortable="false" text="#"/>
|
||||
<TableColumn fx:id="trackTitleTableColumn" editable="false" prefWidth="200.0" sortable="false"
|
||||
text="Title"/>
|
||||
<TableColumn fx:id="trackArtistTableColumn" editable="false" prefWidth="90.0" sortable="false"
|
||||
text="Artist"/>
|
||||
<TableColumn fx:id="trackAlbumTableColumn" editable="false" prefWidth="90.0" sortable="false"
|
||||
text="Album"/>
|
||||
<TableColumn fx:id="trackLengthTableColumn" editable="false" prefWidth="70.0" sortable="false"
|
||||
text="Length"/>
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
|
|
Loading…
Reference in New Issue