diff --git a/src/main/java/org/saturnclient/saturnclient/auth/Auth.java b/src/main/java/org/saturnclient/saturnclient/auth/Auth.java index e035f50..680850f 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/Auth.java +++ b/src/main/java/org/saturnclient/saturnclient/auth/Auth.java @@ -5,6 +5,9 @@ import java.util.Map; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; +import org.saturnclient.ui2.SaturnScreen; +import org.saturnclient.ui2.elements.Notification; +import org.saturnclient.ui2.elements.Notification.NotificationKind; import org.saturnclient.saturnclient.SaturnClient; public class Auth { @@ -109,6 +112,11 @@ public class Auth { default: if (parser.error != null) { SaturnClient.LOGGER.error("Error from the server: " + parser.error); + + if (SaturnClient.client.currentScreen instanceof SaturnScreen) { + String[] a = parser.error.replace("!", "").split(": "); + ((SaturnScreen) SaturnClient.client.currentScreen).draw(new Notification(SaturnClient.client.currentScreen.width, SaturnClient.client.currentScreen.height, NotificationKind.Error, a[0], a[1])); + } } break; } diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index d6a0058..4e4e00c 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -15,6 +15,7 @@ public class Element { public Animation animation; public float scale = 1.0f; public Function curve = Curve::easeInOutCubic; + public Integer duration = null; // Element duration, will fade out if not null public void render(RenderScope renderScope, ElementContext ctx) { } diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index f482ee6..d69b579 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -3,9 +3,9 @@ package org.saturnclient.ui2; import java.util.ArrayList; import java.util.List; -import org.saturnclient.saturnclient.config.ThemeManager; import org.saturnclient.saturnclient.mixin.DrawContextAccessor; import org.saturnclient.ui2.anim.Animation; +import org.saturnclient.ui2.anim.SlideXAbsolute; import org.saturnclient.ui2.components.ElementRenderer; import net.minecraft.client.MinecraftClient; @@ -51,6 +51,25 @@ public abstract class SaturnScreen extends Screen { element.animation.tick(progress, element); }, element.animation.duration); } + + if (element.duration != null) { + new Thread(() -> { + try { + Animation fadeOut = new SlideXAbsolute(700, -(width - element.x)); + Thread.sleep(element.duration); + fadeOut.init(element); + Animation.executeSync((Float progress) -> { + fadeOut.tick(progress, element); + }, fadeOut.duration); + synchronized (elements) { + elements.remove(element); + } + + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + } } @Override @@ -63,8 +82,6 @@ public abstract class SaturnScreen extends Screen { Animation.execute((Float progress) -> { blurProgress = progress; }, blurDuration); - - ThemeManager.load(); } public abstract void ui(); @@ -96,7 +113,7 @@ public abstract class SaturnScreen extends Screen { renderScope.matrices.scale(0.5f, 0.5f, 0.5f); - ElementRenderer.render(elements, renderScope, mouseX, mouseY); + ElementRenderer.render(new ArrayList<>(elements), renderScope, mouseX, mouseY); renderScope.matrices.pop(); } diff --git a/src/main/java/org/saturnclient/ui2/anim/Animation.java b/src/main/java/org/saturnclient/ui2/anim/Animation.java index 6991c73..d1ed85d 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Animation.java +++ b/src/main/java/org/saturnclient/ui2/anim/Animation.java @@ -44,4 +44,32 @@ public abstract class Animation { } }).start(); } + + public static void executeSync(Consumer tick, int duration) { + Function curveFunction = Curve::easeInOutCubic; + float progress = 0.0f; + double incremental = (1000 - duration) / 10000.0; + + for (int i = 0; i <= 100; i++) { + float newProgress = (float) (double) curveFunction.apply(i / 100.0); + + while (Math.abs(newProgress - progress) > 1e-6) { + if (progress < newProgress) { + progress += incremental; + if (progress > newProgress) progress = newProgress; + } else { + progress -= incremental; + if (progress < newProgress) progress = newProgress; + } + + tick.accept(newProgress); + + try { + Thread.sleep(duration / 100); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } } diff --git a/src/main/java/org/saturnclient/ui2/anim/FadeOut.java b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java new file mode 100644 index 0000000..a1fb42a --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java @@ -0,0 +1,22 @@ +package org.saturnclient.ui2.anim; + +import org.saturnclient.ui2.Element; + +public class FadeOut extends Animation { + float targetOpacity; + + public FadeOut(int duration) { + super(duration); + } + + @Override + public void tick(float progress, Element element) { + element.opacity = targetOpacity - progress; + } + + @Override + public void init(Element element) { + targetOpacity = element.opacity; + // element.opacity = 1.0f; + } +} diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideX.java b/src/main/java/org/saturnclient/ui2/anim/SlideX.java new file mode 100644 index 0000000..595c412 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/anim/SlideX.java @@ -0,0 +1,36 @@ +package org.saturnclient.ui2.anim; + +import org.saturnclient.ui2.Element; + +public class SlideX extends Animation { + int offset = 20; + int maxOffset = 20; + int elementX; + + public SlideX(int duration) { + super(duration); + } + + public SlideX(int duration, int offset) { + super(duration); + this.offset = offset; + this.maxOffset = offset; + } + + public SlideX(int duration, int offset, int maxOffset) { + super(duration); + this.offset = offset; + this.maxOffset = maxOffset; // ✅ fixed + } + + @Override + public void tick(float progress, Element element) { + element.x = elementX + (int) (offset * progress); + } + + @Override + public void init(Element element) { + element.x -= offset; + elementX = element.x; + } +} diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java new file mode 100644 index 0000000..ace746f --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java @@ -0,0 +1,35 @@ +package org.saturnclient.ui2.anim; + +import org.saturnclient.ui2.Element; + +public class SlideXAbsolute extends Animation { + int offset = 20; + int maxOffset = 20; + int elementX; + + public SlideXAbsolute(int duration) { + super(duration); + } + + public SlideXAbsolute(int duration, int offset) { + super(duration); + this.offset = offset; + this.maxOffset = offset; + } + + public SlideXAbsolute(int duration, int offset, int maxOffset) { + super(duration); + this.offset = offset; + this.maxOffset = maxOffset; + } + + @Override + public void tick(float progress, Element element) { + element.x = elementX + (int) (offset * progress); + } + + @Override + public void init(Element element) { + elementX = element.x; + } +} diff --git a/src/main/java/org/saturnclient/ui2/elements/Notification.java b/src/main/java/org/saturnclient/ui2/elements/Notification.java new file mode 100644 index 0000000..61916d0 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/elements/Notification.java @@ -0,0 +1,60 @@ +package org.saturnclient.ui2.elements; + +import org.saturnclient.saturnclient.config.Property; +import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.ui2.Element; +import org.saturnclient.ui2.ElementContext; +import org.saturnclient.ui2.RenderScope; +import org.saturnclient.ui2.anim.SlideX; +import org.saturnclient.ui2.resources.Fonts; +import org.saturnclient.ui2.resources.Textures; + +public class Notification extends Element { + private static ThemeManager theme = new ThemeManager("Notification"); + private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); + private static Property error = theme.property("error", Property.color(0xFFbf212f)); + private static Property info = theme.property("info", Property.color(0xFF264b96)); + private static Property success = theme.property("success", Property.color(0xFF27b376)); + + public static enum NotificationKind { + Error, + Info, + Success, + } + + NotificationKind kind; + String text; + String title; + + public Notification(int width, int height, NotificationKind kind, String title, String text) { + this.kind = kind; + this.text = text; + this.title = title; + this.width = (int) Math.max(Fonts.getWidth(text, 1) * 0.6f, Fonts.getWidth(title, 1)) + 20; + this.height = 50; + this.x = width - this.width - 15; + this.y = height - this.height - 15; + this.animation = new SlideX(700, -width); + this.duration = 3000; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + renderScope.drawRoundedRectangle(0, 0, width, height, 10, bgColor.value); + switch (kind) { + case Error: + renderScope.drawTexture(Textures.CIRCLE_X, 9, 9, 0, 0, 15, 15, error.value); + break; + + case Info: + renderScope.drawTexture(Textures.INFO, 9, 9, 0, 0, 15, 15, info.value); + break; + + case Success: + renderScope.drawTexture(Textures.CHECK, 9, 9, 0, 0, 15, 15, success.value); + break; + } + renderScope.drawText(0.7f, title, 32, 10, 1, -1); + renderScope.drawText(0.5f, text, 32, 28, 1, -1); + } +} diff --git a/src/main/java/org/saturnclient/ui2/resources/Textures.java b/src/main/java/org/saturnclient/ui2/resources/Textures.java index 1f62aa9..2e14228 100644 --- a/src/main/java/org/saturnclient/ui2/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui2/resources/Textures.java @@ -20,6 +20,9 @@ public class Textures { public static final Identifier STORE = Identifier.of("saturnclient", "textures/gui/components/store.png"); public static final Identifier COINS = Identifier.of("saturnclient", "textures/gui/components/coins.png"); public static final Identifier SHIRT = Identifier.of("saturnclient", "textures/gui/components/shirt.png"); + public static final Identifier CIRCLE_X = Identifier.of("saturnclient", "textures/gui/components/circle_x.png"); + public static final Identifier INFO = Identifier.of("saturnclient", "textures/gui/components/info.png"); + public static final Identifier CHECK = Identifier.of("saturnclient", "textures/gui/components/check.png"); public static final Identifier LOGO = Identifier.of("saturnclient", "textures/logo/logo.png"); public static final Identifier REALISTIC_LOGO = Identifier.of("saturnclient", "textures/logo/realistic.png"); diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/check.png b/src/main/resources/assets/saturnclient/textures/gui/components/check.png new file mode 100644 index 0000000..039befb Binary files /dev/null and b/src/main/resources/assets/saturnclient/textures/gui/components/check.png differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png b/src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png new file mode 100644 index 0000000..11401de Binary files /dev/null and b/src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/info.png b/src/main/resources/assets/saturnclient/textures/gui/components/info.png new file mode 100644 index 0000000..81686b1 Binary files /dev/null and b/src/main/resources/assets/saturnclient/textures/gui/components/info.png differ