Remember last played playlist and positions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dmitry Isaenko 2023-05-12 00:02:14 +03:00
parent c01b36b772
commit f0068ae4c3
15 changed files with 288 additions and 206 deletions

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -22,8 +22,8 @@ import java.util.prefs.Preferences;
// Rule application settings
public class AppPreferences {
private static AppPreferences INSTANCE = new AppPreferences();
private Preferences preferences = Preferences.userRoot().node("mplayer4anime");
private static final AppPreferences INSTANCE = new AppPreferences();
private final Preferences preferences = Preferences.userRoot().node("mplayer4anime");
private AppPreferences(){}
@ -99,7 +99,7 @@ public class AppPreferences {
/** Return recently opened elements */
public String[] getRecentPlaylists(){
String[] recentPlaylists = new String[10];
for (int i=0; i<10; i++)
for (int i = 0; i < 10; i++)
recentPlaylists[i] = preferences.get("RECENT_PLS_" + i, "");
return recentPlaylists;
}
@ -112,7 +112,7 @@ public class AppPreferences {
preferences.put("RECENT_PLS_" + i, recentPlaylists[i]);
else
preferences.put("RECENT_PLS_" + i, "");
for (;i<10;i++) // Not needed. Logic may handle received String to be less or greater then String[10], but it never happened.
for (;i < 10; i++) // Not needed. Logic may handle received String to be less or greater then String[10], but it never happened.
preferences.put("RECENT_PLS_" + i, "");
}
}
@ -125,4 +125,23 @@ public class AppPreferences {
public int getBackendEngineIndexId(){ return preferences.getInt("backend_player", 0); }
public void setBackendEngineIndexId(int value){ preferences.putInt("backend_player", value); }
public String getRecentPlaylist(){
return preferences.get("RECENT_PLS_0", "");
}
public boolean getOpenLatestPlaylistOnStart(){ return preferences.getBoolean("open_latest_playlist", true); }
public void setOpenLatestPlaylistOnStart(boolean value){ preferences.putBoolean("open_latest_playlist" , value); }
public int getLatestPositionVideo(){ return preferences.getInt("latest_video_pos", 1); }
public void setLatestPositionVideo(int value){
preferences.putInt("latest_video_pos", Math.max(value, 0));
}
public int getLatestPositionAudio(){ return preferences.getInt("latest_audio_pos", 1); }
public void setLatestPositionAudio(int value){
preferences.putInt("latest_audio_pos", Math.max(value, 0));
}
public int getLatestPositionSubs(){ return preferences.getInt("latest_subs_pos", 1); }
public void setLatestPositionSubs(int value){
preferences.putInt("latest_subs_pos", Math.max(value, 0));
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -18,7 +18,7 @@
*/
package mplayer4anime;
public interface ISlaveModeAppOrchestration {
public interface IPlayer {
void subtitlesSwitch();
void fullscreenSwitch();
void mute();

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -18,14 +18,14 @@
*/
package mplayer4anime.mplayer;
import mplayer4anime.ISlaveModeAppOrchestration;
import mplayer4anime.IPlayer;
import mplayer4anime.ui.ServiceWindow;
import java.io.*;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
public class MplayerSlave implements ISlaveModeAppOrchestration {
public class MplayerSlave implements IPlayer {
private Process player;
private PrintStream playerIn;
private BufferedReader playerOutErr;
@ -37,14 +37,14 @@ public class MplayerSlave implements ISlaveModeAppOrchestration {
}
private boolean playerSingleCommand(String command){
if (player != null && player.isAlive()) {
if (player == null || ! player.isAlive())
return false;
playerIn.print(command);
playerIn.print("\n");
playerIn.flush();
return true;
}
return false;
}
@Override
public void subtitlesSwitch(){
if (! playerSingleCommand("get_sub_visibility"))

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -18,11 +18,11 @@
*/
package mplayer4anime.mpv;
import mplayer4anime.ISlaveModeAppOrchestration;
import mplayer4anime.IPlayer;
import java.util.ResourceBundle;
public class MpvSlave implements ISlaveModeAppOrchestration {
public class MpvSlave implements IPlayer {
public MpvSlave(ResourceBundle resourceBundle){

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -24,6 +24,7 @@ import mplayer4anime.ui.ServiceWindow;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ResourceBundle;
public class Playlists {
@ -31,23 +32,22 @@ public class Playlists {
//TODO: Show popUp if unable to write! Or nothing to write! Or overwrite!
//TODO: Disable 'Save' button if no files added
public static boolean SaveAs(ResourceBundle resourceBundle, JsonStorage jStorage){
File playlistFile;
public static boolean saveAs(ResourceBundle resourceBundle, JsonStorage jStorage){
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(resourceBundle.getString("SelectFile"));
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
fileChooser.setInitialFileName("MyPlaylist.alpr");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr"));
playlistFile = fileChooser.showSaveDialog(null);
File playlistFile = fileChooser.showSaveDialog(null);
return writeFile(resourceBundle, playlistFile, jStorage);
}
public static boolean SaveCurrent(ResourceBundle resourceBundle, JsonStorage jStorage) {
if (playlistLocation == null || playlistLocation.equals("")){
return Playlists.SaveAs(resourceBundle, jStorage);
}
public static boolean saveCurrent(ResourceBundle resourceBundle, JsonStorage jStorage) {
if (playlistLocation == null || playlistLocation.equals(""))
return Playlists.saveAs(resourceBundle, jStorage);
return writeFile(resourceBundle, new File(playlistLocation), jStorage);
}
@ -91,7 +91,7 @@ public class Playlists {
/**
* Interface for Opening playlists via FileChooser
**/
public static JsonStorage OpenPlaylistFileChooser(ResourceBundle resourceBundle){
public static JsonStorage openPlaylistFileChooser(ResourceBundle resourceBundle){
File playlistFile;
FileChooser fileChooser = new FileChooser();
@ -101,12 +101,12 @@ public class Playlists {
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr"));
playlistFile = fileChooser.showOpenDialog(null);
return ReadByPath(resourceBundle, playlistFile);
return readByPath(resourceBundle, playlistFile);
}
/**
* Interface for Opening playlists using file itself
* */
public static JsonStorage ReadByPath(ResourceBundle resourceBundle, File playlistFile){
public static JsonStorage readByPath(ResourceBundle resourceBundle, File playlistFile){
if (playlistFile == null) {
ServiceWindow.getErrorNotification(resourceBundle.getString("Error"),
"Playlist file not selected");// TODO: translate
@ -132,6 +132,17 @@ public class Playlists {
return null;
}
public static JsonStorage readByPathSilent(File playlistFile){
try (Reader reader = new InputStreamReader(Files.newInputStream(playlistFile.toPath()))) {
JsonStorage jStorage = new Gson().fromJson(reader, JsonStorage.class);
if (jStorage != null){
playlistLocation = playlistFile.getAbsolutePath();
return jStorage;
}
} catch (Exception ignore){}
return null;
}
/** Return path to file opened */
public static String getPlaylistLocation(){
return playlistLocation;

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -28,7 +28,7 @@ import javafx.scene.control.*;
import javafx.stage.Stage;
import mplayer4anime.ui.about.AboutWindow;
import mplayer4anime.AppPreferences;
import mplayer4anime.ISlaveModeAppOrchestration;
import mplayer4anime.IPlayer;
import mplayer4anime.MediatorControl;
import mplayer4anime.playlists.JsonStorage;
import mplayer4anime.playlists.Playlists;
@ -45,9 +45,9 @@ import java.util.ResourceBundle;
public class LandingController implements Initializable {
@FXML
ControllerPane mkvPaneController, mkaPaneController;
private ControllerPane mkvPaneController, mkaPaneController;
@FXML
ControllerPaneSubtitles subPaneController;
private ControllerPaneSubtitles subPaneController;
@FXML
private PlayerToolbarController playerToolbarController;
@FXML
@ -65,16 +65,17 @@ public class LandingController implements Initializable {
private String currentPlaylistLocation;
private String backend;
ISlaveModeAppOrchestration player;
private IPlayer player;
// If application started with playlist passed as an argument, then we'll try to load it (if it's valid).
public void setPlaylistAsArgument(String playlist) {
JsonStorage jsonStorage = Playlists.ReadByPath(resourceBundle, new File(playlist));
JsonStorage jsonStorage = Playlists.readByPath(resourceBundle, new File(playlist));
setAllLists(jsonStorage);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
// Register this controller in mediator
MediatorControl.getInstance().registerMainController(this);
@ -82,8 +83,6 @@ public class LandingController implements Initializable {
mkaPaneController.setPaneType("Audio");
subPaneController.setPaneType("Subtitles");
resourceBundle = rb;
// Set default list of encodings of the subtitles files:
subPaneController.setEncoding(appPreferences.getSubsEncodingList(), appPreferences.getLastTimeUsedSubsEncoding());
@ -107,13 +106,27 @@ public class LandingController implements Initializable {
player = new MpvSlave(resourceBundle);
}
playerToolbarController.initializeMainUiController(this);
/*
Playlists.ReadByPath(resourceBundle, playListFile);
* */
playerToolbarController.initializeMainUiController(player, mkvPaneController, mkaPaneController, subPaneController);
if (appPreferences.getOpenLatestPlaylistOnStart())
loadLatestPlaylist();
}
private void loadLatestPlaylist(){
try {
String recentPlaylist = appPreferences.getRecentPlaylist();
if ("".equals(recentPlaylist))
return;
// TODO: IF video set, if playlist has been opened before
JsonStorage jsonStorage = Playlists.readByPathSilent(new File(recentPlaylist));
setAllLists(jsonStorage);
mkvPaneController.setElementSelectedByIndex(appPreferences.getLatestPositionVideo());
mkaPaneController.setElementSelectedByIndex(appPreferences.getLatestPositionAudio());
subPaneController.setElementSelectedByIndex(appPreferences.getLatestPositionSubs());
}
catch (Exception ignore){}
}
public void setHostServices(HostServices hostServices) {
public void setHostServices(HostServices hostServices){
this.hostServices = hostServices;
}
@ -130,16 +143,21 @@ public class LandingController implements Initializable {
playerToolbarController.shutdown();
// TODO: remove from here; too sophisticated
String[] storeRecentArr = new String[10];
for (int i =0; i < recentlyOpenedMenu.getItems().size() - 2 && !(i > 9); i++) { // Don't take separator and Clean button
for (int i = 0; i < recentlyOpenedMenu.getItems().size() - 2 && !(i > 9); i++) { // Don't take separator and Clean button
storeRecentArr[i] = (String) recentlyOpenedMenu.getItems().get(i).getUserData();
}
appPreferences.setRecentPlaylists(storeRecentArr);
appPreferences.setLatestPositionVideo(mkvPaneController.getElementSelectedIndex());
appPreferences.setLatestPositionAudio(mkaPaneController.getElementSelectedIndex());
appPreferences.setLatestPositionSubs(subPaneController.getElementSelectedIndex());
Platform.exit();
}
@FXML
private void infoBtn(){
new AboutWindow(this.hostServices);
new AboutWindow(hostServices);
} // TODO: fix this shit with hostSerivces that doesn't work @ linux
/** SETTINGS HANDLE */
@ -170,7 +188,7 @@ public class LandingController implements Initializable {
@FXML
private void openBtn() {
JsonStorage jsonStorage = Playlists.OpenPlaylistFileChooser(resourceBundle);
JsonStorage jsonStorage = Playlists.openPlaylistFileChooser(resourceBundle);
setAllLists(jsonStorage);
}
private void setAllLists(JsonStorage jsonStorage){
@ -197,7 +215,7 @@ public class LandingController implements Initializable {
mkaPaneController.getElementsAll(),
subPaneController.getElementsAll(),
subPaneController.getSelectedEncoding());
if (Playlists.SaveCurrent(resourceBundle, jsonStorage)) {
if (Playlists.saveCurrent(resourceBundle, jsonStorage)) {
this.currentPlaylistLocation = Playlists.getPlaylistLocation();
this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this?
addRecentlyOpened(currentPlaylistLocation);
@ -216,7 +234,7 @@ public class LandingController implements Initializable {
mkaPaneController.getElementsAll(),
subPaneController.getElementsAll(),
subPaneController.getSelectedEncoding());
if (Playlists.SaveAs(resourceBundle, jsonStorage)) {
if (Playlists.saveAs(resourceBundle, jsonStorage)) {
this.currentPlaylistLocation = Playlists.getPlaylistLocation();
this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this?
addRecentlyOpened(currentPlaylistLocation);
@ -246,7 +264,7 @@ public class LandingController implements Initializable {
menuItem.setUserData(playlistPath);
menuItem.setOnAction(actionEvent -> {
JsonStorage jsonStorage = Playlists.ReadByPath(resourceBundle, new File(playlistPath));
JsonStorage jsonStorage = Playlists.readByPath(resourceBundle, new File(playlistPath));
setAllLists(jsonStorage);
});
// Limit list to 13 elements (2 in the end are separator and clear button)

View file

@ -1,27 +1,34 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mcontroller.player.anime.
This file is part of mplayer4anime.
mcontroller.player.anime is free software: you can redistribute it and/or modify
mplayer4anime is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
mcontroller.player.anime is distributed in the hope that it will be useful,
mplayer4anime is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with mcontroller.player.anime. If not, see <https://www.gnu.org/licenses/>.
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
*/
package mplayer4anime.ui.landing;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.SplitMenuButton;
import mplayer4anime.AppPreferences;
import mplayer4anime.IPlayer;
import mplayer4anime.ui.landing.panes.ControllerPane;
import mplayer4anime.ui.landing.panes.ControllerPaneSubtitles;
import java.net.URL;
import java.util.ResourceBundle;
@ -31,9 +38,15 @@ public class PlayerToolbarController implements Initializable {
private CheckMenuItem fullScreen;
@FXML
private CheckMenuItem subsHide;
@FXML
private Button muteBtn, playPrevTrackBtn, playNextTrackBtn, playBtn, stopBtn, volumeUpBtn, volumeDownBtn;
@FXML
private SplitMenuButton subsTriggerBtn, fullscreenBtn;
private AppPreferences appPreferences;
private LandingController landingController;
private IPlayer player;
private ControllerPane mkvPaneController, mkaPaneController;
private ControllerPaneSubtitles subPaneController;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
@ -41,89 +54,111 @@ public class PlayerToolbarController implements Initializable {
fullScreen.setSelected(appPreferences.getFullScreenSelected());
subsHide.setSelected(appPreferences.getSubtitlesHideSelected());
stopBtn.setOnAction(event -> player.stop());
volumeUpBtn.setOnAction(event -> player.volumeUp());
volumeDownBtn.setOnAction(event -> player.volumeDown());
muteBtn.setOnAction(event -> player.mute());
playBtn.setOnAction(event -> play());
playPrevTrackBtn.setOnAction(event -> playPrevTrack());
playNextTrackBtn.setOnAction(event -> playNextTrack());
subsTriggerBtn.setOnAction(event -> player.subtitlesSwitch());
fullscreenBtn.setOnAction(event -> player.fullscreenSwitch());
}
public void initializeMainUiController(LandingController landingController){
this.landingController = landingController;
public void initializeMainUiController(IPlayer player,
ControllerPane mkvPaneController,
ControllerPane mkaPaneController,
ControllerPaneSubtitles subPaneController){
this.player = player;
this.mkvPaneController = mkvPaneController;
this.mkaPaneController = mkaPaneController;
this.subPaneController = subPaneController;
bindButtonToEmptyList(stopBtn);
bindButtonToEmptyList(volumeUpBtn);
bindButtonToEmptyList(volumeDownBtn);
bindButtonToEmptyList(muteBtn);
bindButtonToEmptyList(playBtn);
bindButtonToEmptyList(subsTriggerBtn);
bindButtonToEmptyList(fullscreenBtn);
playPrevTrackBtn.disableProperty().bind(
Bindings.isEmpty(mkvPaneController.getPaneFileList()).or(
Bindings.equal(mkvPaneController.getSelectedIndexProperty(), 0)
));
playNextTrackBtn.disableProperty().bind(
Bindings.isEmpty(mkvPaneController.getPaneFileList()).or(
Bindings.equal(mkvPaneController.getSelectedIndexProperty(),
Bindings.subtract(Bindings.size(mkvPaneController.getPaneFileList()), 1))
));
}
private void bindButtonToEmptyList(ButtonBase button){
button.disableProperty().bind(Bindings.isEmpty(mkvPaneController.getPaneFileList()));
}
@FXML
private void subsTriggerBtn(){
landingController.player.subtitlesSwitch();
}
@FXML
private void fullscreenBtn(){
landingController.player.fullscreenSwitch();
}
@FXML
private void muteBtn(){
landingController.player.mute();
}
@FXML
private void playPrevTrackBtn(){
int index = landingController.mkvPaneController.getElementSelectedIndex();
if (index <= 0)
private void play(){
if (mkvPaneController.getElementSelected() == null)
return;
landingController.mkvPaneController.setElementSelectedByIndex(index-1);
landingController.player.forcePlay(appPreferences.getPath(),
landingController.mkvPaneController.getElementSelected(),
landingController.mkaPaneController.getElementSelected(),
landingController.subPaneController.getElementSelected(),
landingController.subPaneController.getSelectedEncoding(),
player.playPause(appPreferences.getPath(),
mkvPaneController.getElementSelected(),
mkaPaneController.getElementSelected(),
subPaneController.getElementSelected(),
subPaneController.getSelectedEncoding(),
subsHide.isSelected(),
fullScreen.isSelected()
);
}
@FXML
private void playNextTrackBtn(){
int index = landingController.mkvPaneController.getElementSelectedIndex();
if (index + 1 < landingController.mkvPaneController.getElementsCount()) {
landingController.mkvPaneController.setElementSelectedByIndex(index + 1);
}
index = landingController.mkaPaneController.getElementSelectedIndex();
if (index + 1 < landingController.mkaPaneController.getElementsCount()) {
landingController.mkaPaneController.setElementSelectedByIndex(index + 1);
}
index = landingController.subPaneController.getElementSelectedIndex();
if (index + 1 < landingController.subPaneController.getElementsCount()) {
landingController.subPaneController.setElementSelectedByIndex(index + 1);
}
landingController.player.forcePlay(appPreferences.getPath(),
landingController.mkvPaneController.getElementSelected(),
landingController.mkaPaneController.getElementSelected(),
landingController.subPaneController.getElementSelected(),
landingController.subPaneController.getSelectedEncoding(),
subsHide.isSelected(),
fullScreen.isSelected()
);
}
@FXML
private void playBtn(){
if (landingController.mkvPaneController.getElementSelected() == null)
private void playPrevTrack(){
int index = mkvPaneController.getElementSelectedIndex() - 1;
if (index < 0)
return;
landingController.player.playPause(appPreferences.getPath(),
landingController.mkvPaneController.getElementSelected(),
landingController.mkaPaneController.getElementSelected(),
landingController.subPaneController.getElementSelected(),
landingController.subPaneController.getSelectedEncoding(),
mkvPaneController.setElementSelectedByIndex(index);
index = mkaPaneController.getElementSelectedIndex();
if (index > 0)
mkaPaneController.setElementSelectedByIndex(index - 1);
index = subPaneController.getElementSelectedIndex();
if (index > 0)
subPaneController.setElementSelectedByIndex(index - 1);
player.forcePlay(appPreferences.getPath(),
mkvPaneController.getElementSelected(),
mkaPaneController.getElementSelected(),
subPaneController.getElementSelected(),
subPaneController.getSelectedEncoding(),
subsHide.isSelected(),
fullScreen.isSelected()
);
}
@FXML
private void stopBtn(){
landingController.player.stop();
}
@FXML
private void volumeUpBtn(){
landingController.player.volumeUp();
}
@FXML
private void volumeDownBtn(){
landingController.player.volumeDown();
private void playNextTrack(){
int index = mkvPaneController.getElementSelectedIndex() + 1;
if (index >= mkvPaneController.getElementsCount())
return;
mkvPaneController.setElementSelectedByIndex(index);
index = mkaPaneController.getElementSelectedIndex() + 1;
if (index < mkaPaneController.getElementsCount())
mkaPaneController.setElementSelectedByIndex(index);
index = subPaneController.getElementSelectedIndex() + 1;
if (index < subPaneController.getElementsCount())
subPaneController.setElementSelectedByIndex(index);
player.forcePlay(appPreferences.getPath(),
mkvPaneController.getElementSelected(),
mkaPaneController.getElementSelected(),
subPaneController.getElementSelected(),
subPaneController.getSelectedEncoding(),
subsHide.isSelected(),
fullScreen.isSelected()
);
}
void shutdown(){

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -18,6 +18,7 @@
*/
package mplayer4anime.ui.landing.panes;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
@ -50,7 +51,6 @@ public class ControllerPane implements Initializable {
private Label paneLbl;
private String paneType;
@Override
public void initialize(URL url, ResourceBundle resBundle) {
SetCellFactory(paneListView);
@ -58,10 +58,14 @@ public class ControllerPane implements Initializable {
appPreferences = AppPreferences.getINSTANCE();
}
public ObservableList<File> getPaneFileList() {
return paneFileList;
}
public void setPaneType(String paneType){
this.paneType = paneType;
switch (paneType) {
switch (paneType){
case "Video":
paneLbl.setText(resourceBundle.getString("lbl_VideoPane"));
break;
@ -73,7 +77,6 @@ public class ControllerPane implements Initializable {
break;
default:
paneLbl.setText(resourceBundle.getString("?"));
break;
}
}
@ -91,23 +94,20 @@ public class ControllerPane implements Initializable {
}
/** Select element in pane using index recieved */
public void setElementSelectedByIndex(int index){
this.paneListView.getSelectionModel().select(index);
paneListView.getSelectionModel().select(index);
}
/** Get number of elements loaded into the pane */
public int getElementsCount(){
return this.paneFileList.size();
}
/** Check if there are any elements loaded */
public boolean isElementsListEmpty(){
return paneFileList.isEmpty();
return paneFileList.size();
}
/** Get all elements
* Used in Json playlist writer only */
public String[] getElementsAll(){
String[] elementsArray = new String[this.getElementsCount()];
for (int i = 0; i < elementsArray.length; i++){
for (int i = 0; i < elementsArray.length; i++)
elementsArray[i] = paneFileList.get(i).toString();
}
return elementsArray;
}
@ -239,61 +239,63 @@ public class ControllerPane implements Initializable {
* */
public void setFilesFromList(String[] fileLocations){
cleanList();
if (fileLocations != null && fileLocations.length != 0) {
if (fileLocations == null || fileLocations.length == 0)
return;
File[] files = new File[fileLocations.length];
for (int i=0; i < fileLocations.length; i++)
for (int i = 0; i < fileLocations.length; i++)
files[i] = new File(fileLocations[i]);
displayFiles(files);
}
}
private void displayFiles(File[] files){
if (files != null && files.length > 0) {
// spiced java magic
if (files == null || files.length == 0)
return;
Arrays.sort(files);
// Remember the folder used for MKV and reuse it when user opens MKA/subs folder (as new default path instead of user.home)
folderToOpen = files[0].getParent();
//System.out.println(folderToOpen);
paneFileList.addAll(files);
paneListView.setItems(paneFileList);
paneListView.getSelectionModel().select(0);
} else {
System.out.println("\tNo files in this folder");
}
}
@FXML
public void cleanList(){
paneListView.getItems().clear(); // wipe elements from ListView
paneListView.getItems().clear();
}
@FXML
private void Up(){
int index;
index = paneListView.getSelectionModel().getSelectedIndex();
if (index >0){
paneFileList.add(index-1, paneListView.getSelectionModel().getSelectedItem());
paneFileList.remove(index+1);
paneListView.getSelectionModel().select(index-1);
private void up(){
int index = paneListView.getSelectionModel().getSelectedIndex();
if (index > 0){
paneFileList.add(index - 1, paneListView.getSelectionModel().getSelectedItem());
paneFileList.remove(index + 1);
paneListView.getSelectionModel().select(index - 1);
}
}
@FXML
private void Down(){
int index;
index = paneListView.getSelectionModel().getSelectedIndex();
if (index+1 < paneFileList.size() ){
paneFileList.add(index+2, paneListView.getSelectionModel().getSelectedItem());
private void down(){
int index = paneListView.getSelectionModel().getSelectedIndex();
if (index + 1 < paneFileList.size() ){
paneFileList.add(index + 2, paneListView.getSelectionModel().getSelectedItem());
paneFileList.remove(index);
paneListView.getSelectionModel().select(index+1);
paneListView.getSelectionModel().select(index + 1);
}
}
@FXML
private void Del(){ paneFileList.remove(paneListView.getSelectionModel().getSelectedItem()); }
private void delete(){
paneFileList.remove(paneListView.getSelectionModel().getSelectedItem());
}
@FXML
private void KeyPressed(KeyEvent event){
private void keyPressed(KeyEvent event){
if (event.getCode().toString().equals("DELETE"))
Del();
delete();
}
public ReadOnlyIntegerProperty getSelectedIndexProperty(){
return paneListView.getSelectionModel().selectedIndexProperty();
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2021 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime.
@ -41,7 +41,7 @@ public class SettingsController implements Initializable {
@FXML
private Label pathToMplayerLbl;
@FXML
private CheckBox subtitlesFirstCheckBox;
private CheckBox subtitlesFirstCheckBox, openLatestPlaylistCheckBox;
@FXML
private ChoiceBox<String> backEndEngineChoiceBox;
@ -59,6 +59,7 @@ public class SettingsController implements Initializable {
audioExtensionListController.setList(appPreferences.getAudioExtensionsList(), true);
backEndEngineChoiceBox.getItems().addAll("mplayer", "mpv");
backEndEngineChoiceBox.getSelectionModel().select(appPreferences.getBackendEngineIndexId());
openLatestPlaylistCheckBox.setSelected(appPreferences.getOpenLatestPlaylistOnStart());
}
@FXML
@ -67,18 +68,14 @@ public class SettingsController implements Initializable {
fileChooser.setTitle("mplayer");
// In case we use Windows, limit selectable file to .exe
if (System.getProperty("os.name").contains("Windows")) {
fileChooser.getExtensionFilters().setAll(
new FileChooser.ExtensionFilter("mplayer", "*.exe")
);
}
if (System.getProperty("os.name").contains("Windows"))
fileChooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter("mplayer", "*.exe"));
File mplayerExecutableFile = fileChooser.showOpenDialog(null);
if (mplayerExecutableFile != null) {
if (mplayerExecutableFile != null)
pathToMplayerLbl.setText(mplayerExecutableFile.toString());
}
}
@FXML
private void clearPath(){
@ -108,6 +105,7 @@ public class SettingsController implements Initializable {
appPreferences.setVideoExtensionsList(videoExtensionListController.getList());
appPreferences.setAudioExtensionsList(audioExtensionListController.getList());
appPreferences.setBackendEngineIndexId(backEndEngineChoiceBox.getSelectionModel().getSelectedIndex());
appPreferences.setOpenLatestPlaylistOnStart(openLatestPlaylistCheckBox.isSelected());
MediatorControl.getInstance().updateAfterSettingsChanged(); // TODO: implement list to track what should be updated
}

View file

@ -10,26 +10,26 @@
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.shape.SVGPath?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mplayer4anime.ui.landing.PlayerToolbarController">
<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mplayer4anime.ui.landing.PlayerToolbarController">
<ToolBar styleClass="topToolBar" stylesheets="@res/landing.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<HBox>
<children>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#playPrevTrackBtn" styleClass="btnLeft" stylesheets="@res/landing.css">
<Button fx:id="playPrevTrackBtn" minHeight="28.0" mnemonicParsing="false" styleClass="btnLeft" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M 12,12 3.5,6 12,0 Z M 0,0 V 12 H 2 V 0 Z" fill="#e1e1e1" />
</graphic></Button>
<Button minHeight="28.0" minWidth="53.0" mnemonicParsing="false" onAction="#playBtn" styleClass="btnCenter" stylesheets="@res/landing.css" textAlignment="CENTER">
<Button fx:id="playBtn" minHeight="28.0" minWidth="53.0" mnemonicParsing="false" styleClass="btnCenter" stylesheets="@res/landing.css" textAlignment="CENTER">
<graphic>
<SVGPath content="M3,5V19L11,12M13,19H16V5H13M18,5V19H21V5" fill="#61dd4e" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#stopBtn" styleClass="btnCenter" stylesheets="@res/landing.css">
<Button fx:id="stopBtn" minHeight="28.0" mnemonicParsing="false" styleClass="btnCenter" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M18,18H6V6H18V18Z" fill="#e1e1e1" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#playNextTrackBtn" styleClass="btnRight" stylesheets="@res/landing.css">
<Button fx:id="playNextTrackBtn" minHeight="28.0" mnemonicParsing="false" styleClass="btnRight" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M0,12 L8.5,6 L0,0 L0,12 L0,12 Z M10,0 L10,12 L12,12 L12,0 L10,0 L10,0 Z" fill="#e1e1e1" />
</graphic></Button>
@ -41,7 +41,7 @@
<Pane minWidth="20.0" />
<HBox>
<children>
<Button minHeight="28.0" minWidth="36.0" mnemonicParsing="false" onAction="#volumeDownBtn" styleClass="btnLeft" stylesheets="@res/landing.css">
<Button fx:id="volumeDownBtn" minHeight="28.0" minWidth="36.0" mnemonicParsing="false" styleClass="btnLeft" stylesheets="@res/landing.css">
<opaqueInsets>
<Insets />
</opaqueInsets>
@ -49,20 +49,20 @@
<SVGPath content="M13.5,8 C13.5,6.2 12.5,4.7 11,4 L11,12 C12.5,11.3 13.5,9.8 13.5,8 L13.5,8 Z M0,5 L0,11 L4,11 L9,16 L9,0 L4,5 L0,5 L0,5 Z" fill="#e1e1e1" />
</graphic>
</Button>
<Button minHeight="28.0" minWidth="36.0" mnemonicParsing="false" onAction="#volumeUpBtn" styleClass="btnRight" stylesheets="@res/landing.css">
<Button fx:id="volumeUpBtn" minHeight="28.0" minWidth="36.0" mnemonicParsing="false" styleClass="btnRight" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M0,6 L0,12 L4,12 L9,17 L9,1 L4,6 L0,6 L0,6 Z M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,13 C12.5,12.3 13.5,10.8 13.5,9 L13.5,9 Z M11,0.2 L11,2.3 C13.9,3.2 16,5.8 16,9 C16,12.2 13.9,14.8 11,15.7 L11,17.8 C15,16.9 18,13.3 18,9 C18,4.7 15,1.1 11,0.2 L11,0.2 Z" fill="#e1e1e1" />
</graphic>
</Button>
</children>
</HBox>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#muteBtn" styleClass="btnSimple" stylesheets="@res/landing.css">
<Button fx:id="muteBtn" minHeight="28.0" mnemonicParsing="false" styleClass="btnSimple" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z" fill="#e1e1e1" />
</graphic>
</Button>
<Pane HBox.hgrow="ALWAYS" />
<SplitMenuButton mnemonicParsing="false" onAction="#subsTriggerBtn" styleClass="splitMenuButton" stylesheets="@res/landing.css">
<SplitMenuButton fx:id="subsTriggerBtn" mnemonicParsing="false" styleClass="splitMenuButton" stylesheets="@res/landing.css">
<graphic>
<SVGPath content="M 4,18 C 2.8954305,18 2,17.104569 2,16 V 4 C 2,2.89 2.9,2 4,2 h 16 c 1.104569,0 2,0.8954305 2,2 v 12 c 0,1.104569 -0.895431,2 -2,2 m -6,-7 v 1 h 5 V 11 M 5,12 h 8 V 11 H 5 m 0,3 v 1 h 14 v -1 z" fill="#e1e1e1" />
</graphic>
@ -70,7 +70,7 @@
<CheckMenuItem fx:id="subsHide" mnemonicParsing="false" text="%subsShow_option" />
</items>
</SplitMenuButton>
<SplitMenuButton mnemonicParsing="false" onAction="#fullscreenBtn" styleClass="splitMenuButton" stylesheets="@res/landing.css">
<SplitMenuButton fx:id="fullscreenBtn" mnemonicParsing="false" styleClass="splitMenuButton" stylesheets="@res/landing.css">
<items>
<CheckMenuItem fx:id="fullScreen" mnemonicParsing="false" text="%fullscreen_option" />
</items>

View file

@ -13,7 +13,7 @@
<?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?>
<VBox xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mplayer4anime.ui.settings.SettingsController">
<VBox xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mplayer4anime.ui.settings.SettingsController">
<children>
<TabPane side="LEFT" styleClass="tab-paneSettings" stylesheets="@../res/landing.css" tabClosingPolicy="UNAVAILABLE" tabMaxHeight="100.0" tabMaxWidth="500.0" tabMinHeight="100.0" tabMinWidth="80.0" VBox.vgrow="ALWAYS">
<tabs>
@ -49,11 +49,8 @@
<ChoiceBox fx:id="backEndEngineChoiceBox" prefWidth="150.0" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" VBox.vgrow="NEVER">
<children>
<CheckBox fx:id="subtitlesFirstCheckBox" mnemonicParsing="false" text="%settings_SubtitlesTabFirst" />
</children>
</HBox>
<CheckBox fx:id="openLatestPlaylistCheckBox" mnemonicParsing="false" text="%settings_OpenLatestOnStart" />
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />

View file

@ -34,17 +34,17 @@
<Pane HBox.hgrow="ALWAYS" />
<Label fx:id="paneLbl" text="%lbl_VideoPane" />
<Pane HBox.hgrow="ALWAYS" />
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#up">
<graphic>
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#down">
<graphic>
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#delete">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#cc0101" />
</graphic>
@ -54,7 +54,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</HBox>
<ListView fx:id="paneListView" onKeyPressed="#KeyPressed" styleClass="landing" stylesheets="@../res/landing.css" VBox.vgrow="ALWAYS" />
<ListView fx:id="paneListView" onKeyPressed="#keyPressed" styleClass="landing" stylesheets="@../res/landing.css" VBox.vgrow="ALWAYS" />
</children>
</VBox>
</children>

View file

@ -37,17 +37,17 @@
<Pane HBox.hgrow="ALWAYS" />
<Label fx:id="paneLbl" text="%lbl_SubsPane" />
<Pane HBox.hgrow="ALWAYS" />
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#up">
<graphic>
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#down">
<graphic>
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
</graphic>
</Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
<Button minHeight="28.0" mnemonicParsing="false" onAction="#delete">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#b90505" />
</graphic>
@ -57,7 +57,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</HBox>
<ListView fx:id="paneListView" onKeyPressed="#KeyPressed" styleClass="landing" stylesheets="@../res/landing.css" VBox.vgrow="ALWAYS" />
<ListView fx:id="paneListView" onKeyPressed="#keyPressed" styleClass="landing" stylesheets="@../res/landing.css" VBox.vgrow="ALWAYS" />
</children>
</VBox>
</children>

View file

@ -54,6 +54,7 @@ settings_videoExtensionList=Avaliable video files extensions:
settings_audioExtensionList=Avaliable audio layer extensions:
ApplyBtn=Apply
settings_backendSelect=Backend engine:
settings_OpenLatestOnStart=Open latest playlist on start

View file

@ -54,4 +54,5 @@ settings_audioExtensionList=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u04
ApplyBtn=\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C
settings_backendSelect=\u0414\u0432\u0438\u0436\u043E\u043A \u0432\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F:
about_line2=\u0420\u0435\u043B\u0438\u0437: v${project.version}
settings_OpenLatestOnStart=\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442 \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435