diff --git a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java index 4bc3a726584..f01d988cb83 100644 --- a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java @@ -1,15 +1,19 @@ package forge.screens.settings; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; +import com.badlogic.gdx.files.FileHandle; import com.google.common.collect.ImmutableList; import forge.StaticData; import forge.gui.FThreads; import forge.gui.GuiBase; import forge.screens.LoadingOverlay; +import forge.util.ZipUtil; import org.apache.commons.lang3.StringUtils; import com.badlogic.gdx.utils.Align; @@ -44,11 +48,50 @@ public class FilesPage extends TabPage { lstItems.setListItemRenderer(new FilesItemRenderer()); + lstItems.addGroup(Forge.getLocalizer().getMessage("lblDataManagement")); lstItems.addGroup(Forge.getLocalizer().getMessage("lblCardAudit")); lstItems.addGroup(Forge.getLocalizer().getMessage("ContentDownloaders")); lstItems.addGroup(Forge.getLocalizer().getMessage("lblStorageLocations")); - //lstItems.addGroup("Data Import"); + //Backup and Restore + lstItems.addItem(new Extra(Forge.getLocalizer().getMessage("lblBackupRestore"), Forge.getLocalizer().getMessage("lblBackupRestoreDescription")) { + @Override + public void select() { + FOptionPane.showOptionDialog(Forge.getLocalizer().getMessage("lblPlsSelectActions"), "", FOptionPane.QUESTION_ICON, ImmutableList.of(Forge.getLocalizer().getMessage("lblBackup"), Forge.getLocalizer().getMessage("lblRestore"), Forge.getLocalizer().getMessage("lblCancel")), 2, new Callback() { + @Override + public void run(Integer result) { + switch (result) { + case 0: + FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblBackupMsg"), true, () -> { + File source = new FileHandle(ForgeProfileProperties.getUserDir()).file(); + File target = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir()).file(); + try { + ZipUtil.zip(source, target, ZipUtil.backupClsFile); + FOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblSuccess") + "\n" + target.getAbsolutePath() + File.separator + ZipUtil.backupClsFile, Forge.getLocalizer().getMessage("lblBackup"), FOptionPane.INFORMATION_ICON); + } catch (IOException e) { + FOptionPane.showMessageDialog(e.toString(), Forge.getLocalizer().getMessage("lblError"), FOptionPane.ERROR_ICON); + } + })); + break; + case 1: + FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblRestoreMsg"), true, () -> { + File source = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir() + ZipUtil.backupClsFile).file(); + File target = new FileHandle(ForgeProfileProperties.getUserDir()).file().getParentFile(); + try { + String msg = ZipUtil.unzip(source, target); + FOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblSuccess") + "\n" + msg, Forge.getLocalizer().getMessage("lblRestore"), FOptionPane.INFORMATION_ICON); + } catch (IOException e) { + FOptionPane.showMessageDialog(e.toString(), Forge.getLocalizer().getMessage("lblError"), FOptionPane.ERROR_ICON); + } + })); + break; + default: + break; + } + } + }); + } + }, 0); //Auditer lstItems.addItem(new Extra(Forge.getLocalizer().getMessage("btnListImageData"), Forge.getLocalizer().getMessage("lblListImageData")) { @Override @@ -74,7 +117,7 @@ public class FilesPage extends TabPage { }); })); } - }, 0); + }, 1); //content downloaders // lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadPics"), // Forge.getLocalizer().getMessage("lblDownloadPics")) { @@ -82,35 +125,35 @@ public class FilesPage extends TabPage { // protected GuiDownloadService createService() { // return new GuiDownloadPicturesLQ(); // } -// }, 1); +// }, 2); // lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadSetPics"), // Forge.getLocalizer().getMessage("lblDownloadSetPics")) { // @Override // protected GuiDownloadService createService() { // return new GuiDownloadSetPicturesLQ(); // } -// }, 1); +// }, 2); // lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadQuestImages"), // Forge.getLocalizer().getMessage("lblDownloadQuestImages")) { // @Override // protected GuiDownloadService createService() { // return new GuiDownloadQuestImages(); // } -// }, 1); +// }, 2); // lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadAchievementImages"), // Forge.getLocalizer().getMessage("lblDownloadAchievementImages")) { // @Override // protected GuiDownloadService createService() { // return new GuiDownloadAchievementImages(); // } -// }, 1); +// }, 2); lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadPrices"), Forge.getLocalizer().getMessage("lblDownloadPrices")) { @Override protected GuiDownloadService createService() { return new GuiDownloadPrices(); } - }, 1); + }, 2); lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadSkins"), Forge.getLocalizer().getMessage("lblDownloadSkins")) { @Override @@ -121,7 +164,7 @@ public class FilesPage extends TabPage { protected void finishCallback() { SettingsScreen.getSettingsScreen().getSettingsPage().refreshSkinsList(); } - }, 1); + }, 2); lstItems.addItem(new OptionContentDownloader(Forge.getLocalizer().getMessage("btnDownloadCJKFonts"), Forge.getLocalizer().getMessage("lblDownloadCJKFonts"), Forge.getLocalizer().getMessage("lblDownloadCJKFontPrompt")) { @@ -146,7 +189,7 @@ public class FilesPage extends TabPage { protected void finishCallback() { SettingsScreen.getSettingsScreen().getSettingsPage().refreshCJKFontsList(); } - }, 1); + }, 2); //storage locations final StorageOption cardPicsOption = new StorageOption(Forge.getLocalizer().getMessage("lblCardPicsLocation"), ForgeProfileProperties.getCardPicsDir()) { @Override @@ -169,7 +212,7 @@ public class FilesPage extends TabPage { //ensure decks option is updated if needed decksOption.updateDir(ForgeProfileProperties.getDecksDir()); } - }, 2); + }, 3); lstItems.addItem(new StorageOption(Forge.getLocalizer().getMessage("lblImageCacheLocation"), ForgeProfileProperties.getCacheDir()) { @Override protected void onDirectoryChanged(String newDir) { @@ -178,7 +221,7 @@ public class FilesPage extends TabPage { //ensure card pics option is updated if needed cardPicsOption.updateDir(ForgeProfileProperties.getCardPicsDir()); } - }, 2); + }, 3); lstItems.addItem(cardPicsOption, 2); lstItems.addItem(decksOption, 2); } diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 0c7bb7dde9c..739d62deafe 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -3529,4 +3529,11 @@ lblDefeatedDescription=Sie sind besiegt und können nicht weitermachen. Mit letz lblReversePromptButton=Umgekehrte Eingabeaufforderungsschaltflächen nlReversePromptButton=Wenn diese Option aktiviert ist, sind die Schaltflächen „OK“ und „Cancel“ vertauscht. lblPrepareDatabase=Datenbank vorbereiten... -lblLoadingGameResources=Spielressourcen werden geladen... \ No newline at end of file +lblLoadingGameResources=Spielressourcen werden geladen... +lblBackupRestore=Sichern und Wiederherstellen +lblBackupRestoreDescription=Sichern oder Wiederherstellen von Daten des klassischen Spielmodus im/aus dem Download-Ordner +lblDataManagement=Datenmanagement +lblPlsSelectActions=Bitte wählen Sie Optionen zum Ausführen der Aktion aus +lblBackupMsg=Sichern von Dateien +lblRestoreMsg=Wiederherstellen von Dateien +lblSuccess=Erfolg \ No newline at end of file diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 0dbe90189ea..b6d76730457 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -3276,4 +3276,11 @@ lblDefeatedDescription=Defeated and unable to continue, you use the last of your lblReversePromptButton=Reversed Prompt Buttons nlReversePromptButton=If enabled, the OK and Cancel Prompt buttons are reversed. lblPrepareDatabase=Preparing database... -lblLoadingGameResources=Loading game resources... \ No newline at end of file +lblLoadingGameResources=Loading game resources... +lblBackupRestore=Backup and Restore +lblBackupRestoreDescription=Backup or Restore Classic game mode data to/from Downloads folder +lblDataManagement=Data Management +lblPlsSelectActions=Please select options to perform action +lblBackupMsg=Backing up files +lblRestoreMsg=Restoring files +lblSuccess=Success \ No newline at end of file diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index d7070635fbd..538fc9e0382 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -3533,4 +3533,11 @@ lblDefeatedDescription=Derrotado e incapaz de continuar, utilizas lo último de lblReversePromptButton=Botones de aviso invertidos nlReversePromptButton=Si esta opción está habilitada, los botones Aceptar y Cancelar solicitud se invierten. lblPrepareDatabase=Preparando la base de datos... -lblLoadingGameResources=Cargando recursos del juego... \ No newline at end of file +lblLoadingGameResources=Cargando recursos del juego... +lblBackupRestore=Copia de seguridad y restauración +lblBackupRestoreDescription=Realizar una copia de seguridad o restaurar los datos del modo de juego clásico en la carpeta de Descargas +lblDataManagement=Gestión de datos +lblPlsSelectActions=Seleccione las opciones para realizar la acción +lblBackupMsg=Realizar copias de seguridad de archivos +lblRestoreMsg=Restaurando archivos +lblSuccess=Éxito \ No newline at end of file diff --git a/forge-gui/res/languages/fr-FR.properties b/forge-gui/res/languages/fr-FR.properties index b2bd7eed4d0..a1f800d1314 100644 --- a/forge-gui/res/languages/fr-FR.properties +++ b/forge-gui/res/languages/fr-FR.properties @@ -3534,4 +3534,11 @@ lblDefeatedDescription=Vaincu et incapable de continuer, vous utilisez le reste lblReversePromptButton=Boutons d'invite inversés nlReversePromptButton=Si cette option est activée, les boutons OK et Annuler sont inversés. lblPrepareDatabase=Préparation de la base de données... -lblLoadingGameResources=Chargement des ressources du jeu... \ No newline at end of file +lblLoadingGameResources=Chargement des ressources du jeu... +lblBackupRestore=Sauvegarde et restauration +lblBackupRestoreDescription=Sauvegarder ou restaurer les données du mode de jeu classique vers/depuis le dossier Téléchargements +lblDataManagement=Gestion des données +lblPlsSelectActions=Veuillez sélectionner les options pour effectuer l'action +lblBackupMsg=Sauvegarde des fichiers +lblRestoreMsg=Restauration de fichiers +lblSuccess=Succès \ No newline at end of file diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index af7c6ff95ef..e2333d97012 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -3532,4 +3532,11 @@ lblDefeatedDescription=Sconfitto e impossibilitato a proseguire, usi le ultime e lblReversePromptButton=Pulsanti di richiesta invertiti nlReversePromptButton=Se abilitati, i pulsanti OK e Annulla richiesta sono invertiti. lblPrepareDatabase=Preparazione del database... -lblLoadingGameResources=Caricamento delle risorse del gioco... \ No newline at end of file +lblLoadingGameResources=Caricamento delle risorse del gioco... +lblBackupRestore=Backup e ripristino +lblBackupRestoreDescription=Esegui il backup o il ripristino dei dati della modalità di gioco classica nella/dalla cartella Download +lblDataManagement=Gestione dei dati +lblPlsSelectActions=Seleziona le opzioni per eseguire l'azione +lblBackupMsg=Backup dei file +lblRestoreMsg=Ripristino dei file +lblSuccess=Successo \ No newline at end of file diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index 163ad7cfdf1..df0bcf76e05 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -640,27 +640,27 @@ lblPreconstructedDecks=構築済みデッキ lblPreconCommanderDecks=構築済み統率者デッキ lblQuestOpponentDecks=クエスト対戦相手のデッキ lblRandomColorDecks=ランダムカラーデッキ -lblRandomStandardArchetypeDecks=ランダムアーキタイプデッキ スタンダード -lblRandomPioneerArchetypeDecks=ランダムアーキタイプデッキ パイオニア -lblRandomHistoricArchetypeDecks=ランダムアーキタイプデッキ ヒストリック -lblRandomModernArchetypeDecks=ランダムアーキタイプデッキ モダン -lblRandomLegacyArchetypeDecks=ランダムアーキタイプデッキ レガシー -lblRandomVintageArchetypeDecks=ランダムアーキタイプデッキ ビンテージ +lblRandomStandardArchetypeDecks=ランダムアーキタイプデッキ\u3000スタンダード +lblRandomPioneerArchetypeDecks=ランダムアーキタイプデッキ\u3000パイオニア +lblRandomHistoricArchetypeDecks=ランダムアーキタイプデッキ\u3000ヒストリック +lblRandomModernArchetypeDecks=ランダムアーキタイプデッキ\u3000モダン +lblRandomLegacyArchetypeDecks=ランダムアーキタイプデッキ\u3000レガシー +lblRandomVintageArchetypeDecks=ランダムアーキタイプデッキ\u3000ビンテージ lblRandomPauperArchetypeDecks=ランダムなPauperアーキタイプデッキ -lblRandomStandardColorDecks=ランダムカラーデッキ スタンダード -lblRandomModernColorDecks=ランダムカラーデッキ モダン +lblRandomStandardColorDecks=ランダムカラーデッキ\u3000スタンダード +lblRandomModernColorDecks=ランダムカラーデッキ\u3000モダン lblRandomPauperColorDecks=ランダムカラーデッキパウパー lblRandomThemeDecks=ランダムテーマデッキ lblRandomDecks=ランダムデッキ lblNetDecks=ネットデッキ lblNetCommanderDecks=ネット統率者デッキ -lblNetArchiveStandardDecks=ネットアーカイブデッキ スタンダード -lblNetArchivePioneerDecks=ネットアーカイブデッキ パイオニア -lblNetArchiveModernDecks=ネットアーカイブデッキ モダン -lblNetArchiveLegacyDecks=ネットアーカイブデッキ レガシー -lblNetArchiveVintageDecks=ネットアーカイブデッキ ビンテージ -lblNetArchiveBlockDecks=ネットアーカイブデッキ ブロック -lblNetArchivePauperDecks=ネットアーカイブデッキ パウパー +lblNetArchiveStandardDecks=ネットアーカイブデッキ\u3000スタンダード +lblNetArchivePioneerDecks=ネットアーカイブデッキ\u3000パイオニア +lblNetArchiveModernDecks=ネットアーカイブデッキ\u3000モダン +lblNetArchiveLegacyDecks=ネットアーカイブデッキ\u3000レガシー +lblNetArchiveVintageDecks=ネットアーカイブデッキ\u3000ビンテージ +lblNetArchiveBlockDecks=ネットアーカイブデッキ\u3000ブロック +lblNetArchivePauperDecks=ネットアーカイブデッキ\u3000パウパー #VSubmenuTutorial lblTutorial=チュートリアル lblTutorialMode=チュートリアルモード @@ -1860,7 +1860,7 @@ lblDoYouWantFlipNCoinAction={0}枚のコイントスをしますか? lblDoYouWantRollNDiceAction={0}{1}を投げますか? lblDoYouWantRemoveNTargetTypeCounterFromCard={2}から {1}個の {0}カウンターを取り除きますか? lblDoYouWantRemoveCountersFromCard={0}からカウンターを取り除きますか? -lblDoYouWantExileNCardsFromYourLibrary=ライブラリーから {0}枚のカードを追放しますか? +lblDoYouWantExileNCardsFromYourLibrary=ライブラリーから\u3000{0}枚のカードを追放しますか? lblDoYouWantExileAllCardYouGraveyard=墓地から全てのカードを追放しますか? lblDoYouWantExileAllCardHand=Do you want to exile all cards in your hand? lblDoYouWantDiscardYourHand=手札を捨てますか? @@ -3528,4 +3528,11 @@ lblDefeatedDescription=敗北し、続行不可能となったあなたは、最 lblReversePromptButton=逆プロンプトボタン nlReversePromptButton=有効にすると、[OK] ボタンと [Cancel] ボタンが逆になります。 lblPrepareDatabase=データベースを準備しています -lblLoadingGameResources=ゲームリソースを読み込んでいます \ No newline at end of file +lblLoadingGameResources=ゲームリソースを読み込んでいます +lblBackupRestore=バックアップと復元 +lblBackupRestoreDescription=クラシックゲームモードのデータをダウンロードフォルダにバックアップまたは復元する +lblDataManagement=データ管理 +lblPlsSelectActions=アクションを実行するにはオプションを選択してください +lblBackupMsg=ファイルのバックアップ +lblRestoreMsg=ファイルの復元 +lblSuccess=成功 \ No newline at end of file diff --git a/forge-gui/res/languages/pt-BR.properties b/forge-gui/res/languages/pt-BR.properties index a12bb9a4c85..9f115580adb 100644 --- a/forge-gui/res/languages/pt-BR.properties +++ b/forge-gui/res/languages/pt-BR.properties @@ -3618,4 +3618,11 @@ lblDefeatedDescription=Derrotado e incapaz de continuar, você usa o que resta d lblReversePromptButton=Botões de prompt invertidos nlReversePromptButton=Se ativados, os botões OK e Cancelar prompt serão invertidos. lblPrepareDatabase=Preparando banco de dados... -lblLoadingGameResources=Carregando recursos do jogo... \ No newline at end of file +lblLoadingGameResources=Carregando recursos do jogo... +lblBackupRestore=Backup e restauração +lblBackupRestoreDescription=Fazer backup ou restaurar dados do modo de jogo clássico de/para a pasta Downloads +lblDataManagement=Gestão de Dados +lblPlsSelectActions=Selecione as opções para executar a ação +lblBackupMsg=Fazendo backup de arquivos +lblRestoreMsg=Restaurando arquivos +lblSuccess=Sucesso \ No newline at end of file diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 73f2ba7d24a..c3a69b6dd57 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -3519,4 +3519,11 @@ lblDefeatedDescription=你被击败了,无法继续前进,你用尽最后的 lblReversePromptButton=反转提示按钮 nlReversePromptButton=如果启用,则“确定”和“取消提示”按钮将会反转。 lblPrepareDatabase=准备数据库 -lblLoadingGameResources=正在加载游戏资源 \ No newline at end of file +lblLoadingGameResources=正在加载游戏资源 +lblBackupRestore=备份和还原 +lblBackupRestoreDescription=将经典游戏模式数据备份或恢复到“下载”文件夹 +lblDataManagement=数据管理 +lblPlsSelectActions=请选择要执行操作的选项 +lblBackupMsg=备份文件 +lblRestoreMsg=恢复文件 +lblSuccess=成功 \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/util/ZipUtil.java b/forge-gui/src/main/java/forge/util/ZipUtil.java index e1718c72632..eabe48747b3 100644 --- a/forge-gui/src/main/java/forge/util/ZipUtil.java +++ b/forge-gui/src/main/java/forge/util/ZipUtil.java @@ -14,7 +14,10 @@ import java.util.zip.ZipOutputStream; */ public class ZipUtil { public static String backupAdvFile = "forge.adv"; + public static String backupClsFile = "forge.cls"; + private static boolean isClassic = false; public static void zip(File source, File dest, String name) throws IOException { + isClassic = backupClsFile.equalsIgnoreCase(name); try( FileOutputStream fos = new FileOutputStream(dest.getAbsolutePath() + File.separator + name); ZipOutputStream zipOut = new ZipOutputStream(fos)) { @@ -26,7 +29,13 @@ public class ZipUtil { if (fileToZip.isHidden()) { return; } + //skip loose files like forge.log, etc + if (fileToZip.isFile() && isClassic && "Forge".equalsIgnoreCase(fileToZip.getParentFile().getName())) + return; if (fileToZip.isDirectory()) { + //skip adventure since we don't want to overwrite it and adventure has its own backup method + if (isClassic && "adventure".equalsIgnoreCase(fileToZip.getName()) && "Forge".equalsIgnoreCase(fileToZip.getParentFile().getName())) + return; if (fileName.endsWith("/")) { zipOut.putNextEntry(new ZipEntry(fileName)); zipOut.closeEntry(); @@ -54,6 +63,7 @@ public class ZipUtil { } public static String unzip(File fileZip, File destDir) throws IOException { + isClassic = backupClsFile.equalsIgnoreCase(fileZip.getName()); StringBuilder val = new StringBuilder(); byte[] buffer = new byte[1024]; ZipInputStream zis = new ZipInputStream(Files.newInputStream(fileZip.toPath())); @@ -64,6 +74,8 @@ public class ZipUtil { if (!newFile.isDirectory() && !newFile.mkdirs()) { throw new IOException("Failed to create directory " + newFile); } + if (isClassic && "Forge".equalsIgnoreCase(newFile.getParentFile().getName())) + val.append(" * "). append(newFile.getName()).append("\n"); } else { // fix for Windows-created archives File parent = newFile.getParentFile(); @@ -71,8 +83,9 @@ public class ZipUtil { throw new IOException("Failed to create directory " + parent); } + if (!isClassic) + val.append(" * "). append(newFile.getName()).append("\n"); // write file content - val.append(" * "). append(newFile.getName()).append("\n"); try(FileOutputStream fos = new FileOutputStream(newFile)) { int len; while ((len = zis.read(buffer)) > 0) {