diff --git a/pom.xml b/pom.xml index 3a37a6d..c52bdad 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com cemu_UI - 0.2.2-SNAPSHOT + 0.2.3-SNAPSHOT jar cemu_UI diff --git a/src/main/java/com/cemu_UI/application/Main.java b/src/main/java/com/cemu_UI/application/Main.java index 18778cd..652b049 100644 --- a/src/main/java/com/cemu_UI/application/Main.java +++ b/src/main/java/com/cemu_UI/application/Main.java @@ -51,11 +51,11 @@ import javafx.scene.layout.AnchorPane; public class Main extends Application { - Stage primaryStage; - public MainWindowController mainWindowController; // TODO find a better way - CloudController cloudController; - AnchorPane pane; - Scene scene; // TODO make private + private Stage primaryStage; + private MainWindowController mainWindowController; + private CloudController cloudController; + private AnchorPane pane; + private Scene scene; private static String userHome = System.getProperty("user.home"); private static String userName = System.getProperty("user.name"); private static String osName = System.getProperty("os.name"); @@ -69,8 +69,7 @@ public class Main extends Application { private File directory; private File configFile; private File gamesDBFile; - @SuppressWarnings("unused") - private File localDB; + private File reference_gamesFile; private File pictureCache; private static Logger LOGGER; @@ -97,7 +96,7 @@ public class Main extends Application { primaryStage.setTitle("cemu_UI"); // primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream("/resources/Homeflix_Icon_64x64.png"))); //adds application icon - mainWindowController = loader.getController(); // Link of FXMLController and controller class + mainWindowController = loader.getController(); // Link of FXMLController and controller class mainWindowController.setMain(this); // call setMain cloudController = new CloudController(mainWindowController); // call cloudController constructor @@ -106,13 +105,13 @@ public class Main extends Application { directory = new File(dirLinux); configFile = new File(dirLinux + "/config.xml"); gamesDBFile = new File(dirLinux + "/games.db"); - localDB = new File(dirLinux+"/localRoms.db"); + reference_gamesFile = new File(dirLinux + "/reference_games.db"); pictureCache= new File(dirLinux+"/picture_cache"); } else { directory = new File(dirWin); configFile = new File(dirWin + "/config.xml"); gamesDBFile = new File(dirWin + "/games.db"); - localDB = new File(dirWin+"/localRoms.db"); + reference_gamesFile = new File(dirWin + "/reference_games.db"); pictureCache= new File(dirWin+"/picture_cache"); } @@ -139,6 +138,8 @@ public class Main extends Application { firstStart(); mainWindowController.setColor("00a8cc"); mainWindowController.setAutoUpdate(false); + mainWindowController.setLanguage("en_US"); + mainWindowController.setLastLocalSync(0); mainWindowController.setxPosHelper(0); mainWindowController.saveSettings(); Runtime.getRuntime().exec("java -jar cemu_UI.jar"); //start again (preventing Bugs) @@ -149,12 +150,16 @@ public class Main extends Application { pictureCache.mkdir(); } - if (gamesDBFile.exists() != true) { + + if (!reference_gamesFile.exists()) { + if (gamesDBFile.exists()) { + gamesDBFile.delete(); + } try { - LOGGER.info("downloading games.db... "); + LOGGER.info("downloading ReferenceGameList.db... "); URL website = new URL(gamesDBdownloadURL); ReadableByteChannel rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(gamesDBFile); + FileOutputStream fos = new FileOutputStream(reference_gamesFile); fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); fos.close(); LOGGER.info("finished downloading games.db"); @@ -165,11 +170,12 @@ public class Main extends Application { // loading settings and initialize UI, dbController.main() loads all databases mainWindowController.init(); - mainWindowController.dbController.main(); + mainWindowController.dbController.init(); + // if cloud sync is activated start sync if(mainWindowController.isCloudSync()) { cloudController.initializeConnection(mainWindowController.getCloudService(), mainWindowController.getCemuPath()); - cloudController.stratupCheck(mainWindowController.getCloudService(), mainWindowController.getCemuPath()); + cloudController.sync(mainWindowController.getCloudService(), mainWindowController.getCemuPath(), directory.getPath()); } mainWindowController.addUIData(); @@ -224,8 +230,6 @@ public class Main extends Application { @Override public void changed(ObservableValue observable, Number oldValue, final Number newValue) { int xPosHelperMax = (int) Math.floor((mainWindowController.getMainAnchorPane().getWidth() - 36) / 217); - - mainWindowController.refreshplayBtnPosition(); // call only if there is enough space for a new row if (mainWindowController.getOldXPosHelper() != xPosHelperMax) { @@ -308,4 +312,36 @@ public class Main extends Application { public void stop() { System.exit(0); } + + public Stage getPrimaryStage() { + return primaryStage; + } + + public void setPrimaryStage(Stage primaryStage) { + this.primaryStage = primaryStage; + } + + public CloudController getCloudController() { + return cloudController; + } + + public void setCloudController(CloudController cloudController) { + this.cloudController = cloudController; + } + + public AnchorPane getPane() { + return pane; + } + + public void setPane(AnchorPane pane) { + this.pane = pane; + } + + public File getDirectory() { + return directory; + } + + public void setDirectory(File directory) { + this.directory = directory; + } } diff --git a/src/main/java/com/cemu_UI/application/MainWindowController.java b/src/main/java/com/cemu_UI/application/MainWindowController.java index 14a7c71..55fb730 100644 --- a/src/main/java/com/cemu_UI/application/MainWindowController.java +++ b/src/main/java/com/cemu_UI/application/MainWindowController.java @@ -42,7 +42,9 @@ import java.sql.SQLException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Locale; import java.util.Properties; +import java.util.ResourceBundle; import javax.imageio.ImageIO; import javax.swing.ProgressMonitor; @@ -54,7 +56,7 @@ import org.apache.logging.log4j.Logger; import com.cemu_UI.controller.SmmdbAPIController; import com.cemu_UI.controller.UpdateController; -import com.cemu_UI.controller.dbController; +import com.cemu_UI.controller.DBController; import com.cemu_UI.datatypes.CourseTableDataType; import com.cemu_UI.datatypes.SmmdbApiDataType; import com.cemu_UI.datatypes.UIROMDataType; @@ -170,6 +172,9 @@ public class MainWindowController { @FXML private JFXToggleButton fullscreenToggleBtn; + + @FXML + private ChoiceBox languageChoisBox; @FXML private ChoiceBox branchChoisBox; @@ -203,6 +208,9 @@ public class MainWindowController { @FXML private HBox topHBox; + + @FXML + private HBox bottomHBox; @FXML private ImageView smmdbImageView; @@ -221,6 +229,9 @@ public class MainWindowController { @FXML private Label mainColorLbl; + + @FXML + private Label languageLbl; @FXML private Label updateLbl; @@ -253,7 +264,7 @@ public class MainWindowController { private JFXTreeTableColumn timeColumn = new JFXTreeTableColumn<>("time"); Main main; - dbController dbController; + DBController dbController; SmmdbAPIController smmdbAPIController; playGame playGame; private static MainWindowController MWC; @@ -275,8 +286,8 @@ public class MainWindowController { private String selectedGameTitleID; private String selectedGameTitle; private String id; - private String version = "0.2.2"; - private String buildNumber = "061"; + private String version = "0.2.3"; + private String buildNumber = "071"; private String versionName = "Puzzle Plank Galaxy"; private int xPos = -200; private int yPos = 17; @@ -284,6 +295,7 @@ public class MainWindowController { private int oldXPosHelper; private int selectedUIDataIndex; private int selected; + private long lastLocalSync; private double windowWidth; private double windowHeight; private DirectoryChooser directoryChooser = new DirectoryChooser(); @@ -294,6 +306,7 @@ public class MainWindowController { private File pictureCacheWin = new File(dirWin + "/picture_cache"); private File pictureCacheLinux = new File(dirLinux + "/picture_cache"); private ObservableList branches = FXCollections.observableArrayList("stable", "beta"); + private ObservableList languages = FXCollections.observableArrayList("English (en_US)", "Deutsch (de_DE)"); private ObservableList smmIDs = FXCollections.observableArrayList("fe31b7f2", "44fc5929"); // TODO add more IDs private ObservableList games = FXCollections.observableArrayList(); ObservableList courses = FXCollections.observableArrayList(); @@ -322,10 +335,45 @@ public class MainWindowController { private ImageView cached_white = new ImageView(new Image("icons/ic_cached_white_24dp_1x.png")); private ImageView smmdb_white = new ImageView(new Image("icons/ic_get_app_white_24dp_1x.png")); private Image close_black = new Image("icons/close_black_2048x2048.png"); - - public void setMain(Main main) { - this.main = main; - dbController = new dbController(this); + + // language support + private ResourceBundle bundle; + private String language; + private String editHeadingText; + private String editBodyText; + private String removeHeadingText; + private String removeBodyText; + private String addUpdateHeadingText; + private String addUpdateBodyText; + private String addDLCHeadingText; + private String addDLCBodyText; + private String licensesLblHeadingText; + private String licensesLblBodyText; + private String showLicenses; + private String aboutBtnHeadingText; + private String aboutBtnBodyText; + private String cloudSyncWaringHeadingText; + private String cloudSyncWaringBodyText; + private String cloudSyncErrorHeadingText; + private String cloudSyncErrorBodyText; + private String addGameBtnHeadingText; + private String addGameBtnBodyText; + private String addBtnReturnErrorHeadingText; + private String addBtnReturnErrorBodyText; + private String lastPlayed; + private String today; + private String yesterday; + private String never; + + private String playBtnPlay; + private String playBtnUpdating; + private String playBtnCopyingFiles; + private String smmdbDownloadBtnLoading; + private String smmdbDownloadBtnDownload; + + public void setMain(Main m) { + this.main = m; + dbController = new DBController(this); smmdbAPIController = new SmmdbAPIController(); } @@ -349,7 +397,6 @@ public class MainWindowController { if (getWindowWidth() > 100 && getWindowHeight() > 100) { mainAnchorPane.setPrefSize(getWindowWidth(), getWindowHeight()); } - refreshplayBtnPosition(); cemuTextField.setText(cemuPath); romTextField.setText(romPath); @@ -358,6 +405,8 @@ public class MainWindowController { cloudSyncToggleBtn.setSelected(isCloudSync()); autoUpdateToggleBtn.setSelected(isAutoUpdate()); branchChoisBox.setItems(branches); + languageChoisBox.setItems(languages); + bottomHBox.setPickOnBounds(false); if (isUseBeta()) { branchChoisBox.getSelectionModel().select(1); @@ -387,6 +436,8 @@ public class MainWindowController { courseTreeTable.getColumns().add(idColumn); courseTreeTable.getColumns().get(3).setVisible(false); // the idColumn should not bee displayed + setUILanguage(); + LOGGER.info("initializing UI done"); } @@ -433,10 +484,9 @@ public class MainWindowController { String[] gameInfo = dbController.getGameInfo(selectedGameTitleID); // new edit dialog - String headingText = "edit a game"; - String bodyText = "You can edit the tile and rom/cover path."; - JFXEditGameDialog editGameDialog = new JFXEditGameDialog(headingText, bodyText, dialogBtnStyle, 450, - 300, 1, MWC, main.primaryStage, main.pane); + String headingText = editHeadingText + " \"" + selectedGameTitle + "\""; + JFXEditGameDialog editGameDialog = new JFXEditGameDialog(headingText, editBodyText, dialogBtnStyle, 450, + 300, 1, MWC, main.getPrimaryStage(), main.getPane()); editGameDialog.setTitle(gameInfo[0]); editGameDialog.setCoverPath(gameInfo[1]); editGameDialog.setRomPath(gameInfo[2]); @@ -453,8 +503,8 @@ public class MainWindowController { public void handle(ActionEvent event) { try { LOGGER.info("remove " + selectedGameTitle + "(" + selectedGameTitleID + ")"); - String headingText = "remove \"" + selectedGameTitle + "\""; - String bodyText = "Are you sure you want to delete " + selectedGameTitle + " ?"; + String headingText = removeHeadingText + " \"" + selectedGameTitle + "\""; + String bodyText = removeBodyText + " " + selectedGameTitle + " ?"; EventHandler okayAction = new EventHandler() { @Override public void handle(ActionEvent event) { @@ -471,12 +521,12 @@ public class MainWindowController { EventHandler cancelAction = new EventHandler() { @Override public void handle(ActionEvent event) { - // do nothing + LOGGER.info("Action canceld by user!"); } }; JFXOkayCancelDialog removeGameDialog = new JFXOkayCancelDialog(headingText, bodyText, - dialogBtnStyle, 350, 170, okayAction, cancelAction, main.pane); + dialogBtnStyle, 350, 170, okayAction, cancelAction, main.getPane(), bundle); removeGameDialog.show(); } catch (Exception e) { LOGGER.error("error while removing " + selectedGameTitle + "(" + selectedGameTitleID + ")", e); @@ -489,23 +539,16 @@ public class MainWindowController { public void handle(ActionEvent event) { try { LOGGER.info("update: " + selectedGameTitleID); - String headingText = "update \"" + selectedGameTitle + "\""; - String bodyText = "pleas select the update root directory"; + String headingText = addUpdateHeadingText + " \"" + selectedGameTitle + "\""; EventHandler okayAction = new EventHandler() { @Override public void handle(ActionEvent event) { DirectoryChooser directoryChooser = new DirectoryChooser(); - File selectedDirecroty = directoryChooser.showDialog(main.primaryStage); + File selectedDirecroty = directoryChooser.showDialog(main.getPrimaryStage()); String updatePath = selectedDirecroty.getAbsolutePath(); String[] parts = selectedGameTitleID.split("-"); // split string into 2 parts at "-" File srcDir = new File(updatePath); - File destDir; - - if (System.getProperty("os.name").equals("Linux")) { - destDir = new File(cemuPath + "/mlc01/usr/title/" + parts[0] + "/" + parts[1]); - } else { - destDir = new File(cemuPath + "\\mlc01\\usr\\title\\" + parts[0] + "\\" + parts[1]); - } + File destDir = new File(cemuPath + "/mlc01/usr/title/" + parts[0] + "/" + parts[1]); // if directory doesn't exist create it if (destDir.exists() != true) { @@ -514,10 +557,10 @@ public class MainWindowController { try { LOGGER.info("copying the content of " + updatePath + " to " + destDir.toString()); - playBtn.setText("updating..."); + playBtn.setText(playBtnUpdating); playBtn.setDisable(true); - FileUtils.copyDirectory(srcDir, destDir); // TODO progress indicator - playBtn.setText("play"); + FileUtils.copyDirectory(srcDir, destDir); + playBtn.setText(playBtnPlay); playBtn.setDisable(false); LOGGER.info("copying files done!"); } catch (IOException e) { @@ -529,12 +572,12 @@ public class MainWindowController { EventHandler cancelAction = new EventHandler() { @Override public void handle(ActionEvent event) { - // do nothing + LOGGER.info("Action canceld by user!"); } }; - JFXOkayCancelDialog updateGameDialog = new JFXOkayCancelDialog(headingText, bodyText, - dialogBtnStyle, 350, 170, okayAction, cancelAction, main.pane); + JFXOkayCancelDialog updateGameDialog = new JFXOkayCancelDialog(headingText, addUpdateBodyText, + dialogBtnStyle, 350, 170, okayAction, cancelAction, main.getPane(), bundle); updateGameDialog.show(); } catch (Exception e) { LOGGER.warn("trying to update " + selectedGameTitleID + ",which is not a valid type!", e); @@ -547,23 +590,16 @@ public class MainWindowController { public void handle(ActionEvent event) { try { LOGGER.info("add DLC: " + selectedGameTitleID); - String headingText = "add a DLC to \"" + selectedGameTitle + "\""; - String bodyText = "pleas select the DLC root directory"; + String headingText = addDLCHeadingText + " \"" + selectedGameTitle + "\""; EventHandler okayAction = new EventHandler() { @Override public void handle(ActionEvent event) { DirectoryChooser directoryChooser = new DirectoryChooser(); - File selectedDirecroty = directoryChooser.showDialog(main.primaryStage); + File selectedDirecroty = directoryChooser.showDialog(main.getPrimaryStage()); String dlcPath = selectedDirecroty.getAbsolutePath(); String[] parts = selectedGameTitleID.split("-"); // split string into 2 parts at "-" File srcDir = new File(dlcPath); - File destDir; - if (System.getProperty("os.name").equals("Linux")) { - destDir = new File(cemuPath + "/mlc01/usr/title/" + parts[0] + "/" + parts[1] + "/aoc"); - } else { - destDir = new File( - cemuPath + "\\mlc01\\usr\\title\\" + parts[0] + "\\" + parts[1] + "\\aoc"); - } + File destDir = new File(cemuPath + "/mlc01/usr/title/" + parts[0] + "/" + parts[1] + "/aoc"); // if directory doesn't exist create it if (destDir.exists() != true) { @@ -572,10 +608,10 @@ public class MainWindowController { try { LOGGER.info("copying the content of " + dlcPath + " to " + destDir.toString()); - playBtn.setText("copying files..."); + playBtn.setText(playBtnCopyingFiles); playBtn.setDisable(true); - FileUtils.copyDirectory(srcDir, destDir); // TODO progress indicator - playBtn.setText("play"); + FileUtils.copyDirectory(srcDir, destDir); + playBtn.setText(playBtnPlay); playBtn.setDisable(false); LOGGER.info("copying files done!"); } catch (IOException e) { @@ -587,12 +623,12 @@ public class MainWindowController { EventHandler cancelAction = new EventHandler() { @Override public void handle(ActionEvent event) { - // do nothing + LOGGER.info("Action canceld by user!"); } }; - JFXOkayCancelDialog addDLCDialog = new JFXOkayCancelDialog(headingText, bodyText, dialogBtnStyle, - 350, 170, okayAction, cancelAction, main.pane); + JFXOkayCancelDialog addDLCDialog = new JFXOkayCancelDialog(headingText, addDLCBodyText, dialogBtnStyle, + 350, 170, okayAction, cancelAction, main.getPane(), bundle); addDLCDialog.show(); } catch (Exception e) { LOGGER.warn("trying to add a dlc to " + selectedGameTitleID + ",which is not a valid type!", e); @@ -650,7 +686,6 @@ public class MainWindowController { public void changed(ObservableValue observable, Object oldVal, Object newVal) { selected = courseTreeTable.getSelectionModel().getSelectedIndex(); // get selected item - // FIXME if a item is selected and you change the sorting,you can't select a new item id = idColumn.getCellData(selected); // get name of selected item for (int i = 0; i < courses.size(); i++) { @@ -695,6 +730,17 @@ public class MainWindowController { } } }); + + languageChoisBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Number value, Number new_value) { + String language = languageChoisBox.getItems().get((int) new_value).toString(); + language = language.substring(language.length()-6,language.length()-1); //reading only en_US from English (en_US) + setLanguage(language); + setUILanguage(); + saveSettings(); + } + }); branchChoisBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener() { @Override @@ -712,17 +758,7 @@ public class MainWindowController { @Override public void handle(MouseEvent mouseEvent) { if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){ - - String headingText = "cemu_UI"; - String bodyText = "cemu_UI is licensed under the terms of GNU GPL 3.\n\n" - + "JFoenix, Apache License 2.0\n" - + "minimal-json, MIT License\n" - + "sqlite-jdbc, Apache License 2.0\n" - + "Apache Commons IO, Apache License 2.0\n" - + "Apache Commons Logging, Apache License 2.0\n" - + "Apache Commons Codec, Apache License 2.0\n" - + "Apache Log4j 2, Apache License 2.0\n"; - + EventHandler okayAction = new EventHandler() { @Override public void handle(ActionEvent event) { @@ -750,16 +786,17 @@ public class MainWindowController { } JFXTextAreaInfoDialog licenseDialog = new JFXTextAreaInfoDialog(headingText, bodyText, - dialogBtnStyle, 510, 450, main.pane); + dialogBtnStyle, 510, 450, main.getPane()); licenseDialog.show(); licenseDialog.getTextArea().setEditable(false); } }; - JFXOkayCancelDialog licenseOverviewDialog = new JFXOkayCancelDialog(headingText, bodyText, dialogBtnStyle, - 350, 275, okayAction, cancelAction, main.pane); - licenseOverviewDialog.setCancelText("show licenses"); - licenseOverviewDialog.show(); + JFXOkayCancelDialog licenseOverviewDialog = new JFXOkayCancelDialog(licensesLblHeadingText, + licensesLblBodyText, dialogBtnStyle, 350, 275, okayAction, cancelAction, main.getPane(), + bundle); + licenseOverviewDialog.setCancelText(showLicenses); + licenseOverviewDialog.show(); } } }); @@ -774,12 +811,9 @@ public class MainWindowController { @FXML void aboutBtnAction() { - String headingText = "cemu_UI"; String bodyText = "cemu_UI by @Seil0 \nVersion: " + version + " (" + buildNumber + ") \"" + versionName + "\" \n" - + "This Application is made with free Software\n" - + "and licensed under the terms of GNU GPL 3.\n\n" - + "www.kellerkinder.xyz"; - JFXInfoDialog aboutDialog = new JFXInfoDialog(headingText, bodyText, dialogBtnStyle, 350, 200, main.pane); + + aboutBtnBodyText; + JFXInfoDialog aboutDialog = new JFXInfoDialog(aboutBtnHeadingText, bodyText, dialogBtnStyle, 350, 200, main.getPane()); aboutDialog.show(); } @@ -805,9 +839,9 @@ public class MainWindowController { JFXSpinner spinner = new JFXSpinner(); spinner.setPrefSize(30, 30); spinner.setStyle(" -fx-background-color: #f4f4f4;"); - main.pane.getChildren().add(spinner); - AnchorPane.setTopAnchor(spinner, (main.pane.getHeight()-spinner.getPrefHeight())/2); - AnchorPane.setLeftAnchor(spinner, (main.pane.getWidth()-spinner.getPrefWidth())/2); + main.getPane().getChildren().add(spinner); + AnchorPane.setTopAnchor(spinner, (main.getPane().getHeight()-spinner.getPrefHeight())/2); + AnchorPane.setLeftAnchor(spinner, (main.getPane().getWidth()-spinner.getPrefWidth())/2); Thread thread = new Thread(new Runnable() { @Override @@ -816,7 +850,7 @@ public class MainWindowController { Platform.runLater(() -> { refreshUIData(); // refresh the list of games displayed on screen - main.pane.getChildren().remove(spinner); + main.getPane().getChildren().remove(spinner); }); } }); @@ -838,7 +872,7 @@ public class MainWindowController { @Override public void run() { Platform.runLater(() -> { - smmdbDownloadBtn.setText("loading ..."); + smmdbDownloadBtn.setText(smmdbDownloadBtnLoading); smmdbDownloadBtn.setDisable(true); root.getChildren().remove(0,root.getChildren().size()); }); @@ -852,7 +886,7 @@ public class MainWindowController { Platform.runLater(() -> { root.getChildren().add(new TreeItem(helpCourse)); // add data to root-node - smmdbDownloadBtn.setText("Download"); + smmdbDownloadBtn.setText(smmdbDownloadBtnDownload); smmdbDownloadBtn.setDisable(false); }); } @@ -882,7 +916,7 @@ public class MainWindowController { @FXML void cemuTFBtnAction(ActionEvent event) { - File cemuDirectory = directoryChooser.showDialog(main.primaryStage); + File cemuDirectory = directoryChooser.showDialog(main.getPrimaryStage()); if (cemuDirectory == null) { LOGGER.info("No Directory selected"); } else { @@ -900,7 +934,7 @@ public class MainWindowController { @FXML void romTFBtnAction(ActionEvent event) { - File romDirectory = directoryChooser.showDialog(main.primaryStage); + File romDirectory = directoryChooser.showDialog(main.getPrimaryStage()); if (romDirectory == null) { LOGGER.info("No Directory selected"); } else { @@ -1034,10 +1068,6 @@ public class MainWindowController { if(cloudSync) { cloudSync = false; } else { - String headingText = "activate cloud savegame sync (beta)"; - String bodyText = "You just activate the cloud savegame sync function of cemu_UI, " - + "\nwhich is currently in beta. Are you sure you want to do this?"; - EventHandler okayAction = new EventHandler(){ @Override public void handle(ActionEvent event){ @@ -1050,19 +1080,16 @@ public class MainWindowController { @Override public void run() { - if (main.cloudController.initializeConnection(getCloudService(), getCemuPath())) { - main.cloudController.sync(getCloudService(), getCemuPath()); + if (main.getCloudController().initializeConnection(getCloudService(), getCemuPath())) { + main.getCloudController().sync(getCloudService(), getCemuPath(), main.getDirectory().getPath()); saveSettings(); } else { cloudSyncToggleBtn.setSelected(false); //cloud sync init error dialog - String headingText = "Error while initializing cloud sync!"; - String bodyText = "There was some truble adding your game." - + "\nPlease upload the app.log (which can be found in the cemu_UI directory)" - + "\nto \"https://github.com/Seil0/cemu_UI/issues\" so we can fix this."; - JFXInfoDialog cloudSyncErrorDialog = new JFXInfoDialog(headingText, bodyText, dialogBtnStyle, 450, 170, main.pane); - cloudSyncErrorDialog.show(); + JFXInfoDialog cloudSyncErrorDialog = new JFXInfoDialog(cloudSyncErrorHeadingText, + cloudSyncErrorBodyText, dialogBtnStyle, 450, 170, main.getPane()); + cloudSyncErrorDialog.show(); } } @@ -1078,9 +1105,10 @@ public class MainWindowController { } }; - JFXOkayCancelDialog cloudSyncErrorDialog = new JFXOkayCancelDialog(headingText, bodyText, dialogBtnStyle, - 419, 140, okayAction, cancelAction, main.pane); - cloudSyncErrorDialog.show(); + JFXOkayCancelDialog cloudSyncWarningDialog = new JFXOkayCancelDialog(cloudSyncWaringHeadingText, + cloudSyncWaringBodyText, dialogBtnStyle, 419, 140, okayAction, cancelAction, main.getPane(), + bundle); + cloudSyncWarningDialog.show(); } } @@ -1092,10 +1120,10 @@ public class MainWindowController { @FXML void addBtnAction(ActionEvent event) { - String headingText = "add a new game to cemu_UI"; - String bodyText = ""; + String headingText = addGameBtnHeadingText; + String bodyText = addGameBtnBodyText; JFXEditGameDialog addGameDialog = new JFXEditGameDialog(headingText, bodyText, dialogBtnStyle, 450, 300, 0, - this, main.primaryStage, main.pane); + this, main.getPrimaryStage(), main.getPane()); addGameDialog.show(); } @@ -1104,25 +1132,21 @@ public class MainWindowController { * and add them to the database and the UI */ public void addBtnReturn(String title, String coverPath, String romPath, String titleID) { - File pictureCache; - /** * if one parameter dosen't contain any value do not add the game * else convert the cover to .png add copy it into the picture cache, * then add the rom to the local_roms database */ - System.out.println(romPath.length()); if (romPath.length() == 0 || coverPath.length() == 0 || title.length() == 0 || titleID.length() == 0) { LOGGER.info("No parameter set!"); //addGame error dialog - String headingTextError = "Error while adding a new Game!"; - String bodyTextError = "There was some truble adding your game." - + "\nOne of the needed values was empty, please try again to add your game."; - JFXInfoDialog errorDialog = new JFXInfoDialog(headingTextError, bodyTextError, dialogBtnStyle, 350, 170, main.pane); - errorDialog.show(); + JFXInfoDialog errorDialog = new JFXInfoDialog(addBtnReturnErrorHeadingText, addBtnReturnErrorBodyText, + dialogBtnStyle, 350, 170, main.getPane()); + errorDialog.show(); - } else { + } else { + File pictureCache; String coverName = new File(coverPath).getName(); try { if (System.getProperty("os.name").equals("Linux")) { @@ -1134,8 +1158,8 @@ public class MainWindowController { BufferedImage originalImage = ImageIO.read(new File(coverPath)); //load cover int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); BufferedImage resizeImagePNG = resizeImage(originalImage, type, 400, 600); - ImageIO.write(resizeImagePNG, "png", new File(pictureCache+"\\"+coverName)); //save image to pictureCache - coverPath = pictureCache+"\\"+coverName; + coverPath = pictureCache + "/" + coverName; + ImageIO.write(resizeImagePNG, "png", new File(coverPath)); //save image to pictureCache } catch (IOException e) { LOGGER.error("Ops something went wrong! Error while resizing cover.", e); } @@ -1218,21 +1242,21 @@ public class MainWindowController { // setting last played, if lastPlayed is empty game was never played before, else set correct date if (dbController.getLastPlayed(titleID).equals("") || dbController.getLastPlayed(titleID).equals(null)) { - lastTimePlayedBtn.setText("Last played, never"); + lastTimePlayedBtn.setText(lastPlayed + never); totalPlaytimeBtn.setText(dbController.getTotalPlaytime(titleID) + " min"); } else { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - int today = Integer.parseInt(dtf.format(LocalDate.now()).replaceAll("-", "")); - int yesterday = Integer.parseInt(dtf.format(LocalDate.now().minusDays(1)).replaceAll("-", "")); - int lastPlayedDay = Integer.parseInt(dbController.getLastPlayed(titleID).replaceAll("-", "")); + int tToday = Integer.parseInt(dtf.format(LocalDate.now()).replaceAll("-", "")); + int tYesterday = Integer.parseInt(dtf.format(LocalDate.now().minusDays(1)).replaceAll("-", "")); + int tLastPlayedDay = Integer.parseInt(dbController.getLastPlayed(titleID).replaceAll("-", "")); - if (lastPlayedDay == today) { - lastTimePlayedBtn.setText("Last played, today"); - } else if (lastPlayedDay == yesterday) { - lastTimePlayedBtn.setText("Last played, yesterday"); + if (tLastPlayedDay == tToday) { + lastTimePlayedBtn.setText(lastPlayed + today); + } else if (tLastPlayedDay == tYesterday) { + lastTimePlayedBtn.setText(lastPlayed + yesterday); } else { - lastTimePlayedBtn.setText("Last played, " + dbController.getLastPlayed(titleID)); + lastTimePlayedBtn.setText(lastPlayed + dbController.getLastPlayed(titleID)); } } @@ -1295,17 +1319,86 @@ public class MainWindowController { } } - void refreshplayBtnPosition() { - double width; - - if (mainAnchorPane.getWidth() < 10) { - width = mainAnchorPane.getPrefWidth(); - } else { - width = mainAnchorPane.getWidth(); - } - playBtn.setLayoutX((width / 2) - 50); - totalPlaytimeBtn.setLayoutX((width / 2) - 50 - 20.5 - 100); - lastTimePlayedBtn.setLayoutX((width / 2) + 50 + 20.5); + void setUILanguage(){ + switch(getLanguage()){ + case "en_US": + bundle = ResourceBundle.getBundle("locals.cemu_UI-Local", Locale.US); //us_English + languageChoisBox.getSelectionModel().select(0); + break; + case "de_DE": + bundle = ResourceBundle.getBundle("locals.cemu_UI-Local", Locale.GERMAN); //German + languageChoisBox.getSelectionModel().select(1); + break; + default: + bundle = ResourceBundle.getBundle("locals.cemu_UI-Local", Locale.US); //default local + languageChoisBox.getSelectionModel().select(0); + break; + } + + // Buttons + aboutBtn.setText(bundle.getString("aboutBtn")); + settingsBtn.setText(bundle.getString("settingsBtn")); + addBtn.setText(bundle.getString("addBtn")); + reloadRomsBtn.setText(bundle.getString("reloadRomsBtn")); + smmdbBtn.setText(bundle.getString("smmdbBtn")); + cemuTFBtn.setText(bundle.getString("cemuTFBtn")); + romTFBtn.setText(bundle.getString("romTFBtn")); + updateBtn.setText(bundle.getString("updateBtnCheckNow")); + smmdbDownloadBtn.setText(bundle.getString("smmdbDownloadBtn")); + playBtn.setText(bundle.getString("playBtn")); + cloudSyncToggleBtn.setText(bundle.getString("cloudSyncToggleBtn")); + autoUpdateToggleBtn.setText(bundle.getString("autoUpdateToggleBtn")); + fullscreenToggleBtn.setText(bundle.getString("fullscreenToggleBtn")); + + // Labels + cemu_UISettingsLbl.setText(bundle.getString("cemu_UISettingsLbl")); + cemuDirectoryLbl.setText(bundle.getString("cemuDirectoryLbl")); + romDirectoryLbl.setText(bundle.getString("romDirectoryLbl")); + mainColorLbl.setText(bundle.getString("mainColorLbl")); + languageLbl.setText(bundle.getString("languageLbl")); + updateLbl.setText(bundle.getString("updateLbl")); + branchLbl.setText(bundle.getString("branchLbl")); + cemuSettingsLbl.setText(bundle.getString("cemuSettingsLbl")); + licensesLbl.setText(bundle.getString("licensesLbl")); + + // Columns + titleColumn.setText(bundle.getString("titleColumn")); + idColumn.setText(bundle.getString("idColumn")); + starsColumn.setText(bundle.getString("starsColumn")); + timeColumn.setText(bundle.getString("timeColumn")); + + // Strings + editHeadingText = bundle.getString("editHeadingText"); + editBodyText = bundle.getString("editBodyText"); + removeHeadingText = bundle.getString("removeHeadingText"); + removeBodyText = bundle.getString("removeBodyText"); + addUpdateHeadingText = bundle.getString("addUpdateHeadingText"); + addUpdateBodyText = bundle.getString("addUpdateBodyText"); + addDLCHeadingText = bundle.getString("addDLCHeadingText"); + addDLCBodyText = bundle.getString("addDLCBodyText"); + licensesLblHeadingText = bundle.getString("licensesLblHeadingText"); + licensesLblBodyText = bundle.getString("licensesLblBodyText"); + showLicenses = bundle.getString("showLicenses"); + aboutBtnHeadingText = bundle.getString("aboutBtnHeadingText"); + aboutBtnBodyText = bundle.getString("aboutBtnBodyText"); + cloudSyncWaringHeadingText = bundle.getString("cloudSyncWaringHeadingText"); + cloudSyncWaringBodyText = bundle.getString("cloudSyncWaringBodyText"); + cloudSyncErrorHeadingText = bundle.getString("cloudSyncErrorHeadingText"); + cloudSyncErrorBodyText = bundle.getString("cloudSyncErrorBodyText"); + addGameBtnHeadingText = bundle.getString("addGameBtnHeadingText"); + addGameBtnBodyText = bundle.getString("addGameBtnBodyText"); + addBtnReturnErrorHeadingText = bundle.getString("addBtnReturnErrorHeadingText"); + addBtnReturnErrorBodyText = bundle.getString("addBtnReturnErrorBodyText"); + lastPlayed = bundle.getString("lastPlayed"); + today = bundle.getString("today"); + yesterday = bundle.getString("yesterday"); + never = bundle.getString("never"); + + playBtnPlay = bundle.getString("playBtnPlay"); + playBtnUpdating = bundle.getString("playBtnUpdating"); + playBtnCopyingFiles = bundle.getString("playBtnCopyingFiles"); + smmdbDownloadBtnLoading = bundle.getString("smmdbDownloadBtnLoading"); + smmdbDownloadBtnDownload = bundle.getString("smmdbDownloadBtnDownload"); } private void checkAutoUpdate() { @@ -1547,6 +1640,7 @@ public class MainWindowController { props.setProperty("cemuPath", getCemuPath()); props.setProperty("romPath", getRomPath()); props.setProperty("color", getColor()); + props.setProperty("language", getLanguage()); props.setProperty("fullscreen", String.valueOf(isFullscreen())); props.setProperty("cloudSync", String.valueOf(isCloudSync())); props.setProperty("autoUpdate", String.valueOf(isAutoUpdate())); @@ -1556,7 +1650,8 @@ public class MainWindowController { } else { props.setProperty("cloudService", getCloudService()); } - props.setProperty("folderID", main.cloudController.getFolderID(getCloudService())); + props.setProperty("folderID", main.getCloudController().getFolderID(getCloudService())); + props.setProperty("lastLocalSync", String.valueOf(getLastLocalSync())); props.setProperty("windowWidth", String.valueOf(mainAnchorPane.getWidth())); props.setProperty("windowHeight", String.valueOf(mainAnchorPane.getHeight())); if(System.getProperty("os.name").equals("Linux")){ @@ -1608,6 +1703,13 @@ public class MainWindowController { setColor("00a8cc"); } + if (props.getProperty("language") == null) { + LOGGER.error("cloud not load language, setting default instead"); + setLanguage("en_US"); + } else { + setLanguage(props.getProperty("language")); + } + try { setFullscreen(Boolean.parseBoolean(props.getProperty("fullscreen"))); } catch (Exception e) { @@ -1644,11 +1746,18 @@ public class MainWindowController { } try { - main.cloudController.setFolderID(props.getProperty("folderID"), getCloudService()); + main.getCloudController().setFolderID(props.getProperty("folderID"), getCloudService()); } catch (Exception e) { LOGGER.error("could not load folderID, disable cloud sync. Please contact an developer", e); setCloudSync(false); } + + try { + setLastLocalSync(Long.parseLong(props.getProperty("lastLocalSync"))); + } catch (Exception e) { + LOGGER.error("could not load lastSuccessSync, setting default instead", e); + setLastLocalSync(0); + } try { setWindowWidth(Double.parseDouble(props.getProperty("windowWidth"))); @@ -1689,43 +1798,21 @@ public class MainWindowController { } private void playBtnSlideIn(){ - playBtn.setVisible(true); - lastTimePlayedBtn.setVisible(true); - totalPlaytimeBtn.setVisible(true); + bottomHBox.setVisible(true); playTrue = true; - TranslateTransition playBtnTransition = new TranslateTransition(Duration.millis(300), playBtn); + TranslateTransition playBtnTransition = new TranslateTransition(Duration.millis(300), bottomHBox); playBtnTransition.setFromY(56); playBtnTransition.setToY(0); playBtnTransition.play(); - - TranslateTransition lastTimePlayedBtnTransition = new TranslateTransition(Duration.millis(300), lastTimePlayedBtn); - lastTimePlayedBtnTransition.setFromY(56); - lastTimePlayedBtnTransition.setToY(0); - lastTimePlayedBtnTransition.play(); - - TranslateTransition timePlayedBtnTransition = new TranslateTransition(Duration.millis(300), totalPlaytimeBtn); - timePlayedBtnTransition.setFromY(56); - timePlayedBtnTransition.setToY(0); - timePlayedBtnTransition.play(); } private void playBtnSlideOut(){ playTrue = false; - TranslateTransition playBtnTransition = new TranslateTransition(Duration.millis(300), playBtn); + TranslateTransition playBtnTransition = new TranslateTransition(Duration.millis(300), bottomHBox); playBtnTransition.setFromY(0); playBtnTransition.setToY(56); playBtnTransition.play(); - - TranslateTransition lastTimePlayedBtnTransition = new TranslateTransition(Duration.millis(300), lastTimePlayedBtn); - lastTimePlayedBtnTransition.setFromY(0); - lastTimePlayedBtnTransition.setToY(56); - lastTimePlayedBtnTransition.play(); - - TranslateTransition timePlayedBtnTransition = new TranslateTransition(Duration.millis(300), totalPlaytimeBtn); - timePlayedBtnTransition.setFromY(0); - timePlayedBtnTransition.setToY(56); - timePlayedBtnTransition.play(); } private void editColor(String input){ @@ -1831,6 +1918,14 @@ public class MainWindowController { this.xPosHelper = xPosHelper; } + public long getLastLocalSync() { + return lastLocalSync; + } + + public void setLastLocalSync(long lastLocalSync) { + this.lastLocalSync = lastLocalSync; + } + public boolean isFullscreen() { return fullscreen; } @@ -1919,6 +2014,22 @@ public class MainWindowController { this.oldXPosHelper = oldXPosHelper; } + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ResourceBundle getBundle() { + return bundle; + } + + public void setBundle(ResourceBundle bundle) { + this.bundle = bundle; + } + public AnchorPane getMainAnchorPane() { return mainAnchorPane; } diff --git a/src/main/java/com/cemu_UI/application/playGame.java b/src/main/java/com/cemu_UI/application/playGame.java index 89d8474..b6afd6b 100644 --- a/src/main/java/com/cemu_UI/application/playGame.java +++ b/src/main/java/com/cemu_UI/application/playGame.java @@ -22,21 +22,22 @@ package com.cemu_UI.application; import java.io.IOException; +import java.time.Instant; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.cemu_UI.controller.dbController; +import com.cemu_UI.controller.DBController; import javafx.application.Platform; public class playGame extends Thread{ MainWindowController mainWindowController; - dbController dbController; + DBController dbController; private static final Logger LOGGER = LogManager.getLogger(playGame.class.getName()); - public playGame(MainWindowController m, com.cemu_UI.controller.dbController db){ + public playGame(MainWindowController m, com.cemu_UI.controller.DBController db){ mainWindowController = m; dbController = db; } @@ -52,7 +53,7 @@ public class playGame extends Thread{ Process p; Platform.runLater(() -> { - mainWindowController.main.primaryStage.setIconified(true); + mainWindowController.main.getPrimaryStage().setIconified(true); // minimize cemu_UI }); startTime = System.currentTimeMillis(); try{ @@ -86,14 +87,15 @@ public class playGame extends Thread{ }else{ mainWindowController.totalPlaytimeBtn.setText(dbController.getTotalPlaytime(selectedGameTitleID)+ " min"); } - mainWindowController.main.primaryStage.setIconified(false); + mainWindowController.main.getPrimaryStage().setIconified(false); // maximize cemu_UI }); -// System.out.println(mainWindowController.getCemuPath()+"/mlc01/emulatorSave/"+); //sync savegame with cloud service - if(mainWindowController.isCloudSync()) { - mainWindowController.main.cloudController.sync(mainWindowController.getCloudService(), mainWindowController.getCemuPath()); - } + if (mainWindowController.isCloudSync()) { + mainWindowController.setLastLocalSync(Instant.now().getEpochSecond()); + mainWindowController.main.getCloudController().sync(mainWindowController.getCloudService(), + mainWindowController.getCemuPath(), mainWindowController.main.getDirectory().getPath()); + } }catch (IOException | InterruptedException e){ e.printStackTrace(); diff --git a/src/main/java/com/cemu_UI/controller/CloudController.java b/src/main/java/com/cemu_UI/controller/CloudController.java index f2db2fd..3358eb4 100644 --- a/src/main/java/com/cemu_UI/controller/CloudController.java +++ b/src/main/java/com/cemu_UI/controller/CloudController.java @@ -22,7 +22,12 @@ package com.cemu_UI.controller; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.time.Instant; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -31,6 +36,8 @@ import com.cemu_UI.application.MainWindowController; import com.cemu_UI.vendorCloudController.GoogleDriveController; import javafx.application.Platform; +import net.lingala.zip4j.core.ZipFile; +import net.lingala.zip4j.exception.ZipException; public class CloudController { @@ -63,105 +70,144 @@ public class CloudController { LOGGER.info("cloud initialisation done!"); return success; } - - public void stratupCheck(String cloudService, String cemuDirectory) { - if(cloudService.equals("GoogleDrive")) { - LOGGER.info("starting startup check google drive ..."); - try { - if (!googleDriveController.checkFolder()) { - googleDriveController.creatFolder(); - mwc.saveSettings(); - - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - Platform.runLater(() -> { - mwc.getPlayBtn().setText("syncing..."); - }); - googleDriveController.uploadAllFiles(); - Platform.runLater(() -> { - mwc.getPlayBtn().setText("play"); - }); - } - }); - thread.start(); - } else { - sync(cloudService, cemuDirectory); - } - } catch (IOException e) { - LOGGER.error("google drive startup check failed", e); - } - } - if(cloudService.equals("Dropbox")) { - - } - } - - - - public void sync(String cloudService, String cemuDirectory) { - - //running sync in a new thread, instead of blocking the main thread + + /** + * to trigger a new sync set the mwc LastLocalSync to the actual time and call the sync method + * @param cloudService + * @param cemuDirectory + * @param cemu_UIDirectory + */ + public void sync(String cloudService, String cemuDirectory, String cemu_UIDirectory) { + + // running sync in a new thread, instead of blocking the main thread Thread thread = new Thread(new Runnable() { @Override public void run() { - Platform.runLater(() -> { - mwc.getPlayBtn().setText("syncing..."); - }); - LOGGER.info("starting synchronization in new thread ..."); - - if(cloudService.equals("GoogleDrive")) { - try { - googleDriveController.sync(cemuDirectory); - } catch (IOException e) { - LOGGER.error("google drive synchronization failed", e); - } - } - if(cloudService.equals("Dropbox")) { - - } - Platform.runLater(() -> { - mwc.getPlayBtn().setText("play"); - mwc.saveSettings(); - }); - LOGGER.info("synchronization successful!"); - } - }); - thread.start(); - - } - - void uploadFile(String cloudService, File file) { - - //running uploadFile in a new thread, instead of blocking the main thread - new Thread() { - @Override - public void run() { - LOGGER.info("starting uploadFile in new thread ..."); - - if(cloudService.equals("GoogleDrive")) { - try { - googleDriveController.uploadFile(file); - } catch (IOException e) { - LOGGER.error("google drive uploadFile failed" ,e); - } - } - if(cloudService.equals("Dropbox")) { + try { + Platform.runLater(() -> { + mwc.getPlayBtn().setDisable(true); + mwc.getPlayBtn().setText("syncing..."); + }); + LOGGER.info("starting synchronization in new thread ..."); + + // zip the saves folder + File zipFile = zipSavegames(cemu_UIDirectory, cemuDirectory); - } - } - }.start(); + // upload the zip + switch (cloudService) { + + // use GoogleDriveController + case "GoogleDrive": + LOGGER.info("using GoogleDriveController"); + long lastCloudSync = googleDriveController.getLastCloudSync(); + + if (!googleDriveController.checkFolder()) { + LOGGER.info("cloud sync folder dosen't exist, creating one!"); + googleDriveController.creatFolder(); + googleDriveController.uploadZipFile(zipFile); + } else if (mwc.getLastLocalSync() > lastCloudSync) { + LOGGER.info("local is new, going to upload zip"); + googleDriveController.uploadZipFile(zipFile); + } else if(mwc.getLastLocalSync() < lastCloudSync) { + LOGGER.info("cloud is new, going to download zip"); + unzipSavegames(cemuDirectory, googleDriveController.downloadZipFile(cemu_UIDirectory)); + mwc.setLastLocalSync(lastCloudSync); + break; + } else { + LOGGER.info("nothing to do"); + break; + } + mwc.setLastLocalSync(Long.parseLong(zipFile.getName().substring(0, zipFile.getName().length()-4))); // set time of last sucessfull sync + break; + + + + case "Dropbox": + + break; + + + default: + LOGGER.warn("no cloud vendor found!"); + break; + } + + zipFile.delete(); // delete zipfile in cem_UI directory + + Platform.runLater(() -> { + mwc.getPlayBtn().setText("play"); + mwc.getPlayBtn().setDisable(false); + mwc.saveSettings(); + }); + + + LOGGER.info("synchronization successful!"); + } catch (Exception e) { + LOGGER.error("There was an error during syncronisation! Please open a new issue on the cemu_UI github page:", e); + } + } + }); + thread.start(); + } + private File zipSavegames(String cemu_UIDirectory, String cemuDirectory) throws Exception { + long unixTimestamp = Instant.now().getEpochSecond(); + FileOutputStream fos = new FileOutputStream(cemu_UIDirectory + "/" + unixTimestamp + ".zip"); + ZipOutputStream zos = new ZipOutputStream(fos); + addDirToZipArchive(zos, new File(cemuDirectory + "/mlc01/usr/save"), null); + zos.flush(); + fos.flush(); + zos.close(); + fos.close(); + return new File(cemu_UIDirectory + "/" + unixTimestamp + ".zip"); + } + + private static void addDirToZipArchive(ZipOutputStream zos, File fileToZip, String parrentDirectoryName) throws Exception { + if (fileToZip == null || !fileToZip.exists()) { + return; + } + + String zipEntryName = fileToZip.getName(); + if (parrentDirectoryName!=null && !parrentDirectoryName.isEmpty()) { + zipEntryName = parrentDirectoryName + "/" + fileToZip.getName(); + } + + if (fileToZip.isDirectory()) { + for (File file : fileToZip.listFiles()) { + addDirToZipArchive(zos, file, zipEntryName); + } + } else { + byte[] buffer = new byte[1024]; + FileInputStream fis = new FileInputStream(fileToZip); + zos.putNextEntry(new ZipEntry(zipEntryName)); + int length; + while ((length = fis.read(buffer)) > 0) { + zos.write(buffer, 0, length); + } + zos.closeEntry(); + fis.close(); + } + } + + private void unzipSavegames(String cemuDirectory, File outputFile) { + try { + ZipFile zipFile = new ZipFile(outputFile); + zipFile.extractAll(cemuDirectory + "/mlc01/usr"); + outputFile.delete(); + LOGGER.info("unzip successfull"); + } catch (ZipException e) { + LOGGER.error("an error occurred during unziping the file!", e); + } } public String getFolderID(String cloudService) { String folderID = ""; if (cloudService != null) { - if(cloudService.equals("GoogleDrive")) { + if (cloudService.equals("GoogleDrive")) { folderID = googleDriveController.getFolderID(); } - if(cloudService.equals("Dropbox")) { - + if (cloudService.equals("Dropbox")) { + } } return folderID; @@ -173,8 +219,9 @@ public class CloudController { googleDriveController.setFolderID(folderID); } if (cloudService.equals("Dropbox")) { - + } } } + } diff --git a/src/main/java/com/cemu_UI/controller/dbController.java b/src/main/java/com/cemu_UI/controller/DBController.java similarity index 88% rename from src/main/java/com/cemu_UI/controller/dbController.java rename to src/main/java/com/cemu_UI/controller/DBController.java index be4facf..394b7ca 100644 --- a/src/main/java/com/cemu_UI/controller/dbController.java +++ b/src/main/java/com/cemu_UI/controller/DBController.java @@ -47,10 +47,10 @@ import org.xml.sax.SAXException; import com.cemu_UI.application.MainWindowController; -public class dbController { +public class DBController { - public dbController(MainWindowController m) { - mainWindowController = m; + public DBController(MainWindowController mwc) { + mainWindowController = mwc; } private MainWindowController mainWindowController; @@ -59,9 +59,14 @@ public class dbController { private String DB_PATH_games; private Connection connection = null; private Connection connectionGames = null; - private static final Logger LOGGER = LogManager.getLogger(dbController.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(DBController.class.getName()); - public void main(){ + /** + * initialize the sqlite database controller + * load ROM and games database + * load all games + */ + public void init(){ LOGGER.info("<==========starting loading sql==========>"); loadRomDatabase(); loadGamesDatabase(); @@ -97,13 +102,13 @@ public class dbController { * set the path to the localRoms.db file and initialize the connection * * games.dbcontains a reverence list to for the automatic detection mode - * TODO this should be called ReferenceGameList the games table should be called reference_games + * TODO rework paths */ private void loadGamesDatabase() { if (System.getProperty("os.name").equals("Linux")) { - DB_PATH_games = System.getProperty("user.home") + "/cemu_UI/games.db"; + DB_PATH_games = System.getProperty("user.home") + "/cemu_UI/reference_games.db"; } else { - DB_PATH_games = System.getProperty("user.home") + "\\Documents\\cemu_UI" + "\\" + "games.db"; + DB_PATH_games = System.getProperty("user.home") + "\\Documents\\cemu_UI" + "\\" + "reference_games.db"; } try { // create a database connection @@ -221,37 +226,30 @@ public class dbController { LOGGER.info("Getting all .rpx files in " + dir.getCanonicalPath()+" including those in subdirectories"); // for all files in dir get the app.xml for (File file : files) { - if(System.getProperty("os.name").equals("Linux")){ - appFile = new File(file.getParent()+"/app.xml"); - } else { - appFile = new File(file.getParent()+"\\app.xml"); - } + appFile = new File(file.getParent() + "/app.xml"); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(appFile); - String title_ID = document.getElementsByTagName("title_id").item(0).getTextContent(); //get titile_ID from app.xml + String title_ID = document.getElementsByTagName("title_id").item(0).getTextContent(); // get titile_ID from app.xml title_ID = title_ID.substring(0, 8) + "-" + title_ID.substring(8, title_ID.length()); - LOGGER.info("Name: "+file.getName()+"; Title ID: "+title_ID); - ResultSet rs = stmt.executeQuery("SELECT * FROM games WHERE TitleID = '"+title_ID+"';"); + LOGGER.info("Name: " + file.getName() + "; Title ID: " + title_ID); + ResultSet rs = stmt.executeQuery("SELECT * FROM games WHERE TitleID = '" + title_ID + "';"); + // for all elements in the games table check if it's already present, else add it while (rs.next()) { if (checkEntry(rs.getString(2))) { LOGGER.info(rs.getString(2) + ": game already in database"); - }else{ + } else { LOGGER.info("adding cover to cache ..."); - BufferedImage originalImage = ImageIO.read(new URL(rs.getString(6)));//change path to where file is located - int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); - BufferedImage resizeImagePNG = resizeImage(originalImage, type, 400, 600); - if(System.getProperty("os.name").equals("Linux")) { - ImageIO.write(resizeImagePNG, "png", new File(pictureCache+"/"+rs.getString(3)+".png")); //change path where you want it saved - coverPath = pictureCache+"/"+rs.getString(3)+".png"; - } else { - ImageIO.write(resizeImagePNG, "png", new File(pictureCache+"\\"+rs.getString(3)+".png")); //change path where you want it saved - coverPath = pictureCache+"\\"+rs.getString(3)+".png"; - } - + BufferedImage originalImage = ImageIO.read(new URL(rs.getString(6)));// change path to where file is located + int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); + BufferedImage resizeImagePNG = resizeImage(originalImage, type, 400, 600); + + ImageIO.write(resizeImagePNG, "png", new File(pictureCache + "/" + rs.getString(3) + ".png")); + coverPath = pictureCache + "/" + rs.getString(3) + ".png"; LOGGER.info(rs.getString(2) + ": adding ROM"); - addGame(rs.getString(2), coverPath, file.getCanonicalPath(), rs.getString(1), rs.getString(3), rs.getString(5),"","0"); + addGame(rs.getString(2), coverPath, file.getCanonicalPath(), rs.getString(1), rs.getString(3), + rs.getString(5), "", "0"); } } } diff --git a/src/main/java/com/cemu_UI/controller/UpdateController.java b/src/main/java/com/cemu_UI/controller/UpdateController.java index 6b7d820..a7d69be 100644 --- a/src/main/java/com/cemu_UI/controller/UpdateController.java +++ b/src/main/java/com/cemu_UI/controller/UpdateController.java @@ -40,7 +40,6 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonValue; - import javafx.application.Platform; public class UpdateController implements Runnable { @@ -49,9 +48,12 @@ public class UpdateController implements Runnable { private String buildNumber; private String apiOutput; private String updateBuildNumber; // tag_name from Github +// private String updateName; +// private String updateChanges; private String browserDownloadUrl; // update download link private String githubApiRelease = "https://api.github.com/repos/Seil0/cemu_UI/releases/latest"; private String githubApiBeta = "https://api.github.com/repos/Seil0/cemu_UI/releases"; + private URL githubApiUrl; private boolean useBeta; private static final Logger LOGGER = LogManager.getLogger(UpdateController.class.getName()); @@ -70,7 +72,7 @@ public class UpdateController implements Runnable { public void run() { LOGGER.info("beta:" + useBeta + "; checking for updates ..."); Platform.runLater(() -> { - mainWindowController.getUpdateBtn().setText("checking for updates ..."); + mainWindowController.getUpdateBtn().setText(mainWindowController.getBundle().getString("updateBtnChecking")); }); try { @@ -97,8 +99,8 @@ public class UpdateController implements Runnable { JsonArray objectAssets = object.asObject().get("assets").asArray(); updateBuildNumber = object.asObject().getString("tag_name", ""); - // updateName = object.asObject().getString("name", ""); - // updateChanges = object.asObject().getString("body", ""); +// updateName = object.asObject().getString("name", ""); +// updateChanges = object.asObject().getString("body", ""); for (JsonValue asset : objectAssets) { browserDownloadUrl = asset.asObject().getString("browser_download_url", ""); @@ -109,8 +111,8 @@ public class UpdateController implements Runnable { JsonArray objectAssets = Json.parse(apiOutput).asObject().get("assets").asArray(); updateBuildNumber = object.getString("tag_name", ""); - // updateName = object.getString("name", ""); - // updateChanges = object.getString("body", ""); +// updateName = object.getString("name", ""); +// updateChanges = object.getString("body", ""); for (JsonValue asset : objectAssets) { browserDownloadUrl = asset.asObject().getString("browser_download_url", ""); @@ -126,26 +128,26 @@ public class UpdateController implements Runnable { if (iversion >= iaktVersion) { Platform.runLater(() -> { - mainWindowController.getUpdateBtn().setText("no update available"); + mainWindowController.getUpdateBtn().setText(mainWindowController.getBundle().getString("updateBtnNoUpdateAvailable")); }); LOGGER.info("no update available"); } else { Platform.runLater(() -> { - mainWindowController.getUpdateBtn().setText("update available"); + mainWindowController.getUpdateBtn().setText(mainWindowController.getBundle().getString("updateBtnUpdateAvailable")); }); LOGGER.info("update available"); LOGGER.info("download link: " + browserDownloadUrl); try { // open new Http connection, ProgressMonitorInputStream for downloading the data - HttpURLConnection conn = (HttpURLConnection) new URL(browserDownloadUrl).openConnection(); - ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, "Downloading...", conn.getInputStream()); + HttpURLConnection connection = (HttpURLConnection) new URL(browserDownloadUrl).openConnection(); + ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, "Downloading...", connection.getInputStream()); ProgressMonitor pm = pmis.getProgressMonitor(); pm.setMillisToDecideToPopup(0); pm.setMillisToPopup(0); - pm.setMinimum(0);// tell the progress bar that we start at the beginning of the stream - pm.setMaximum(conn.getContentLength());// tell the progress bar the total number of bytes we are going to read. + pm.setMinimum(0);// set beginning of the progress bar to 0 + pm.setMaximum(connection.getContentLength());// set the end to the file length FileUtils.copyInputStreamToFile(pmis, new File("cemu_UI_update.jar")); // download update - org.apache.commons.io.FileUtils.copyFile(new File("cemu_UI_update.jar"), new File("cemu_UI.jar")); // TODO rename update to old name + org.apache.commons.io.FileUtils.copyFile(new File("cemu_UI_update.jar"), new File("cemu_UI.jar")); org.apache.commons.io.FileUtils.deleteQuietly(new File("cemu_UI_update.jar")); // delete update Runtime.getRuntime().exec("java -jar cemu_UI.jar"); // start again System.exit(0); // finishes itself diff --git a/src/main/java/com/cemu_UI/uiElements/JFXEditGameDialog.java b/src/main/java/com/cemu_UI/uiElements/JFXEditGameDialog.java index 3e25f36..c5cdb67 100644 --- a/src/main/java/com/cemu_UI/uiElements/JFXEditGameDialog.java +++ b/src/main/java/com/cemu_UI/uiElements/JFXEditGameDialog.java @@ -88,18 +88,15 @@ public class JFXEditGameDialog { StackPane stackPane = new StackPane(); stackPane.autosize(); JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true); - - Label placeholder = new Label(); - placeholder.setPrefSize(15, 10); - + TextField gameTitleTF = new TextField(); - gameTitleTF.setPromptText("game tile"); + gameTitleTF.setPromptText(mwc.getBundle().getString("gameTitle")); TextField gameTitleIDTF = new TextField(); - gameTitleIDTF.setPromptText("title ID"); + gameTitleIDTF.setPromptText(mwc.getBundle().getString("titleID")); TextField romPathTF = new TextField(); - romPathTF.setPromptText("ROM path"); + romPathTF.setPromptText(mwc.getBundle().getString("romPath")); TextField gameCoverTF = new TextField(); - gameCoverTF.setPromptText("cover path"); + gameCoverTF.setPromptText(mwc.getBundle().getString("coverPath")); if (mode == 1) { gameTitleTF.setText(title); @@ -110,7 +107,7 @@ public class JFXEditGameDialog { gameTitleIDTF.setEditable(false); } - JFXButton okayBtn = new JFXButton("Okay"); + JFXButton okayBtn = new JFXButton(mwc.getBundle().getString("okayBtnText")); okayBtn.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { @@ -120,9 +117,8 @@ public class JFXEditGameDialog { // LOGGER.info("No parameter set!"); // addGame error dialog - String headingTextError = "Error while adding a new Game!"; - String bodyTextError = "There was some truble adding your game." - + "\nOne of the needed values was empty, please try again to add your game."; + String headingTextError = mwc.getBundle().getString("editGameDialogHeadingTextError"); + String bodyTextError = mwc.getBundle().getString("editGameDialogBodyTextError"); JFXInfoDialog errorDialog = new JFXInfoDialog(headingTextError, bodyTextError, dialogBtnStyle, 350,170, pane); errorDialog.show(); } else { @@ -150,7 +146,7 @@ public class JFXEditGameDialog { okayBtn.setPrefHeight(32); okayBtn.setStyle(dialogBtnStyle); - JFXButton cancelBtn = new JFXButton("Cancel"); + JFXButton cancelBtn = new JFXButton(mwc.getBundle().getString("cancelBtnText")); cancelBtn.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { @@ -161,7 +157,7 @@ public class JFXEditGameDialog { cancelBtn.setPrefHeight(32); cancelBtn.setStyle(dialogBtnStyle); - JFXButton selectPathBtn = new JFXButton("select .rpx file"); + JFXButton selectPathBtn = new JFXButton(mwc.getBundle().getString("editGameDialogSelectPathBtn")); selectPathBtn.setPrefWidth(110); selectPathBtn.setStyle(dialogBtnStyle); selectPathBtn.setOnAction(new EventHandler() { @@ -173,7 +169,7 @@ public class JFXEditGameDialog { } }); - JFXButton selectCoverBtn = new JFXButton("select cover file"); + JFXButton selectCoverBtn = new JFXButton(mwc.getBundle().getString("editGameDialogSelectCoverBtn")); selectCoverBtn.setPrefWidth(110); selectCoverBtn.setStyle(dialogBtnStyle); selectCoverBtn.setOnAction(new EventHandler() { @@ -189,14 +185,14 @@ public class JFXEditGameDialog { grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(15, 10, 10, 10)); - grid.add(new Label("game title:"), 0, 0); + grid.add(new Label(mwc.getBundle().getString("gameTitle") + ":"), 0, 0); grid.add(gameTitleTF, 1, 0); - grid.add(new Label("title id:"), 0, 1); + grid.add(new Label(mwc.getBundle().getString("titleID") + ":"), 0, 1); grid.add(gameTitleIDTF, 1, 1); - grid.add(new Label("ROM path:"), 0, 2); + grid.add(new Label(mwc.getBundle().getString("romPath") + ":"), 0, 2); grid.add(romPathTF, 1, 2); grid.add(selectPathBtn, 2, 2); - grid.add(new Label("cover path:"), 0, 3); + grid.add(new Label(mwc.getBundle().getString("coverPath") + ":"), 0, 3); grid.add(gameCoverTF, 1, 3); grid.add(selectCoverBtn, 2, 3); @@ -207,7 +203,7 @@ public class JFXEditGameDialog { content.setHeading(new Text(headingText)); content.setBody(vbox); - content.setActions(cancelBtn, placeholder, okayBtn); + content.setActions(cancelBtn, okayBtn); content.setPrefSize(dialogWidth, dialogHeight); pane.getChildren().add(stackPane); AnchorPane.setTopAnchor(stackPane, (pane.getHeight()-content.getPrefHeight())/2); diff --git a/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java b/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java index 4bf378f..5dd4d1a 100644 --- a/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java +++ b/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java @@ -22,13 +22,14 @@ package com.cemu_UI.uiElements; +import java.util.ResourceBundle; + import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialogLayout; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.Label; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; @@ -39,8 +40,8 @@ public class JFXOkayCancelDialog { private String headingText; private String bodyText; private String dialogBtnStyle; - private String okayText = "okay"; - private String cancelText = "cancel"; + private String okayText; + private String cancelText; private int dialogWidth; private int dialogHeight; private EventHandler okayAction; @@ -59,7 +60,8 @@ public class JFXOkayCancelDialog { * @param pane pane to which the dialog belongs */ public JFXOkayCancelDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth, - int dialogHeight, EventHandler okayAction, EventHandler cancelAction, Pane pane) { + int dialogHeight, EventHandler okayAction, EventHandler cancelAction, Pane pane, + ResourceBundle bundle) { this.headingText = headingText; this.bodyText = bodyText; this.dialogBtnStyle = dialogBtnStyle; @@ -68,9 +70,12 @@ public class JFXOkayCancelDialog { this.okayAction = okayAction; this.cancelAction = cancelAction; this.pane = pane; + okayText = bundle.getString("okayBtnText"); + cancelText = bundle.getString("cancelBtnText"); } public void show() { + JFXDialogLayout content = new JFXDialogLayout(); content.setHeading(new Text(headingText)); content.setBody(new Text(bodyText)); @@ -93,9 +98,7 @@ public class JFXOkayCancelDialog { cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); cancelBtn.setPrefHeight(32); cancelBtn.setStyle(dialogBtnStyle); - Label placeholder = new Label(); - placeholder.setPrefSize(15, 10); - content.setActions(cancelBtn, placeholder, okayBtn); + content.setActions(cancelBtn, okayBtn); content.setPrefSize(dialogWidth, dialogHeight); pane.getChildren().add(stackPane); AnchorPane.setTopAnchor(stackPane, (pane.getHeight()-content.getPrefHeight())/2); diff --git a/src/main/java/com/cemu_UI/vendorCloudController/GoogleDriveController.java b/src/main/java/com/cemu_UI/vendorCloudController/GoogleDriveController.java index 51d55ab..485ceef 100644 --- a/src/main/java/com/cemu_UI/vendorCloudController/GoogleDriveController.java +++ b/src/main/java/com/cemu_UI/vendorCloudController/GoogleDriveController.java @@ -21,17 +21,12 @@ package com.cemu_UI.vendorCloudController; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; - -import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -56,15 +51,11 @@ import com.google.api.services.drive.model.FileList; public class GoogleDriveController { Drive service; - private String saveDirectory; private String folderID; - private ArrayList localSavegames = new ArrayList<>(); - private ArrayList cloudSavegames = new ArrayList<>(); - private ArrayList localSavegamesName = new ArrayList<>(); - private ArrayList cloudSavegamesName = new ArrayList<>(); + private File downloadFile; private static final Logger LOGGER = LogManager.getLogger(GoogleDriveController.class.getName()); - private final String APPLICATION_NAME ="cemu_Ui Drive API Controller"; //TODO add Google + private final String APPLICATION_NAME ="cemu_Ui Google Drive API Controller"; //Directory to store user credentials for this application private final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".credentials/cemu_UI_credential"); @@ -125,69 +116,15 @@ public class GoogleDriveController { .build(); } - - public void main(String cemuDirectory) throws IOException { - java.io.File dir = new java.io.File(cemuDirectory + "/mlc01/usr/save"); - - service = getDriveService(); - - // cemu >= 1.11 uses /mlc01/usr/save/... instead of /mlc01/emulatorSave/... - if (dir.exists()) { - LOGGER.info("using new save path"); - saveDirectory = cemuDirectory + "/mlc01/usr/save"; - } else { - LOGGER.info("using old save path"); - saveDirectory = cemuDirectory + "/mlc01/emulatorSave"; - } - } - - public void sync(String cemuDirectory) throws IOException { - //in case there is no folderID saved, look it up first + public void main(String cemuDirectory) throws IOException { + service = getDriveService(); + if (getFolderID() == "" || getFolderID() == null) { getSavegamesFolderID(); } - getLocalSavegames(); - getCloudSavegames(); - - // download files from cloud which don't exist locally - for (int i = 0; i < cloudSavegames.size(); i++) { - - // if the file exists locally, check which one is newer - if (localSavegamesName.contains(cloudSavegames.get(i).getName())) { - - int localSavegamesNumber = localSavegamesName.indexOf(cloudSavegames.get(i).getName()); - long localModified = new DateTime(localSavegames.get(localSavegamesNumber).lastModified()).getValue(); - long cloudModified = cloudSavegames.get(i).getModifiedTime().getValue(); - FileInputStream fis = new FileInputStream(localSavegames.get(localSavegamesNumber)); - - if (cloudSavegames.get(i).getMd5Checksum().equals(org.apache.commons.codec.digest.DigestUtils.md5Hex(fis))) { - LOGGER.info("both files are the same, nothing to do"); - } else { - if (localModified >= cloudModified) { - LOGGER.info("local is newer"); - updateFile(cloudSavegames.get(i), localSavegames.get(localSavegamesNumber)); - } else { - LOGGER.info("cloud is newer"); - downloadFile(cloudSavegames.get(i)); - } - } - - } else { - LOGGER.info("file doesn't exist locally"); - downloadFile(cloudSavegames.get(i)); - } - } - - // upload file to cloud which don't exist in the cloud - for (int j = 0; j < localSavegames.size(); j++) { - if (!cloudSavegamesName.contains(localSavegamesName.get(j))) { - LOGGER.info("file doesn't exist in the cloud"); - uploadFile(localSavegames.get(j)); - } - } } - //create a folder in google drive + // create a folder in google drive public void creatFolder() throws IOException { LOGGER.info("creating new folder"); File fileMetadata = new File(); @@ -199,8 +136,8 @@ public class GoogleDriveController { folderID = file.getId(); } - //check if folder already exist - public boolean checkFolder() { + // check if folder already exist + public boolean checkFolder() { try { Files.List request = service.files().list().setQ("mimeType = 'application/vnd.google-apps.folder' and name = 'cemu_savegames'"); FileList files = request.execute(); @@ -215,32 +152,58 @@ public class GoogleDriveController { } } - //reading all local savegames - private void getLocalSavegames() throws IOException { - java.io.File dir = new java.io.File(saveDirectory); - String[] extensions = new String[] { "dat","sav","bin" }; - localSavegames.removeAll(localSavegames); - localSavegamesName.removeAll(localSavegamesName); - LOGGER.info("Getting all dat,sav,bin files in " + dir.getCanonicalPath()+" including those in subdirectories"); - List files = (List) FileUtils.listFiles(dir, extensions, true); - for (java.io.File file : files) { - localSavegamesName.add(file.getParentFile().getName()+"_"+file.getName()); - localSavegames.add(file); - } - } - - //reading all cloud savegames - private void getCloudSavegames() throws IOException { - LOGGER.info("getting all cloud savegames"); - cloudSavegames.removeAll(cloudSavegames); - cloudSavegamesName.removeAll(cloudSavegamesName); + // FIXME it seams like there is a bug in this method + // get the name of the zip in the semu_savegames folder, which is the last upload Unix time + public long getLastCloudSync() throws IOException { + LOGGER.info("getting last cloud sync"); + long lastCloudSync = 0; Files.List request = service.files().list().setQ("'"+folderID+"' in parents").setFields("nextPageToken, files(id, name, size, modifiedTime, createdTime, md5Checksum)"); FileList files = request.execute(); for (File file : files.getFiles()) { - cloudSavegamesName.add(file.getName()); - cloudSavegames.add(file); + downloadFile = file; + lastCloudSync = Long.parseLong(file.getName().substring(0, file.getName().length()-4)); + } + + return lastCloudSync; + } + + /** + * delete all existing files in cemu_savegames at first + * upload the new savegames zip file + * @param uploadFile savegames zip file + * @throws IOException + */ + public void uploadZipFile(java.io.File uploadFile) throws IOException{ + + LOGGER.info("deleting old savegames ..."); + Files.List request = service.files().list().setQ("'"+folderID+"' in parents").setFields("nextPageToken, files(id, name, size, modifiedTime, createdTime, md5Checksum)"); + FileList files = request.execute(); + + for (File file : files.getFiles()) { + service.files().delete(file.getId()).execute(); // deleting old file } + + LOGGER.info("uploading " + uploadFile.getName() + " ..."); + File fileMetadata = new File(); + fileMetadata.setName(uploadFile.getName()); + fileMetadata.setParents(Collections.singletonList(folderID)); + fileMetadata.setModifiedTime(new DateTime(uploadFile.lastModified())); + FileContent mediaContent = new FileContent("", uploadFile); + File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute(); + LOGGER.info("upload successfull, File ID: " + file.getId()); + } + + // download zip file from the cloud and unzip it + public java.io.File downloadZipFile(String cemu_UIDirectory) throws IOException{ + LOGGER.info("downloading "+downloadFile.getName()+" ..."); + java.io.File outputFile = new java.io.File(cemu_UIDirectory + "/" + downloadFile.getName()); + + OutputStream outputStream = new FileOutputStream(outputFile); + service.files().get(downloadFile.getId()).executeMediaAndDownloadTo(outputStream); + outputStream.close(); + LOGGER.info("download successfull: " + downloadFile.getName()); + return outputFile; } private void getSavegamesFolderID() throws IOException { @@ -253,72 +216,14 @@ public class GoogleDriveController { } catch (Exception e) { LOGGER.error("Oops, something went wrong! It seems that you have more than one folder called 'cemu_savegames'!", e); } - } - +} - //upload a file to the cloud from the local savegames folder - public void uploadFile(java.io.File uploadFile) throws IOException{ - LOGGER.info("uploading " + uploadFile.getName() + " ..."); - File fileMetadata = new File(); - fileMetadata.setName(uploadFile.getParentFile().getName()+"_"+uploadFile.getName()); - fileMetadata.setParents(Collections.singletonList(folderID)); - fileMetadata.setModifiedTime(new DateTime(uploadFile.lastModified())); - FileContent mediaContent = new FileContent("", uploadFile); - File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute(); - LOGGER.info("upload successfull, File ID: " + file.getId()); - } - - //download a file from the cloud to the local savegames folder - private void downloadFile(File downloadFile) throws IOException{ - LOGGER.info("downloading "+downloadFile.getName()+" ..."); - java.io.File directory = new java.io.File(saveDirectory + "/" + downloadFile.getName().substring(0,8)); - String file = downloadFile.getName().substring(9,downloadFile.getName().length()); - if(!directory.exists()) { - LOGGER.info("dir dosent exist"); - directory.mkdir(); - } - - OutputStream outputStream = new FileOutputStream(directory +"/"+ file); - service.files().get(downloadFile.getId()).executeMediaAndDownloadTo(outputStream); - outputStream.close(); - LOGGER.info("download successfull, File ID: " + file); //TODO add FileID - } - - //update a file in the cloud, by deleting the old one and uploading an new with the same id - private void updateFile(File oldFile, java.io.File newFile) throws IOException { - LOGGER.info("updating " +oldFile.getName()+" ..."); - service.files().delete(oldFile.getId()).execute(); //deleting old file - - //uploading new file - File fileMetadata = new File(); - fileMetadata.setName(newFile.getParentFile().getName()+"_"+newFile.getName()); - fileMetadata.setParents(Collections.singletonList(folderID)); - fileMetadata.setModifiedTime(new DateTime(newFile.lastModified())); - - FileContent mediaContent = new FileContent("", newFile); - File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute(); - LOGGER.info("update successfull, File ID: " + file.getId()); - } - - public void uploadAllFiles() { - try { - getLocalSavegames(); - LOGGER.info("uploading " + localSavegames.size() + " files ..."); - for (int i = 0; i < localSavegames.size(); i++) { - uploadFile(localSavegames.get(i)); - } - LOGGER.info("finished uploading all files"); - } catch (IOException e) { - LOGGER.error("error while uploading all files", e); - } - } - - public String getFolderID() { return folderID; } public void setFolderID(String folderID) { this.folderID = folderID; - } +} + } diff --git a/src/main/resources/fxml/MainWindow.fxml b/src/main/resources/fxml/MainWindow.fxml index 4f85bb4..d67e830 100644 --- a/src/main/resources/fxml/MainWindow.fxml +++ b/src/main/resources/fxml/MainWindow.fxml @@ -118,10 +118,16 @@ - + + + + @@ -205,13 +211,17 @@ - - - - + + + - - - + + + + + + + + diff --git a/src/main/resources/locals/cemu_UI-Local_de_DE.properties b/src/main/resources/locals/cemu_UI-Local_de_DE.properties new file mode 100644 index 0000000..598d579 --- /dev/null +++ b/src/main/resources/locals/cemu_UI-Local_de_DE.properties @@ -0,0 +1,87 @@ +#HomeFlix-Local_de_DE.properties geramn Local + +# Buttons +aboutBtn = \u00dcber +settingsBtn = Einstellungen +addBtn = Spiel hinzuf\u00fcgen +reloadRomsBtn = ROMs neu laden +smmdbBtn = smmdb +cemuTFBtn = Ordner \u00F6ffnen +romTFBtn = Ordner \u00F6ffnen +smmdbDownloadBtn = Download +playBtn = spielen +cloudSyncToggleBtn = Spielst\u00e4nde \u00fcber die Cloud syncronisieren (Google Drive) +autoUpdateToggleBtn = beim Start nach Updates suchen +fullscreenToggleBtn = Spiel im Vollbildmodus starten + +# Labels +cemu_UISettingsLbl = cemu_UI Einstellungen +cemuDirectoryLbl = cemu directory +romDirectoryLbl = ROM directory +mainColorLbl = Hauptfarbe +languageLbl = Sprache +updateLbl = updates +branchLbl = Updatezweig +cemuSettingsLbl = cemu Einstellungen +licensesLbl = Lizenzen + +# Columns +titleColumn = Titel +idColumn = ID +starsColumn = Sterne +timeColumn = Zeit + +# Strings +editHeadingText = bearbeiten +editBodyText = Du kannst den Title und den ROM-/Coverpfad bearbeiten. +removeHeadingText = löschen +removeBodyText = Bist du sicher dass du flgendes Spiel l\u00f6schen m\u00f6chtest +addUpdateHeadingText = update +addUpdateBodyText = Bitte w\u00e4hle das Update-Verzeichniss aus. +addDLCHeadingText = ein DLC hinzufügen +addDLCBodyText = Bitte w\u00e4hle das DLC-Verzeichniss aus. + +licensesLblHeadingText = cemu_UI +licensesLblBodyText = cemu_UI ist lizensiert unter der GNU GPL 3.\n\nJFoenix, Apache License 2.0\nminimal-json, MIT License\nsqlite-jdbc, Apache License 2.0\nApache Commons IO, Apache License 2.0\nApache Commons Logging, Apache License 2.0\nApache Commons Codec, Apache License 2.0\nApache Log4j 2, Apache License 2.0\n +showLicenses = Lizenzen \u00f6ffnen + +aboutBtnHeadingText = cemu_UI +aboutBtnBodyText = Diese Programm wurde mit freier Software erstellt\nund ist lizensiert unter der GNU GPL 3.\n\nwww.kellerkinder.xyz + +cloudSyncWaringHeadingText = Spielst\u00e4nde über die Cloud syncronisieren (beta) +cloudSyncWaringBodyText = WARNING this is a completly WIP cloud save integration,\nit's NOT recomended to use this!!\n\nUse it on your own risk and backup everthing before! + +cloudSyncErrorHeadingText = Fehler beim initialisieren der Cloud-Verbindung! +cloudSyncErrorBodyText = Fehler beim initialisieren der Cloud-Verbindung.\nBitte lade die app.log (welceh du im cemu_UI Verzeichniss findest)\nauf \"https://github.com/Seil0/cemu_UI/issues\" hoch. + +addGameBtnHeadingText = eine neues Spiel zu cemu_Ui hinzuf\u00fcgen +addGameBtnBodyText = +addBtnReturnErrorHeadingText = Fehler beim hinzuf\u00fcgen des Spiels! +addBtnReturnErrorBodyText = Fehler beim hinzuf\u00fcgen des Spiels.\nEiner der benötigten Werte war leer, bitte versuche es erneut. +lastPlayed = zuletzt gespielt, +today = heute +yesterday = gestern +never = nie + +# button strings +playBtnPlay = spieles +playBtnUpdating = updating... +playBtnCopyingFiles = kopiere Dateien... +smmdbDownloadBtnLoading = laden +smmdbDownloadBtnDownload = Download +okayBtnText = okay +cancelBtnText = abbruch +updateBtnCheckNow = Auf Update pr\u00FCfen +updateBtnChecking = Es wird nach Updates gesucht... +updateBtnNoUpdateAvailable = Kein Update verf\u00FCgbar +updateBtnUpdateAvailable = Update verf\u00FCgbar + +#EditGameDialog +gameTitle = Spiel Titel +titleID = Titel ID +romPath = ROM Pfad +coverPath = Cover-Pfad +editGameDialogHeadingTextError = Fehler beim hinzuf\u00fcgen des Spiels! +editGameDialogBodyTextError = Fehler beim hinzuf\u00fcgen des Spiels.\nEiner der benötigten Werte war leer, bitte versuche es erneut. +editGameDialogSelectPathBtn = .rpx Datei ausw\u00E4hlen +editGameDialogSelectCoverBtn = cover Datei ausw\u00E4hlen diff --git a/src/main/resources/locals/cemu_UI-Local_en_US.properties b/src/main/resources/locals/cemu_UI-Local_en_US.properties new file mode 100644 index 0000000..f93fce9 --- /dev/null +++ b/src/main/resources/locals/cemu_UI-Local_en_US.properties @@ -0,0 +1,87 @@ +#HomeFlix-Local_en_US.properties US-English Local and default + +# Buttons +aboutBtn = About +settingsBtn = Setting +addBtn = Add new Game +reloadRomsBtn = reload ROMs +smmdbBtn = smmdb +cemuTFBtn = choose directory +romTFBtn = choose directory +smmdbDownloadBtn = Download +playBtn = play +cloudSyncToggleBtn = cloud savegames (Google Drive) +autoUpdateToggleBtn = check for updates on startup +fullscreenToggleBtn = start game in fullscreen + +# Labels +cemu_UISettingsLbl = cemu_UI Settings +cemuDirectoryLbl = cemu directory +romDirectoryLbl = ROM directory +mainColorLbl = main color +languageLbl = language +updateLbl = updates +branchLbl = branch +cemuSettingsLbl = cemu Settings +licensesLbl = Licenses + +# Columns +titleColumn = title +idColumn = ID +starsColumn = stars +timeColumn = time + +# Strings +editHeadingText = edit +editBodyText = You can edit the tile and rom/cover path. +removeHeadingText = remove +removeBodyText = Are you sure you want to delete +addUpdateHeadingText = update +addUpdateBodyText = Please select the update root directory. +addDLCHeadingText = add a DLC to +addDLCBodyText = Please select the DLC root directory. + +licensesLblHeadingText = cemu_UI +licensesLblBodyText = cemu_UI is licensed under the terms of GNU GPL 3.\n\nJFoenix, Apache License 2.0\nminimal-json, MIT License\nsqlite-jdbc, Apache License 2.0\nApache Commons IO, Apache License 2.0\nApache Commons Logging, Apache License 2.0\nApache Commons Codec, Apache License 2.0\nApache Log4j 2, Apache License 2.0\n +showLicenses = show licenses + +aboutBtnHeadingText = cemu_UI +aboutBtnBodyText = This Application is made with free Software\nand licensed under the terms of GNU GPL 3.\n\nwww.kellerkinder.xyz + +cloudSyncWaringHeadingText = activate cloud savegame sync (beta) +cloudSyncWaringBodyText = WARNING this is a completly WIP cloud save integration,\nit's NOT recomended to use this!!\n\nUse it on your own risk and backup everthing before! + +cloudSyncErrorHeadingText = Error while initializing cloud sync! +cloudSyncErrorBodyText = There was some truble while initializing cloud sync.\nPlease upload the app.log (which can be found in the cemu_UI directory)\nto \"https://github.com/Seil0/cemu_UI/issues\" so we can fix this. + +addGameBtnHeadingText = add a new game to cemu_UI +addGameBtnBodyText = +addBtnReturnErrorHeadingText = Error while adding a new Game! +addBtnReturnErrorBodyText = There was some truble adding your game.\nOne of the needed values was empty, please try again to add your game. +lastPlayed = Last played, +today = today +yesterday = yesterday +never = never + +# button strings +playBtnPlay = play +playBtnUpdating = updating... +playBtnCopyingFiles = copying files... +smmdbDownloadBtnLoading = loading +smmdbDownloadBtnDownload = Download +okayBtnText = okay +cancelBtnText = cancel +updateBtnCheckNow = check now! +updateBtnChecking = checking for updates ... +updateBtnNoUpdateAvailable = no update available +updateBtnUpdateAvailable = update available + +#EditGameDialog +gameTitle = game title +titleID = title ID +romPath = ROM path +coverPath = cover path +editGameDialogHeadingTextError = Error while adding a new Game! +editGameDialogBodyTextError = There was some truble adding your game.\nOne of the needed values was empty, please try again to add your game. +editGameDialogSelectPathBtn = select .rpx file +editGameDialogSelectCoverBtn = select cover file