package net.minecraft.client.gui.screens.friends; import java.util.Collection; import java.util.List; import java.util.Objects; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.AbstractContainerWidget; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.ImageWidget; import net.minecraft.client.gui.components.PlainTextButton; import net.minecraft.client.gui.components.SpriteIconButton; import net.minecraft.client.gui.components.StringWidget; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.WidgetSprites; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.screens.social.RemoteFriendListUpdateHandler; import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.Identifier; class AddFriendWidget extends AbstractContainerWidget { private static final WidgetSprites ADD_SPRITE = new WidgetSprites(Identifier.withDefaultNamespace("icon/draft_report")); private static final Identifier LIST_SEPARATOR_TOP = Identifier.withDefaultNamespace("friends/list_separator_top"); private static final Component ENTER_NICKNAME = Component.translatable("gui.friends.enter_nickname"); private static final Component SEND_REQUEST = Component.translatable("gui.friends.send_request"); private static final Component EMPTY_NICKNAME_MESSAGE = Component.translatable("gui.friends.empty_nickname"); private static final Component COPY_TO_CLIPBOARD = Component.translatable("gui.friends.copy_to_clipboard"); private static final Component PROFILE_NAME_LABEL = Component.translatable("gui.friends.my_profile_name").withColor(-6250336); private static final int WINDOW_MARGIN = 8; private static final int SEPARATOR_HEIGHT = 2; private static final int INPUT_SPACING = 3; private static final int ADD_BUTTON_SIZE = 20; private static final int SEPARATOR_PADDING = 4; private static final int PROFILE_NAME_HEIGHT = 9; private static final int PROFILE_NAME_MARGIN = 6; private final EditBox editBox; private final SpriteIconButton addButton; private final PlainTextButton profileNameButton; private final Minecraft minecraft = Minecraft.getInstance(); private final LinearLayout layout; AddFriendWidget(final int width, final Runnable onSend) { super(0, 0, width, 0, Component.empty()); this.editBox = new EditBox(this.minecraft.font, width - 20 - 3 - 16, 20, ENTER_NICKNAME) { { Objects.requireNonNull(AddFriendWidget.this); } @Override public boolean keyPressed(final KeyEvent event) { boolean enterPressed = event.key() == 257 || event.key() == 335; boolean elementsActive = this.isActive() && AddFriendWidget.this.addButton.active; if (elementsActive && this.isFocused() && enterPressed) { AddFriendWidget.this.addButton.playDownSound(AddFriendWidget.this.minecraft.getSoundManager()); AddFriendWidget.this.addButton.onPress(event); return true; } else { return super.keyPressed(event); } } }; this.editBox.setHint(ENTER_NICKNAME); this.editBox.setResponder(this::editBoxResponder); this.addButton = SpriteIconButton.builder(SEND_REQUEST, var1 -> onSend.run(), true) .sprite(ADD_SPRITE, 15, 15) .size(20, 20) .spriteOffset(-1, 1) .tooltip(SEND_REQUEST) .switchToLoadingAfterPress() .build(); this.applyState(AddFriendWidget.State.EMPTY_INPUT); String profileName = this.minecraft.getUser().getName(); final Component profileNameComponent = Component.literal(profileName); int profileNameWidth = this.minecraft.font.width(profileNameComponent); this.profileNameButton = new PlainTextButton( 0, 0, profileNameWidth, 9, profileNameComponent, var2 -> this.minecraft.keyboardHandler.setClipboard(profileName), this.minecraft.font ) { { Objects.requireNonNull(AddFriendWidget.this); } @Override protected MutableComponent createNarrationMessage() { return wrapDefaultNarrationMessage(Component.translatable("gui.friends.my_profile_name.narration", new Object[]{profileNameComponent})); } }; this.profileNameButton.setTooltip(Tooltip.create(COPY_TO_CLIPBOARD)); this.layout = LinearLayout.vertical(); LinearLayout inputRow = LinearLayout.horizontal().spacing(3); inputRow.addChild(this.editBox); inputRow.addChild(this.addButton); this.layout.addChild(inputRow, settings -> settings.paddingLeft(8).paddingTop(3)); LinearLayout profileRow = LinearLayout.horizontal(); profileRow.addChild(new StringWidget(PROFILE_NAME_LABEL, this.minecraft.font)); profileRow.addChild(this.profileNameButton); this.layout.addChild(profileRow, settings -> settings.paddingLeft(8).paddingTop(6)); this.layout.addChild(ImageWidget.sprite(width, 2, LIST_SEPARATOR_TOP), settings -> settings.paddingTop(4)); this.layout.arrangeElements(); this.setHeight(this.layout.getHeight()); } private void editBoxResponder(final String value) { this.applyState(value.trim().isEmpty() ? AddFriendWidget.State.EMPTY_INPUT : AddFriendWidget.State.READY); } public void applyState(final AddFriendWidget.State newState) { switch (newState) { case EMPTY_INPUT: this.editBox.setEditable(true); this.editBox.active = true; this.addButton.setLoading(false); this.addButton.active = false; this.addButton.setTooltip(Tooltip.create(EMPTY_NICKNAME_MESSAGE)); break; case READY: RemoteFriendListUpdateHandler.State friendListState = this.minecraft.getPlayerSocialManager().getFriendListState(); boolean listReady = friendListState == RemoteFriendListUpdateHandler.State.SUCCESS; this.editBox.setEditable(true); this.editBox.active = true; this.addButton.setLoading(false); this.addButton.active = listReady; this.addButton.setTooltip(Tooltip.create(SEND_REQUEST)); break; case SENDING: this.editBox.setEditable(false); this.editBox.active = false; this.editBox.setFocused(false); this.addButton.active = false; this.addButton.setLoading(true); break; case DISABLED: this.editBox.setEditable(false); this.editBox.active = false; this.editBox.setFocused(false); this.addButton.active = false; this.addButton.setLoading(false); } } public EditBox getEditBox() { return this.editBox; } public String getValue() { return this.editBox.getValue().trim(); } public void setValue(final String value) { this.editBox.setValue(value); } @Override protected int contentHeight() { return this.height; } @Override public void setX(final int x) { super.setX(x); this.layout.setX(x); this.layout.arrangeElements(); } @Override public void setY(final int y) { super.setY(y); this.layout.setY(y); this.layout.arrangeElements(); } @Override protected void extractWidgetRenderState(final GuiGraphicsExtractor graphics, final int mouseX, final int mouseY, final float a) { this.layout.visitWidgets(child -> child.extractRenderState(graphics, mouseX, mouseY, a)); } @Override protected void updateWidgetNarration(final NarrationElementOutput output) { } @Override public Collection getNarratables() { return List.of(this.editBox, this.addButton, this.profileNameButton); } @Override public List children() { return List.of(this.editBox, this.addButton, this.profileNameButton); } static enum State { EMPTY_INPUT, READY, SENDING, DISABLED; } }