package net.minecraft.client.gui.screens.reporting; import com.mojang.authlib.minecraft.report.AbuseReportLimits; import java.util.function.Consumer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.GuiMessageTag; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.MultiLineLabel; import net.minecraft.client.gui.components.ObjectSelectionList; import net.minecraft.client.gui.navigation.ScreenDirection; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.reporting.ChatSelectionLogFiller.Output; import net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.DividerEntry; import net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Heading; import net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.MessageEntry; import net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.MessageHeadingEntry; import net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.PaddingEntry; import net.minecraft.client.multiplayer.chat.ChatTrustLevel; import net.minecraft.client.multiplayer.chat.LoggedChatMessage; import net.minecraft.client.multiplayer.chat.LoggedChatMessage.Player; import net.minecraft.client.multiplayer.chat.report.ReportingContext; import net.minecraft.client.multiplayer.chat.report.ChatReport.Builder; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class ChatSelectionScreen extends Screen { static final ResourceLocation CHECKMARK_SPRITE = ResourceLocation.withDefaultNamespace("icon/checkmark"); private static final Component TITLE = Component.translatable("gui.chatSelection.title"); private static final Component CONTEXT_INFO = Component.translatable("gui.chatSelection.context"); @Nullable private final Screen lastScreen; private final ReportingContext reportingContext; private Button confirmSelectedButton; private MultiLineLabel contextInfoLabel; @Nullable private ChatSelectionScreen.ChatSelectionList chatSelectionList; final Builder report; private final Consumer onSelected; private ChatSelectionLogFiller chatLogFiller; public ChatSelectionScreen(@Nullable Screen lastScreen, ReportingContext reportingContext, Builder report, Consumer onSelected) { super(TITLE); this.lastScreen = lastScreen; this.reportingContext = reportingContext; this.report = report.copy(); this.onSelected = onSelected; } @Override protected void init() { this.chatLogFiller = new ChatSelectionLogFiller(this.reportingContext, this::canReport); this.contextInfoLabel = MultiLineLabel.create(this.font, CONTEXT_INFO, this.width - 16); this.chatSelectionList = this.addRenderableWidget(new ChatSelectionScreen.ChatSelectionList(this.minecraft, (this.contextInfoLabel.getLineCount() + 1) * 9)); this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, button -> this.onClose()).bounds(this.width / 2 - 155, this.height - 32, 150, 20).build()); this.confirmSelectedButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, button -> { this.onSelected.accept(this.report); this.onClose(); }).bounds(this.width / 2 - 155 + 160, this.height - 32, 150, 20).build()); this.updateConfirmSelectedButton(); this.extendLog(); this.chatSelectionList.setScrollAmount(this.chatSelectionList.maxScrollAmount()); } private boolean canReport(LoggedChatMessage message) { return message.canReport(this.report.reportedProfileId()); } private void extendLog() { int i = this.chatSelectionList.getMaxVisibleEntries(); this.chatLogFiller.fillNextPage(i, this.chatSelectionList); } void onReachedScrollTop() { this.extendLog(); } void updateConfirmSelectedButton() { this.confirmSelectedButton.active = !this.report.reportedMessages().isEmpty(); } @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { super.render(guiGraphics, mouseX, mouseY, partialTick); guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 10, -1); AbuseReportLimits abuseReportLimits = this.reportingContext.sender().reportLimits(); int i = this.report.reportedMessages().size(); int j = abuseReportLimits.maxReportedMessageCount(); Component component = Component.translatable("gui.chatSelection.selected", i, j); guiGraphics.drawCenteredString(this.font, component, this.width / 2, 26, -1); this.contextInfoLabel.renderCentered(guiGraphics, this.width / 2, this.chatSelectionList.getFooterTop()); } @Override public void onClose() { this.minecraft.setScreen(this.lastScreen); } @Override public Component getNarrationMessage() { return CommonComponents.joinForNarration(super.getNarrationMessage(), CONTEXT_INFO); } @Environment(EnvType.CLIENT) public class ChatSelectionList extends ObjectSelectionList implements Output { @Nullable private Heading previousHeading; public ChatSelectionList(final Minecraft minecraft, final int height) { super(minecraft, ChatSelectionScreen.this.width, ChatSelectionScreen.this.height - height - 80, 40, 16); } @Override public void setScrollAmount(double scrollAmount) { double d = this.scrollAmount(); super.setScrollAmount(scrollAmount); if (this.maxScrollAmount() > 1.0E-5F && scrollAmount <= 1.0E-5F && !Mth.equal(scrollAmount, d)) { ChatSelectionScreen.this.onReachedScrollTop(); } } @Override public void acceptMessage(int chatId, Player playerMessage) { boolean bl = playerMessage.canReport(ChatSelectionScreen.this.report.reportedProfileId()); ChatTrustLevel chatTrustLevel = playerMessage.trustLevel(); GuiMessageTag guiMessageTag = chatTrustLevel.createTag(playerMessage.message()); net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry = new MessageEntry( this, chatId, playerMessage.toContentComponent(), playerMessage.toNarrationComponent(), guiMessageTag, bl, true ); this.addEntryToTop(entry); this.updateHeading(playerMessage, bl); } private void updateHeading(Player loggedPlayerChatMessage, boolean canReport) { net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry = new MessageHeadingEntry( this, loggedPlayerChatMessage.profile(), loggedPlayerChatMessage.toHeadingComponent(), canReport ); this.addEntryToTop(entry); Heading heading = new Heading(loggedPlayerChatMessage.profileId(), entry); if (this.previousHeading != null && this.previousHeading.canCombine(heading)) { this.removeEntryFromTop(this.previousHeading.entry()); } this.previousHeading = heading; } @Override public void acceptDivider(Component text) { this.addEntryToTop(new PaddingEntry()); this.addEntryToTop(new DividerEntry(this, text)); this.addEntryToTop(new PaddingEntry()); this.previousHeading = null; } @Override public int getRowWidth() { return Math.min(350, this.width - 50); } public int getMaxVisibleEntries() { return Mth.positiveCeilDiv(this.height, this.itemHeight); } @Override protected void renderItem(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, int index, int left, int top, int width, int height) { net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry = this.getEntry(index); if (this.shouldHighlightEntry(entry)) { boolean bl = this.getSelected() == entry; int i = this.isFocused() && bl ? -1 : -8355712; this.renderSelection(guiGraphics, top, width, height, i, -16777216); } entry.render(guiGraphics, index, top, left, width, height, mouseX, mouseY, this.getHovered() == entry, partialTick); } private boolean shouldHighlightEntry(net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry) { if (entry.canSelect()) { boolean bl = this.getSelected() == entry; boolean bl2 = this.getSelected() == null; boolean bl3 = this.getHovered() == entry; return bl || bl2 && bl3 && entry.canReport(); } else { return false; } } @Nullable protected net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry nextEntry(ScreenDirection screenDirection) { return this.nextEntry(screenDirection, net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry::canSelect); } public void setSelected(@Nullable net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry) { super.setSelected(entry); net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry2 = this.nextEntry(ScreenDirection.UP); if (entry2 == null) { ChatSelectionScreen.this.onReachedScrollTop(); } } @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry entry = this.getSelected(); return entry != null && entry.keyPressed(keyCode, scanCode, modifiers) ? true : super.keyPressed(keyCode, scanCode, modifiers); } public int getFooterTop() { return this.getBottom() + 9; } } }