From c8c301430e1a583fccd2bb23a708c04805deb1cc Mon Sep 17 00:00:00 2001 From: johni0702 Date: Tue, 16 Aug 2016 13:20:54 +0200 Subject: [PATCH] Rewrite upload replay gui Upload jGui --- jGui | 2 +- .../online/api/replay/FileUploader.java | 92 ++-- .../replaymod/online/gui/GuiUploadFile.java | 460 ------------------ .../replaymod/online/gui/GuiUploadReplay.java | 292 +++++++++++ .../replaymod/online/handler/GuiHandler.java | 11 +- .../assets/replaymod/lang/en_US.lang | 4 +- 6 files changed, 329 insertions(+), 532 deletions(-) delete mode 100755 src/main/java/com/replaymod/online/gui/GuiUploadFile.java create mode 100644 src/main/java/com/replaymod/online/gui/GuiUploadReplay.java diff --git a/jGui b/jGui index 10103ec7..95d9d873 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 10103ec71d17c9445d497fea35c6f8eba7602be1 +Subproject commit 95d9d873fbcb86763d58a0485cb2bb1fdfd6357d diff --git a/src/main/java/com/replaymod/online/api/replay/FileUploader.java b/src/main/java/com/replaymod/online/api/replay/FileUploader.java index c8a64100..f369b310 100755 --- a/src/main/java/com/replaymod/online/api/replay/FileUploader.java +++ b/src/main/java/com/replaymod/online/api/replay/FileUploader.java @@ -2,17 +2,22 @@ package com.replaymod.online.api.replay; import com.google.gson.Gson; import com.replaymod.online.api.ApiClient; +import com.replaymod.online.api.ApiException; import com.replaymod.online.api.replay.holders.ApiError; import com.replaymod.online.api.replay.holders.Category; -import com.replaymod.online.gui.GuiUploadFile; import lombok.RequiredArgsConstructor; -import net.minecraft.client.resources.I18n; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; -import java.io.*; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; -import java.util.List; +import java.util.Set; +import java.util.function.Consumer; @RequiredArgsConstructor public class FileUploader { @@ -20,36 +25,20 @@ public class FileUploader { private final ApiClient apiClient; - private boolean uploading = false; + private volatile boolean uploading = false; + private volatile boolean cancel; private long filesize; private long current; - private boolean cancel = false; - - private GuiUploadFile parent; - - public void uploadFile(GuiUploadFile gui, String filename, List tags, File file, Category category, String description) { - boolean success = false; - String info = null; - + public synchronized void uploadFile(File file, String filename, Set tags, Category category, + String description, Consumer progress) throws Exception { try { - parent = gui; - gui.onStartUploading(); - filesize = 0; - - if(uploading) throw new RuntimeException("FileUploader is already uploading"); uploading = true; String postData = "?auth=" + apiClient.getAuthKey() + "&category=" + category.getId(); if(tags.size() > 0) { - postData += "&tags="; - for(String tag : tags) { - postData += tag; - if(!tag.equals(tags.get(tags.size() - 1))) { - postData += ","; - } - } + postData += "&tags=" + StringUtils.join(tags.toArray(new String[tags.size()]), ","); } if(description != null && description.length() > 0) { @@ -88,17 +77,11 @@ public class FileUploader { request.write(buf); current += len; - parent.onProgressChanged(getUploadProgress()); + progress.accept(getUploadProgress()); if(cancel) { - parent.onProgressChanged(0f); - - uploading = false; - current = 0; - cancel = false; - parent.onFinishUploading(false, I18n.format("replaymod.gui.upload.canceled")); fis.close(); - return; + throw new CancelledException(); } } fis.close(); @@ -109,51 +92,34 @@ public class FileUploader { request.flush(); request.close(); - success = false; int responseCode = con.getResponseCode(); - InputStream is; - if(responseCode == 200) { - success = true; - is = con.getInputStream(); - } else { - success = false; - is = con.getErrorStream(); + InputStream is = responseCode == 200 ? con.getInputStream() : con.getErrorStream(); + if (is == null) { + throw new RuntimeException("Input stream was null."); } - if(is != null) { - BufferedReader r = new BufferedReader(new InputStreamReader(is)); - info = null; - String result = ""; - while(r.ready()) { - result += r.readLine(); - } - if(responseCode != 200) { - ApiError error = gson.fromJson(result, ApiError.class); - info = error.getTranslatedDesc(); - } + String result = IOUtils.toString(is); + if (responseCode != 200) { + ApiError error = gson.fromJson(result, ApiError.class); + throw new ApiException(error); } con.disconnect(); - if(info == null) info = I18n.format("replaymod.gui.unknownerror"); - } catch(Exception e) { - success = false; - e.printStackTrace(); } finally { - parent.onFinishUploading(success, info); uploading = false; + cancel = false; + current = 0; } } - public float getUploadProgress() { + public double getUploadProgress() { if(!uploading || filesize == 0) return 0; - return (float) ((double) current / (double) filesize); - } - - public boolean isUploading() { - return uploading; + return (double) current / filesize; } public void cancelUploading() { cancel = true; } + + public static final class CancelledException extends Exception {} } diff --git a/src/main/java/com/replaymod/online/gui/GuiUploadFile.java b/src/main/java/com/replaymod/online/gui/GuiUploadFile.java deleted file mode 100755 index d155cf23..00000000 --- a/src/main/java/com/replaymod/online/gui/GuiUploadFile.java +++ /dev/null @@ -1,460 +0,0 @@ -package com.replaymod.online.gui; - -import com.google.common.base.Optional; -import com.replaymod.core.ReplayMod; -import com.replaymod.core.utils.Utils; -import com.replaymod.online.api.ApiClient; -import com.replaymod.replay.gui.screen.GuiReplayViewer; -import com.replaymod.replaystudio.replay.ReplayFile; -import com.replaymod.replaystudio.replay.ReplayMetaData; -import com.replaymod.replaystudio.replay.ZipReplayFile; -import com.replaymod.replaystudio.studio.ReplayStudio; -import com.replaymod.online.api.replay.FileUploader; -import com.replaymod.online.api.replay.holders.Category; -import eu.crushedpixel.replaymod.gui.GuiConstants; -import eu.crushedpixel.replaymod.gui.elements.*; -import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener; -import eu.crushedpixel.replaymod.utils.MouseUtils; -import com.replaymod.core.utils.Patterns; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiTextField; -import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.client.resources.I18n; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.client.settings.KeyBinding; -import net.minecraft.util.ResourceLocation; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.lwjgl.input.Keyboard; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Callable; - -// TODO: Rewrite using new GUI API -public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener { - - private final Minecraft mc = Minecraft.getMinecraft(); - - private final ResourceLocation textureResource; - private DynamicTexture dynTex = null; - - private boolean initialized; - - private int columnWidth; - private int columnRight; - - private GuiAdvancedTextField name, tags; - private GuiToggleButton category; - private GuiString serverIP, duration; - private GuiAdvancedCheckBox hideServerIP; - private GuiTextArea description; - - private ComposedElement content; - - private GuiTextField messageTextField; - private GuiAdvancedButton startUploadButton, cancelUploadButton, backButton; - private GuiProgressBar progressBar; - - private File replayFile; - - private ReplayMetaData metaData; - private BufferedImage thumb; - private boolean hasThumbnail; - - private FileUploader uploader; - - private GuiReplayViewer parent; - - private boolean lockUploadButton = false; - - public GuiUploadFile(ApiClient apiClient, File file, GuiReplayViewer parent) { - this.parent = parent; - - uploader = new FileUploader(apiClient); - - this.textureResource = new ResourceLocation("upload_thumbs/" + FilenameUtils.getBaseName(file.getAbsolutePath())); - dynTex = null; - - boolean correctFile = false; - this.replayFile = file; - - ReplayFile archive = null; - try { - archive = new ZipReplayFile(new ReplayStudio(), file); - - metaData = archive.getMetaData(); - Optional img = archive.getThumb(); - if(img.isPresent()) { - thumb = img.get(); - hasThumbnail = true; - } - - archive.close(); - correctFile = true; - } catch(Exception e) { - e.printStackTrace(); - } finally { - try { - if (archive != null) { - archive.close(); - } - } catch (IOException ignored) {} - } - - if(!correctFile) { - Logger logger = LogManager.getLogger(); - logger.error("Invalid file provided to upload"); - parent.display(); - replayFile = null; - return; - } - - //If thumb is null, set image to placeholder - if(thumb == null) { - thumb = Utils.DEFAULT_THUMBNAIL; - } - } - - @Override - public void initGui() { - if(replayFile == null) { - parent.display(); - return; - } - - if (!initialized) { - initialized = true; - - int y = 20; - - name = new GuiAdvancedTextField(fontRendererObj, 0, y, 0, 20); - name.hint = I18n.format("replaymod.gui.upload.namehint"); - name.text = FilenameUtils.getBaseName(replayFile.getAbsolutePath()); - name.setMaxStringLength(30); - y+=25; - - int secs = metaData.getDuration() / 1000; - String durationString = I18n.format("replaymod.gui.duration") + String.format(": %02dm%02ds", secs / 60, secs % 60); - duration = new GuiString(0, y, Color.WHITE, durationString); - y+=15; - - hideServerIP = new GuiAdvancedCheckBox(0, y, I18n.format("replaymod.gui.upload.hideip"), false); - hideServerIP.enabled = !metaData.isSingleplayer(); - y+=15; - - serverIP = new GuiString(0, y, Color.GRAY, new Callable() { - @Override - public String call() throws Exception { - if (hideServerIP.isChecked()){ - return I18n.format("replaymod.gui.iphidden"); - } else { - return metaData.getServerName(); - } - } - }); - y+=15; - - category = new GuiToggleButton(0, 0, y, I18n.format("replaymod.category") + ": ", Category.stringValues()); - y+=25; - - tags = new GuiAdvancedTextField(fontRendererObj, 0, y, 0, 20); - tags.setMaxStringLength(30); - tags.hint = I18n.format("replaymod.gui.upload.tagshint"); - y+=20; - - description = new GuiTextArea(fontRendererObj, 0, name.yPosition, 0, y - name.yPosition, 1000, 100, 1000); - } - - columnWidth = Math.min(200, (width - 60) / 3); - int columnLeft = width / 2 - columnWidth / 2 * 3 - 10; - int columnMiddle = width / 2 - columnWidth / 2; - columnRight = width / 2 + columnWidth / 2 + 10; - - name.xPosition = columnLeft; - name.width = columnWidth; - - duration.positionX = columnLeft; - hideServerIP.xPosition = columnLeft - 1; - serverIP.positionX = columnLeft; - - category.xPosition = columnLeft - 1; - category.width = columnWidth + 2; - - tags.xPosition = columnLeft; - tags.width = columnWidth; - - description.positionX = columnMiddle; - description.setWidth(columnWidth); - - List elements = new ArrayList(Arrays.asList( - name, category, tags, description, serverIP, duration - )); - if (!metaData.isSingleplayer()) { - elements.add(hideServerIP); - } - content = new ComposedElement(elements.toArray(new GuiElement[elements.size()])); - - @SuppressWarnings("unchecked") - List buttonList = this.buttonList; - if(startUploadButton == null) { - List bottomBar = new ArrayList(); - startUploadButton = new GuiAdvancedButton(GuiConstants.UPLOAD_START_BUTTON, 0, 0, I18n.format("replaymod.gui.upload.start")); - bottomBar.add(startUploadButton); - - cancelUploadButton = new GuiAdvancedButton(GuiConstants.UPLOAD_CANCEL_BUTTON, 0, 0, I18n.format("replaymod.gui.upload.cancel")); - cancelUploadButton.enabled = false; - bottomBar.add(cancelUploadButton); - - backButton = new GuiAdvancedButton(GuiConstants.UPLOAD_BACK_BUTTON, 0, 0, I18n.format("replaymod.gui.back")); - bottomBar.add(backButton); - - int i = 0; - for(GuiButton b : bottomBar) { - int w = this.width - 30; - int w2 = w / bottomBar.size(); - - int x = 15 + (w2 * i); - b.xPosition = x + 2; - b.yPosition = height - 30; - b.width = w2 - 4; - - buttonList.add(b); - - i++; - } - } else { - List bottomBar = new ArrayList(); - - bottomBar.add(startUploadButton); - bottomBar.add(cancelUploadButton); - bottomBar.add(backButton); - - int i = 0; - for(GuiButton b : bottomBar) { - int w = this.width - 30; - int w2 = w / bottomBar.size(); - - int x = 15 + (w2 * i); - b.xPosition = x + 2; - b.yPosition = height - 30; - b.width = w2 - 4; - - buttonList.add(b); - - i++; - } - } - - if(messageTextField == null) { - messageTextField = new GuiTextField(GuiConstants.UPLOAD_INFO_FIELD, fontRendererObj, 20, height - 80, width - 40, 20); - messageTextField.setEnabled(true); - messageTextField.setFocused(false); - messageTextField.setMaxStringLength(Integer.MAX_VALUE); - } else { - messageTextField.yPosition = height - 80; - messageTextField.width = width - 40; - } - - if(progressBar == null) { - progressBar = new GuiProgressBar(19, height - 52, width - (2*19), 15); - } else { - progressBar.setBounds(19, height - 52, width - (2*19), 15); - } - - validateStartButton(); - } - - @Override - protected void actionPerformed(GuiButton button) throws IOException { - if(!button.enabled) return; - if(button.id == GuiConstants.UPLOAD_BACK_BUTTON) { - parent.display(); - } else if(button.id == GuiConstants.UPLOAD_START_BUTTON) { - final String name = this.name.getText().trim(); - new Thread(new Runnable() { - @Override - public void run() { - try { - String tagsRaw = tags.getText(); - String[] split = tagsRaw.split(","); - List tags = new ArrayList(); - for(String str : split) { - if(!tags.contains(str) && str.length() > 0) { - tags.add(str); - } - } - - Category category = Category.values()[GuiUploadFile.this.category.getValue()]; - - String desc = StringUtils.join(description.getText(), '\n'); - - if(hideServerIP.isChecked()) { - File tmp = File.createTempFile("replay_hidden_ip", "mcpr"); - - ReplayMetaData newMetaData = new ReplayMetaData(metaData); - newMetaData.setServerName(null); - ReplayFile replay = new ZipReplayFile(new ReplayStudio(), replayFile); - replay.writeMetaData(newMetaData); - replay.saveTo(tmp); - - uploader.uploadFile(GuiUploadFile.this, name, tags, tmp, category, desc); - - FileUtils.deleteQuietly(tmp); - } else { - uploader.uploadFile(GuiUploadFile.this, name, tags, replayFile, category, desc); - } - } catch(Exception e) { - messageTextField.setText(I18n.format("replaymod.gui.unknownerror")); - messageTextField.setTextColor(Color.RED.getRGB()); - e.printStackTrace(); - } - } - }, "replaymod-file-uploader").start(); - } else if(button.id == GuiConstants.UPLOAD_CANCEL_BUTTON) { - uploader.cancelUploading(); - } - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - this.drawDefaultBackground(); - - drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.upload.title"), this.width / 2, 5, Color.WHITE.getRGB()); - - //Draw thumbnail - if(thumb != null) { - if(dynTex == null) { - dynTex = new DynamicTexture(thumb); - mc.getTextureManager().loadTexture(textureResource, dynTex); - dynTex.updateDynamicTexture(); - } - - mc.getTextureManager().bindTexture(textureResource); //Will be freed by the ResourceHelper - int height = columnWidth * 720 / 1280; - Gui.drawScaledCustomSizeModalRect(columnRight, 20, 0, 0, 1280, 720, columnWidth, height, 1280, 720); - - if (!hasThumbnail) { - KeyBinding keyBinding = ReplayMod.instance.getKeyBindingRegistry().getKeyBindings().get("replaymod.input.thumbnail"); - String str = I18n.format("replaymod.gui.upload.nothumbnail", - keyBinding == null ? "???" : GameSettings.getKeyDisplayString(keyBinding.getKeyCode())); - int y = 20 + height + 10; - fontRendererObj.drawSplitString(str, columnRight, y, columnWidth, Color.RED.getRGB()); - } - } - - messageTextField.drawTextBox(); - - super.drawScreen(mouseX, mouseY, partialTicks); - - progressBar.drawProgressBar(); - - startUploadButton.drawOverlay(mc, mouseX, mouseY); - - content.draw(mc, mouseX, mouseY); - content.drawOverlay(mc, mouseX, mouseY); - } - - @Override - public void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { - super.mouseClicked(mouseX, mouseY, mouseButton); - content.mouseClick(mc, mouseX, mouseY, mouseButton); - } - - @Override - public void updateScreen() { - content.tick(mc); - } - - @Override - public void onGuiClosed() { - // Note: Currently intentionally leaks resources, will be fixed soon - Keyboard.enableRepeatEvents(false); - super.onGuiClosed(); - } - - @Override - protected void keyTyped(char typedChar, int keyCode) throws IOException { - org.lwjgl.util.Point mouse = MouseUtils.getMousePos(); - content.buttonPressed(mc, mouse.getX(), mouse.getY(), typedChar, keyCode); - - if(uploader.isUploading()) { - startUploadButton.enabled = false; - } else { - validateStartButton(); - } - } - - private void validateStartButton() { - boolean enabled = true; - if(name.getText().trim().length() < 5 || name.getText().trim().length() > 30) { - enabled = false; - name.setTextColor(Color.RED.getRGB()); - startUploadButton.hoverText = I18n.format("replaymod.gui.upload.error.name.length"); - } else if(!Patterns.ALPHANUMERIC_SPACE_HYPHEN_UNDERSCORE.matcher(name.getText()).matches()) { - enabled = false; - name.setTextColor(Color.RED.getRGB()); - startUploadButton.hoverText = I18n.format("replaymod.gui.upload.error.name"); - } else if(!Patterns.ALPHANUMERIC_COMMA.matcher(tags.getText()).matches()) { - enabled = false; - tags.setTextColor(Color.RED.getRGB()); - startUploadButton.hoverText = I18n.format("replaymod.gui.upload.error.tags"); - } else { - name.setTextColor(Color.WHITE.getRGB()); - tags.setTextColor(Color.WHITE.getRGB()); - startUploadButton.hoverText = null; - } - - if(lockUploadButton) enabled = false; - - startUploadButton.enabled = enabled; - } - - public void onStartUploading() { - startUploadButton.enabled = false; - cancelUploadButton.enabled = true; - backButton.enabled = false; - category.enabled = false; - name.setElementEnabled(false); - description.enabled = false; - messageTextField.setText(I18n.format("replaymod.gui.upload.uploading")); - messageTextField.setTextColor(Color.WHITE.getRGB()); - } - - public void onFinishUploading(boolean success, String info) { - validateStartButton(); - cancelUploadButton.enabled = false; - backButton.enabled = true; - category.enabled = true; - name.setElementEnabled(true); - description.enabled = true; - if(success) { - messageTextField.setText(I18n.format("replaymod.gui.upload.success")); - messageTextField.setTextColor(Color.GREEN.getRGB()); - startUploadButton.enabled = false; - lockUploadButton = true; - } else { - messageTextField.setText(info); - messageTextField.setTextColor(Color.RED.getRGB()); - } - } - - @Override - public void onProgressChanged(float progress) { - if(progressBar != null) progressBar.setProgress(progress); - } - - @Override - public void onProgressChanged(float progress, String progressString) {} -} diff --git a/src/main/java/com/replaymod/online/gui/GuiUploadReplay.java b/src/main/java/com/replaymod/online/gui/GuiUploadReplay.java new file mode 100644 index 00000000..6c53ef47 --- /dev/null +++ b/src/main/java/com/replaymod/online/gui/GuiUploadReplay.java @@ -0,0 +1,292 @@ +package com.replaymod.online.gui; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.replaymod.core.KeyBindingRegistry; +import com.replaymod.core.utils.Patterns; +import com.replaymod.core.utils.Utils; +import com.replaymod.online.ReplayModOnline; +import com.replaymod.online.api.ApiException; +import com.replaymod.online.api.replay.FileUploader; +import com.replaymod.online.api.replay.holders.Category; +import com.replaymod.replaystudio.replay.ReplayFile; +import com.replaymod.replaystudio.replay.ReplayMetaData; +import com.replaymod.replaystudio.replay.ZipReplayFile; +import com.replaymod.replaystudio.studio.ReplayStudio; +import de.johni0702.minecraft.gui.container.GuiContainer; +import de.johni0702.minecraft.gui.container.GuiPanel; +import de.johni0702.minecraft.gui.container.GuiScreen; +import de.johni0702.minecraft.gui.element.*; +import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu; +import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar; +import de.johni0702.minecraft.gui.element.advanced.GuiTextArea; +import de.johni0702.minecraft.gui.layout.CustomLayout; +import de.johni0702.minecraft.gui.layout.GridLayout; +import de.johni0702.minecraft.gui.layout.VerticalLayout; +import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; +import de.johni0702.minecraft.gui.popup.GuiYesNoPopup; +import de.johni0702.minecraft.gui.utils.Colors; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.crash.CrashReport; +import net.minecraft.util.ReportedException; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nullable; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Arrays.stream; + +public class GuiUploadReplay extends GuiScreen { + public final GuiScreen parent; + + public final GuiTextField name = new GuiTextField().setHeight(20).setMaxLength(30) + .setI18nHint("replaymod.gui.upload.namehint"); + public final GuiLabel durationLabel = new GuiLabel(); + public final GuiCheckbox hideServerIP = new GuiCheckbox(); + public final GuiDropdownMenu category = new GuiDropdownMenu().setHeight(20) + .setValues(Category.values()).setToString(v -> I18n.format("replaymod.category") + ": " + v.toNiceString()); + public final GuiTextField tags = new GuiTextField().setHeight(20).setMaxLength(30) + .setI18nHint("replaymod.gui.upload.tagshint"); + + public final GuiTextArea description = new GuiTextArea() + .setI18nHint("replaymod.gui.upload.descriptionhint") + .setMaxTextWidth(1000).setMaxTextHeight(100).setMaxCharCount(1000); + + public final GuiButton startButton = new GuiButton().setI18nLabel("replaymod.gui.upload.start"); + public final GuiButton backButton = new GuiButton().setI18nLabel("replaymod.gui.back"); + + public final GuiPanel inputPanel = new GuiPanel() + .setLayout(new VerticalLayout().setSpacing(5)) + .addElements(null, name, durationLabel, hideServerIP, category, tags); + + public final GuiImage thumbnail = new GuiImage(); + public final GuiLabel thumbnailWarning = new GuiLabel().setColor(Colors.RED); + + public final GuiPanel topPanel = new GuiPanel() + .setLayout(new GridLayout().setColumns(3).setSpacingX(5)) + .setLayout(new CustomLayout() { + @Override + protected void layout(GuiPanel container, int width, int height) { + pos(inputPanel, 0, 0); + width(inputPanel, width / 2 - 4); + + y(thumbnail, y(inputPanel) + height(inputPanel) + 10); + width(thumbnail, Math.min(width(inputPanel), (height - y(thumbnail)) * 16 / 9)); + height(thumbnail, width(thumbnail) * 9 / 16); + x(thumbnail, (width / 2 - 4) / 2 - width(thumbnail) / 2); + + pos(thumbnailWarning, x(thumbnail) + 5, y(thumbnail) + 5); + size(thumbnailWarning, width(thumbnail) - 10, height(thumbnail) - 10); + + pos(description, width / 2 + 4, 0); + size(description, width - x(description), height); + } + }) + .addElements(null, inputPanel, description, thumbnail, thumbnailWarning); + + public final GuiPanel buttonPanel = new GuiPanel() + .setLayout(new GridLayout().setColumns(2).setSpacingX(6)) + .addElements(null, startButton, backButton); + + { + setTitle(new GuiLabel().setI18nText("replaymod.gui.upload.title")); + setLayout(new CustomLayout() { + @Override + protected void layout(GuiScreen container, int width, int height) { + pos(topPanel, 5, 25); + pos(buttonPanel, 5, height - height(buttonPanel) - 5); + + size(topPanel, width - 10, y(buttonPanel) - y(topPanel) - 10); + width(buttonPanel, width - 10); + } + }); + addElements(null, topPanel, buttonPanel); + } + + private final FileUploader uploader; + + public GuiUploadReplay(GuiScreen parent, ReplayModOnline mod, File file) { + this.parent = parent; + this.uploader = new FileUploader(mod.getApiClient()); + + ReplayMetaData metaData; + Optional optThumbnail; + + // Read from replay file + try (ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), file)) { + metaData = replayFile.getMetaData(); + optThumbnail = replayFile.getThumb(); + } catch (IOException e) { + throw new ReportedException(CrashReport.makeCrashReport(e, "Read replay file " + file.getName())); + } + + // Apply to gui + name.setText(FilenameUtils.getBaseName(file.getName())); + int secs = metaData.getDuration() / 1000; + durationLabel.setI18nText("replaymod.gui.upload.duration", secs / 60, secs % 60); + hideServerIP.setEnabled(!metaData.isSingleplayer()); + hideServerIP.setI18nLabel("replaymod.gui.upload.hideip2", metaData.getServerName()); + + if (optThumbnail.isPresent()) { + // Thumbnail is preset, just add the thumbnail to the panel + thumbnail.setTexture(optThumbnail.get()); + } else { + // Get name of key used for thumbnail creation + KeyBindingRegistry registry = mod.getCore().getKeyBindingRegistry(); + KeyBinding keyBinding = registry.getKeyBindings().get("replaymod.input.thumbnail"); + String keyName = keyBinding == null ? "???" : GameSettings.getKeyDisplayString(keyBinding.getKeyCode()); + + // No thumbnail, show default thumbnail and hint on how to create one + thumbnail.setTexture(Utils.DEFAULT_THUMBNAIL); + thumbnailWarning.setI18nText("replaymod.gui.upload.nothumbnail", keyName); + } + + backButton.onClick(parent::display); + + startButton.onClick(() -> { + GuiProgressPopup popup = new GuiProgressPopup(this); + popup.open(); + + // Read values + String name = GuiUploadReplay.this.name.getText(); + Category category = GuiUploadReplay.this.category.getSelectedValue(); + String desc = StringUtils.join(description.getText(), '\n'); + Set tagSet = stream(tags.getText().split(",")).collect(Collectors.toSet()); + tagSet.remove(""); // Remove the empty tag (if it exists) + + // Start upload + new Thread(new Runnable() { + @Override + public void run() { + try { + // Check if we need to remove the server address + if (hideServerIP.isChecked()) { + File tmp = File.createTempFile("replay_hidden_ip", "mcpr"); + + // Overide the server name + try (ReplayFile replay = new ZipReplayFile(new ReplayStudio(), file)) { + ReplayMetaData newMetaData = new ReplayMetaData(metaData); + newMetaData.setServerName(null); + replay.writeMetaData(newMetaData); + replay.saveTo(tmp); + } + + // Upload modified file + uploader.uploadFile(tmp, name, tagSet, category, desc, + progress -> popup.progressBar.setProgress(progress.floatValue())); + + FileUtils.deleteQuietly(tmp); + } else { + // Upload original file + uploader.uploadFile(file, name, tagSet, category, desc, + progress -> popup.progressBar.setProgress(progress.floatValue())); + } + + // Success + mod.getCore().runLater(popup::close); + } catch (FileUploader.CancelledException ignored) { + // Cancelled + mod.getCore().runLater(popup::close); + } catch (Exception e) { + // Failure + e.printStackTrace(); + + String message; + if (e instanceof ApiException) { + message = e.getLocalizedMessage(); + } else { + message = I18n.format("replaymod.gui.unknownerror"); + } + mod.getCore().runLater(() -> { + // Show error popup + GuiYesNoPopup errorPopup = GuiYesNoPopup.open(GuiUploadReplay.this, + new GuiLabel().setText(message).setColor(Colors.BLACK), + new GuiLabel().setI18nText("replaymod.gui.upload.tryagain").setColor(Colors.BLACK)) + .setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no"); + Futures.addCallback(errorPopup.getFuture(), new FutureCallback() { + @Override + public void onSuccess(@Nullable Boolean result) { + popup.close(); + if (result == Boolean.TRUE) { + startButton.onClick(); + } + } + + @Override + public void onFailure(Throwable t) { + t.printStackTrace(); + popup.close(); + } + }); + }); + } + } + }, "replaymod-file-uploader").start(); + }); + + validateInputs(); + } + + public void validateInputs() { + if (name.getText().trim().length() < 5 || name.getText().trim().length() > 30) { + name.setTextColor(Colors.RED); + startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.name.length")); + } else if (!Patterns.ALPHANUMERIC_SPACE_HYPHEN_UNDERSCORE.matcher(name.getText()).matches()) { + name.setTextColor(Colors.RED); + startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.name")); + } else if (!Patterns.ALPHANUMERIC_COMMA.matcher(tags.getText()).matches()) { + tags.setTextColor(Colors.RED); + startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.tags")); + } else { + name.setTextColor(Colors.WHITE); + tags.setTextColor(Colors.WHITE); + startButton.setEnabled().setTooltip(null); + } + } + + @Override + protected GuiUploadReplay getThis() { + return this; + } + + private final class GuiProgressPopup extends AbstractGuiPopup { + public final GuiProgressBar progressBar = new GuiProgressBar().setSize(400, 20); + public final GuiButton cancelButton = new GuiButton().setSize(200, 20).setI18nLabel("replaymod.gui.cancel"); + + { + setBackgroundColor(Colors.DARK_TRANSPARENT); + popup.setLayout(new VerticalLayout().setSpacing(5)); + popup.addElements(new VerticalLayout.Data(0.5), progressBar, cancelButton); + + cancelButton.onClick(uploader::cancelUploading); + } + + public GuiProgressPopup(GuiContainer container) { + super(container); + } + + @Override + public void open() { + super.open(); + } + + @Override + public void close() { + super.close(); + } + + @Override + protected GuiProgressPopup getThis() { + return this; + } + } +} diff --git a/src/main/java/com/replaymod/online/handler/GuiHandler.java b/src/main/java/com/replaymod/online/handler/GuiHandler.java index caa964bd..bf631767 100644 --- a/src/main/java/com/replaymod/online/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/online/handler/GuiHandler.java @@ -3,13 +3,12 @@ package com.replaymod.online.handler; import com.replaymod.online.ReplayModOnline; import com.replaymod.online.gui.GuiLoginPrompt; import com.replaymod.online.gui.GuiReplayCenter; -import com.replaymod.online.gui.GuiUploadFile; +import com.replaymod.online.gui.GuiUploadReplay; import com.replaymod.replay.gui.screen.GuiReplayViewer; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.element.GuiElement; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.resources.I18n; @@ -24,8 +23,6 @@ import java.util.List; public class GuiHandler { private static final int BUTTON_REPLAY_CENTER = 17890236; - private static final Minecraft mc = Minecraft.getMinecraft(); - private final ReplayModOnline mod; public GuiHandler(ReplayModOnline mod) { @@ -64,11 +61,11 @@ public class GuiHandler { @Override public void run() { File replayFile = replayViewer.list.getSelected().file; - GuiUploadFile uploadGui = new GuiUploadFile(mod.getApiClient(), replayFile, replayViewer); + GuiUploadReplay uploadGui = new GuiUploadReplay(replayViewer, mod, replayFile); if (mod.isLoggedIn()) { - mc.displayGuiScreen(uploadGui); + uploadGui.display(); } else { - new GuiLoginPrompt(mod.getApiClient(), replayViewer, GuiScreen.wrap(uploadGui), true); + new GuiLoginPrompt(mod.getApiClient(), replayViewer, uploadGui, true); } } }).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled(); diff --git a/src/main/resources/assets/replaymod/lang/en_US.lang b/src/main/resources/assets/replaymod/lang/en_US.lang index c885307d..8e863bb5 100644 --- a/src/main/resources/assets/replaymod/lang/en_US.lang +++ b/src/main/resources/assets/replaymod/lang/en_US.lang @@ -206,11 +206,13 @@ replaymod.gui.upload.cancel=Cancel Upload replaymod.gui.upload.tagshint=Tags separated by comma replaymod.gui.upload.namehint=Replay Title replaymod.gui.upload.descriptionhint=Description +replaymod.gui.upload.duration=Duration: %02dm%02ds replaymod.gui.upload.uploading=Uploading... replaymod.gui.upload.success=File has been successfully uploaded replaymod.gui.upload.canceled=Upload has been canceled -replaymod.gui.upload.hideip=Hide Server IP +replaymod.gui.upload.hideip2=Hide Server IP (%s) replaymod.gui.upload.nothumbnail=Missing Thumbnail. Please create a Thumbnail in the Replay using the %1$s key. +replaymod.gui.upload.tryagain=Try again? replaymod.gui.upload.error.name.length=The Replay Name has to be between 5 and 30 characters long replaymod.gui.upload.error.name=The Replay Name may not contain special characters