4141import io .github .axolotlclient .modules .hud .util .DrawUtil ;
4242import io .github .axolotlclient .util .ButtonWidgetTextures ;
4343import io .github .axolotlclient .util .ClientColors ;
44+ import io .github .axolotlclient .util .ThreadExecuter ;
4445import io .github .axolotlclient .util .Watcher ;
46+ import io .github .axolotlclient .util .notifications .Notifications ;
4547import net .fabricmc .loader .api .FabricLoader ;
4648import net .minecraft .client .MinecraftClient ;
4749import net .minecraft .client .font .TextRenderer ;
5658import net .minecraft .client .gui .widget .ElementListWidget ;
5759import net .minecraft .client .render .Tessellator ;
5860import net .minecraft .client .render .VertexFormats ;
61+ import net .minecraft .client .resource .language .I18n ;
5962import net .minecraft .client .util .math .MatrixStack ;
6063import net .minecraft .text .LiteralText ;
6164import net .minecraft .text .MutableText ;
@@ -87,7 +90,10 @@ public SkinManagementScreen(Screen parent, Account account) {
8790 super (new TranslatableText ("skins.manage" ));
8891 this .parent = parent ;
8992 this .account = account ;
90- skinDirWatcher = Watcher .createSelfTicking (SKINS_DIR , this ::loadSkinsList );
93+ skinDirWatcher = Watcher .createSelfTicking (SKINS_DIR , () -> {
94+ AxolotlClientCommon .getInstance ().getLogger ().info ("Reloading screen as local files changed!" );
95+ loadSkinsList ();
96+ });
9197 if (account .needsRefresh ()) {
9298 refreshFuture = account .refresh (Auth .getInstance ().getMsApi ());
9399 } else {
@@ -367,14 +373,33 @@ private void populateSkinList(List<? extends Skin> skins, int columns) {
367373 @ Override
368374 public void filesDragged (List <Path > packs ) {
369375 if (packs .isEmpty ()) return ;
370- packs .forEach (p -> {
371- try {
372- Files .copy (p , SKINS_DIR .resolve (p .getFileName ()));
373- } catch (IOException e ) {
374- AxolotlClientCommon .getInstance ().getLogger ().warn ("Failed to copy skin file: " , e );
375- }
376- });
377- loadSkinsList ();
376+
377+ CompletableFuture <?>[] futs = new CompletableFuture [packs .size ()];
378+ for (int i = 0 ; i < packs .size (); i ++) {
379+ Path p = packs .get (i );
380+ futs [i ] = CompletableFuture .runAsync (() -> {
381+ try {
382+ var target = SKINS_DIR .resolve (p .getFileName ());
383+ if (Files .exists (target )) {
384+ int counter = 0 ;
385+ do {
386+ counter ++;
387+ target = target .resolveSibling (target .getFileName ().toString ()+"_" +counter );
388+ } while (Files .exists (target ));
389+ }
390+ var skin = Auth .getInstance ().getSkinManager ().read (p , false );
391+ if (skin != null ) {
392+ Files .write (target , skin .image ().join ());
393+ } else {
394+ AxolotlClientCommon .getInstance ().getLogger ().info ("Skipping dragged file {} because it does not seem to be a valid skin!" , p );
395+ Notifications .getInstance ().addStatus ("skins.notification.title" , "skins.notification.not_copied" , p .getFileName ());
396+ }
397+ } catch (IOException e ) {
398+ AxolotlClientCommon .getInstance ().getLogger ().warn ("Failed to copy skin file: " , e );
399+ }
400+ }, ThreadExecuter .service ());
401+ }
402+ CompletableFuture .allOf (futs ).thenRun (this ::loadSkinsList );
378403 }
379404
380405 private @ NotNull Entry createEntryForSkin (Skin skin , int entryHeight ) {
@@ -538,9 +563,40 @@ public Entry(int height, SkinWidget widget, @Nullable Text label) {
538563 super (0 , 0 , widget .getWidth (), height , LiteralText .EMPTY );
539564 widget .setWidth (getWidth () - 4 );
540565 var asset = widget .getFocusedAsset ();
566+ class SpriteButton extends ButtonWidget {
567+ private Identifier sprite ;
568+
569+ public SpriteButton (Text message , PressAction onPress , Identifier sprite ) {
570+ super (0 , 0 , 11 , 11 , message , onPress );
571+ this .sprite = sprite ;
572+ }
573+
574+ @ Override
575+ public void renderButton (MatrixStack graphics , int mouseX , int mouseY , float delta ) {
576+ Identifier tex = ButtonWidgetTextures .get (getYImage (hovered ));
577+ DrawUtil .blitSprite (tex , x , y , width , height , new DrawUtil .NineSlice (200 , 20 , 3 ));
578+ client .getTextureManager ().bindTexture (sprite );
579+ drawTexture (graphics , x + 2 , y + 2 , 0 , 0 , 7 , 7 , 7 , 7 );
580+ if (this .isHovered ()) {
581+ tooltip = getMessage ();
582+ }
583+ }
584+ }
585+ if (asset instanceof Skin skin ) {
586+ var wideSprite = new Identifier ("axolotlclient" , "textures/gui/sprites/wide.png" );
587+ var slimSprite = new Identifier ("axolotlclient" , "textures/gui/sprites/slim.png" );
588+ var slimText = new TranslatableText ("skins.manage.variant.classic" );
589+ var wideText = new TranslatableText ("skins.manage.variant.slim" );
590+ actionButtons .add (new SpriteButton (skin .classicVariant () ? wideText : slimText , btn -> {
591+ var self = (SpriteButton ) btn ;
592+ skin .classicVariant (!skin .classicVariant ());
593+ self .sprite = skin .classicVariant () ? slimSprite : wideSprite ;
594+ self .setMessage (skin .classicVariant () ? wideText : slimText );
595+ }, skin .classicVariant () ? slimSprite : wideSprite ));
596+ }
541597 if (asset != null ) {
542598 if (asset .isLocal ()) {
543- var delete = new ButtonWidget ( 0 , 0 , 11 , 11 , new TranslatableText ("skins.manage.delete" ), btn -> {
599+ this . actionButtons . add ( new SpriteButton ( new TranslatableText ("skins.manage.delete" ), btn -> {
544600 btn .active = false ;
545601 client .openScreen (new ConfirmScreen (confirmed -> {
546602 client .openScreen (SkinManagementScreen .this );
@@ -557,25 +613,10 @@ public Entry(int height, SkinWidget widget, @Nullable Text label) {
557613 new TranslatableText ("skins.manage.delete.confirm.desc_active" ) :
558614 new TranslatableText ("skins.manage.delete.confirm.desc" )
559615 ).br$color (Colors .RED .toInt ())));
560- }) {
561-
562- private final Identifier sprite = new Identifier ("axolotlclient" , "textures/gui/sprites/delete.png" );
563-
564- @ Override
565- public void renderButton (MatrixStack graphics , int mouseX , int mouseY , float delta ) {
566- Identifier tex = ButtonWidgetTextures .get (getYImage (hovered ));
567- DrawUtil .blitSprite (tex , x , y , width , height , new DrawUtil .NineSlice (200 , 20 , 3 ));
568- client .getTextureManager ().bindTexture (sprite );
569- drawTexture (graphics , x + 2 , y + 2 , 0 , 0 , 7 , 7 , 7 , 7 );
570- if (this .isHovered ()) {
571- tooltip = getMessage ();
572- }
573- }
574- };
575- this .actionButtons .add (delete );
616+ }, new Identifier ("axolotlclient" , "textures/gui/sprites/delete.png" )));
576617 }
577618 if (asset .supportsDownload () && !asset .isLocal ()) {
578- var download = new ButtonWidget ( 0 , 0 , 11 , 11 , new TranslatableText ("skins.manage.download" ), btn -> {
619+ this . actionButtons . add ( new SpriteButton ( new TranslatableText ("skins.manage.download" ), btn -> {
579620 btn .active = false ;
580621 asset .image ().thenAcceptAsync (b -> {
581622 try {
@@ -588,21 +629,7 @@ public void renderButton(MatrixStack graphics, int mouseX, int mouseY, float del
588629 refreshCurrentList ();
589630 btn .active = true ;
590631 });
591- }) {
592- private final Identifier sprite = new Identifier ("axolotlclient" , "textures/gui/sprites/download.png" );
593-
594- @ Override
595- public void renderButton (MatrixStack graphics , int mouseX , int mouseY , float delta ) {
596- Identifier tex = ButtonWidgetTextures .get (getYImage (hovered ));
597- DrawUtil .blitSprite (tex , x , y , width , height , new DrawUtil .NineSlice (200 , 20 , 3 ));
598- client .getTextureManager ().bindTexture (sprite );
599- drawTexture (graphics , x + 2 , y + 2 , 0 , 0 , 7 , 7 , 7 , 7 );
600- if (this .isHovered ()) {
601- tooltip = getMessage ();
602- }
603- }
604- };
605- this .actionButtons .add (download );
632+ }, new Identifier ("axolotlclient" , "textures/gui/sprites/download.png" )));
606633 }
607634 }
608635 if (label != null ) {
0 commit comments