3535import com .mojang .blaze3d .systems .RenderSystem ;
3636import io .github .axolotlclient .AxolotlClientCommon ;
3737import io .github .axolotlclient .AxolotlClientConfig .api .util .Colors ;
38+ import io .github .axolotlclient .api .SimpleTextInputScreen ;
39+ import io .github .axolotlclient .api .util .UUIDHelper ;
3840import io .github .axolotlclient .modules .auth .Account ;
3941import io .github .axolotlclient .modules .auth .Auth ;
4042import io .github .axolotlclient .modules .auth .MSApi ;
4143import io .github .axolotlclient .modules .hud .util .DrawUtil ;
4244import io .github .axolotlclient .util .ButtonWidgetTextures ;
4345import io .github .axolotlclient .util .ClientColors ;
44- import io .github .axolotlclient .util .ThreadExecuter ;
4546import io .github .axolotlclient .util .Watcher ;
4647import io .github .axolotlclient .util .notifications .Notifications ;
4748import net .fabricmc .loader .api .FabricLoader ;
@@ -146,7 +147,7 @@ protected MutableText getNarrationMessage() {
146147 skinList .visible = skinList .active = false ;
147148 }
148149 List <AbstractButtonWidget > navBar = new ArrayList <>();
149- var skinsTab = new ButtonWidget (width * 3 / 4 - 102 , headerHeight , 100 , 20 , new TranslatableText ("skins.nav.skins" ), btn -> {
150+ var skinsTab = new ButtonWidget (Math . max ( width * 3 / 4 - 102 , width / 2 + 2 ), headerHeight , Math . min ( 100 , width / 4 - 2 ) , 20 , new TranslatableText ("skins.nav.skins" ), btn -> {
150151 navBar .forEach (w -> {
151152 if (w != btn ) w .active = true ;
152153 });
@@ -156,7 +157,7 @@ protected MutableText getNarrationMessage() {
156157 capesTab = false ;
157158 });
158159 navBar .add (skinsTab );
159- var capesTab = new ButtonWidget (width * 3 / 4 + 2 , headerHeight , 100 , 20 , new TranslatableText ("skins.nav.capes" ), btn -> {
160+ var capesTab = new ButtonWidget (width * 3 / 4 + 2 , headerHeight , Math . min ( 100 , width / 4 - 2 ) , 20 , new TranslatableText ("skins.nav.capes" ), btn -> {
160161 navBar .forEach (w -> {
161162 if (w != btn ) w .active = true ;
162163 });
@@ -170,14 +171,23 @@ protected MutableText getNarrationMessage() {
170171 btn .active = false ;
171172 SkinImportUtil .openImportSkinDialog ().thenAccept (this ::filesDragged ).thenRun (() -> btn .active = true );
172173 }, new Identifier ("axolotlclient" , "textures/gui/sprites/folder.png" ));
173- importButton .x = capesTab .x + capesTab .getWidth () - 11 ;
174- importButton .y = capesTab .y - 13 ;
175174 var downloadButton = new SpriteButton (new TranslatableText ("skins.manage.import.online" ), btn -> {
176175 btn .active = false ;
177- // TODO
176+ promptForSkinDownload ();
178177 }, new Identifier ("axolotlclient" , "textures/gui/sprites/download.png" ));
179178 downloadButton .x = importButton .x - 2 - 11 ;
180179 downloadButton .y = capesTab .y - 13 ;
180+ if (width - (capesTab .x + capesTab .getWidth ()) > 28 ) {
181+ importButton .x = width - importButton .getWidth () - 2 ;
182+ downloadButton .x = importButton .x - downloadButton .getWidth () - 2 ;
183+ importButton .y = capesTab .y + capesTab .getHeight () - 11 ;
184+ downloadButton .y = importButton .y ;
185+ } else {
186+ importButton .x = capesTab .x + capesTab .getWidth () - 11 ;
187+ importButton .y = capesTab .y - 13 ;
188+ downloadButton .x = importButton .x - 2 - 11 ;
189+ downloadButton .y = importButton .y ;
190+ }
181191 skinsTab .active = this .capesTab ;
182192 capesTab .active = !this .capesTab ;
183193 Runnable addWidgets = () -> {
@@ -229,6 +239,39 @@ public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float del
229239 });
230240 }
231241
242+ private void promptForSkinDownload () {
243+ client .openScreen (new SimpleTextInputScreen (this , new TranslatableText ("skins.manage.import.online" ), new TranslatableText ("skins.manage.import.online.input" ), s ->
244+ UUIDHelper .ensureUuidOpt (s ).thenAccept (o -> {
245+ if (o .isPresent ()) {
246+ AxolotlClientCommon .getInstance ().getLogger ().info ("Downloading skin of {} ({})" , s , o .get ());
247+ Auth .getInstance ().getMsApi ().getTextures (o .get ())
248+ .exceptionally (th -> {
249+ AxolotlClientCommon .getInstance ().getLogger ().info ("Failed to download skin of {} ({})" , s , o .get (), th );
250+ return null ;
251+ }).thenAccept (t -> {
252+ if (t == null ) {
253+ Notifications .getInstance ().addStatus ("skins.notification.title" , "skins.notification.import.online.failed_to_download" , s );
254+ return ;
255+ }
256+ try {
257+ var bytes = t .skin ().join ();
258+ var out = ensureNonexistent (SKINS_DIR .resolve (t .skinKey ()));
259+ Skin .Local .writeMetadata (out , Map .of (Skin .Local .CLASSIC_METADATA_KEY , t .classicModel (), "name" , t .name (), "uuid" , t .id ()));
260+ Files .write (out , bytes );
261+ client .execute (this ::loadSkinsList );
262+ Notifications .getInstance ().addStatus ("skins.notification.title" , "skins.notification.import.online.downloaded" , t .name ());
263+ AxolotlClientCommon .getInstance ().getLogger ().info ("Downloaded skin of {} ({})" , t .name (), o .get ());
264+ } catch (IOException e ) {
265+ AxolotlClientCommon .getInstance ().getLogger ().warn ("Failed to write skin file" , e );
266+ Notifications .getInstance ().addStatus ("skins.notification.title" , "skins.notification.import.online.failed_to_save" , t .name ());
267+ }
268+ });
269+ } else {
270+ Notifications .getInstance ().addStatus ("skins.notification.title" , "skins.notification.import.online.not_found" , s );
271+ }
272+ })));
273+ }
274+
232275 private <T extends Drawable & Element > T addDrawableChild (T child ) {
233276 drawables .add (child );
234277 return addChild (child );
@@ -365,6 +408,17 @@ private void populateSkinList(List<? extends Skin> skins, int columns) {
365408 }
366409 }
367410
411+ private Path ensureNonexistent (Path p ) {
412+ if (Files .exists (p )) {
413+ int counter = 0 ;
414+ do {
415+ counter ++;
416+ p = p .resolveSibling (p .getFileName ().toString () + "_" + counter );
417+ } while (Files .exists (p ));
418+ }
419+ return p ;
420+ }
421+
368422 @ Override
369423 public void filesDragged (List <Path > packs ) {
370424 if (packs .isEmpty ()) return ;
@@ -374,14 +428,7 @@ public void filesDragged(List<Path> packs) {
374428 Path p = packs .get (i );
375429 futs [i ] = CompletableFuture .runAsync (() -> {
376430 try {
377- var target = SKINS_DIR .resolve (p .getFileName ());
378- if (Files .exists (target )) {
379- int counter = 0 ;
380- do {
381- counter ++;
382- target = target .resolveSibling (target .getFileName ().toString () + "_" + counter );
383- } while (Files .exists (target ));
384- }
431+ var target = ensureNonexistent (SKINS_DIR .resolve (p .getFileName ()));
385432 var skin = Auth .getInstance ().getSkinManager ().read (p , false );
386433 if (skin != null ) {
387434 Files .write (target , skin .image ().join ());
@@ -392,7 +439,7 @@ public void filesDragged(List<Path> packs) {
392439 } catch (IOException e ) {
393440 AxolotlClientCommon .getInstance ().getLogger ().warn ("Failed to copy skin file: " , e );
394441 }
395- }, ThreadExecuter . service () );
442+ }, client );
396443 }
397444 CompletableFuture .allOf (futs ).thenRun (this ::loadSkinsList );
398445 }
@@ -579,6 +626,7 @@ public Entry(int height, SkinWidget widget, @Nullable Text label) {
579626 if (confirmed ) {
580627 try {
581628 Files .delete (asset .file ());
629+ Files .deleteIfExists (asset .file ().resolveSibling (asset .file ().getFileName () + Skin .Local .METADATA_SUFFIX ));
582630 refreshCurrentList ();
583631 } catch (IOException e ) {
584632 AxolotlClientCommon .getInstance ().getLogger ().warn ("Failed to delete: " , e );
@@ -701,6 +749,8 @@ private float applyEasing(float x) {
701749 public void renderButton (MatrixStack guiGraphics , int mouseX , int mouseY , float partialTick ) {
702750 int y = this .y + 4 ;
703751 int x = this .x + 2 ;
752+ skinWidget .setPosition (x , y );
753+ skinWidget .setWidth (getWidth () - 4 );
704754 if (skinWidget .isEquipped () || equipping ) {
705755 long prog ;
706756 if (Auth .getInstance ().skinManagerAnimations .get ()) {
@@ -719,8 +769,6 @@ public void renderButton(MatrixStack guiGraphics, int mouseX, int mouseY, float
719769 gradientWidth ,
720770 equipping ? 0xFFFF0088 : ClientColors .SELECTOR_GREEN .toInt (), 0 );
721771 }
722- skinWidget .setPosition (x , y );
723- skinWidget .setWidth (getWidth () - 4 );
724772 skinWidget .render (guiGraphics , mouseX , mouseY , partialTick );
725773 int actionButtonY = this .y + 2 ;
726774 for (var button : actionButtons ) {
0 commit comments