From 3e602b2d4ea0e192e00213a6f3bfda74e07d4fe5 Mon Sep 17 00:00:00 2001 From: TiggerTakkyTTT Date: Sat, 26 Sep 2026 07:50:35 +0700 Subject: [PATCH 1/2] Add read all button to changelog dialog --- .../base/dialog/ui/ChangelogDialog.java | 21 +++++++++++++++---- base/src/main/resources/lang/en_US.yml | 5 +++-- base/src/main/resources/lang/ru_RU.yml | 3 ++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java b/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java index f1909f2..053a9e0 100644 --- a/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java +++ b/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java @@ -12,6 +12,7 @@ import com.github.retrooper.packetevents.protocol.dialog.CommonDialogData; import com.github.retrooper.packetevents.protocol.dialog.Dialog; import com.github.retrooper.packetevents.protocol.dialog.DialogAction; +import com.github.retrooper.packetevents.protocol.dialog.MultiActionDialog; import com.github.retrooper.packetevents.protocol.dialog.NoticeDialog; import com.github.retrooper.packetevents.protocol.dialog.body.DialogBody; import com.github.retrooper.packetevents.protocol.dialog.body.ItemDialogBody; @@ -76,11 +77,17 @@ public class ChangelogDialog implements IDialog { null, true, false, canManage ? DialogAction.NONE : DialogAction.CLOSE, body, List.of() ); - ActionButton button = new ActionButton(new CommonButtonData( + ActionButton readAllButton = new ActionButton(new CommonButtonData( + translatableManual(p, "dialog.changelog.button.read_all"), + null, 100 + ), sessionManager.createStaticAction(this, "confirm_read")); + ActionButton closeButton = new ActionButton(new CommonButtonData( translatableManual(p, "dialog.changelog.button.close"), null, 60 - ), sessionManager.createStaticAction(this, "confirm_read")); - return new NoticeDialog(common, button); + ), sessionManager.createStaticAction(this, "close")); + boolean hasUnreadEntries = this.storage.listEntries().stream().anyMatch(e -> !e.hasRead(p)); + if (!hasUnreadEntries) return new NoticeDialog(common, closeButton); + return new MultiActionDialog(common, List.of(readAllButton), closeButton, 1); } private @NotNull Component formatEntry(@NotNull ChangelogEntry entry, @NotNull IPlayer player, @NotNull DialogSessionManager sessionManager, boolean canManage) { @@ -134,6 +141,12 @@ public void onActionTriggered(@NotNull String action, @Nullable NBTCompound data if (!uids.isEmpty()) source.asAudience().sendMessage(translatable("dialog.changelog.read", text(uids.size()))); } + case "close" -> { + if (canManage) { + sessionManager.endSession(source); + DialogPackets.clearDialog(source, DialogPackets.PacketPhase.PLAY); + } + } case "reopen" -> { if (canManage) this.showTo(source, sessionManager, DialogPackets.PacketPhase.PLAY); } @@ -166,7 +179,7 @@ public void onActionTriggered(@NotNull String action, @Nullable NBTCompound data } } finally { // Ensure the player is able to continue gameplay even if any exceptions occur - if (action.equals("confirm_read")) sessionManager.unfreeze(source); + if (action.equals("confirm_read") || action.equals("close")) sessionManager.unfreeze(source); } } diff --git a/base/src/main/resources/lang/en_US.yml b/base/src/main/resources/lang/en_US.yml index da9eab0..d8033a2 100644 --- a/base/src/main/resources/lang/en_US.yml +++ b/base/src/main/resources/lang/en_US.yml @@ -121,7 +121,8 @@ dialog: # Translations for the plugin's dialog UIs entry_line: "- " # The format for a single changelog line (adds a gray dash in front) unspecified_author: "Unspecified" # The author that will be shown when this field was left empty during publishing button: - close: " Exit" + read_all: " Read All" + close: " Exit" read: " Marked entries as read!" manage: changelog_action: @@ -133,4 +134,4 @@ dialog: # Translations for the plugin's dialog UIs content: |- Are you sure that you want to delete the selected changelog? - Please note that this action CANNOT BE UNDONE! \ No newline at end of file + Please note that this action CANNOT BE UNDONE! diff --git a/base/src/main/resources/lang/ru_RU.yml b/base/src/main/resources/lang/ru_RU.yml index 690ac85..47561eb 100644 --- a/base/src/main/resources/lang/ru_RU.yml +++ b/base/src/main/resources/lang/ru_RU.yml @@ -121,7 +121,8 @@ dialog: # Переводы диалоговых интерфейсов (UI) пл entry_line: "- " # Формат строки (добавляет серый дефис в начале) unspecified_author: "Не указан" # Автор по умолчанию button: - close: " Выход" + read_all: " Прочитать всё" + close: " Выход" read: " Отмечено как прочитанные: !" manage: changelog_action: From cd56fde51451eb6e9df856f068812a88a16bd309 Mon Sep 17 00:00:00 2001 From: TiggerTakkyTTT Date: Mon, 28 Sep 2026 07:31:52 +0700 Subject: [PATCH 2/2] Address read all review feedback --- .../changelogs/base/config/PluginConfig.java | 4 ++++ .../codingcat/changelogs/base/dialog/IDialog.java | 3 ++- .../changelogs/base/dialog/ui/ChangelogDialog.java | 14 +++++++++++--- base/src/main/resources/defaults/config.yml | 6 +++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/base/src/main/java/com/codingcat/changelogs/base/config/PluginConfig.java b/base/src/main/java/com/codingcat/changelogs/base/config/PluginConfig.java index 12ecf98..a1c24c3 100644 --- a/base/src/main/java/com/codingcat/changelogs/base/config/PluginConfig.java +++ b/base/src/main/java/com/codingcat/changelogs/base/config/PluginConfig.java @@ -92,6 +92,10 @@ public boolean showChangelogHeader() { return getBoolean("dialog_header", true); } + public boolean allowCloseWithoutRead() { + return getBoolean("allow_close_without_read", false); + } + public boolean useNativeFallbackPermissions() { return getBoolean("use_native_fallback_permissions", false); } diff --git a/base/src/main/java/com/codingcat/changelogs/base/dialog/IDialog.java b/base/src/main/java/com/codingcat/changelogs/base/dialog/IDialog.java index bcb3ebe..91a7113 100644 --- a/base/src/main/java/com/codingcat/changelogs/base/dialog/IDialog.java +++ b/base/src/main/java/com/codingcat/changelogs/base/dialog/IDialog.java @@ -51,7 +51,8 @@ public void recreate() { plugin.pluginConfig().getDateFormatter(), plugin.pluginConfig().showChangelogHeader(), plugin.pluginConfig().createChangelogHeaderStack(), - plugin.pluginConfig().useNativeFallbackPermissions() + plugin.pluginConfig().useNativeFallbackPermissions(), + plugin.pluginConfig().allowCloseWithoutRead() )); } diff --git a/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java b/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java index 053a9e0..057ab20 100644 --- a/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java +++ b/base/src/main/java/com/codingcat/changelogs/base/dialog/ui/ChangelogDialog.java @@ -10,10 +10,11 @@ import com.codingcat.changelogs.base.dialog.ui.editor.EditorSession; import com.codingcat.changelogs.platformapi.player.IPlayer; import com.github.retrooper.packetevents.protocol.dialog.CommonDialogData; +import com.github.retrooper.packetevents.protocol.dialog.ConfirmationDialog; import com.github.retrooper.packetevents.protocol.dialog.Dialog; import com.github.retrooper.packetevents.protocol.dialog.DialogAction; -import com.github.retrooper.packetevents.protocol.dialog.MultiActionDialog; import com.github.retrooper.packetevents.protocol.dialog.NoticeDialog; +import com.github.retrooper.packetevents.protocol.dialog.action.Action; import com.github.retrooper.packetevents.protocol.dialog.body.DialogBody; import com.github.retrooper.packetevents.protocol.dialog.body.ItemDialogBody; import com.github.retrooper.packetevents.protocol.dialog.body.PlainMessage; @@ -50,6 +51,7 @@ public class ChangelogDialog implements IDialog { private final boolean addHeader; private final @Nullable ItemStack headerItem; private final boolean useFallbackPermissions; + private final boolean allowCloseWithoutRead; @Override public @NotNull Dialog build(@NotNull IPlayer p, @NotNull DialogSessionManager sessionManager) { @@ -81,13 +83,19 @@ public class ChangelogDialog implements IDialog { translatableManual(p, "dialog.changelog.button.read_all"), null, 100 ), sessionManager.createStaticAction(this, "confirm_read")); + Action closeAction = null; + if (canManage) closeAction = sessionManager.createSessionBasedAction(this, "close", false); + // Configuration-phase viewers need a callback to release the join freeze after closing without reading. + else if (this.allowCloseWithoutRead && sessionManager.isFrozen(p)) + closeAction = sessionManager.createStaticAction(this, "close"); ActionButton closeButton = new ActionButton(new CommonButtonData( translatableManual(p, "dialog.changelog.button.close"), null, 60 - ), sessionManager.createStaticAction(this, "close")); + ), closeAction); boolean hasUnreadEntries = this.storage.listEntries().stream().anyMatch(e -> !e.hasRead(p)); if (!hasUnreadEntries) return new NoticeDialog(common, closeButton); - return new MultiActionDialog(common, List.of(readAllButton), closeButton, 1); + if (this.allowCloseWithoutRead) return new ConfirmationDialog(common, readAllButton, closeButton); + return new NoticeDialog(common, new ActionButton(closeButton.getButton(), readAllButton.getAction())); } private @NotNull Component formatEntry(@NotNull ChangelogEntry entry, @NotNull IPlayer player, @NotNull DialogSessionManager sessionManager, boolean canManage) { diff --git a/base/src/main/resources/defaults/config.yml b/base/src/main/resources/defaults/config.yml index c27abf4..c571396 100644 --- a/base/src/main/resources/defaults/config.yml +++ b/base/src/main/resources/defaults/config.yml @@ -44,6 +44,10 @@ use_native_fallback_permissions: false # The CONFIGURATION phase has the advantage of players not being able to take damage etc. due to the dialogs. dialog_phase: CONFIGURATION +# Whether players can close the changelog dialog without marking unread entries as read. +# When disabled, exiting the dialog automatically marks all entries as read. +allow_close_without_read: false + # Whether to add a header section to the changelog dialog that will show # above the actual changelogs. This can be used to give players a bit of context, # or link to e.g. a discord to give feedback, follow announcements, etc. @@ -60,4 +64,4 @@ dialog_header_item: "minecraft:written_book" # -- DO NOT MODIFY UNLESS YOU KNOW WHAT YOU ARE DOING -- # Manually enable workarounds/fixes for certain bugs in e.g. PacketEvents # that normally don't apply to the current version -enable_manual_workarounds: [] \ No newline at end of file +enable_manual_workarounds: []