Files
Team/src/main/java/me/viper/teamplugin/gui/MailboxGUI.java
2026-03-24 08:54:30 +01:00

313 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package me.viper.teamplugin.gui;
import me.viper.teamplugin.manager.LangManager;
import me.viper.teamplugin.manager.MailboxManager;
import me.viper.teamplugin.manager.MessageManager;
import me.viper.teamplugin.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.*;
/**
* MailboxGUI two-view postfach for TeamPlugin.
*
* LIST VIEW (54 slots)
* ┌─────────────────────────┐
* │ Header row (glass) │ slot 4 = mailbox info item
* │ Message items 9-44 │ WRITTEN_BOOK=unread, BOOK=read
* │ Footer nav 45/49/53 │ ← page | close | page →
* └─────────────────────────┘
*
* READ VIEW (54 slots)
* ┌─────────────────────────┐
* │ Background filler │
* │ Full message at 22 │
* │ Delete:20 Reply:24 │
* │ Back:49 │
* └─────────────────────────┘
*/
public class MailboxGUI {
private static final int ITEMS_PER_PAGE = 36; // rows 1-4, slots 9-44
/** UUID → current list-view page number */
private static final Map<UUID, Integer> CURRENT_PAGE = new HashMap<>();
/** UUID → whose mailbox is open (player name) */
private static final Map<UUID, String> OPEN_FOR_PLAYER = new HashMap<>();
/** UUID → msgId of message currently being read */
private static final Map<UUID, String> READING_ID = new HashMap<>();
// ── Open: list view ───────────────────────────────────────────────
/** Opens the caller's own mailbox at page 0. */
public static void openMailbox(Player viewer) {
openMailbox(viewer, viewer.getName(), 0);
}
/** Opens a specific player's mailbox at a given page (admins can inspect others). */
public static void openMailbox(Player viewer, String targetPlayer, int page) {
List<String[]> messages = MailboxManager.getParsedMessages(targetPlayer);
int totalPages = Math.max(1, (int) Math.ceil((double) messages.size() / ITEMS_PER_PAGE));
page = Math.max(0, Math.min(page, totalPages - 1));
OPEN_FOR_PLAYER.put(viewer.getUniqueId(), targetPlayer);
CURRENT_PAGE.put(viewer.getUniqueId(), page);
Inventory inv = Bukkit.createInventory(null, 54, Utils.color(getListTitle()));
// Header row
ItemStack headerGlass = filler(Material.CYAN_STAINED_GLASS_PANE);
for (int i = 0; i < 9; i++) inv.setItem(i, headerGlass);
// Footer row
ItemStack footerGlass = filler(Material.BLACK_STAINED_GLASS_PANE);
for (int i = 45; i < 54; i++) inv.setItem(i, footerGlass);
// Info item (slot 4)
int unread = MailboxManager.getUnreadCount(targetPlayer);
inv.setItem(4, buildInfoItem(targetPlayer, unread, page + 1, totalPages));
// Message items (slots 9-44)
int start = page * ITEMS_PER_PAGE;
for (int i = 0; i < ITEMS_PER_PAGE; i++) {
int idx = start + i;
if (idx >= messages.size()) break;
inv.setItem(9 + i, buildMessageListItem(messages.get(idx)));
}
// Navigation
if (page > 0) inv.setItem(45, navItem(Material.ARROW,
Utils.color(LangManager.get("mailbox_prev_page")),
List.of(Utils.color("&7Vorherige Seite"))));
inv.setItem(49, navItem(Material.BARRIER,
Utils.color(LangManager.get("mailbox_close")),
List.of(Utils.color("&7Postfach schließen"))));
if (page + 1 < totalPages) inv.setItem(53, navItem(Material.ARROW,
Utils.color(LangManager.get("mailbox_next_page")),
List.of(Utils.color("&7Nächste Seite"))));
viewer.openInventory(inv);
}
// ── Open: read view ───────────────────────────────────────────────
private static void openMessage(Player viewer, String[] parts) {
// parts: [id, from, isoTimestamp, read, text]
String msgId = parts[0];
String from = parts[1];
String date = Utils.prettifyIso(parts[2]);
String text = parts[4];
READING_ID.put(viewer.getUniqueId(), msgId);
String targetPlayer = OPEN_FOR_PLAYER.getOrDefault(viewer.getUniqueId(), viewer.getName());
MailboxManager.markRead(targetPlayer, msgId);
Inventory inv = Bukkit.createInventory(null, 54, Utils.color(getReadTitle()));
// Background
ItemStack bg = filler(Material.GRAY_STAINED_GLASS_PANE);
for (int i = 0; i < 54; i++) inv.setItem(i, bg);
// Message paper at slot 22
inv.setItem(22, buildFullMessageItem(from, date, text));
// Delete (slot 20)
inv.setItem(20, navItem(Material.RED_CONCRETE,
Utils.color(LangManager.get("mailbox_delete_btn")),
List.of(Utils.color("&7Nachricht endgültig löschen"))));
// Reply (slot 24)
inv.setItem(24, navItem(Material.WRITABLE_BOOK,
Utils.color(Utils.replace(LangManager.get("mailbox_reply_btn"), "%player%", from)),
List.of(Utils.color("&7An &b" + from + " &7antworten"))));
// Back (slot 49)
inv.setItem(49, navItem(Material.ARROW,
Utils.color(LangManager.get("mailbox_back_btn")),
List.of(Utils.color("&7Zurück zur Liste"))));
viewer.openInventory(inv);
}
// ── Click handlers ────────────────────────────────────────────────
public static void handleListClick(Player player, InventoryClickEvent e) {
e.setCancelled(true);
int slot = e.getRawSlot();
ItemStack clicked = e.getCurrentItem();
if (clicked == null || clicked.getType().isAir()) return;
String target = OPEN_FOR_PLAYER.getOrDefault(player.getUniqueId(), player.getName());
int page = CURRENT_PAGE.getOrDefault(player.getUniqueId(), 0);
switch (slot) {
case 45 -> openMailbox(player, target, page - 1);
case 49 -> {
cleanup(player.getUniqueId());
player.closeInventory();
}
case 53 -> openMailbox(player, target, page + 1);
default -> {
if (slot >= 9 && slot <= 44) {
List<String[]> messages = MailboxManager.getParsedMessages(target);
int idx = page * ITEMS_PER_PAGE + (slot - 9);
if (idx < messages.size()) openMessage(player, messages.get(idx));
}
}
}
}
public static void handleReadClick(Player player, InventoryClickEvent e) {
e.setCancelled(true);
int slot = e.getRawSlot();
ItemStack clicked = e.getCurrentItem();
if (clicked == null || clicked.getType().isAir()) return;
String target = OPEN_FOR_PLAYER.getOrDefault(player.getUniqueId(), player.getName());
String msgId = READING_ID.get(player.getUniqueId());
int page = CURRENT_PAGE.getOrDefault(player.getUniqueId(), 0);
switch (slot) {
case 20 -> { // delete
if (msgId != null) MailboxManager.delete(target, msgId);
READING_ID.remove(player.getUniqueId());
player.sendMessage(Utils.color(LangManager.get("mail_deleted")));
openMailbox(player, target, page);
}
case 24 -> { // reply
if (msgId != null) {
MailboxManager.getParsedMessages(target).stream()
.filter(a -> a[0].equals(msgId))
.findFirst()
.ifPresent(parts -> {
cleanup(player.getUniqueId());
player.closeInventory();
MessageManager.startReply(player, parts[1]);
});
}
}
case 49 -> { // back
READING_ID.remove(player.getUniqueId());
openMailbox(player, target, page);
}
}
}
// ── Title helpers ─────────────────────────────────────────────────
public static String getListTitle() {
return LangManager.get("mailbox_title");
}
public static String getReadTitle() {
return LangManager.get("mailbox_read_title");
}
public static boolean isListTitle(String colored) {
return colored.equals(Utils.color(getListTitle()));
}
public static boolean isReadTitle(String colored) {
return colored.equals(Utils.color(getReadTitle()));
}
// ── State cleanup ─────────────────────────────────────────────────
public static void cleanup(UUID uuid) {
CURRENT_PAGE.remove(uuid);
OPEN_FOR_PLAYER.remove(uuid);
READING_ID.remove(uuid);
}
// ── Item builders ─────────────────────────────────────────────────
private static ItemStack buildInfoItem(String owner, int unread, int page, int total) {
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
ItemMeta m = item.getItemMeta();
if (m != null) {
m.setDisplayName(Utils.color("&b&lPostfach &8 &7" + owner));
m.setLore(List.of(
Utils.color("&7Ungelesen&8: &e" + unread),
Utils.color("&7Seite &e" + page + " &7/ &e" + total)
));
item.setItemMeta(m);
}
return item;
}
private static ItemStack buildMessageListItem(String[] parts) {
// parts: [id, from, iso, read, text]
boolean read = "true".equals(parts[3]);
ItemStack item = new ItemStack(read ? Material.BOOK : Material.WRITTEN_BOOK);
ItemMeta m = item.getItemMeta();
if (m != null) {
m.setDisplayName(Utils.color((read ? "&7" : "&e&l") + "Von: " + parts[1]));
String preview = parts[4].length() > 38 ? parts[4].substring(0, 38) + "" : parts[4];
m.setLore(List.of(
Utils.color("&7" + Utils.prettifyIso(parts[2])),
Utils.color("&f" + preview),
"",
Utils.color(read ? "&8Gelesen" : "&eUngelesen Klicken zum Lesen")
));
item.setItemMeta(m);
}
return item;
}
private static ItemStack buildFullMessageItem(String from, String date, String text) {
ItemStack item = new ItemStack(Material.PAPER);
ItemMeta m = item.getItemMeta();
if (m != null) {
m.setDisplayName(Utils.color("&bVon: &e" + from + " &8| &7" + date));
List<String> lore = new ArrayList<>();
lore.add("");
for (String line : wrapText(text, 40)) lore.add(Utils.color("&f" + line));
m.setLore(lore);
item.setItemMeta(m);
}
return item;
}
// ── Generic helpers ───────────────────────────────────────────────
private static ItemStack filler(Material mat) {
ItemStack item = new ItemStack(mat);
ItemMeta m = item.getItemMeta();
if (m != null) { m.setDisplayName(" "); item.setItemMeta(m); }
return item;
}
private static ItemStack navItem(Material mat, String name, List<String> lore) {
ItemStack item = new ItemStack(mat);
ItemMeta m = item.getItemMeta();
if (m != null) { m.setDisplayName(name); m.setLore(lore); item.setItemMeta(m); }
return item;
}
/** Word-wraps {@code text} at {@code maxChars} characters per line. */
private static List<String> wrapText(String text, int maxChars) {
List<String> lines = new ArrayList<>();
String[] words = text.split(" ");
StringBuilder cur = new StringBuilder();
for (String w : words) {
if (cur.length() > 0 && cur.length() + 1 + w.length() > maxChars) {
lines.add(cur.toString());
cur = new StringBuilder(w);
} else {
if (cur.length() > 0) cur.append(' ');
cur.append(w);
}
}
if (cur.length() > 0) lines.add(cur.toString());
return lines.isEmpty() ? List.of(text) : lines;
}
}