v0.2
This commit is contained in:
parent
c4d0959cf3
commit
f5a9ddf8df
13 changed files with 162 additions and 91 deletions
18
README.md
18
README.md
|
@ -34,7 +34,7 @@ Install JRE/JDK 8 or higher (openJDK is good. Oracle's one is also good). JavaFX
|
||||||
|
|
||||||
See 'Linux' section.
|
See 'Linux' section.
|
||||||
|
|
||||||
Set 'Security & Privacy' if needed.
|
Set 'Security & Privacy' settings if needed.
|
||||||
|
|
||||||
### Windows:
|
### Windows:
|
||||||
|
|
||||||
|
@ -63,10 +63,18 @@ Table 'Status' = 'Uploaded' does not means that file installed. It means that it
|
||||||
Handling successful/failed installation is a purpose of the other side application (TinFoil/GoldLeaf). (And they don't provide any feedback interfaces so I can't detect success/failure.)
|
Handling successful/failed installation is a purpose of the other side application (TinFoil/GoldLeaf). (And they don't provide any feedback interfaces so I can't detect success/failure.)
|
||||||
|
|
||||||
## TODO:
|
## TODO:
|
||||||
- [x] macOS QA by [Konstanin Kelemen](https://github.com/konstantin-kelemen). Appreciate assistance of [Vitaliy Natarov](https://github.com/SebastianUA).
|
- [x] macOS QA
|
||||||
|
-[x] v0.1
|
||||||
|
-[ ] v0.2 (partly)
|
||||||
- [x] Windows support
|
- [x] Windows support
|
||||||
- [ ] code refactoring
|
- [ ] code refactoring (almost. todo: printLog() )
|
||||||
- [ ] GoldLeaf support
|
- [x] GoldLeaf support
|
||||||
- [ ] XCI support
|
- [ ] XCI support
|
||||||
- [ ] Settings
|
|
||||||
- [ ] File order sort (non-critical)
|
- [ ] File order sort (non-critical)
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened.
|
||||||
|
|
||||||
|
[Konstanin Kelemen](https://github.com/konstantin-kelemen)
|
||||||
|
|
||||||
|
[Vitaliy Natarov](https://github.com/SebastianUA)
|
23
src/main/java/nsusbloader/AppPreferences.java
Normal file
23
src/main/java/nsusbloader/AppPreferences.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package nsusbloader;
|
||||||
|
|
||||||
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
public class AppPreferences {
|
||||||
|
private static final AppPreferences INSTANCE = new AppPreferences();
|
||||||
|
public static AppPreferences getInstance() { return INSTANCE; }
|
||||||
|
|
||||||
|
private Preferences preferences;
|
||||||
|
|
||||||
|
private AppPreferences(){ preferences = Preferences.userRoot().node("NS-USBloader"); }
|
||||||
|
|
||||||
|
public String getTheme(){
|
||||||
|
String theme = preferences.get("THEME", "/res/app_dark.css"); // Don't let user to change settings manually
|
||||||
|
if (!theme.matches("(^/res/app_dark.css$)|(^/res/app_light.css$)"))
|
||||||
|
theme = "/res/app_dark.css";
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
public void setTheme(String theme){ preferences.put("THEME", theme); }
|
||||||
|
|
||||||
|
public String getRecent(){ return preferences.get("RECENT", System.getProperty("user.home")); }
|
||||||
|
public void setRecent(String path){ preferences.put("RECENT", path); }
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package nsusbloader;
|
package nsusbloader.Controllers;
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
@ -8,7 +8,10 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import nsusbloader.Controllers.NSTableViewController;
|
import nsusbloader.AppPreferences;
|
||||||
|
import nsusbloader.MediatorControl;
|
||||||
|
import nsusbloader.NSLMain;
|
||||||
|
import nsusbloader.UsbCommunications;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
@ -81,18 +84,20 @@ public class NSLMainController implements Initializable {
|
||||||
btnSwitchImage.getStyleClass().add("regionLamp");
|
btnSwitchImage.getStyleClass().add("regionLamp");
|
||||||
switchThemeBtn.setGraphic(btnSwitchImage);
|
switchThemeBtn.setGraphic(btnSwitchImage);
|
||||||
this.switchThemeBtn.setOnAction(e->switchTheme());
|
this.switchThemeBtn.setOnAction(e->switchTheme());
|
||||||
|
|
||||||
|
previouslyOpenedPath = AppPreferences.getInstance().getRecent();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Changes UI theme on the go
|
* Changes UI theme on the go
|
||||||
* */
|
* */
|
||||||
private void switchTheme(){
|
private void switchTheme(){
|
||||||
if (switchThemeBtn.getScene().getStylesheets().get(0).equals("/res/app.css")) {
|
if (switchThemeBtn.getScene().getStylesheets().get(0).equals("/res/app_dark.css")) {
|
||||||
switchThemeBtn.getScene().getStylesheets().remove("/res/app.css");
|
switchThemeBtn.getScene().getStylesheets().remove("/res/app_dark.css");
|
||||||
switchThemeBtn.getScene().getStylesheets().add("/res/app_light.css");
|
switchThemeBtn.getScene().getStylesheets().add("/res/app_light.css");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switchThemeBtn.getScene().getStylesheets().add("/res/app.css");
|
|
||||||
switchThemeBtn.getScene().getStylesheets().remove("/res/app_light.css");
|
switchThemeBtn.getScene().getStylesheets().remove("/res/app_light.css");
|
||||||
|
switchThemeBtn.getScene().getStylesheets().add("/res/app_dark.css");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -103,16 +108,14 @@ public class NSLMainController implements Initializable {
|
||||||
List<File> filesList;
|
List<File> filesList;
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
fileChooser.setTitle(resourceBundle.getString("btnFileOpen"));
|
fileChooser.setTitle(resourceBundle.getString("btnFileOpen"));
|
||||||
if (previouslyOpenedPath == null)
|
|
||||||
fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); // TODO: read from prefs
|
|
||||||
else {
|
|
||||||
File validator = new File(previouslyOpenedPath);
|
File validator = new File(previouslyOpenedPath);
|
||||||
if (validator.exists())
|
if (validator.exists())
|
||||||
fileChooser.setInitialDirectory(validator); // TODO: read from prefs
|
fileChooser.setInitialDirectory(validator); // TODO: read from prefs
|
||||||
else
|
else
|
||||||
fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); // TODO: read from prefs
|
fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); // TODO: read from prefs
|
||||||
}
|
|
||||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS ROM", "*.nsp"));
|
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NSP ROM", "*.nsp"));
|
||||||
|
|
||||||
filesList = fileChooser.showOpenMultipleDialog(logArea.getScene().getWindow());
|
filesList = fileChooser.showOpenMultipleDialog(logArea.getScene().getWindow());
|
||||||
if (filesList != null && !filesList.isEmpty()) {
|
if (filesList != null && !filesList.isEmpty()) {
|
||||||
|
@ -156,7 +159,7 @@ public class NSLMainController implements Initializable {
|
||||||
* This thing modify UI for reusing 'Upload to NS' button and make functionality set for "Stop transmission"
|
* This thing modify UI for reusing 'Upload to NS' button and make functionality set for "Stop transmission"
|
||||||
* Called from mediator
|
* Called from mediator
|
||||||
* */
|
* */
|
||||||
void notifyTransmissionStarted(boolean isTransmissionStarted){
|
public void notifyTransmissionStarted(boolean isTransmissionStarted){
|
||||||
if (isTransmissionStarted) {
|
if (isTransmissionStarted) {
|
||||||
selectNspBtn.setDisable(true);
|
selectNspBtn.setDisable(true);
|
||||||
uploadStopBtn.setOnAction(e->{ stopBtnAction(); });
|
uploadStopBtn.setOnAction(e->{ stopBtnAction(); });
|
||||||
|
@ -182,4 +185,11 @@ public class NSLMainController implements Initializable {
|
||||||
uploadStopBtn.getStyleClass().add("buttonUp");
|
uploadStopBtn.getStyleClass().add("buttonUp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Save preferences before exit
|
||||||
|
* */
|
||||||
|
public void exit(){
|
||||||
|
AppPreferences.getInstance().setTheme(switchThemeBtn.getScene().getStylesheets().get(0));
|
||||||
|
AppPreferences.getInstance().setRecent(previouslyOpenedPath);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -39,14 +39,14 @@ public class NSLRowModel {
|
||||||
public void setStatus(EFileStatus status){ // TODO: Localization
|
public void setStatus(EFileStatus status){ // TODO: Localization
|
||||||
switch (status){
|
switch (status){
|
||||||
case UPLOADED:
|
case UPLOADED:
|
||||||
this.status = "Uploaded";
|
this.status = "Success";
|
||||||
markForUpload = false;
|
markForUpload = false;
|
||||||
break;
|
break;
|
||||||
case FAILED:
|
case FAILED:
|
||||||
this.status = "Upload failed";
|
this.status = "Failed";
|
||||||
break;
|
break;
|
||||||
case INCORRECT_FILE_FAILED:
|
case INCORRECT_FILE_FAILED:
|
||||||
this.status = "File incorrect";
|
this.status = "Failed: Incorrect file";
|
||||||
markForUpload = false;
|
markForUpload = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,15 +33,29 @@ public class NSTableViewController implements Initializable {
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
rowsObsLst = FXCollections.observableArrayList();
|
rowsObsLst = FXCollections.observableArrayList();
|
||||||
table.setPlaceholder(new Label());
|
table.setPlaceholder(new Label());
|
||||||
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
|
||||||
TableColumn<NSLRowModel, String> statusColumn = new TableColumn<>(resourceBundle.getString("tableStatusLbl"));
|
TableColumn<NSLRowModel, String> statusColumn = new TableColumn<>(resourceBundle.getString("tableStatusLbl"));
|
||||||
TableColumn<NSLRowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
TableColumn<NSLRowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||||
TableColumn<NSLRowModel, String> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
TableColumn<NSLRowModel, String> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||||
TableColumn<NSLRowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
TableColumn<NSLRowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||||
statusColumn.setMinWidth(70.0);
|
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||||
fileNameColumn.setMinWidth(250.0);
|
statusColumn.setMinWidth(100.0);
|
||||||
fileSizeColumn.setMinWidth(70.0);
|
statusColumn.setPrefWidth(100.0);
|
||||||
uploadColumn.setMinWidth(70.0);
|
statusColumn.setMaxWidth(100.0);
|
||||||
|
statusColumn.setResizable(false);
|
||||||
|
|
||||||
|
fileNameColumn.setMinWidth(25.0);
|
||||||
|
|
||||||
|
fileSizeColumn.setMinWidth(120.0);
|
||||||
|
fileSizeColumn.setPrefWidth(120.0);
|
||||||
|
fileSizeColumn.setMaxWidth(120.0);
|
||||||
|
fileSizeColumn.setResizable(false);
|
||||||
|
|
||||||
|
uploadColumn.setMinWidth(100.0);
|
||||||
|
uploadColumn.setPrefWidth(100.0);
|
||||||
|
uploadColumn.setMaxWidth(100.0);
|
||||||
|
uploadColumn.setResizable(false);
|
||||||
|
|
||||||
statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
|
statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
|
||||||
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("nspFileName"));
|
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("nspFileName"));
|
||||||
|
@ -76,12 +90,6 @@ public class NSTableViewController implements Initializable {
|
||||||
|
|
||||||
table.setItems(rowsObsLst);
|
table.setItems(rowsObsLst);
|
||||||
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
|
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
|
||||||
/* debug content
|
|
||||||
rowsObsLst.add(new NSLRowModel(new File("/home/loper/стихи_2"), true));
|
|
||||||
rowsObsLst.add(new NSLRowModel(new File("/home/loper/стихи_2"), false));
|
|
||||||
rowsObsLst.add(new NSLRowModel(new File("/home/loper/стихи_2"), false));
|
|
||||||
rowsObsLst.add(new NSLRowModel(new File("/home/loper/стихи_2"), true));
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* See uploadColumn callback. In case of GoldLeaf we have to restrict selection
|
* See uploadColumn callback. In case of GoldLeaf we have to restrict selection
|
||||||
|
@ -145,6 +153,7 @@ public class NSTableViewController implements Initializable {
|
||||||
model.setStatus(status);
|
model.setStatus(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table.refresh();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Called if selected different USB protocol
|
* Called if selected different USB protocol
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
package nsusbloader;
|
package nsusbloader;
|
||||||
|
|
||||||
|
import nsusbloader.Controllers.NSLMainController;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
class MediatorControl {
|
public class MediatorControl {
|
||||||
private AtomicBoolean isTransferActive = new AtomicBoolean(false); // Overcoded just for sure
|
private AtomicBoolean isTransferActive = new AtomicBoolean(false); // Overcoded just for sure
|
||||||
private NSLMainController applicationController;
|
private NSLMainController applicationController;
|
||||||
|
|
||||||
static MediatorControl getInstance(){
|
public static MediatorControl getInstance(){
|
||||||
return MediatorControlHold.INSTANCE;
|
return MediatorControlHold.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MediatorControlHold {
|
private static class MediatorControlHold {
|
||||||
private static final MediatorControl INSTANCE = new MediatorControl();
|
private static final MediatorControl INSTANCE = new MediatorControl();
|
||||||
}
|
}
|
||||||
void setController(NSLMainController controller){
|
public void setController(NSLMainController controller){
|
||||||
this.applicationController = controller;
|
this.applicationController = controller;
|
||||||
}
|
}
|
||||||
NSLMainController getContoller(){ return this.applicationController; }
|
NSLMainController getContoller(){ return this.applicationController; }
|
||||||
|
|
||||||
synchronized void setTransferActive(boolean state) {
|
public synchronized void setTransferActive(boolean state) {
|
||||||
isTransferActive.set(state);
|
isTransferActive.set(state);
|
||||||
applicationController.notifyTransmissionStarted(state);
|
applicationController.notifyTransmissionStarted(state);
|
||||||
}
|
}
|
||||||
synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
|
public synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,16 +49,15 @@ public class MessagesConsumer extends AnimationTimer {
|
||||||
if (progressRecieved > 0)
|
if (progressRecieved > 0)
|
||||||
progress.forEach(prg -> progressBar.setProgress(prg));
|
progress.forEach(prg -> progressBar.setProgress(prg));
|
||||||
|
|
||||||
if (isInterrupted) {
|
if (isInterrupted) { // It's safe 'cuz it's could't be interrupted while HashMap populating
|
||||||
MediatorControl.getInstance().setTransferActive(false);
|
MediatorControl.getInstance().setTransferActive(false);
|
||||||
progressBar.setProgress(0.0);
|
progressBar.setProgress(0.0);
|
||||||
|
|
||||||
if (statusMap.size() > 0) // It's safe 'cuz it's could't be interrupted while HashMap populating
|
if (statusMap.size() > 0)
|
||||||
for (String key : statusMap.keySet())
|
for (String key : statusMap.keySet())
|
||||||
tableViewController.setFileStatus(key, statusMap.get(key));
|
tableViewController.setFileStatus(key, statusMap.get(key));
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void interrupt(){
|
void interrupt(){
|
||||||
|
|
|
@ -6,22 +6,24 @@ import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import nsusbloader.Controllers.NSLMainController;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class NSLMain extends Application {
|
public class NSLMain extends Application {
|
||||||
static final String appVersion = "v0.2-DEVELOPMENT";
|
public static final String appVersion = "v0.2";
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception{
|
public void start(Stage primaryStage) throws Exception{
|
||||||
|
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
||||||
|
|
||||||
ResourceBundle rb;
|
ResourceBundle rb;
|
||||||
if (Locale.getDefault().getISO3Language().equals("rus"))
|
if (Locale.getDefault().getISO3Language().equals("rus"))
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("ru"));
|
rb = ResourceBundle.getBundle("locale", new Locale("ru"));
|
||||||
else
|
else
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("en"));
|
rb = ResourceBundle.getBundle("locale", new Locale("en"));
|
||||||
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
|
||||||
|
|
||||||
loader.setResources(rb);
|
loader.setResources(rb);
|
||||||
Parent root = loader.load();
|
Parent root = loader.load();
|
||||||
|
|
||||||
|
@ -36,7 +38,9 @@ public class NSLMain extends Application {
|
||||||
primaryStage.setMinWidth(600);
|
primaryStage.setMinWidth(600);
|
||||||
primaryStage.setMinHeight(375);
|
primaryStage.setMinHeight(375);
|
||||||
Scene mainScene = new Scene(root, 800, 400);
|
Scene mainScene = new Scene(root, 800, 400);
|
||||||
mainScene.getStylesheets().add("/res/app.css");
|
|
||||||
|
mainScene.getStylesheets().add(AppPreferences.getInstance().getTheme());
|
||||||
|
|
||||||
primaryStage.setScene(mainScene);
|
primaryStage.setScene(mainScene);
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
|
|
||||||
|
@ -45,6 +49,9 @@ public class NSLMain extends Application {
|
||||||
if(! ServiceWindow.getConfirmationWindow(rb.getString("windowTitleConfirmExit"), rb.getString("windowBodyConfirmExit")))
|
if(! ServiceWindow.getConfirmationWindow(rb.getString("windowTitleConfirmExit"), rb.getString("windowBodyConfirmExit")))
|
||||||
e.consume();
|
e.consume();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
NSLMainController controller = loader.getController();
|
||||||
|
primaryStage.setOnHidden(e-> controller.exit());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -35,12 +35,9 @@ public class ServiceWindow {
|
||||||
alertBox.getDialogPane().setMinWidth(Region.USE_PREF_SIZE);
|
alertBox.getDialogPane().setMinWidth(Region.USE_PREF_SIZE);
|
||||||
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||||
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
||||||
alertBox.getDialogPane().getStylesheets().add("/res/app.css");
|
alertBox.getDialogPane().getStylesheets().add(AppPreferences.getInstance().getTheme());
|
||||||
Optional<ButtonType> result = alertBox.showAndWait();
|
Optional<ButtonType> result = alertBox.showAndWait();
|
||||||
if (result.get() == ButtonType.OK)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
return (result.isPresent() && result.get() == ButtonType.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,13 @@ import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
class UsbCommunications extends Task<Void> {
|
public class UsbCommunications extends Task<Void> {
|
||||||
private final int DEFAULT_INTERFACE = 0;
|
private final int DEFAULT_INTERFACE = 0;
|
||||||
|
|
||||||
private BlockingQueue<String> msgQueue;
|
private BlockingQueue<String> msgQueue;
|
||||||
private BlockingQueue<Double> progressQueue;
|
private BlockingQueue<Double> progressQueue;
|
||||||
private HashMap<String, EFileStatus> statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap
|
private HashMap<String, EFileStatus> statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap
|
||||||
|
private EFileStatus status = EFileStatus.FAILED;
|
||||||
|
|
||||||
private MessagesConsumer msgConsumer;
|
private MessagesConsumer msgConsumer;
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ class UsbCommunications extends Task<Void> {
|
||||||
Since this application let user an ability (theoretically) to choose same files in different folders, the latest selected file will be added to the list and handled correctly.
|
Since this application let user an ability (theoretically) to choose same files in different folders, the latest selected file will be added to the list and handled correctly.
|
||||||
I have no idea why he/she will make a decision to do that. Just in case, we're good in this point.
|
I have no idea why he/she will make a decision to do that. Just in case, we're good in this point.
|
||||||
*/
|
*/
|
||||||
UsbCommunications(List<File> nspList, String protocol){
|
public UsbCommunications(List<File> nspList, String protocol){
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
this.nspMap = new HashMap<>();
|
this.nspMap = new HashMap<>();
|
||||||
for (File f: nspList)
|
for (File f: nspList)
|
||||||
|
@ -275,28 +276,17 @@ class UsbCommunications extends Task<Void> {
|
||||||
printLog("\tEnd chain", EMsgType.INFO);
|
printLog("\tEnd chain", EMsgType.INFO);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Report transfer status
|
|
||||||
* */
|
|
||||||
private void reportTransferStatus(EFileStatus status){
|
|
||||||
for (String fileName: nspMap.keySet())
|
|
||||||
statusMap.put(fileName, status);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Tinfoil processing
|
* Tinfoil processing
|
||||||
* */
|
* */
|
||||||
private class TinFoil{
|
private class TinFoil{
|
||||||
TinFoil(){
|
TinFoil(){
|
||||||
|
|
||||||
if (!sendListOfNSP()) {
|
if (!sendListOfNSP())
|
||||||
reportTransferStatus(EFileStatus.FAILED);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (proceedCommands()) // REPORT SUCCESS
|
if (proceedCommands()) // REPORT SUCCESS
|
||||||
reportTransferStatus(EFileStatus.UPLOADED);
|
status = EFileStatus.UPLOADED; // Don't change status that is already set to FAILED
|
||||||
else // REPORT FAILURE
|
|
||||||
reportTransferStatus(EFileStatus.FAILED);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Send what NSP will be transferred
|
* Send what NSP will be transferred
|
||||||
|
@ -547,15 +537,14 @@ class UsbCommunications extends Task<Void> {
|
||||||
PFSProvider pfsElement = new PFSProvider(nspMap.get(nspMap.keySet().toArray()[0]), msgQueue);
|
PFSProvider pfsElement = new PFSProvider(nspMap.get(nspMap.keySet().toArray()[0]), msgQueue);
|
||||||
if (!pfsElement.init()) {
|
if (!pfsElement.init()) {
|
||||||
printLog("GL File provided have incorrect structure and won't be uploaded", EMsgType.FAIL);
|
printLog("GL File provided have incorrect structure and won't be uploaded", EMsgType.FAIL);
|
||||||
reportTransferStatus(EFileStatus.INCORRECT_FILE_FAILED);
|
status = EFileStatus.INCORRECT_FILE_FAILED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printLog("GL File structure validated and it will be uploaded", EMsgType.PASS);
|
printLog("GL File structure validated and it will be uploaded", EMsgType.PASS);
|
||||||
|
|
||||||
if (initGoldLeafProtocol(pfsElement))
|
if (initGoldLeafProtocol(pfsElement))
|
||||||
reportTransferStatus(EFileStatus.UPLOADED);
|
status = EFileStatus.UPLOADED;
|
||||||
else
|
// else - no change status that is already set to FAILED
|
||||||
reportTransferStatus(EFileStatus.FAILED);
|
|
||||||
}
|
}
|
||||||
private boolean initGoldLeafProtocol(PFSProvider pfsElement){
|
private boolean initGoldLeafProtocol(PFSProvider pfsElement){
|
||||||
// Go parse commands
|
// Go parse commands
|
||||||
|
@ -774,6 +763,11 @@ class UsbCommunications extends Task<Void> {
|
||||||
LibUsb.exit(contextNS);
|
LibUsb.exit(contextNS);
|
||||||
printLog("Requested context close", EMsgType.INFO);
|
printLog("Requested context close", EMsgType.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Report status
|
||||||
|
for (String fileName: nspMap.keySet())
|
||||||
|
statusMap.put(fileName, status);
|
||||||
|
|
||||||
msgConsumer.interrupt();
|
msgConsumer.interrupt();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.shape.SVGPath?>
|
<?import javafx.scene.shape.SVGPath?>
|
||||||
|
|
||||||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.NSLMainController">
|
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
|
||||||
<children>
|
<children>
|
||||||
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
<children>
|
<children>
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
-fx-background-color: #f7fafa;
|
-fx-background-color: #f7fafa;
|
||||||
-fx-min-height: 1;
|
-fx-min-height: 1;
|
||||||
}
|
}
|
||||||
|
// -======================== Choice box =========================-
|
||||||
.choice-box {
|
.choice-box {
|
||||||
-fx-background-color: #4f4f4f;
|
-fx-background-color: #4f4f4f;
|
||||||
-fx-border-color: #4f4f4f;
|
-fx-border-color: #4f4f4f;
|
||||||
|
@ -120,13 +120,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background color of the whole context menu
|
// Background color of the whole context menu
|
||||||
.choice-box .context-menu { -fx-background-color: #2d2d2d; }
|
.choice-box .context-menu {
|
||||||
|
-fx-background-color: #2d2d2d;
|
||||||
|
}
|
||||||
|
|
||||||
// Focused item background color in the list
|
// Focused item background color in the list
|
||||||
.choice-box .menu-item:focused { -fx-background-color: #eea11e; }
|
.choice-box .context-menu .menu-item:focused {
|
||||||
// Text color of non-focused items in the list
|
-fx-background-color: #eea11e;
|
||||||
.choice-box .menu-item > .label { -fx-text-fill: #f7fafa; }
|
|
||||||
// Text color of focused item in the list
|
}
|
||||||
.choice-box .menu-item:focused > .label { -fx-text-fill: #2d2d2d; }
|
.choice-box .context-menu .menu-item:focused .label {
|
||||||
|
-fx-text-fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -======================== TAB PANE =========================-
|
// -======================== TAB PANE =========================-
|
||||||
.tab-pane .tab SVGPath{
|
.tab-pane .tab SVGPath{
|
||||||
|
@ -176,12 +182,18 @@
|
||||||
-fx-border-radius: 3;
|
-fx-border-radius: 3;
|
||||||
-fx-border-width: 2;
|
-fx-border-width: 2;
|
||||||
}
|
}
|
||||||
|
.table-view .arrow {
|
||||||
|
-fx-mark-color: #08f3ff ;
|
||||||
|
}
|
||||||
.table-view .column-header {
|
.table-view .column-header {
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
|
-fx-border-width: 0 1 2 0;
|
||||||
|
-fx-border-color: #6d8484;
|
||||||
}
|
}
|
||||||
.table-view .column-header-background .label{
|
.table-view .column-header-background .label{
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
-fx-text-fill: #08f3ff;
|
-fx-text-fill: #08f3ff;
|
||||||
|
|
||||||
}
|
}
|
||||||
.table-view .column-header-background, .table-view .filler{
|
.table-view .column-header-background, .table-view .filler{
|
||||||
-fx-background-color: #4f4f4f;
|
-fx-background-color: #4f4f4f;
|
||||||
|
@ -194,14 +206,14 @@
|
||||||
-fx-background-color: -fx-table-cell-border-color, #424242;
|
-fx-background-color: -fx-table-cell-border-color, #424242;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #f7fafa;
|
-fx-table-cell-border-color: #6d8484;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
||||||
-fx-background-color: -fx-table-cell-border-color, #4f4f4f;
|
-fx-background-color: -fx-table-cell-border-color, #4f4f4f;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #f7fafa;
|
-fx-table-cell-border-color: #6d8484;
|
||||||
}
|
}
|
||||||
// -========================== Context menu =====================-
|
// -========================== Context menu =====================-
|
||||||
.context-menu {
|
.context-menu {
|
|
@ -99,7 +99,7 @@
|
||||||
-fx-background-color: #2c2c2c;
|
-fx-background-color: #2c2c2c;
|
||||||
-fx-min-height: 1;
|
-fx-min-height: 1;
|
||||||
}
|
}
|
||||||
|
// -======================== Choice box =========================-
|
||||||
.choice-box {
|
.choice-box {
|
||||||
-fx-background-color: #fefefe;
|
-fx-background-color: #fefefe;
|
||||||
-fx-border-color: #fefefe;
|
-fx-border-color: #fefefe;
|
||||||
|
@ -121,13 +121,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background color of the whole context menu
|
// Background color of the whole context menu
|
||||||
.choice-box .context-menu { -fx-background-color: #fefefe; }
|
.choice-box .context-menu {
|
||||||
|
-fx-background-color: #fefefe;
|
||||||
|
}
|
||||||
|
|
||||||
// Focused item background color in the list
|
// Focused item background color in the list
|
||||||
.choice-box .menu-item:focused { -fx-background-color: #eea11e; }
|
.choice-box .context-menu .menu-item:focused {
|
||||||
// Text color of non-focused items in the list
|
-fx-background-color: #eea11e;
|
||||||
.choice-box .menu-item > .label { -fx-text-fill: #2c2c2c; }
|
|
||||||
// Text color of focused item in the list
|
}
|
||||||
.choice-box .menu-item:focused > .label { -fx-text-fill: #2d2d2d; }
|
.choice-box .context-menu .menu-item:focused .label {
|
||||||
|
-fx-text-fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
|
||||||
// -======================== TAB PANE =========================-
|
// -======================== TAB PANE =========================-
|
||||||
.tab-pane .tab SVGPath{
|
.tab-pane .tab SVGPath{
|
||||||
|
@ -177,8 +182,13 @@
|
||||||
-fx-border-radius: 3;
|
-fx-border-radius: 3;
|
||||||
-fx-border-width: 2;
|
-fx-border-width: 2;
|
||||||
}
|
}
|
||||||
|
.table-view .arrow {
|
||||||
|
-fx-mark-color: #2c2c2c ;
|
||||||
|
}
|
||||||
.table-view .column-header {
|
.table-view .column-header {
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
|
-fx-border-width: 0 1 2 0;
|
||||||
|
-fx-border-color: #b0b0b0;
|
||||||
}
|
}
|
||||||
.table-view .column-header-background .label{
|
.table-view .column-header-background .label{
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
|
@ -195,14 +205,14 @@
|
||||||
-fx-background-color: -fx-table-cell-border-color, #d3fffd;
|
-fx-background-color: -fx-table-cell-border-color, #d3fffd;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #2c2c2c;
|
-fx-table-cell-border-color: #b0b0b0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
||||||
-fx-background-color: -fx-table-cell-border-color, #fefefe;
|
-fx-background-color: -fx-table-cell-border-color, #fefefe;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #2c2c2c;
|
-fx-table-cell-border-color: #b0b0b0;
|
||||||
}
|
}
|
||||||
// -========================== Context menu =====================-
|
// -========================== Context menu =====================-
|
||||||
.context-menu {
|
.context-menu {
|
||||||
|
|
Loading…
Reference in a new issue