package com.mojang.realmsclient.gui.screens; import com.mojang.logging.LogUtils; import com.mojang.realmsclient.RealmsMainScreen; import com.mojang.realmsclient.client.RealmsClient; import com.mojang.realmsclient.dto.PendingInvite; import com.mojang.realmsclient.exception.RealmsServiceException; import com.mojang.realmsclient.gui.RealmsDataFetcher; import com.mojang.realmsclient.gui.RowButton; import com.mojang.realmsclient.gui.screens.RealmsPendingInvitesScreen.Entry.AcceptRowButton; import com.mojang.realmsclient.gui.screens.RealmsPendingInvitesScreen.Entry.RejectRowButton; import com.mojang.realmsclient.util.RealmsUtil; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.ObjectSelectionList; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.realms.RealmsScreen; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class RealmsPendingInvitesScreen extends RealmsScreen { static final ResourceLocation ACCEPT_HIGHLIGHTED_SPRITE = ResourceLocation.withDefaultNamespace("pending_invite/accept_highlighted"); static final ResourceLocation ACCEPT_SPRITE = ResourceLocation.withDefaultNamespace("pending_invite/accept"); static final ResourceLocation REJECT_HIGHLIGHTED_SPRITE = ResourceLocation.withDefaultNamespace("pending_invite/reject_highlighted"); static final ResourceLocation REJECT_SPRITE = ResourceLocation.withDefaultNamespace("pending_invite/reject"); private static final Logger LOGGER = LogUtils.getLogger(); private static final Component NO_PENDING_INVITES_TEXT = Component.translatable("mco.invites.nopending"); static final Component ACCEPT_INVITE = Component.translatable("mco.invites.button.accept"); static final Component REJECT_INVITE = Component.translatable("mco.invites.button.reject"); private final Screen lastScreen; private final CompletableFuture> pendingInvites = CompletableFuture.supplyAsync(() -> { try { return RealmsClient.getOrCreate().pendingInvites().pendingInvites; } catch (RealmsServiceException var1) { LOGGER.error("Couldn't list invites", (Throwable)var1); return List.of(); } }, Util.ioPool()); @Nullable Component toolTip; RealmsPendingInvitesScreen.PendingInvitationSelectionList pendingInvitationSelectionList; private Button acceptButton; private Button rejectButton; public RealmsPendingInvitesScreen(Screen lastScreen, Component title) { super(title); this.lastScreen = lastScreen; } @Override public void init() { RealmsMainScreen.refreshPendingInvites(); this.pendingInvitationSelectionList = new RealmsPendingInvitesScreen.PendingInvitationSelectionList(); this.pendingInvites.thenAcceptAsync(list -> { List list2 = list.stream().map(pendingInvite -> new RealmsPendingInvitesScreen.Entry(pendingInvite)).toList(); this.pendingInvitationSelectionList.replaceEntries(list2); if (list2.isEmpty()) { this.minecraft.getNarrator().say(NO_PENDING_INVITES_TEXT); } }, this.screenExecutor); this.addRenderableWidget(this.pendingInvitationSelectionList); this.acceptButton = this.addRenderableWidget( Button.builder(ACCEPT_INVITE, button -> this.handleInvitation(true)).bounds(this.width / 2 - 174, this.height - 32, 100, 20).build() ); this.addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, button -> this.onClose()).bounds(this.width / 2 - 50, this.height - 32, 100, 20).build()); this.rejectButton = this.addRenderableWidget( Button.builder(REJECT_INVITE, button -> this.handleInvitation(false)).bounds(this.width / 2 + 74, this.height - 32, 100, 20).build() ); this.updateButtonStates(); } @Override public void onClose() { this.minecraft.setScreen(this.lastScreen); } void handleInvitation(boolean accept) { if (this.pendingInvitationSelectionList.getSelected() instanceof RealmsPendingInvitesScreen.Entry entry) { String string = entry.pendingInvite.invitationId; CompletableFuture.supplyAsync(() -> { try { RealmsClient realmsClient = RealmsClient.getOrCreate(); if (accept) { realmsClient.acceptInvitation(string); } else { realmsClient.rejectInvitation(string); } return true; } catch (RealmsServiceException var3) { LOGGER.error("Couldn't handle invite", (Throwable)var3); return false; } }, Util.ioPool()).thenAcceptAsync(boolean_ -> { if (boolean_) { this.pendingInvitationSelectionList.removeInvitation(entry); this.updateButtonStates(); RealmsDataFetcher realmsDataFetcher = this.minecraft.realmsDataFetcher(); if (accept) { realmsDataFetcher.serverListUpdateTask.reset(); } realmsDataFetcher.pendingInvitesTask.reset(); } }, this.screenExecutor); } } @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { this.toolTip = null; super.render(guiGraphics, mouseX, mouseY, partialTick); guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 12, -1); if (this.toolTip != null) { guiGraphics.renderTooltip(this.font, this.toolTip, mouseX, mouseY); } if (this.pendingInvites.isDone() && this.pendingInvitationSelectionList.hasPendingInvites()) { guiGraphics.drawCenteredString(this.font, NO_PENDING_INVITES_TEXT, this.width / 2, this.height / 2 - 20, -1); } } void updateButtonStates() { RealmsPendingInvitesScreen.Entry entry = this.pendingInvitationSelectionList.getSelected(); this.acceptButton.visible = entry != null; this.rejectButton.visible = entry != null; } @Environment(EnvType.CLIENT) class Entry extends ObjectSelectionList.Entry { private static final int TEXT_LEFT = 38; final PendingInvite pendingInvite; private final List rowButtons; Entry(final PendingInvite pendingInvite) { this.pendingInvite = pendingInvite; this.rowButtons = Arrays.asList(new AcceptRowButton(this), new RejectRowButton(this)); } @Override public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { this.renderPendingInvitationItem(guiGraphics, this.pendingInvite, left, top, mouseX, mouseY); } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { RowButton.rowButtonMouseClicked(RealmsPendingInvitesScreen.this.pendingInvitationSelectionList, this, this.rowButtons, button, mouseX, mouseY); return super.mouseClicked(mouseX, mouseY, button); } private void renderPendingInvitationItem(GuiGraphics guiGraphics, PendingInvite pendingInvite, int x, int y, int mouseX, int mouseY) { guiGraphics.drawString(RealmsPendingInvitesScreen.this.font, pendingInvite.realmName, x + 38, y + 1, -1); guiGraphics.drawString(RealmsPendingInvitesScreen.this.font, pendingInvite.realmOwnerName, x + 38, y + 12, 7105644); guiGraphics.drawString(RealmsPendingInvitesScreen.this.font, RealmsUtil.convertToAgePresentationFromInstant(pendingInvite.date), x + 38, y + 24, 7105644); RowButton.drawButtonsInRow(guiGraphics, this.rowButtons, RealmsPendingInvitesScreen.this.pendingInvitationSelectionList, x, y, mouseX, mouseY); RealmsUtil.renderPlayerFace(guiGraphics, x, y, 32, pendingInvite.realmOwnerUuid); } @Override public Component getNarration() { Component component = CommonComponents.joinLines( Component.literal(this.pendingInvite.realmName), Component.literal(this.pendingInvite.realmOwnerName), RealmsUtil.convertToAgePresentationFromInstant(this.pendingInvite.date) ); return Component.translatable("narrator.select", component); } } @Environment(EnvType.CLIENT) class PendingInvitationSelectionList extends ObjectSelectionList { public PendingInvitationSelectionList() { super(Minecraft.getInstance(), RealmsPendingInvitesScreen.this.width, RealmsPendingInvitesScreen.this.height - 72, 32, 36); } @Override public int getRowWidth() { return 260; } @Override public void setSelectedIndex(int selected) { super.setSelectedIndex(selected); RealmsPendingInvitesScreen.this.updateButtonStates(); } public boolean hasPendingInvites() { return this.getItemCount() == 0; } public void removeInvitation(RealmsPendingInvitesScreen.Entry entry) { this.removeEntry(entry); } } }