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. This file is part of mplayer4anime.
@ -22,8 +22,8 @@ import java.util.prefs.Preferences;
// Rule application settings // Rule application settings
public class AppPreferences { public class AppPreferences {
private static AppPreferences INSTANCE = new AppPreferences(); private static final AppPreferences INSTANCE = new AppPreferences();
private Preferences preferences = Preferences.userRoot().node("mplayer4anime"); private final Preferences preferences = Preferences.userRoot().node("mplayer4anime");
private AppPreferences(){} private AppPreferences(){}
@ -125,4 +125,23 @@ public class AppPreferences {
public int getBackendEngineIndexId(){ return preferences.getInt("backend_player", 0); } public int getBackendEngineIndexId(){ return preferences.getInt("backend_player", 0); }
public void setBackendEngineIndexId(int value){ preferences.putInt("backend_player", value); } 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. This file is part of mplayer4anime.
@ -18,7 +18,7 @@
*/ */
package mplayer4anime; package mplayer4anime;
public interface ISlaveModeAppOrchestration { public interface IPlayer {
void subtitlesSwitch(); void subtitlesSwitch();
void fullscreenSwitch(); void fullscreenSwitch();
void mute(); void mute();

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2018-2021 Dmitry Isaenko Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime. This file is part of mplayer4anime.
@ -18,14 +18,14 @@
*/ */
package mplayer4anime.mplayer; package mplayer4anime.mplayer;
import mplayer4anime.ISlaveModeAppOrchestration; import mplayer4anime.IPlayer;
import mplayer4anime.ui.ServiceWindow; import mplayer4anime.ui.ServiceWindow;
import java.io.*; import java.io.*;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class MplayerSlave implements ISlaveModeAppOrchestration { public class MplayerSlave implements IPlayer {
private Process player; private Process player;
private PrintStream playerIn; private PrintStream playerIn;
private BufferedReader playerOutErr; private BufferedReader playerOutErr;
@ -37,14 +37,14 @@ public class MplayerSlave implements ISlaveModeAppOrchestration {
} }
private boolean playerSingleCommand(String command){ private boolean playerSingleCommand(String command){
if (player != null && player.isAlive()) { if (player == null || ! player.isAlive())
return false;
playerIn.print(command); playerIn.print(command);
playerIn.print("\n"); playerIn.print("\n");
playerIn.flush(); playerIn.flush();
return true; return true;
} }
return false;
}
@Override @Override
public void subtitlesSwitch(){ public void subtitlesSwitch(){
if (! playerSingleCommand("get_sub_visibility")) 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. This file is part of mplayer4anime.
@ -18,11 +18,11 @@
*/ */
package mplayer4anime.mpv; package mplayer4anime.mpv;
import mplayer4anime.ISlaveModeAppOrchestration; import mplayer4anime.IPlayer;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class MpvSlave implements ISlaveModeAppOrchestration { public class MpvSlave implements IPlayer {
public MpvSlave(ResourceBundle resourceBundle){ 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. This file is part of mplayer4anime.
@ -24,6 +24,7 @@ import mplayer4anime.ui.ServiceWindow;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class Playlists { public class Playlists {
@ -31,23 +32,22 @@ public class Playlists {
//TODO: Show popUp if unable to write! Or nothing to write! Or overwrite! //TODO: Show popUp if unable to write! Or nothing to write! Or overwrite!
//TODO: Disable 'Save' button if no files added //TODO: Disable 'Save' button if no files added
public static boolean SaveAs(ResourceBundle resourceBundle, JsonStorage jStorage){ public static boolean saveAs(ResourceBundle resourceBundle, JsonStorage jStorage){
File playlistFile;
FileChooser fileChooser = new FileChooser(); FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(resourceBundle.getString("SelectFile")); fileChooser.setTitle(resourceBundle.getString("SelectFile"));
fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
fileChooser.setInitialFileName("MyPlaylist.alpr"); fileChooser.setInitialFileName("MyPlaylist.alpr");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr")); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr"));
playlistFile = fileChooser.showSaveDialog(null); File playlistFile = fileChooser.showSaveDialog(null);
return writeFile(resourceBundle, playlistFile, jStorage); return writeFile(resourceBundle, playlistFile, jStorage);
} }
public static boolean SaveCurrent(ResourceBundle resourceBundle, JsonStorage jStorage) { public static boolean saveCurrent(ResourceBundle resourceBundle, JsonStorage jStorage) {
if (playlistLocation == null || playlistLocation.equals("")){ if (playlistLocation == null || playlistLocation.equals(""))
return Playlists.SaveAs(resourceBundle, jStorage); return Playlists.saveAs(resourceBundle, jStorage);
}
return writeFile(resourceBundle, new File(playlistLocation), jStorage); return writeFile(resourceBundle, new File(playlistLocation), jStorage);
} }
@ -91,7 +91,7 @@ public class Playlists {
/** /**
* Interface for Opening playlists via FileChooser * Interface for Opening playlists via FileChooser
**/ **/
public static JsonStorage OpenPlaylistFileChooser(ResourceBundle resourceBundle){ public static JsonStorage openPlaylistFileChooser(ResourceBundle resourceBundle){
File playlistFile; File playlistFile;
FileChooser fileChooser = new FileChooser(); FileChooser fileChooser = new FileChooser();
@ -101,12 +101,12 @@ public class Playlists {
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr")); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Playlists (*.alpr)", "*.alpr"));
playlistFile = fileChooser.showOpenDialog(null); playlistFile = fileChooser.showOpenDialog(null);
return ReadByPath(resourceBundle, playlistFile); return readByPath(resourceBundle, playlistFile);
} }
/** /**
* Interface for Opening playlists using file itself * 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) { if (playlistFile == null) {
ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), ServiceWindow.getErrorNotification(resourceBundle.getString("Error"),
"Playlist file not selected");// TODO: translate "Playlist file not selected");// TODO: translate
@ -132,6 +132,17 @@ public class Playlists {
return null; 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 */ /** Return path to file opened */
public static String getPlaylistLocation(){ public static String getPlaylistLocation(){
return playlistLocation; return playlistLocation;

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2018-2021 Dmitry Isaenko Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime. This file is part of mplayer4anime.
@ -28,7 +28,7 @@ import javafx.scene.control.*;
import javafx.stage.Stage; import javafx.stage.Stage;
import mplayer4anime.ui.about.AboutWindow; import mplayer4anime.ui.about.AboutWindow;
import mplayer4anime.AppPreferences; import mplayer4anime.AppPreferences;
import mplayer4anime.ISlaveModeAppOrchestration; import mplayer4anime.IPlayer;
import mplayer4anime.MediatorControl; import mplayer4anime.MediatorControl;
import mplayer4anime.playlists.JsonStorage; import mplayer4anime.playlists.JsonStorage;
import mplayer4anime.playlists.Playlists; import mplayer4anime.playlists.Playlists;
@ -45,9 +45,9 @@ import java.util.ResourceBundle;
public class LandingController implements Initializable { public class LandingController implements Initializable {
@FXML @FXML
ControllerPane mkvPaneController, mkaPaneController; private ControllerPane mkvPaneController, mkaPaneController;
@FXML @FXML
ControllerPaneSubtitles subPaneController; private ControllerPaneSubtitles subPaneController;
@FXML @FXML
private PlayerToolbarController playerToolbarController; private PlayerToolbarController playerToolbarController;
@FXML @FXML
@ -65,16 +65,17 @@ public class LandingController implements Initializable {
private String currentPlaylistLocation; private String currentPlaylistLocation;
private String backend; 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). // 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) { public void setPlaylistAsArgument(String playlist) {
JsonStorage jsonStorage = Playlists.ReadByPath(resourceBundle, new File(playlist)); JsonStorage jsonStorage = Playlists.readByPath(resourceBundle, new File(playlist));
setAllLists(jsonStorage); setAllLists(jsonStorage);
} }
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
// Register this controller in mediator // Register this controller in mediator
MediatorControl.getInstance().registerMainController(this); MediatorControl.getInstance().registerMainController(this);
@ -82,8 +83,6 @@ public class LandingController implements Initializable {
mkaPaneController.setPaneType("Audio"); mkaPaneController.setPaneType("Audio");
subPaneController.setPaneType("Subtitles"); subPaneController.setPaneType("Subtitles");
resourceBundle = rb;
// Set default list of encodings of the subtitles files: // Set default list of encodings of the subtitles files:
subPaneController.setEncoding(appPreferences.getSubsEncodingList(), appPreferences.getLastTimeUsedSubsEncoding()); subPaneController.setEncoding(appPreferences.getSubsEncodingList(), appPreferences.getLastTimeUsedSubsEncoding());
@ -107,10 +106,24 @@ public class LandingController implements Initializable {
player = new MpvSlave(resourceBundle); player = new MpvSlave(resourceBundle);
} }
playerToolbarController.initializeMainUiController(this); playerToolbarController.initializeMainUiController(player, mkvPaneController, mkaPaneController, subPaneController);
/*
Playlists.ReadByPath(resourceBundle, playListFile); 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){
@ -134,12 +147,17 @@ public class LandingController implements Initializable {
storeRecentArr[i] = (String) recentlyOpenedMenu.getItems().get(i).getUserData(); storeRecentArr[i] = (String) recentlyOpenedMenu.getItems().get(i).getUserData();
} }
appPreferences.setRecentPlaylists(storeRecentArr); appPreferences.setRecentPlaylists(storeRecentArr);
appPreferences.setLatestPositionVideo(mkvPaneController.getElementSelectedIndex());
appPreferences.setLatestPositionAudio(mkaPaneController.getElementSelectedIndex());
appPreferences.setLatestPositionSubs(subPaneController.getElementSelectedIndex());
Platform.exit(); Platform.exit();
} }
@FXML @FXML
private void infoBtn(){ private void infoBtn(){
new AboutWindow(this.hostServices); new AboutWindow(hostServices);
} // TODO: fix this shit with hostSerivces that doesn't work @ linux } // TODO: fix this shit with hostSerivces that doesn't work @ linux
/** SETTINGS HANDLE */ /** SETTINGS HANDLE */
@ -170,7 +188,7 @@ public class LandingController implements Initializable {
@FXML @FXML
private void openBtn() { private void openBtn() {
JsonStorage jsonStorage = Playlists.OpenPlaylistFileChooser(resourceBundle); JsonStorage jsonStorage = Playlists.openPlaylistFileChooser(resourceBundle);
setAllLists(jsonStorage); setAllLists(jsonStorage);
} }
private void setAllLists(JsonStorage jsonStorage){ private void setAllLists(JsonStorage jsonStorage){
@ -197,7 +215,7 @@ public class LandingController implements Initializable {
mkaPaneController.getElementsAll(), mkaPaneController.getElementsAll(),
subPaneController.getElementsAll(), subPaneController.getElementsAll(),
subPaneController.getSelectedEncoding()); subPaneController.getSelectedEncoding());
if (Playlists.SaveCurrent(resourceBundle, jsonStorage)) { if (Playlists.saveCurrent(resourceBundle, jsonStorage)) {
this.currentPlaylistLocation = Playlists.getPlaylistLocation(); this.currentPlaylistLocation = Playlists.getPlaylistLocation();
this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this?
addRecentlyOpened(currentPlaylistLocation); addRecentlyOpened(currentPlaylistLocation);
@ -216,7 +234,7 @@ public class LandingController implements Initializable {
mkaPaneController.getElementsAll(), mkaPaneController.getElementsAll(),
subPaneController.getElementsAll(), subPaneController.getElementsAll(),
subPaneController.getSelectedEncoding()); subPaneController.getSelectedEncoding());
if (Playlists.SaveAs(resourceBundle, jsonStorage)) { if (Playlists.saveAs(resourceBundle, jsonStorage)) {
this.currentPlaylistLocation = Playlists.getPlaylistLocation(); this.currentPlaylistLocation = Playlists.getPlaylistLocation();
this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this?
addRecentlyOpened(currentPlaylistLocation); addRecentlyOpened(currentPlaylistLocation);
@ -246,7 +264,7 @@ public class LandingController implements Initializable {
menuItem.setUserData(playlistPath); menuItem.setUserData(playlistPath);
menuItem.setOnAction(actionEvent -> { menuItem.setOnAction(actionEvent -> {
JsonStorage jsonStorage = Playlists.ReadByPath(resourceBundle, new File(playlistPath)); JsonStorage jsonStorage = Playlists.readByPath(resourceBundle, new File(playlistPath));
setAllLists(jsonStorage); setAllLists(jsonStorage);
}); });
// Limit list to 13 elements (2 in the end are separator and clear button) // 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (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 but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License 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; package mplayer4anime.ui.landing;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.CheckMenuItem; import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.SplitMenuButton;
import mplayer4anime.AppPreferences; import mplayer4anime.AppPreferences;
import mplayer4anime.IPlayer;
import mplayer4anime.ui.landing.panes.ControllerPane;
import mplayer4anime.ui.landing.panes.ControllerPaneSubtitles;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -31,9 +38,15 @@ public class PlayerToolbarController implements Initializable {
private CheckMenuItem fullScreen; private CheckMenuItem fullScreen;
@FXML @FXML
private CheckMenuItem subsHide; private CheckMenuItem subsHide;
@FXML
private Button muteBtn, playPrevTrackBtn, playNextTrackBtn, playBtn, stopBtn, volumeUpBtn, volumeDownBtn;
@FXML
private SplitMenuButton subsTriggerBtn, fullscreenBtn;
private AppPreferences appPreferences; private AppPreferences appPreferences;
private LandingController landingController; private IPlayer player;
private ControllerPane mkvPaneController, mkaPaneController;
private ControllerPaneSubtitles subPaneController;
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
@ -41,89 +54,111 @@ public class PlayerToolbarController implements Initializable {
fullScreen.setSelected(appPreferences.getFullScreenSelected()); fullScreen.setSelected(appPreferences.getFullScreenSelected());
subsHide.setSelected(appPreferences.getSubtitlesHideSelected()); 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){ public void initializeMainUiController(IPlayer player,
this.landingController = landingController; 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 play(){
private void subsTriggerBtn(){ if (mkvPaneController.getElementSelected() == null)
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)
return; return;
landingController.mkvPaneController.setElementSelectedByIndex(index-1); player.playPause(appPreferences.getPath(),
landingController.player.forcePlay(appPreferences.getPath(), mkvPaneController.getElementSelected(),
landingController.mkvPaneController.getElementSelected(), mkaPaneController.getElementSelected(),
landingController.mkaPaneController.getElementSelected(), subPaneController.getElementSelected(),
landingController.subPaneController.getElementSelected(), subPaneController.getSelectedEncoding(),
landingController.subPaneController.getSelectedEncoding(),
subsHide.isSelected(), subsHide.isSelected(),
fullScreen.isSelected() fullScreen.isSelected()
); );
} }
@FXML
private void playNextTrackBtn(){
int index = landingController.mkvPaneController.getElementSelectedIndex();
if (index + 1 < landingController.mkvPaneController.getElementsCount()) { private void playPrevTrack(){
landingController.mkvPaneController.setElementSelectedByIndex(index + 1); int index = mkvPaneController.getElementSelectedIndex() - 1;
} if (index < 0)
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)
return; return;
landingController.player.playPause(appPreferences.getPath(), mkvPaneController.setElementSelectedByIndex(index);
landingController.mkvPaneController.getElementSelected(),
landingController.mkaPaneController.getElementSelected(), index = mkaPaneController.getElementSelectedIndex();
landingController.subPaneController.getElementSelected(), if (index > 0)
landingController.subPaneController.getSelectedEncoding(), 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(), subsHide.isSelected(),
fullScreen.isSelected() fullScreen.isSelected()
); );
} }
@FXML
private void stopBtn(){ private void playNextTrack(){
landingController.player.stop(); int index = mkvPaneController.getElementSelectedIndex() + 1;
} if (index >= mkvPaneController.getElementsCount())
@FXML return;
private void volumeUpBtn(){
landingController.player.volumeUp(); mkvPaneController.setElementSelectedByIndex(index);
}
@FXML index = mkaPaneController.getElementSelectedIndex() + 1;
private void volumeDownBtn(){ if (index < mkaPaneController.getElementsCount())
landingController.player.volumeDown(); 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(){ void shutdown(){

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2018-2021 Dmitry Isaenko Copyright 2018-2023 Dmitry Isaenko
This file is part of mplayer4anime. This file is part of mplayer4anime.
@ -18,6 +18,7 @@
*/ */
package mplayer4anime.ui.landing.panes; package mplayer4anime.ui.landing.panes;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -50,7 +51,6 @@ public class ControllerPane implements Initializable {
private Label paneLbl; private Label paneLbl;
private String paneType; private String paneType;
@Override @Override
public void initialize(URL url, ResourceBundle resBundle) { public void initialize(URL url, ResourceBundle resBundle) {
SetCellFactory(paneListView); SetCellFactory(paneListView);
@ -58,6 +58,10 @@ public class ControllerPane implements Initializable {
appPreferences = AppPreferences.getINSTANCE(); appPreferences = AppPreferences.getINSTANCE();
} }
public ObservableList<File> getPaneFileList() {
return paneFileList;
}
public void setPaneType(String paneType){ public void setPaneType(String paneType){
this.paneType = paneType; this.paneType = paneType;
@ -73,7 +77,6 @@ public class ControllerPane implements Initializable {
break; break;
default: default:
paneLbl.setText(resourceBundle.getString("?")); paneLbl.setText(resourceBundle.getString("?"));
break;
} }
} }
@ -91,23 +94,20 @@ public class ControllerPane implements Initializable {
} }
/** Select element in pane using index recieved */ /** Select element in pane using index recieved */
public void setElementSelectedByIndex(int index){ public void setElementSelectedByIndex(int index){
this.paneListView.getSelectionModel().select(index); paneListView.getSelectionModel().select(index);
} }
/** Get number of elements loaded into the pane */ /** Get number of elements loaded into the pane */
public int getElementsCount(){ public int getElementsCount(){
return this.paneFileList.size(); return paneFileList.size();
}
/** Check if there are any elements loaded */
public boolean isElementsListEmpty(){
return paneFileList.isEmpty();
} }
/** Get all elements /** Get all elements
* Used in Json playlist writer only */ * Used in Json playlist writer only */
public String[] getElementsAll(){ public String[] getElementsAll(){
String[] elementsArray = new String[this.getElementsCount()]; 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(); elementsArray[i] = paneFileList.get(i).toString();
}
return elementsArray; return elementsArray;
} }
@ -239,39 +239,36 @@ public class ControllerPane implements Initializable {
* */ * */
public void setFilesFromList(String[] fileLocations){ public void setFilesFromList(String[] fileLocations){
cleanList(); cleanList();
if (fileLocations != null && fileLocations.length != 0) {
if (fileLocations == null || fileLocations.length == 0)
return;
File[] files = new File[fileLocations.length]; 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]); files[i] = new File(fileLocations[i]);
displayFiles(files); displayFiles(files);
} }
}
private void displayFiles(File[] files){ private void displayFiles(File[] files){
if (files != null && files.length > 0) { if (files == null || files.length == 0)
// spiced java magic return;
Arrays.sort(files); 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) // 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(); folderToOpen = files[0].getParent();
//System.out.println(folderToOpen);
paneFileList.addAll(files); paneFileList.addAll(files);
paneListView.setItems(paneFileList); paneListView.setItems(paneFileList);
paneListView.getSelectionModel().select(0); paneListView.getSelectionModel().select(0);
} else {
System.out.println("\tNo files in this folder");
}
} }
@FXML @FXML
public void cleanList(){ public void cleanList(){
paneListView.getItems().clear(); // wipe elements from ListView paneListView.getItems().clear();
} }
@FXML @FXML
private void Up(){ private void up(){
int index; int index = paneListView.getSelectionModel().getSelectedIndex();
index = paneListView.getSelectionModel().getSelectedIndex();
if (index > 0){ if (index > 0){
paneFileList.add(index - 1, paneListView.getSelectionModel().getSelectedItem()); paneFileList.add(index - 1, paneListView.getSelectionModel().getSelectedItem());
paneFileList.remove(index + 1); paneFileList.remove(index + 1);
@ -279,9 +276,8 @@ public class ControllerPane implements Initializable {
} }
} }
@FXML @FXML
private void Down(){ private void down(){
int index; int index = paneListView.getSelectionModel().getSelectedIndex();
index = paneListView.getSelectionModel().getSelectedIndex();
if (index + 1 < paneFileList.size() ){ if (index + 1 < paneFileList.size() ){
paneFileList.add(index + 2, paneListView.getSelectionModel().getSelectedItem()); paneFileList.add(index + 2, paneListView.getSelectionModel().getSelectedItem());
paneFileList.remove(index); paneFileList.remove(index);
@ -289,11 +285,17 @@ public class ControllerPane implements Initializable {
} }
} }
@FXML @FXML
private void Del(){ paneFileList.remove(paneListView.getSelectionModel().getSelectedItem()); } private void delete(){
paneFileList.remove(paneListView.getSelectionModel().getSelectedItem());
}
@FXML @FXML
private void KeyPressed(KeyEvent event){ private void keyPressed(KeyEvent event){
if (event.getCode().toString().equals("DELETE")) 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. This file is part of mplayer4anime.
@ -41,7 +41,7 @@ public class SettingsController implements Initializable {
@FXML @FXML
private Label pathToMplayerLbl; private Label pathToMplayerLbl;
@FXML @FXML
private CheckBox subtitlesFirstCheckBox; private CheckBox subtitlesFirstCheckBox, openLatestPlaylistCheckBox;
@FXML @FXML
private ChoiceBox<String> backEndEngineChoiceBox; private ChoiceBox<String> backEndEngineChoiceBox;
@ -59,6 +59,7 @@ public class SettingsController implements Initializable {
audioExtensionListController.setList(appPreferences.getAudioExtensionsList(), true); audioExtensionListController.setList(appPreferences.getAudioExtensionsList(), true);
backEndEngineChoiceBox.getItems().addAll("mplayer", "mpv"); backEndEngineChoiceBox.getItems().addAll("mplayer", "mpv");
backEndEngineChoiceBox.getSelectionModel().select(appPreferences.getBackendEngineIndexId()); backEndEngineChoiceBox.getSelectionModel().select(appPreferences.getBackendEngineIndexId());
openLatestPlaylistCheckBox.setSelected(appPreferences.getOpenLatestPlaylistOnStart());
} }
@FXML @FXML
@ -67,18 +68,14 @@ public class SettingsController implements Initializable {
fileChooser.setTitle("mplayer"); fileChooser.setTitle("mplayer");
// In case we use Windows, limit selectable file to .exe // In case we use Windows, limit selectable file to .exe
if (System.getProperty("os.name").contains("Windows")) { if (System.getProperty("os.name").contains("Windows"))
fileChooser.getExtensionFilters().setAll( fileChooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter("mplayer", "*.exe"));
new FileChooser.ExtensionFilter("mplayer", "*.exe")
);
}
File mplayerExecutableFile = fileChooser.showOpenDialog(null); File mplayerExecutableFile = fileChooser.showOpenDialog(null);
if (mplayerExecutableFile != null) { if (mplayerExecutableFile != null)
pathToMplayerLbl.setText(mplayerExecutableFile.toString()); pathToMplayerLbl.setText(mplayerExecutableFile.toString());
} }
}
@FXML @FXML
private void clearPath(){ private void clearPath(){
@ -108,6 +105,7 @@ public class SettingsController implements Initializable {
appPreferences.setVideoExtensionsList(videoExtensionListController.getList()); appPreferences.setVideoExtensionsList(videoExtensionListController.getList());
appPreferences.setAudioExtensionsList(audioExtensionListController.getList()); appPreferences.setAudioExtensionsList(audioExtensionListController.getList());
appPreferences.setBackendEngineIndexId(backEndEngineChoiceBox.getSelectionModel().getSelectedIndex()); appPreferences.setBackendEngineIndexId(backEndEngineChoiceBox.getSelectionModel().getSelectedIndex());
appPreferences.setOpenLatestPlaylistOnStart(openLatestPlaylistCheckBox.isSelected());
MediatorControl.getInstance().updateAfterSettingsChanged(); // TODO: implement list to track what should be updated 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.layout.Pane?>
<?import javafx.scene.shape.SVGPath?> <?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"> <ToolBar styleClass="topToolBar" stylesheets="@res/landing.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items> <items>
<HBox> <HBox>
<children> <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> <graphic>
<SVGPath content="M 12,12 3.5,6 12,0 Z M 0,0 V 12 H 2 V 0 Z" fill="#e1e1e1" /> <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> </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> <graphic>
<SVGPath content="M3,5V19L11,12M13,19H16V5H13M18,5V19H21V5" fill="#61dd4e" /> <SVGPath content="M3,5V19L11,12M13,19H16V5H13M18,5V19H21V5" fill="#61dd4e" />
</graphic> </graphic>
</Button> </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> <graphic>
<SVGPath content="M18,18H6V6H18V18Z" fill="#e1e1e1" /> <SVGPath content="M18,18H6V6H18V18Z" fill="#e1e1e1" />
</graphic> </graphic>
</Button> </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> <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" /> <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> </graphic></Button>
@ -41,7 +41,7 @@
<Pane minWidth="20.0" /> <Pane minWidth="20.0" />
<HBox> <HBox>
<children> <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> <opaqueInsets>
<Insets /> <Insets />
</opaqueInsets> </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" /> <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> </graphic>
</Button> </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> <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" /> <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> </graphic>
</Button> </Button>
</children> </children>
</HBox> </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> <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" /> <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> </graphic>
</Button> </Button>
<Pane HBox.hgrow="ALWAYS" /> <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> <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" /> <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> </graphic>
@ -70,7 +70,7 @@
<CheckMenuItem fx:id="subsHide" mnemonicParsing="false" text="%subsShow_option" /> <CheckMenuItem fx:id="subsHide" mnemonicParsing="false" text="%subsShow_option" />
</items> </items>
</SplitMenuButton> </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> <items>
<CheckMenuItem fx:id="fullScreen" mnemonicParsing="false" text="%fullscreen_option" /> <CheckMenuItem fx:id="fullScreen" mnemonicParsing="false" text="%fullscreen_option" />
</items> </items>

View file

@ -13,7 +13,7 @@
<?import javafx.scene.shape.SVGPath?> <?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?> <?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> <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"> <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> <tabs>
@ -49,11 +49,8 @@
<ChoiceBox fx:id="backEndEngineChoiceBox" prefWidth="150.0" /> <ChoiceBox fx:id="backEndEngineChoiceBox" prefWidth="150.0" />
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" VBox.vgrow="NEVER">
<children>
<CheckBox fx:id="subtitlesFirstCheckBox" mnemonicParsing="false" text="%settings_SubtitlesTabFirst" /> <CheckBox fx:id="subtitlesFirstCheckBox" mnemonicParsing="false" text="%settings_SubtitlesTabFirst" />
</children> <CheckBox fx:id="openLatestPlaylistCheckBox" mnemonicParsing="false" text="%settings_OpenLatestOnStart" />
</HBox>
</children> </children>
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />

View file

@ -34,17 +34,17 @@
<Pane HBox.hgrow="ALWAYS" /> <Pane HBox.hgrow="ALWAYS" />
<Label fx:id="paneLbl" text="%lbl_VideoPane" /> <Label fx:id="paneLbl" text="%lbl_VideoPane" />
<Pane HBox.hgrow="ALWAYS" /> <Pane HBox.hgrow="ALWAYS" />
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#up">
<graphic> <graphic>
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" /> <SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
</graphic> </graphic>
</Button> </Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#down">
<graphic> <graphic>
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" /> <SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
</graphic> </graphic>
</Button> </Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#delete">
<graphic> <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" /> <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> </graphic>
@ -54,7 +54,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin> </VBox.margin>
</HBox> </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> </children>
</VBox> </VBox>
</children> </children>

View file

@ -37,17 +37,17 @@
<Pane HBox.hgrow="ALWAYS" /> <Pane HBox.hgrow="ALWAYS" />
<Label fx:id="paneLbl" text="%lbl_SubsPane" /> <Label fx:id="paneLbl" text="%lbl_SubsPane" />
<Pane HBox.hgrow="ALWAYS" /> <Pane HBox.hgrow="ALWAYS" />
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#up">
<graphic> <graphic>
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" /> <SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
</graphic> </graphic>
</Button> </Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#down">
<graphic> <graphic>
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" /> <SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
</graphic> </graphic>
</Button> </Button>
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del"> <Button minHeight="28.0" mnemonicParsing="false" onAction="#delete">
<graphic> <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" /> <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> </graphic>
@ -57,7 +57,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin> </VBox.margin>
</HBox> </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> </children>
</VBox> </VBox>
</children> </children>

View file

@ -54,6 +54,7 @@ settings_videoExtensionList=Avaliable video files extensions:
settings_audioExtensionList=Avaliable audio layer extensions: settings_audioExtensionList=Avaliable audio layer extensions:
ApplyBtn=Apply ApplyBtn=Apply
settings_backendSelect=Backend engine: 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 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: 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} 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