diff --git a/build.gradle.kts b/build.gradle.kts index 1265ee7..821e9c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ labyMod { author = "RappyTV" description = "Upload your minecraft screenshots to your custom destinations." minecraftVersion = "*" - version = System.getenv().getOrDefault("VERSION", "1.0.1") + version = System.getenv().getOrDefault("VERSION", "1.0.2") } minecraft { diff --git a/core/src/main/java/com/rappytv/uploader/activity/UploadActivity.java b/core/src/main/java/com/rappytv/uploader/activity/UploadActivity.java new file mode 100644 index 0000000..4ed1d7c --- /dev/null +++ b/core/src/main/java/com/rappytv/uploader/activity/UploadActivity.java @@ -0,0 +1,112 @@ +package com.rappytv.uploader.activity; + +import com.rappytv.uploader.api.ApiRequest; +import com.rappytv.uploader.api.Uploader; +import com.rappytv.uploader.api.Uploaders; +import net.labymod.api.Laby; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.client.gui.screen.Parent; +import net.labymod.api.client.gui.screen.activity.AutoActivity; +import net.labymod.api.client.gui.screen.activity.Link; +import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; +import net.labymod.api.client.gui.screen.widget.Widget; +import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.input.ButtonWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.FlexibleContentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.list.VerticalListWidget; +import net.labymod.api.client.gui.screen.widget.widgets.renderer.IconWidget; +import net.labymod.api.notification.Notification; +import java.io.File; + +@Link("upload.lss") +@AutoActivity +public class UploadActivity extends SimpleActivity { + + private final File file; + + public UploadActivity(File file) { + this.file = file; + } + + @Override + public void initialize(Parent parent) { + super.initialize(parent); + + FlexibleContentWidget windowWidget = new FlexibleContentWidget().addId("window"); + HorizontalListWidget headerWidget = new HorizontalListWidget().addId("header"); + ComponentWidget titleWidget = ComponentWidget.i18n("uploader.activity.title").addId("title"); + VerticalListWidget content = new VerticalListWidget<>().addId("content"); + + headerWidget.addEntry(titleWidget); + + for(Uploaders uploaderId : Uploaders.values()) { + Uploader uploader = uploaderId.getUploader(); + + HorizontalListWidget uploaderWidget = new HorizontalListWidget().addId("uploader"); + IconWidget icon = new IconWidget(uploader.getIcon()).addId("icon"); + ComponentWidget name = ComponentWidget.text(uploader.getName()).addId("name"); + ButtonWidget button = new ButtonWidget().addId("button"); + if(uploader.getAuth()[1].isBlank()) { + button.setEnabled(false); + button.updateComponent(Component.translatable("uploader.activity.noAuth", NamedTextColor.RED)); + } else button.updateComponent(Component.translatable("uploader.activity.button")); + + button.setActionListener(() -> { + button.setEnabled(false); + button.updateComponent(Component.translatable("uploader.activity.uploading", NamedTextColor.AQUA)); + ApiRequest request = new ApiRequest(uploader, file); + request.sendAsyncRequest().thenAccept((result) -> { + if(request.isSuccessful()) { + button.setEnabled(true); + button.updateComponent(Component.translatable("uploader.activity.copy", NamedTextColor.GREEN)); + Laby.labyAPI().notificationController().push( + Notification.builder() + .title(Component.translatable("uploader.toast.success")) + .text(Component.translatable("uploader.activity.uploaded", Component.text(uploader.getName()))) + .build() + ); + button.setActionListener(() -> { + Laby.labyAPI().notificationController().push( + Notification.builder() + .title(Component.translatable("uploader.toast.success")) + .text(Component.translatable("uploader.activity.copied")) + .build() + ); + Laby.labyAPI().minecraft().chatExecutor().copyToClipboard(!request.getUploadLink().isBlank() ? request.getUploadLink() : ""); + }); + } else { + button.setEnabled(true); + button.updateComponent(Component.translatable("uploader.activity.error", NamedTextColor.RED)); + Laby.labyAPI().notificationController().push( + Notification.builder() + .title(Component.translatable("uploader.toast.error")) + .text(Component.text(request.getError())) + .build() + ); + } + }).exceptionally((e) -> { + button.setEnabled(true); + button.updateComponent(Component.translatable("uploader.activity.error", NamedTextColor.RED)); + Laby.labyAPI().notificationController().push( + Notification.builder() + .title(Component.translatable("uploader.toast.error")) + .text(Component.text(e.getMessage())) + .build() + ); + return null; + }); + }); + + uploaderWidget.addEntry(icon); + uploaderWidget.addEntry(name); + uploaderWidget.addEntry(button); + content.addChild(uploaderWidget); + } + + windowWidget.addContent(headerWidget); + windowWidget.addContent(content); + this.document.addChild(windowWidget); + } +} diff --git a/core/src/main/java/com/rappytv/uploader/api/ApiRequest.java b/core/src/main/java/com/rappytv/uploader/api/ApiRequest.java index 1e74186..18e5c33 100644 --- a/core/src/main/java/com/rappytv/uploader/api/ApiRequest.java +++ b/core/src/main/java/com/rappytv/uploader/api/ApiRequest.java @@ -30,26 +30,27 @@ public CompletableFuture sendAsyncRequest() { .uri(new URI(uploader.getUri())) .header("Content-Type", data.getContentType()) .header(uploader.getAuth()[0], uploader.getAuth()[1]) - .method(uploader.getMethod(), data.getBodyPublisher()) + .method("POST", data.getBodyPublisher()) .build(); HttpClient client = HttpClient.newHttpClient(); client .sendAsync(request, BodyHandlers.ofString()) .thenAccept((response) -> { - int status = uploader.getStatus(response); - successful = status >= 200 && status <= 299; + successful = response.statusCode() >= 200 && response.statusCode() <= 299; uploadLink = uploader.resolveUrl(response); if(!successful) error = uploader.getError(response); future.complete(null); }) .exceptionally((e) -> { future.completeExceptionally(e); + successful = false; error = e.getMessage(); return null; }); } catch (Exception e) { error = e.getMessage(); + successful = false; future.completeExceptionally(e); } diff --git a/core/src/main/java/com/rappytv/uploader/api/Uploader.java b/core/src/main/java/com/rappytv/uploader/api/Uploader.java index aed2268..678b1b8 100644 --- a/core/src/main/java/com/rappytv/uploader/api/Uploader.java +++ b/core/src/main/java/com/rappytv/uploader/api/Uploader.java @@ -1,6 +1,8 @@ package com.rappytv.uploader.api; import com.rappytv.uploader.UploaderAddon; +import net.labymod.api.client.gui.icon.Icon; +import net.labymod.api.client.resources.ResourceLocation; import java.io.File; import java.io.IOException; import java.net.http.HttpResponse; @@ -10,10 +12,13 @@ public abstract class Uploader { private static final Map uploaders = new HashMap<>(); + protected static final ResourceLocation icons = ResourceLocation.create("uploader", "themes/vanilla/textures/settings.png"); protected final UploaderAddon addon; + private final String name; public Uploader(String name, UploaderAddon addon) { this.addon = addon; + this.name = name; uploaders.put(name.toLowerCase(), this); } @@ -25,10 +30,13 @@ public static Uploader get(String id) { return uploaders.get(id.toLowerCase()); } - public abstract String getMethod(); + public String getName() { + return name; + } + + public abstract Icon getIcon(); public abstract String getUri(); public abstract String[] getAuth(); - public abstract int getStatus(HttpResponse response); public abstract String getError(HttpResponse response); public abstract String resolveUrl(HttpResponse response); public MultipartData getMultipartData(File file) throws IOException { diff --git a/core/src/main/java/com/rappytv/uploader/api/uploaders/EShareUploader.java b/core/src/main/java/com/rappytv/uploader/api/uploaders/EShareUploader.java index b18b292..6e2e57c 100644 --- a/core/src/main/java/com/rappytv/uploader/api/uploaders/EShareUploader.java +++ b/core/src/main/java/com/rappytv/uploader/api/uploaders/EShareUploader.java @@ -4,18 +4,19 @@ import com.google.gson.JsonParser; import com.rappytv.uploader.UploaderAddon; import com.rappytv.uploader.api.Uploader; +import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.util.I18n; import java.net.http.HttpResponse; public class EShareUploader extends Uploader { public EShareUploader(UploaderAddon addon) { - super("eshare", addon); + super("EShare", addon); } @Override - public String getMethod() { - return "POST"; + public Icon getIcon() { + return Icon.sprite32(icons, 0, 1); } @Override @@ -28,11 +29,6 @@ public String[] getAuth() { return new String[]{"api-key", addon.configuration().eshare().auth()}; } - @Override - public int getStatus(HttpResponse response) { - return response.statusCode(); - } - @Override public String getError(HttpResponse response) { try { diff --git a/core/src/main/java/com/rappytv/uploader/api/uploaders/ImgurUploader.java b/core/src/main/java/com/rappytv/uploader/api/uploaders/ImgurUploader.java index 3154ec3..149206e 100644 --- a/core/src/main/java/com/rappytv/uploader/api/uploaders/ImgurUploader.java +++ b/core/src/main/java/com/rappytv/uploader/api/uploaders/ImgurUploader.java @@ -5,6 +5,7 @@ import com.rappytv.uploader.UploaderAddon; import com.rappytv.uploader.api.MultipartData; import com.rappytv.uploader.api.Uploader; +import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.util.I18n; import java.io.File; import java.io.IOException; @@ -13,12 +14,12 @@ public class ImgurUploader extends Uploader { public ImgurUploader(UploaderAddon addon) { - super("imgur", addon); + super("Imgur", addon); } @Override - public String getMethod() { - return "POST"; + public Icon getIcon() { + return Icon.sprite32(icons, 1, 1); } @Override @@ -31,11 +32,6 @@ public String[] getAuth() { return new String[]{"Authorization", "Client-ID (this is just a placeholder)"}; } - @Override - public int getStatus(HttpResponse response) { - return response.statusCode(); - } - @Override public String getError(HttpResponse response) { try { diff --git a/core/src/main/java/com/rappytv/uploader/api/uploaders/XBackBoneUploader.java b/core/src/main/java/com/rappytv/uploader/api/uploaders/XBackBoneUploader.java index e99915d..3ac837f 100644 --- a/core/src/main/java/com/rappytv/uploader/api/uploaders/XBackBoneUploader.java +++ b/core/src/main/java/com/rappytv/uploader/api/uploaders/XBackBoneUploader.java @@ -5,6 +5,7 @@ import com.rappytv.uploader.UploaderAddon; import com.rappytv.uploader.api.MultipartData; import com.rappytv.uploader.api.Uploader; +import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.util.I18n; import java.io.File; import java.io.IOException; @@ -13,12 +14,12 @@ public class XBackBoneUploader extends Uploader { public XBackBoneUploader(UploaderAddon addon) { - super("xbackbone", addon); + super("XBackBone", addon); } @Override - public String getMethod() { - return "POST"; + public Icon getIcon() { + return Icon.sprite32(icons, 2, 1); } @Override @@ -31,11 +32,6 @@ public String[] getAuth() { return new String[]{"token", addon.configuration().xbackbone().auth()}; } - @Override - public int getStatus(HttpResponse response) { - return response.statusCode(); - } - @Override public String getError(HttpResponse response) { try { diff --git a/core/src/main/java/com/rappytv/uploader/api/uploaders/ZiplineUploader.java b/core/src/main/java/com/rappytv/uploader/api/uploaders/ZiplineUploader.java index ef03186..fa31076 100644 --- a/core/src/main/java/com/rappytv/uploader/api/uploaders/ZiplineUploader.java +++ b/core/src/main/java/com/rappytv/uploader/api/uploaders/ZiplineUploader.java @@ -4,18 +4,19 @@ import com.google.gson.JsonParser; import com.rappytv.uploader.UploaderAddon; import com.rappytv.uploader.api.Uploader; +import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.util.I18n; import java.net.http.HttpResponse; public class ZiplineUploader extends Uploader { public ZiplineUploader(UploaderAddon addon) { - super("zipline", addon); + super("Zipline", addon); } @Override - public String getMethod() { - return "POST"; + public Icon getIcon() { + return Icon.sprite32(icons, 3, 1); } @Override @@ -28,18 +29,6 @@ public String[] getAuth() { return new String[]{"Authorization", addon.configuration().zipline().auth()}; } - @Override - public int getStatus(HttpResponse response) { - try { - JsonObject object = JsonParser.parseString(response.body()).getAsJsonObject(); - - return object.has("code") ? object.get("code").getAsInt() : response.statusCode(); - } catch (Exception e) { - e.printStackTrace(); - return response.statusCode(); - } - } - @Override public String getError(HttpResponse response) { try { diff --git a/core/src/main/java/com/rappytv/uploader/command/UploadCommand.java b/core/src/main/java/com/rappytv/uploader/command/UploadCommand.java index 3af5f4f..eabbacb 100644 --- a/core/src/main/java/com/rappytv/uploader/command/UploadCommand.java +++ b/core/src/main/java/com/rappytv/uploader/command/UploadCommand.java @@ -1,8 +1,8 @@ package com.rappytv.uploader.command; import com.rappytv.uploader.UploaderAddon; -import com.rappytv.uploader.api.ApiRequest; -import com.rappytv.uploader.api.Uploader; +import com.rappytv.uploader.activity.UploadActivity; +import net.labymod.api.Laby; import net.labymod.api.client.chat.command.Command; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.event.ClickEvent; @@ -11,10 +11,13 @@ import net.labymod.api.client.component.format.Style; import net.labymod.api.client.component.format.TextDecoration; import java.io.File; +import java.util.HashSet; +import java.util.Set; public class UploadCommand extends Command { private final UploaderAddon addon; + private final Set history = new HashSet<>(); public UploadCommand(UploaderAddon addon) { super("supload"); @@ -23,11 +26,6 @@ public UploadCommand(UploaderAddon addon) { @Override public boolean execute(String prefix, String[] args) { - Uploader uploader = addon.configuration().uploader(); - if(uploader.getAuth()[1].isBlank()) { - displayMessage(UploaderAddon.prefix.copy().append(Component.translatable("uploader.upload.noToken", NamedTextColor.RED))); - return true; - } if(args.length < 1) { displayMessage(UploaderAddon.prefix.copy().append(Component.translatable("uploader.upload.file", NamedTextColor.RED))); return true; @@ -37,41 +35,31 @@ public boolean execute(String prefix, String[] args) { displayMessage(UploaderAddon.prefix.copy().append(Component.translatable("uploader.upload.file", NamedTextColor.RED))); return true; } - displayMessage(UploaderAddon.prefix.copy().append(Component.translatable("uploader.upload.uploading", NamedTextColor.GRAY))); - ApiRequest request = new ApiRequest(uploader, file); - request.sendAsyncRequest().thenAccept((result) -> { - if(request.isSuccessful()) { - Component copy = Component.translatable( - "uploader.upload.copy", - Style.empty() - .color(NamedTextColor.AQUA) - .decorate(TextDecoration.BOLD) - .hoverEvent(HoverEvent.showText(Component.translatable("uploader.upload.hover").color(NamedTextColor.GREEN))) - .clickEvent(ClickEvent.copyToClipboard(!request.getUploadLink().isBlank() ? request.getUploadLink() : "")) - ); - Component component = Component.translatable( - "uploader.upload.uploaded", - !request.getUploadLink().isBlank() ? copy : Component.text("") - ).color(NamedTextColor.GRAY); - - displayMessage(UploaderAddon.prefix.copy().append(component)); - } else { - displayMessage( - UploaderAddon.prefix.copy().append(Component.text( - request.getError(), - NamedTextColor.RED + if(history.contains(file.getName()) && addon.configuration().askBeforeDoubleUploads()) { + if(args.length < 2 || !args[1].equalsIgnoreCase("force")) { + displayMessage(UploaderAddon.prefix.copy().append( + Component.translatable( + "uploader.upload.already", + NamedTextColor.RED, + Component.translatable( + "uploader.upload.openAnyway", + Style.empty() + .color(NamedTextColor.RED) + .decorate(TextDecoration.UNDERLINED) + .hoverEvent(HoverEvent.showText(Component.translatable("uploader.upload.hover", NamedTextColor.GREEN))) + .clickEvent(ClickEvent.runCommand(String.format( + "/%s %s force", + prefix, + file.getName() + ))) + ) )) ); + return true; } - }).exceptionally((e) -> { - displayMessage( - UploaderAddon.prefix.copy().append(Component.text( - e.getMessage(), - NamedTextColor.RED - )) - ); - return null; - }); + } + history.add(file.getName()); + Laby.labyAPI().minecraft().executeNextTick(() -> Laby.labyAPI().minecraft().minecraftWindow().displayScreen(new UploadActivity(file))); return true; } } diff --git a/core/src/main/java/com/rappytv/uploader/config/UploaderConfig.java b/core/src/main/java/com/rappytv/uploader/config/UploaderConfig.java index 7f4aaf7..eeb38da 100644 --- a/core/src/main/java/com/rappytv/uploader/config/UploaderConfig.java +++ b/core/src/main/java/com/rappytv/uploader/config/UploaderConfig.java @@ -1,13 +1,10 @@ package com.rappytv.uploader.config; -import com.rappytv.uploader.api.Uploader; -import com.rappytv.uploader.api.Uploaders; import com.rappytv.uploader.config.subconfig.EShareSubconfig; import com.rappytv.uploader.config.subconfig.XBackBoneSubconfig; import com.rappytv.uploader.config.subconfig.ZiplineSubconfig; import net.labymod.api.addon.AddonConfig; import net.labymod.api.client.gui.screen.widget.widgets.input.SwitchWidget.SwitchSetting; -import net.labymod.api.client.gui.screen.widget.widgets.input.dropdown.DropdownWidget.DropdownSetting; import net.labymod.api.configuration.loader.annotation.SpriteSlot; import net.labymod.api.configuration.loader.annotation.SpriteTexture; import net.labymod.api.configuration.loader.property.ConfigProperty; @@ -20,22 +17,22 @@ public class UploaderConfig extends AddonConfig { @SwitchSetting private final ConfigProperty enabled = new ConfigProperty<>(true); @SpriteSlot(size = 32, x = 1) - @DropdownSetting - private final ConfigProperty uploader = new ConfigProperty<>(Uploaders.IMGUR); + @SwitchSetting + private final ConfigProperty askBeforeDoubleUploads = new ConfigProperty<>(true); @SettingSection("uploaders") @SpriteSlot(size = 32, y = 1) private final EShareSubconfig eshare = new EShareSubconfig(); - @SpriteSlot(size = 32, y = 1, x = 1) - private final XBackBoneSubconfig xbackbone = new XBackBoneSubconfig(); @SpriteSlot(size = 32, y = 1, x = 2) + private final XBackBoneSubconfig xbackbone = new XBackBoneSubconfig(); + @SpriteSlot(size = 32, y = 1, x = 3) private final ZiplineSubconfig zipline = new ZiplineSubconfig(); @Override public ConfigProperty enabled() { return enabled; } - public Uploader uploader() { - return uploader.get().getUploader(); + public boolean askBeforeDoubleUploads() { + return askBeforeDoubleUploads.get(); } public EShareSubconfig eshare() { return eshare; diff --git a/core/src/main/resources/assets/uploader/i18n/en_us.json b/core/src/main/resources/assets/uploader/i18n/en_us.json index 1a5389e..d56aacd 100644 --- a/core/src/main/resources/assets/uploader/i18n/en_us.json +++ b/core/src/main/resources/assets/uploader/i18n/en_us.json @@ -10,6 +10,9 @@ "enabled": { "name": "Enabled" }, + "askBeforeDoubleUploads": { + "name": "Ask before double uploads" + }, "uploader": { "name": "Uploader", "entries": { @@ -52,16 +55,26 @@ "upload": { "noToken": "Please provide the API Key for your uploader in the addon config.", "file": "File not found!", + "already": "You've already opened the menu for this screenshot! %s", + "openAnyway": "Want to open it anyway?", "upload": "Click here to upload the screenshot!", - "uploading": "Uploading screenshot...", - "uploaded": "Screenshot uploaded! %s", "hover": "Clickable", - "copy": "[COPY URL]", "emptyError": "Empty error!", "xError": "An unknown error ocurred! Please check your XBackBone configuration!", "ziplineError": "An unknown error ocurred! Please check your Zipline configuration!" }, + "activity": { + "title": "Upload Screenshot", + "noAuth": "No Auth", + "button": "Upload", + "uploading": "Uploading", + "copy": "Copy", + "error": "Error", + "uploaded": "Your screenshot was successfully uploaded to %s!", + "copied": "The link was copied to your clipboard!" + }, "toast": { + "success": "Success!", "error": "An error ocurred!", "http": "The base must start with http:// or https://", "slash": "The base must not end with a /" diff --git a/core/src/main/resources/assets/uploader/themes/fancy/lss/upload.lss b/core/src/main/resources/assets/uploader/themes/fancy/lss/upload.lss new file mode 100644 index 0000000..c1b5fef --- /dev/null +++ b/core/src/main/resources/assets/uploader/themes/fancy/lss/upload.lss @@ -0,0 +1,54 @@ +.window { + left: 50%; + top: 50%; + width: 200; + height: 140; + alignment-x: center; + alignment-y: center; + background-color: rgba(20, 20, 20, 0.9); + border: 1 dark_gray; + + .header { + left: 50%; + width: 100%; + height: 20; + padding: 0 2 0 2; + background-color: rgba(10, 10, 10, 0.4); + + .title { + alignment: center; + } + } + + .content { + width: 100%; + height: 100%; + margin: 10; + alignment-x: center; + alignment-y: center; + overwrite-width: false; + + .uploader { + left: 50%; + width: 100%; + height: 20; + margin-bottom: 5; + space-between-entries: 5; + + .icon { + width: 16; + height: width; + alignment: left; + } + + .name { + + } + + .button { + alignment: right; + width: 35; + } + } + } +} \ No newline at end of file diff --git a/core/src/main/resources/assets/uploader/themes/vanilla/lss/upload.lss b/core/src/main/resources/assets/uploader/themes/vanilla/lss/upload.lss new file mode 100644 index 0000000..353eed4 --- /dev/null +++ b/core/src/main/resources/assets/uploader/themes/vanilla/lss/upload.lss @@ -0,0 +1,53 @@ +.window { + left: 50%; + top: 50%; + width: 200; + height: 140; + alignment-x: center; + alignment-y: center; + background-color: rgba(20, 20, 20, 0.9); + border: 1 dark_gray; + + .header { + left: 50%; + width: 100%; + height: 20; + padding: 0 2 0 2; + background-color: rgba(10, 10, 10, 0.4); + + .title { + alignment: center; + } + } + + .content { + width: 100%; + height: 100%; + margin: 10; + alignment-x: center; + alignment-y: center; + overwrite-width: false; + + .uploader { + left: 50%; + width: 100%; + height: 20; + margin-bottom: 5; + space-between-entries: 5; + + .icon { + width: 16; + height: width; + alignment: left; + } + + .name { + + } + + .button { + alignment: right; + } + } + } +} \ No newline at end of file diff --git a/core/src/main/resources/assets/uploader/themes/vanilla/textures/settings.png b/core/src/main/resources/assets/uploader/themes/vanilla/textures/settings.png index 0384e17..b8bb3ed 100644 Binary files a/core/src/main/resources/assets/uploader/themes/vanilla/textures/settings.png and b/core/src/main/resources/assets/uploader/themes/vanilla/textures/settings.png differ diff --git a/settings.gradle.kts b/settings.gradle.kts index 9f72c7c..6d1baaa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ rootProject.name = "ScreenshotUploader" pluginManagement { - val labyGradlePluginVersion = "0.3.40" + val labyGradlePluginVersion = "0.3.43" plugins { id("net.labymod.gradle") version (labyGradlePluginVersion) }