From c190fab22f8b6e45f6fe495d7ad7b5184e39f564 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Fri, 14 Mar 2025 22:01:24 +0100 Subject: [PATCH 01/27] Add FriendWidgets and lss code --- .../ui/widgets/FriendWidget.java | 70 ++++++++++++++ .../ui/widgets/FriendlistFriendWidget.java | 95 +++++++++++++++++++ .../themes/vanilla/lss/friend.lss | 39 ++++++++ 3 files changed, 204 insertions(+) create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java create mode 100644 core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java new file mode 100644 index 0000000..588ef87 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -0,0 +1,70 @@ +package com.rappytv.betterfriends.ui.widgets; + +import net.labymod.api.Laby; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.TextColor; +import net.labymod.api.client.gui.icon.Icon; +import net.labymod.api.client.gui.lss.property.annotation.AutoWidget; +import net.labymod.api.client.gui.screen.Parent; +import net.labymod.api.client.gui.screen.activity.Link; +import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.input.ButtonWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; +import net.labymod.api.client.gui.screen.widget.widgets.renderer.IconWidget; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import java.util.List; + +@Link("friend.lss") +@AutoWidget +public abstract class FriendWidget extends HorizontalListWidget { + + protected final Friend friend; + + public FriendWidget(Friend friend) { + this.friend = friend; + } + + @Override + public void initialize(Parent parent) { + super.initialize(parent); + + IconWidget headWidget = new IconWidget(Icon.head(this.friend.getUniqueId())) + .addId("player-head"); + headWidget.setHoverComponent(Component.translatable("Open on laby.net")); + headWidget.setPressable(() -> + Laby.references().chatExecutor().openUrl("https://laby.net/@" + this.friend.getUniqueId()) + ); + + ComponentWidget usernameWidget = ComponentWidget + .component(Component.text( + this.friend.getName(), + TextColor.color(this.friend.gameUser().visibleGroup().getColor().getRGB()) + )) + .addId("username"); + + usernameWidget.setHoverComponent(Component.translatable("Click to copy UUID")); + usernameWidget.setPressable(() -> + Laby.references().chatExecutor().copyToClipboard(this.friend.getUniqueId().toString()) + ); + + this.addEntry(headWidget); + this.addEntry(usernameWidget); + List buttons = this.getButtons(); + + if(!buttons.isEmpty()) { + HorizontalListWidget buttonWrapper = new HorizontalListWidget().addId("buttons"); + + for(ButtonWidget button : buttons) { + buttonWrapper.addEntry(button); + } + + this.addEntry(buttonWrapper); + } + } + + public Friend getFriend() { + return this.friend; + } + + public abstract List getButtons(); +} diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java new file mode 100644 index 0000000..480fad8 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java @@ -0,0 +1,95 @@ +package com.rappytv.betterfriends.ui.widgets; + +import net.labymod.api.Laby; +import net.labymod.api.Textures; +import net.labymod.api.Textures.SpriteCommon; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.client.gui.lss.property.annotation.AutoWidget; +import net.labymod.api.client.gui.screen.key.Key; +import net.labymod.api.client.gui.screen.widget.widgets.input.ButtonWidget; +import net.labymod.api.event.Subscribe; +import net.labymod.api.event.client.input.KeyEvent; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import java.util.List; + +@AutoWidget +public class FriendlistFriendWidget extends FriendWidget { + + private boolean skipConfirmation = false; + private ButtonWidget pinButton = null; + + public FriendlistFriendWidget(Friend friend) { + super(friend); + Laby.labyAPI().eventBus().registerListener(this); + } + + @Override + public List getButtons() { + this.pinButton = ButtonWidget.icon(Textures.SpriteCommon.PIN, () -> { + if (this.friend.isPinned()) { + this.friend.unpin(); + } else { + this.friend.pin(); + } + this.updatePinButton(); + }).addId("pin-button"); + this.updatePinButton(); + ButtonWidget noteButton = ButtonWidget.icon( + SpriteCommon.PAINT, + this.friend::openNoteEditor + ).addId("note-button"); + noteButton.setHoverComponent(Component.translatable( + "labymod.activity.labyconnect.chat.action.note" + )); + ButtonWidget removeButton = ButtonWidget.icon(Textures.SpriteCommon.X, () -> { + if (this.skipConfirmation) { + System.out.println("Removed " + this.friend.getName() + " without confirmation"); +// this.friend.remove(); + } else { + // TODO: show confirmation + System.out.println("Open friend remove confirmation for " + this.friend.getName()); + } + }).addId("remove-button"); + removeButton.setHoverComponent( + Component.translatable("Remove friend", NamedTextColor.RED) + .append(Component.newline()) + .append(Component.translatable( + "(Hold shift to skip confirmation)", + NamedTextColor.DARK_GRAY + )) + ); + return List.of(this.pinButton, noteButton, removeButton); + } + + private void updatePinButton() { + if (this.pinButton == null) { + return; + } + this.pinButton.setHoverComponent( + Component.translatable( + this.friend.isPinned() + ? "labymod.activity.labyconnect.chat.action.unpin" + : "labymod.activity.labyconnect.chat.action.pin" + ) + ); + } + + @Subscribe + public void onKeyDown(KeyEvent event) { + if (event.key() != Key.L_SHIFT) { + return; + } + if (event.state() == KeyEvent.State.PRESS) { + this.skipConfirmation = true; + } else if (event.state() == KeyEvent.State.UNPRESSED) { + this.skipConfirmation = false; + } + } + + @Override + public void destroy() { + super.destroy(); + Laby.labyAPI().eventBus().unregisterListener(this); + } +} diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss new file mode 100644 index 0000000..55d59dc --- /dev/null +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss @@ -0,0 +1,39 @@ +Friend, FriendlistFriend { + width: 100%; + height: 20; + padding: 1; + + .player-head { + margin-left: 3; + width: 16; + height: width; + } + + .username { + max-width: 80%; + width: fit-content; + scale-to-fit: true; + max-lines: 1; + margin-left: 2; + top: 2; + } + + .buttons { + height: fit-content; + width: fit-content; + alignment: right; + + Button { + width: 20; + height: width; + padding: 0; + } + + .pin-button { + .button-icon { + width: 50%; + height: width; + } + } + } +} \ No newline at end of file From fd5e182522c0c5cd62200b2406f6a80e4ad3e825 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Fri, 14 Mar 2025 22:01:53 +0100 Subject: [PATCH 02/27] Implement friend list activity --- .../config/BetterFriendsConfig.java | 10 ++ .../config/AdvancedFriendListActivity.java | 123 ++++++++++++++++++ .../themes/vanilla/lss/friend_list.lss | 31 +++++ 3 files changed, 164 insertions(+) create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java create mode 100644 core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index 4d7d52d..74040b8 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -2,7 +2,10 @@ import com.rappytv.betterfriends.config.subconfig.FriendNoteTagConfig; import com.rappytv.betterfriends.config.subconfig.PinIconConfig; +import com.rappytv.betterfriends.ui.activities.config.AdvancedFriendListActivity; import net.labymod.api.addon.AddonConfig; +import net.labymod.api.client.gui.screen.activity.Activity; +import net.labymod.api.client.gui.screen.widget.widgets.activity.settings.ActivitySettingWidget.ActivitySetting; import net.labymod.api.client.gui.screen.widget.widgets.input.SwitchWidget.SwitchSetting; import net.labymod.api.client.gui.screen.widget.widgets.input.TextFieldWidget.TextFieldSetting; import net.labymod.api.client.gui.screen.widget.widgets.input.color.ColorPickerWidget.ColorPickerSetting; @@ -13,6 +16,7 @@ import net.labymod.api.configuration.settings.annotation.SettingRequires; import net.labymod.api.configuration.settings.annotation.SettingSection; import net.labymod.api.util.Color; +import net.labymod.api.util.MethodOrder; @SpriteTexture("settings.png") public class BetterFriendsConfig extends AddonConfig { @@ -32,6 +36,12 @@ public class BetterFriendsConfig extends AddonConfig { @TextFieldSetting private final ConfigProperty friendPrefix = new ConfigProperty<>("&aⒻ"); + @MethodOrder(after = "friendPrefix") + @ActivitySetting + public Activity advancedFriendlist() { + return new AdvancedFriendListActivity(); + } + @SettingSection(value = "notifications", center = true) @SpriteSlot(x = 5) @SwitchSetting diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java new file mode 100644 index 0000000..89e5289 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java @@ -0,0 +1,123 @@ +package com.rappytv.betterfriends.ui.activities.config; + +import com.rappytv.betterfriends.ui.widgets.FriendWidget; +import com.rappytv.betterfriends.ui.widgets.FriendlistFriendWidget; +import net.labymod.api.Laby; +import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.client.gui.screen.Parent; +import net.labymod.api.client.gui.screen.activity.AutoActivity; +import net.labymod.api.client.gui.screen.activity.Link; +import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; +import net.labymod.api.client.gui.screen.widget.Widget; +import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.FlexibleContentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.ScrollWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.list.VerticalListWidget; +import net.labymod.api.event.Phase; +import net.labymod.api.event.Subscribe; +import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendAddEvent; +import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendRemoveEvent; +import net.labymod.api.event.labymod.labyconnect.session.login.LabyConnectFriendAddBulkEvent; +import net.labymod.api.event.labymod.user.UserUpdateDataEvent; +import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import net.labymod.api.util.ThreadSafe; +import java.util.List; + +@Link("friend_list.lss") +@AutoActivity +public class AdvancedFriendListActivity extends SimpleActivity { + + private final VerticalListWidget entries = new VerticalListWidget<>() + .addId("friends"); + + @Override + public void initialize(Parent parent) { + super.initialize(parent); + + FlexibleContentWidget container = new FlexibleContentWidget().addId("container"); + + // TODO: Fix sorting + this.entries.setComparator((f1, f2) -> { + if (!(f1 instanceof FriendWidget friendA && f2 instanceof FriendWidget friendB)) { + return 0; + } + System.out.println(friendA.getFriend().getName()); + System.out.println(friendB.getFriend().getName()); + return friendA.getFriend().getName().compareToIgnoreCase(friendB.getFriend().getName()); + }); + + ScrollWidget scroll = new ScrollWidget(this.entries); + container.addFlexibleContent(scroll); + this.document.addChild(container); + + LabyConnectSession session = Laby.references().labyConnect().getSession(); + + if (session == null || !session.isAuthenticated()) { + Laby.labyAPI().minecraft().executeOnRenderThread( + () -> container.addContentInitialized( + ComponentWidget.text("You are not connected to the LabyChat!", NamedTextColor.RED) + .addId("error") + ) + ); + scroll.setVisible(false); + } else { + this.initializeWithInfo(session.getFriends()); + } + } + + private void initializeWithInfo(List friends) { + if (ThreadSafe.isRenderThread()) { + this.initializeWithInfo(friends, false); + } else { + Laby.labyAPI().minecraft().executeOnRenderThread( + () -> this.initializeWithInfo(friends, true) + ); + } + } + + private void initializeWithInfo(List friends, boolean initialized) { + this.entries.getChildren().clear(); + for (Friend friend : friends) { + if (initialized) { + this.entries.addChildInitialized(new FriendlistFriendWidget(friend)); + } else { + this.entries.addChild(new FriendlistFriendWidget(friend)); + } + } + } + + @Subscribe + public void onUserUpdateData(final UserUpdateDataEvent event) { + if (event.phase() == Phase.POST) { + this.labyAPI.minecraft().executeOnRenderThread(() -> + AdvancedFriendListActivity.this.entries.reInitializeChildrenIf( + FriendWidget.class, + widget -> widget.getFriend().getUniqueId().equals( + event.gameUser().getUniqueId() + ) + ) + ); + } + } + + @Subscribe + public void onLabyConnectFriendAdd(LabyConnectFriendAddEvent event) { + this.entries.addChildAsync(new FriendlistFriendWidget(event.friend())); + } + + @Subscribe + public void onLabyConnectFriendAddBulk(LabyConnectFriendAddBulkEvent event) { + for (Friend friend : event.getFriends()) { + this.entries.addChildAsync(new FriendlistFriendWidget(friend)); + } + } + + @Subscribe + public void onLabyConnectFriendRemove(LabyConnectFriendRemoveEvent event) { + this.entries.removeChildIf( + FriendWidget.class, + widget -> widget.getFriend().getUniqueId().equals(event.friend().getUniqueId()) + ); + } +} \ No newline at end of file diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss new file mode 100644 index 0000000..0dddca1 --- /dev/null +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss @@ -0,0 +1,31 @@ +.container { + height: 100%; + width: 100%; + + Scroll { + width: 100%; + height: 100%; + + .friends { + margin-top: 5; + width: 100%; + height: fit-content; + } + + Scrollbar { + left: 0; + top: 0; + width: 5; + height: 100%; + margin-left: 5; + } + } + + .error { + font-size: 0.8; + width: fit-content; + margin-top: 100; + alignment-x: center; + alignment-y: center; + } + } \ No newline at end of file From 2ef6a7f1f3702eec3ca8b7d774d0c88980344561 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Fri, 14 Mar 2025 22:04:08 +0100 Subject: [PATCH 03/27] Optimize imports --- .../ui/activities/config/AdvancedFriendListActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java index 89e5289..fb63c58 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java @@ -2,13 +2,13 @@ import com.rappytv.betterfriends.ui.widgets.FriendWidget; import com.rappytv.betterfriends.ui.widgets.FriendlistFriendWidget; +import java.util.List; import net.labymod.api.Laby; import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.client.gui.screen.Parent; import net.labymod.api.client.gui.screen.activity.AutoActivity; import net.labymod.api.client.gui.screen.activity.Link; import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; -import net.labymod.api.client.gui.screen.widget.Widget; import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.FlexibleContentWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.ScrollWidget; @@ -22,7 +22,6 @@ import net.labymod.api.labyconnect.LabyConnectSession; import net.labymod.api.labyconnect.protocol.model.friend.Friend; import net.labymod.api.util.ThreadSafe; -import java.util.List; @Link("friend_list.lss") @AutoActivity From f8c003a9377f6570076291cb41c42a1e09ff488a Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 15 Mar 2025 19:57:51 +0100 Subject: [PATCH 04/27] Fix and improve FriendWidget sorting comparator --- .../config/AdvancedFriendListActivity.java | 31 ++++++++++++++++--- .../ui/widgets/FriendWidget.java | 8 ++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java index fb63c58..3cf75e8 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java @@ -20,6 +20,7 @@ import net.labymod.api.event.labymod.labyconnect.session.login.LabyConnectFriendAddBulkEvent; import net.labymod.api.event.labymod.user.UserUpdateDataEvent; import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.chat.ChatMessage; import net.labymod.api.labyconnect.protocol.model.friend.Friend; import net.labymod.api.util.ThreadSafe; @@ -36,14 +37,34 @@ public void initialize(Parent parent) { FlexibleContentWidget container = new FlexibleContentWidget().addId("container"); - // TODO: Fix sorting this.entries.setComparator((f1, f2) -> { - if (!(f1 instanceof FriendWidget friendA && f2 instanceof FriendWidget friendB)) { + if (!(f1 instanceof FriendWidget friendWidget1 && f2 instanceof FriendWidget friendWidget2)) { return 0; } - System.out.println(friendA.getFriend().getName()); - System.out.println(friendB.getFriend().getName()); - return friendA.getFriend().getName().compareToIgnoreCase(friendB.getFriend().getName()); + Friend friend1 = friendWidget1.getFriend(); + Friend friend2 = friendWidget2.getFriend(); + int comparePin = Boolean.compare(friend2.isPinned(), friend1.isPinned()); + if (comparePin != 0) { + return comparePin; + } else { + int compareStatus = Boolean.compare(friend2.isOnline(), friend1.isOnline()); + if (compareStatus != 0) { + return compareStatus; + } else { + ChatMessage message1 = friend1.chat().getLastMessage(); + ChatMessage message2 = friend2.chat().getLastMessage(); + if (message1 != null || message2 != null) { + int compareLastMessage = Long.compare( + message2 != null ? message2.getTimestamp() : 0L, + message1 != null ? message1.getTimestamp() : 0L + ); + if (compareLastMessage != 0) { + return compareLastMessage; + } + } + return Long.compare(friend2.getLastOnline(), friend1.getLastOnline()); + } + } }); ScrollWidget scroll = new ScrollWidget(this.entries); diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index 588ef87..fa8d956 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -1,5 +1,6 @@ package com.rappytv.betterfriends.ui.widgets; +import java.util.List; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.format.TextColor; @@ -12,7 +13,6 @@ import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; import net.labymod.api.client.gui.screen.widget.widgets.renderer.IconWidget; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import java.util.List; @Link("friend.lss") @AutoWidget @@ -66,5 +66,11 @@ public Friend getFriend() { return this.friend; } + // Without this the comparator just doesn't work for whatever reason + @Override + public int getSortingValue() { + return 1; + } + public abstract List getButtons(); } From 1e3afb1c678ae2e01fa722c23c60eac7b1fce02e Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 15 Mar 2025 20:08:17 +0100 Subject: [PATCH 05/27] Generalize AdvancedFriendListActivity --- .../config/BetterFriendsConfig.java | 5 +++-- ...tActivity.java => FriendListActivity.java} | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) rename core/src/main/java/com/rappytv/betterfriends/ui/activities/config/{AdvancedFriendListActivity.java => FriendListActivity.java} (86%) diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index 74040b8..842d3bc 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -2,7 +2,8 @@ import com.rappytv.betterfriends.config.subconfig.FriendNoteTagConfig; import com.rappytv.betterfriends.config.subconfig.PinIconConfig; -import com.rappytv.betterfriends.ui.activities.config.AdvancedFriendListActivity; +import com.rappytv.betterfriends.ui.activities.config.FriendListActivity; +import com.rappytv.betterfriends.ui.widgets.FriendlistFriendWidget; import net.labymod.api.addon.AddonConfig; import net.labymod.api.client.gui.screen.activity.Activity; import net.labymod.api.client.gui.screen.widget.widgets.activity.settings.ActivitySettingWidget.ActivitySetting; @@ -39,7 +40,7 @@ public class BetterFriendsConfig extends AddonConfig { @MethodOrder(after = "friendPrefix") @ActivitySetting public Activity advancedFriendlist() { - return new AdvancedFriendListActivity(); + return new FriendListActivity<>(FriendlistFriendWidget::new); } @SettingSection(value = "notifications", center = true) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java similarity index 86% rename from core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java rename to core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java index 3cf75e8..fa07969 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/AdvancedFriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java @@ -1,8 +1,8 @@ package com.rappytv.betterfriends.ui.activities.config; import com.rappytv.betterfriends.ui.widgets.FriendWidget; -import com.rappytv.betterfriends.ui.widgets.FriendlistFriendWidget; import java.util.List; +import java.util.function.Function; import net.labymod.api.Laby; import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.client.gui.screen.Parent; @@ -26,10 +26,15 @@ @Link("friend_list.lss") @AutoActivity -public class AdvancedFriendListActivity extends SimpleActivity { +public class FriendListActivity extends SimpleActivity { - private final VerticalListWidget entries = new VerticalListWidget<>() + private final VerticalListWidget entries = new VerticalListWidget<>() .addId("friends"); + private final Function friendWidgetConstructor; + + public FriendListActivity(Function friendWidgetConstructor) { + this.friendWidgetConstructor = friendWidgetConstructor; + } @Override public void initialize(Parent parent) { @@ -100,9 +105,9 @@ private void initializeWithInfo(List friends, boolean initialized) { this.entries.getChildren().clear(); for (Friend friend : friends) { if (initialized) { - this.entries.addChildInitialized(new FriendlistFriendWidget(friend)); + this.entries.addChildInitialized(this.friendWidgetConstructor.apply(friend)); } else { - this.entries.addChild(new FriendlistFriendWidget(friend)); + this.entries.addChild(this.friendWidgetConstructor.apply(friend)); } } } @@ -111,7 +116,7 @@ private void initializeWithInfo(List friends, boolean initialized) { public void onUserUpdateData(final UserUpdateDataEvent event) { if (event.phase() == Phase.POST) { this.labyAPI.minecraft().executeOnRenderThread(() -> - AdvancedFriendListActivity.this.entries.reInitializeChildrenIf( + FriendListActivity.this.entries.reInitializeChildrenIf( FriendWidget.class, widget -> widget.getFriend().getUniqueId().equals( event.gameUser().getUniqueId() @@ -123,13 +128,13 @@ public void onUserUpdateData(final UserUpdateDataEvent event) { @Subscribe public void onLabyConnectFriendAdd(LabyConnectFriendAddEvent event) { - this.entries.addChildAsync(new FriendlistFriendWidget(event.friend())); + this.entries.addChildAsync(this.friendWidgetConstructor.apply(event.friend())); } @Subscribe public void onLabyConnectFriendAddBulk(LabyConnectFriendAddBulkEvent event) { for (Friend friend : event.getFriends()) { - this.entries.addChildAsync(new FriendlistFriendWidget(friend)); + this.entries.addChildAsync(this.friendWidgetConstructor.apply(friend)); } } From a211998dc15387c91b70ad475dafd4f80e0641af Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 15 Mar 2025 20:17:12 +0100 Subject: [PATCH 06/27] Add pinned icon, improve logic of pin button --- .../ui/widgets/FriendWidget.java | 8 +++++ .../ui/widgets/FriendlistFriendWidget.java | 30 +++++++------------ .../themes/vanilla/lss/friend.lss | 6 ++++ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index fa8d956..4312470 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -2,6 +2,7 @@ import java.util.List; import net.labymod.api.Laby; +import net.labymod.api.Textures.SpriteCommon; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.format.TextColor; import net.labymod.api.client.gui.icon.Icon; @@ -49,6 +50,13 @@ public void initialize(Parent parent) { this.addEntry(headWidget); this.addEntry(usernameWidget); + + if (this.friend.isPinned()) { + IconWidget pinIconWidget = new IconWidget(SpriteCommon.PIN) + .addId("pin-icon"); + this.addEntry(pinIconWidget); + } + List buttons = this.getButtons(); if(!buttons.isEmpty()) { diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java index 480fad8..a4e0ad3 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java @@ -1,5 +1,6 @@ package com.rappytv.betterfriends.ui.widgets; +import java.util.List; import net.labymod.api.Laby; import net.labymod.api.Textures; import net.labymod.api.Textures.SpriteCommon; @@ -11,13 +12,11 @@ import net.labymod.api.event.Subscribe; import net.labymod.api.event.client.input.KeyEvent; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import java.util.List; @AutoWidget public class FriendlistFriendWidget extends FriendWidget { private boolean skipConfirmation = false; - private ButtonWidget pinButton = null; public FriendlistFriendWidget(Friend friend) { super(friend); @@ -26,15 +25,21 @@ public FriendlistFriendWidget(Friend friend) { @Override public List getButtons() { - this.pinButton = ButtonWidget.icon(Textures.SpriteCommon.PIN, () -> { + ButtonWidget pinButton = ButtonWidget.icon(Textures.SpriteCommon.PIN, () -> { if (this.friend.isPinned()) { this.friend.unpin(); } else { this.friend.pin(); } - this.updatePinButton(); + this.reInitialize(); }).addId("pin-button"); - this.updatePinButton(); + pinButton.setHoverComponent( + Component.translatable( + this.friend.isPinned() + ? "labymod.activity.labyconnect.chat.action.unpin" + : "labymod.activity.labyconnect.chat.action.pin" + ) + ); ButtonWidget noteButton = ButtonWidget.icon( SpriteCommon.PAINT, this.friend::openNoteEditor @@ -59,20 +64,7 @@ public List getButtons() { NamedTextColor.DARK_GRAY )) ); - return List.of(this.pinButton, noteButton, removeButton); - } - - private void updatePinButton() { - if (this.pinButton == null) { - return; - } - this.pinButton.setHoverComponent( - Component.translatable( - this.friend.isPinned() - ? "labymod.activity.labyconnect.chat.action.unpin" - : "labymod.activity.labyconnect.chat.action.pin" - ) - ); + return List.of(pinButton, noteButton, removeButton); } @Subscribe diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss index 55d59dc..26d97b9 100644 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss @@ -18,6 +18,12 @@ Friend, FriendlistFriend { top: 2; } + .pin-icon { + margin-left: 3; + width: 8; + height: width; + } + .buttons { height: fit-content; width: fit-content; From 5dbf8d4bbe19eb1a2efabd15784b83489a160655 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 15 Mar 2025 20:34:44 +0100 Subject: [PATCH 07/27] Add status indicator --- .../ui/widgets/FriendWidget.java | 20 +++++++++++++++++++ .../themes/vanilla/lss/friend.lss | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index 4312470..6e9ba2a 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -4,6 +4,7 @@ import net.labymod.api.Laby; import net.labymod.api.Textures.SpriteCommon; import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.client.component.format.TextColor; import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.client.gui.lss.property.annotation.AutoWidget; @@ -13,6 +14,7 @@ import net.labymod.api.client.gui.screen.widget.widgets.input.ButtonWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; import net.labymod.api.client.gui.screen.widget.widgets.renderer.IconWidget; +import net.labymod.api.labyconnect.protocol.model.UserStatus; import net.labymod.api.labyconnect.protocol.model.friend.Friend; @Link("friend.lss") @@ -29,6 +31,23 @@ public FriendWidget(Friend friend) { public void initialize(Parent parent) { super.initialize(parent); + UserStatus userStatus = this.friend.userStatus(); + IconWidget indicatorWidget = new IconWidget(SpriteCommon.STATUS_INDICATOR); + indicatorWidget.addId("indicator"); + indicatorWidget.color().set(userStatus.getColor().getRGB()); + Component statusComponent = Component.translatable( + userStatus.getLocalTranslationKey(), + userStatus.textColor() + ); + + if (userStatus == UserStatus.OFFLINE) { + statusComponent = Component.translatable( + "betterfriends.notifications.statusUpdate.offline", + NamedTextColor.DARK_GRAY + ); + } + indicatorWidget.setHoverComponent(statusComponent); + IconWidget headWidget = new IconWidget(Icon.head(this.friend.getUniqueId())) .addId("player-head"); headWidget.setHoverComponent(Component.translatable("Open on laby.net")); @@ -48,6 +67,7 @@ public void initialize(Parent parent) { Laby.references().chatExecutor().copyToClipboard(this.friend.getUniqueId().toString()) ); + this.addEntry(indicatorWidget); this.addEntry(headWidget); this.addEntry(usernameWidget); diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss index 26d97b9..06ddd72 100644 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss @@ -9,6 +9,11 @@ Friend, FriendlistFriend { height: width; } + .indicator { + width: 8; + height: width; + } + .username { max-width: 80%; width: fit-content; From c9473496b1082eced078734ffc2fcb5fd024e8ed Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 15 Mar 2025 20:38:08 +0100 Subject: [PATCH 08/27] Move advanced friend list up, add translation key --- .../betterfriends/config/BetterFriendsConfig.java | 13 +++++++------ .../resources/assets/betterfriends/i18n/en_us.json | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index 842d3bc..82b66e4 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -29,6 +29,13 @@ public class BetterFriendsConfig extends AddonConfig { @SpriteSlot(x = 1) @ColorPickerSetting private final ConfigProperty prefixColor = new ConfigProperty<>(Color.ofRGB(255, 102, 0)); + + @MethodOrder(after = "prefixColor") + @ActivitySetting + public Activity advancedFriendlist() { + return new FriendListActivity<>(FriendlistFriendWidget::new); + } + @SpriteSlot(size = 8, x = 4) private final PinIconConfig pinIconConfig = new PinIconConfig(); @SpriteSlot(x = 3) @@ -37,12 +44,6 @@ public class BetterFriendsConfig extends AddonConfig { @TextFieldSetting private final ConfigProperty friendPrefix = new ConfigProperty<>("&aⒻ"); - @MethodOrder(after = "friendPrefix") - @ActivitySetting - public Activity advancedFriendlist() { - return new FriendListActivity<>(FriendlistFriendWidget::new); - } - @SettingSection(value = "notifications", center = true) @SpriteSlot(x = 5) @SwitchSetting diff --git a/core/src/main/resources/assets/betterfriends/i18n/en_us.json b/core/src/main/resources/assets/betterfriends/i18n/en_us.json index 6c2d601..61abe89 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -22,6 +22,9 @@ "name": "Prefix color", "description": "This option changes the color theme of the \"BF »\" prefix which is prepended to addon messages." }, + "advancedFriendlist": { + "name": "Advanced friend list" + }, "pinIconConfig": { "name": "Friend pin icon", "pinIcon": { From 054764d7f27f486b29b3df079aeb4e41ec00b855 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sun, 16 Mar 2025 20:04:13 +0100 Subject: [PATCH 09/27] Change friend list behavior, add search filter --- .../activities/config/FriendListActivity.java | 92 ++++++++++++------- .../themes/vanilla/lss/friend_list.lss | 1 + 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java index fa07969..f905d19 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java @@ -1,17 +1,20 @@ package com.rappytv.betterfriends.ui.activities.config; import com.rappytv.betterfriends.ui.widgets.FriendWidget; +import java.util.ArrayList; import java.util.List; import java.util.function.Function; import net.labymod.api.Laby; -import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.client.component.Component; import net.labymod.api.client.gui.screen.Parent; import net.labymod.api.client.gui.screen.activity.AutoActivity; import net.labymod.api.client.gui.screen.activity.Link; import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; +import net.labymod.api.client.gui.screen.widget.widgets.input.TextFieldWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.FlexibleContentWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.ScrollWidget; +import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.list.VerticalListWidget; import net.labymod.api.event.Phase; import net.labymod.api.event.Subscribe; @@ -20,17 +23,20 @@ import net.labymod.api.event.labymod.labyconnect.session.login.LabyConnectFriendAddBulkEvent; import net.labymod.api.event.labymod.user.UserUpdateDataEvent; import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.User; import net.labymod.api.labyconnect.protocol.model.chat.ChatMessage; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import net.labymod.api.util.ThreadSafe; @Link("friend_list.lss") @AutoActivity public class FriendListActivity extends SimpleActivity { + private final Function friendWidgetConstructor; private final VerticalListWidget entries = new VerticalListWidget<>() .addId("friends"); - private final Function friendWidgetConstructor; + private final ComponentWidget error = ComponentWidget.empty().addId("error"); + private ScrollWidget scroll; + private String filterQuery = ""; public FriendListActivity(Function friendWidgetConstructor) { this.friendWidgetConstructor = friendWidgetConstructor; @@ -42,6 +48,16 @@ public void initialize(Parent parent) { FlexibleContentWidget container = new FlexibleContentWidget().addId("container"); + HorizontalListWidget filterSettings = new HorizontalListWidget(); + + TextFieldWidget searchField = new TextFieldWidget(); + searchField.addId("search-field"); + searchField.placeholder(Component.translatable("labymod.ui.textfield.search")); + searchField.setText(this.filterQuery); + searchField.updateListener(this::applyFriendsFilter); + + filterSettings.addEntry(searchField); + this.entries.setComparator((f1, f2) -> { if (!(f1 instanceof FriendWidget friendWidget1 && f2 instanceof FriendWidget friendWidget2)) { return 0; @@ -71,45 +87,59 @@ public void initialize(Parent parent) { } } }); + this.initializeFriendlist(false); - ScrollWidget scroll = new ScrollWidget(this.entries); - container.addFlexibleContent(scroll); + this.scroll = new ScrollWidget(this.entries); + container.addContent(filterSettings); + container.addFlexibleContent(this.scroll); this.document.addChild(container); + } + private void initializeFriendlist(boolean initialized) { + this.entries.getChildren().clear(); LabyConnectSession session = Laby.references().labyConnect().getSession(); - if (session == null || !session.isAuthenticated()) { - Laby.labyAPI().minecraft().executeOnRenderThread( - () -> container.addContentInitialized( - ComponentWidget.text("You are not connected to the LabyChat!", NamedTextColor.RED) - .addId("error") - ) - ); - scroll.setVisible(false); - } else { - this.initializeWithInfo(session.getFriends()); + this.error.setComponent(Component.text("You are not connected to the LabyChat!")); + this.error.setVisible(true); + this.scroll.setVisible(false); + return; + } + this.error.setVisible(false); + this.scroll.setVisible(true); + + List children = new ArrayList<>(); + int addedOfflineFriends = 0; + + for (Friend friend : session.getFriends()) { + boolean offline = !friend.isOnline(); + if ((!offline || addedOfflineFriends < 100 || friend.isPinned()) && this.isUserInFilter( + friend)) { + children.add(this.friendWidgetConstructor.apply(friend)); + if (offline) { + addedOfflineFriends++; + } + } } - } - private void initializeWithInfo(List friends) { - if (ThreadSafe.isRenderThread()) { - this.initializeWithInfo(friends, false); + if (initialized) { + this.entries.addChildrenInitialized(children, true); } else { - Laby.labyAPI().minecraft().executeOnRenderThread( - () -> this.initializeWithInfo(friends, true) - ); + this.entries.addChildren(children, true); } } - private void initializeWithInfo(List friends, boolean initialized) { - this.entries.getChildren().clear(); - for (Friend friend : friends) { - if (initialized) { - this.entries.addChildInitialized(this.friendWidgetConstructor.apply(friend)); - } else { - this.entries.addChild(this.friendWidgetConstructor.apply(friend)); - } - } + private void applyFriendsFilter(String query) { + this.filterQuery = query; + this.initializeFriendlist(true); + } + + private boolean hasFilter() { + return this.filterQuery != null && !this.filterQuery.isEmpty(); + } + + private boolean isUserInFilter(User user) { + return !this.hasFilter() || user.getName().toLowerCase() + .contains(this.filterQuery.toLowerCase()); } @Subscribe diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss index 0dddca1..20ee684 100644 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss @@ -23,6 +23,7 @@ .error { font-size: 0.8; + text-color: red; width: fit-content; margin-top: 100; alignment-x: center; From 6e798a9dc50f9db27d61621e0eb689bfd71fc03f Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sun, 16 Mar 2025 20:23:03 +0100 Subject: [PATCH 10/27] Translate FriendWidget --- .../com/rappytv/betterfriends/ui/widgets/FriendWidget.java | 4 ++-- core/src/main/resources/assets/betterfriends/i18n/en_us.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index 6e9ba2a..5e8602a 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -50,7 +50,7 @@ public void initialize(Parent parent) { IconWidget headWidget = new IconWidget(Icon.head(this.friend.getUniqueId())) .addId("player-head"); - headWidget.setHoverComponent(Component.translatable("Open on laby.net")); + headWidget.setHoverComponent(Component.translatable("betterfriends.general.labynet")); headWidget.setPressable(() -> Laby.references().chatExecutor().openUrl("https://laby.net/@" + this.friend.getUniqueId()) ); @@ -62,7 +62,7 @@ public void initialize(Parent parent) { )) .addId("username"); - usernameWidget.setHoverComponent(Component.translatable("Click to copy UUID")); + usernameWidget.setHoverComponent(Component.translatable("betterfriends.general.copyUuid")); usernameWidget.setPressable(() -> Laby.references().chatExecutor().copyToClipboard(this.friend.getUniqueId().toString()) ); diff --git a/core/src/main/resources/assets/betterfriends/i18n/en_us.json b/core/src/main/resources/assets/betterfriends/i18n/en_us.json index 61abe89..c73b6ca 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -136,7 +136,8 @@ } }, "general": { - "labynet": "Open on laby.net" + "labynet": "Open on laby.net", + "copyUuid": "Click to copy UUID" }, "errors": { "notConnected": "You're not connected to the LabyChat!" From 29c635b74777bd95501ee2f65542437b350fd76b Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sun, 16 Mar 2025 21:28:15 +0100 Subject: [PATCH 11/27] Rename NameHelper, add group sorting functionality --- .../betterfriends/BetterFriendsAddon.java | 2 + .../command/BetterFriendsCommand.java | 6 +-- .../listeners/FriendRemoveListener.java | 4 +- .../FriendRequestReceiveListener.java | 4 +- .../FriendRequestRemoveListener.java | 4 +- .../listeners/FriendServerStateListener.java | 4 +- .../listeners/FriendStatusUpdateListener.java | 4 +- .../listeners/LabyChatReceiveListener.java | 6 +-- .../betterfriends/utils/GroupHelper.java | 53 +++++++++++++++++++ .../betterfriends/utils/NameHelper.java | 16 ------ 10 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java delete mode 100644 core/src/main/java/com/rappytv/betterfriends/utils/NameHelper.java diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index 4a64d06..8298378 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -19,6 +19,7 @@ import com.rappytv.betterfriends.ui.hud.UnreadChatCountWidget; import com.rappytv.betterfriends.ui.tags.FriendNoteNameTag; import com.rappytv.betterfriends.ui.tags.FriendPinIconTag; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.addon.LabyAddon; import net.labymod.api.client.component.Component; @@ -41,6 +42,7 @@ public class BetterFriendsAddon extends LabyAddon { protected void enable() { instance = this; this.registerSettingCategory(); + GroupHelper.registerGroupIds(); this.registerCommand(new BetterFriendsCommand()); diff --git a/core/src/main/java/com/rappytv/betterfriends/command/BetterFriendsCommand.java b/core/src/main/java/com/rappytv/betterfriends/command/BetterFriendsCommand.java index 5e12afe..0401b9b 100644 --- a/core/src/main/java/com/rappytv/betterfriends/command/BetterFriendsCommand.java +++ b/core/src/main/java/com/rappytv/betterfriends/command/BetterFriendsCommand.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.UUID; import com.rappytv.betterfriends.listeners.LabyChatReceiveListener; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.client.chat.command.Command; import net.labymod.api.client.chat.command.SubCommand; @@ -99,7 +99,7 @@ public boolean execute(String prefix, String[] arguments) { .append(Component.translatable( this.getTranslationKey("success.accept"), NamedTextColor.GRAY, - NameHelper.getColoredName(request.getName(), request.gameUser()) + GroupHelper.getColoredName(request.getName(), request.gameUser()) )) ); return true; @@ -160,7 +160,7 @@ public boolean execute(String prefix, String[] arguments) { .append(Component.translatable( this.getTranslationKey("success.decline"), NamedTextColor.GRAY, - NameHelper.getColoredName(request.getName(), request.gameUser()) + GroupHelper.getColoredName(request.getName(), request.gameUser()) )) ); return true; diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java index 24e6fe9..a849989 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.client.component.Component; import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.event.Subscribe; @@ -25,7 +25,7 @@ public void onFriendRemove(LabyConnectFriendRemoveEvent event) { .title(Component.translatable("betterfriends.notifications.friendRemoval.title")) .text(Component.translatable( "betterfriends.notifications.friendRemoval.description", - NameHelper.getColoredName(event.friend()) + GroupHelper.getColoredName(event.friend()) )) .icon(Icon.head(event.friend().getUniqueId(), true)) .duration(15000) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java index db2ac5f..066d751 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.event.ClickEvent; @@ -25,7 +25,7 @@ public void onFriendRequestReceive(LabyConnectIncomingFriendRequestAddEvent even return; } IncomingFriendRequest request = event.request(); - Component sender = NameHelper.getColoredName(request.getName(), request.gameUser()) + Component sender = GroupHelper.getColoredName(request.getName(), request.gameUser()) .hoverEvent(HoverEvent.showText(Component.translatable( "betterfriends.general.labynet", NamedTextColor.DARK_PURPLE diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java index 43efb4d..65b385c 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.client.component.Component; import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.event.Subscribe; @@ -34,7 +34,7 @@ public void onFriendRequestRemove(LabyConnectOutgoingFriendRequestRemoveEvent ev .title(Component.translatable("betterfriends.notifications.friendRequestRemoval.title")) .text(Component.translatable( "betterfriends.notifications.friendRequestRemoval.description", - NameHelper.getColoredName(event.request().getName(), event.request().gameUser()) + GroupHelper.getColoredName(event.request().getName(), event.request().gameUser()) )) .icon(Icon.head(event.request().getUniqueId(), true)) .duration(15000) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java index 05b3e41..a7418f5 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.event.ClickEvent; import net.labymod.api.client.component.event.HoverEvent; @@ -68,7 +68,7 @@ public void onServerUpdate(LabyConnectFriendServerEvent event) { this.addon.displayMessage( Component.empty() .append(BetterFriendsAddon.getPrefix()) - .append(NameHelper.getColoredName(friend)) + .append(GroupHelper.getColoredName(friend)) .append(Component.space()) .append(text) .color(NamedTextColor.GRAY) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendStatusUpdateListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendStatusUpdateListener.java index c2e74a8..064e7b5 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendStatusUpdateListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendStatusUpdateListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.event.Subscribe; @@ -39,7 +39,7 @@ public void onStatusUpdate(LabyConnectFriendStatusEvent event) { .append(BetterFriendsAddon.getPrefix()) .append(Component.translatable( "betterfriends.notifications.statusUpdate.message", - NameHelper.getColoredName(event.friend()), + GroupHelper.getColoredName(event.friend()), stateComponent )) .color(NamedTextColor.GRAY) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java index 0d7b77f..760fde3 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.listeners; import com.rappytv.betterfriends.BetterFriendsAddon; -import com.rappytv.betterfriends.utils.NameHelper; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.event.ClickEvent; @@ -51,9 +51,9 @@ public void onChatReceive(LabyConnectChatMessageEvent event) { Component component = Component.empty() .append(BetterFriendsAddon.getPrefix()) - .append(NameHelper.getColoredName(sender.getName(), sender.gameUser())) + .append(GroupHelper.getColoredName(sender.getName(), sender.gameUser())) .append(Component.text(" → ", NamedTextColor.DARK_GRAY)) - .append(NameHelper.getColoredName(receiver.getName(), receiver.gameUser())) + .append(GroupHelper.getColoredName(receiver.getName(), receiver.gameUser())) .append(Component.text(" » ", NamedTextColor.DARK_GRAY)) .append(Component.text(message.getMessage(), NamedTextColor.WHITE)); diff --git a/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java new file mode 100644 index 0000000..0a10e09 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java @@ -0,0 +1,53 @@ +package com.rappytv.betterfriends.utils; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.labymod.api.Constants.LegacyUrls; +import net.labymod.api.client.component.Component; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import net.labymod.api.user.GameUser; +import net.labymod.api.user.group.Group; +import net.labymod.api.util.GsonUtil; +import net.labymod.api.util.io.web.request.Request; +import java.util.ArrayList; +import java.util.List; + +public class GroupHelper { + + private static final List groupIds = new ArrayList<>(); + + @SuppressWarnings("deprecation") + public static void registerGroupIds() { + Request.ofGson(JsonElement.class) + .url(LegacyUrls.GROUPS) + .execute(response -> { + if (response.hasException()) { + return; + } + JsonElement element = response.get(); + if (!element.isJsonObject()) { + return; + } + JsonObject groupContainer = element.getAsJsonObject(); + + for(JsonElement groupElement : groupContainer.getAsJsonArray("groups")) { + Group group = GsonUtil.DEFAULT_GSON.fromJson(groupElement, Group.class); + group.initialize(); + groupIds.add(group.getIdentifier()); + } + }); + } + + public static int getGroupIndex(int identifier) { + int index = groupIds.indexOf(identifier); + return index != -1 ? index : groupIds.size(); + } + + public static Component getColoredName(Friend friend) { + return getColoredName(friend.getName(), friend.gameUser()); + } + + public static Component getColoredName(String name, GameUser user) { + return Component.text(name, user.visibleGroup().getTextColor()); + } +} diff --git a/core/src/main/java/com/rappytv/betterfriends/utils/NameHelper.java b/core/src/main/java/com/rappytv/betterfriends/utils/NameHelper.java deleted file mode 100644 index d68389d..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/utils/NameHelper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.rappytv.betterfriends.utils; - -import net.labymod.api.client.component.Component; -import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import net.labymod.api.user.GameUser; - -public class NameHelper { - - public static Component getColoredName(Friend friend) { - return getColoredName(friend.getName(), friend.gameUser()); - } - - public static Component getColoredName(String name, GameUser user) { - return Component.text(name, user.visibleGroup().getTextColor()); - } -} From f07a61a91c6a4b45f9135b2982b2dc558f8a15f1 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sun, 16 Mar 2025 21:29:22 +0100 Subject: [PATCH 12/27] Allow custom sorting with dropdown menu --- .../activities/config/FriendListActivity.java | 90 ++++++++++++++----- .../assets/betterfriends/i18n/en_us.json | 11 ++- .../themes/vanilla/lss/friend_list.lss | 13 +++ 3 files changed, 90 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java index f905d19..03970ee 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java @@ -3,7 +3,9 @@ import com.rappytv.betterfriends.ui.widgets.FriendWidget; import java.util.ArrayList; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Function; +import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.gui.screen.Parent; @@ -12,6 +14,7 @@ import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; import net.labymod.api.client.gui.screen.widget.widgets.input.TextFieldWidget; +import net.labymod.api.client.gui.screen.widget.widgets.input.dropdown.DropdownWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.FlexibleContentWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.ScrollWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; @@ -37,6 +40,7 @@ public class FriendListActivity extends SimpleActivity { private final ComponentWidget error = ComponentWidget.empty().addId("error"); private ScrollWidget scroll; private String filterQuery = ""; + private SortingStrategy sortingStrategy = SortingStrategy.ONLINE_STATUS; public FriendListActivity(Function friendWidgetConstructor) { this.friendWidgetConstructor = friendWidgetConstructor; @@ -48,7 +52,8 @@ public void initialize(Parent parent) { FlexibleContentWidget container = new FlexibleContentWidget().addId("container"); - HorizontalListWidget filterSettings = new HorizontalListWidget(); + HorizontalListWidget filterSettings = new HorizontalListWidget() + .addId("filter-settings"); TextFieldWidget searchField = new TextFieldWidget(); searchField.addId("search-field"); @@ -56,8 +61,18 @@ public void initialize(Parent parent) { searchField.setText(this.filterQuery); searchField.updateListener(this::applyFriendsFilter); + DropdownWidget sortingDropdown = new DropdownWidget<>(); + for (SortingStrategy sortingStrategy : SortingStrategy.values()) { + sortingDropdown.add(sortingStrategy); + } + sortingDropdown.setSelected(this.sortingStrategy); + sortingDropdown.setTranslationKeyPrefix("betterfriends.settings.advancedFriendlist.sorting"); + sortingDropdown.setChangeListener(this::applySortingStrategy); + filterSettings.addEntry(searchField); + filterSettings.addEntry(sortingDropdown); + this.scroll = new ScrollWidget(this.entries); this.entries.setComparator((f1, f2) -> { if (!(f1 instanceof FriendWidget friendWidget1 && f2 instanceof FriendWidget friendWidget2)) { return 0; @@ -67,30 +82,28 @@ public void initialize(Parent parent) { int comparePin = Boolean.compare(friend2.isPinned(), friend1.isPinned()); if (comparePin != 0) { return comparePin; - } else { - int compareStatus = Boolean.compare(friend2.isOnline(), friend1.isOnline()); - if (compareStatus != 0) { - return compareStatus; - } else { - ChatMessage message1 = friend1.chat().getLastMessage(); - ChatMessage message2 = friend2.chat().getLastMessage(); - if (message1 != null || message2 != null) { - int compareLastMessage = Long.compare( - message2 != null ? message2.getTimestamp() : 0L, - message1 != null ? message1.getTimestamp() : 0L - ); - if (compareLastMessage != 0) { - return compareLastMessage; - } - } - return Long.compare(friend2.getLastOnline(), friend1.getLastOnline()); + } + int selectedComparator = sortingDropdown.getSelected().compare(friend1, friend2); + if (selectedComparator != 0) { + return selectedComparator; + } + ChatMessage message1 = friend1.chat().getLastMessage(); + ChatMessage message2 = friend2.chat().getLastMessage(); + if (message1 != null || message2 != null) { + int compareLastMessage = Long.compare( + message2 != null ? message2.getTimestamp() : 0L, + message1 != null ? message1.getTimestamp() : 0L + ); + if (compareLastMessage != 0) { + return compareLastMessage; } } + return Long.compare(friend2.getLastOnline(), friend1.getLastOnline()); }); this.initializeFriendlist(false); - this.scroll = new ScrollWidget(this.entries); container.addContent(filterSettings); + container.addContent(this.error); container.addFlexibleContent(this.scroll); this.document.addChild(container); } @@ -99,9 +112,11 @@ private void initializeFriendlist(boolean initialized) { this.entries.getChildren().clear(); LabyConnectSession session = Laby.references().labyConnect().getSession(); if (session == null || !session.isAuthenticated()) { - this.error.setComponent(Component.text("You are not connected to the LabyChat!")); - this.error.setVisible(true); - this.scroll.setVisible(false); + this.handleError("betterfriends.errors.notConnected"); + return; + } + if (session.getFriends().isEmpty()) { + this.handleError("betterfriends.errors.emptyList"); return; } this.error.setVisible(false); @@ -128,11 +143,22 @@ private void initializeFriendlist(boolean initialized) { } } + private void handleError(String translatable) { + this.error.setComponent(Component.translatable(translatable)); + this.error.setVisible(true); + this.scroll.setVisible(false); + } + private void applyFriendsFilter(String query) { this.filterQuery = query; this.initializeFriendlist(true); } + private void applySortingStrategy(SortingStrategy strategy) { + this.sortingStrategy = strategy; + this.initializeFriendlist(true); + } + private boolean hasFilter() { return this.filterQuery != null && !this.filterQuery.isEmpty(); } @@ -175,4 +201,24 @@ public void onLabyConnectFriendRemove(LabyConnectFriendRemoveEvent event) { widget -> widget.getFriend().getUniqueId().equals(event.friend().getUniqueId()) ); } + + private enum SortingStrategy { + ONLINE_STATUS((a, b) -> Boolean.compare(b.isOnline(), a.isOnline())), + ROLE((a, b) -> Integer.compare( + GroupHelper.getGroupIndex(a.gameUser().visibleGroup().getIdentifier()), + GroupHelper.getGroupIndex(b.gameUser().visibleGroup().getIdentifier()) + )), + A_TO_Z((a, b) -> a.getName().compareToIgnoreCase(b.getName())), + Z_TO_A((a, b) -> b.getName().compareToIgnoreCase(a.getName())); + + private final BiFunction sortingFunction; + + SortingStrategy(BiFunction sortingFunction) { + this.sortingFunction = sortingFunction; + } + + public int compare(Friend f1, Friend f2) { + return this.sortingFunction.apply(f1, f2); + } + } } \ No newline at end of file diff --git a/core/src/main/resources/assets/betterfriends/i18n/en_us.json b/core/src/main/resources/assets/betterfriends/i18n/en_us.json index c73b6ca..b6a24f0 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -23,7 +23,13 @@ "description": "This option changes the color theme of the \"BF »\" prefix which is prepended to addon messages." }, "advancedFriendlist": { - "name": "Advanced friend list" + "name": "Advanced friend list", + "sorting": { + "onlineStatus": "Online status", + "role": "LabyMod role", + "aToZ": "A-Z", + "zToA": "Z-A" + } }, "pinIconConfig": { "name": "Friend pin icon", @@ -140,7 +146,8 @@ "copyUuid": "Click to copy UUID" }, "errors": { - "notConnected": "You're not connected to the LabyChat!" + "notConnected": "You're not connected to the LabyChat!", + "emptyList": "Your friend list is empty!" }, "command": { "usage": "Usage: %s", diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss index 20ee684..a0de43b 100644 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss @@ -2,6 +2,19 @@ height: 100%; width: 100%; + .filter-settings { + width: 99%; + height: 20; + + TextField { + width: 60%; + } + + Dropdown { + width: 40%; + } + } + Scroll { width: 100%; height: 100%; From 3ba2706935e1baa5fd7329791d29933e4d9376aa Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sun, 16 Mar 2025 22:26:22 +0100 Subject: [PATCH 13/27] Implement removal button functionality --- .../config/BetterFriendsConfig.java | 4 +- ...tActivity.java => FriendlistActivity.java} | 6 +-- .../ui/widgets/FriendlistFriendWidget.java | 39 +++++++++++++++---- .../assets/betterfriends/i18n/en_us.json | 6 +++ 4 files changed, 43 insertions(+), 12 deletions(-) rename core/src/main/java/com/rappytv/betterfriends/ui/activities/config/{FriendListActivity.java => FriendlistActivity.java} (97%) diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index 82b66e4..f9a06a5 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -2,7 +2,7 @@ import com.rappytv.betterfriends.config.subconfig.FriendNoteTagConfig; import com.rappytv.betterfriends.config.subconfig.PinIconConfig; -import com.rappytv.betterfriends.ui.activities.config.FriendListActivity; +import com.rappytv.betterfriends.ui.activities.config.FriendlistActivity; import com.rappytv.betterfriends.ui.widgets.FriendlistFriendWidget; import net.labymod.api.addon.AddonConfig; import net.labymod.api.client.gui.screen.activity.Activity; @@ -33,7 +33,7 @@ public class BetterFriendsConfig extends AddonConfig { @MethodOrder(after = "prefixColor") @ActivitySetting public Activity advancedFriendlist() { - return new FriendListActivity<>(FriendlistFriendWidget::new); + return new FriendlistActivity<>(FriendlistFriendWidget::new); } @SpriteSlot(size = 8, x = 4) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java similarity index 97% rename from core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java rename to core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java index 03970ee..131c123 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendListActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java @@ -32,7 +32,7 @@ @Link("friend_list.lss") @AutoActivity -public class FriendListActivity extends SimpleActivity { +public class FriendlistActivity extends SimpleActivity { private final Function friendWidgetConstructor; private final VerticalListWidget entries = new VerticalListWidget<>() @@ -42,7 +42,7 @@ public class FriendListActivity extends SimpleActivity { private String filterQuery = ""; private SortingStrategy sortingStrategy = SortingStrategy.ONLINE_STATUS; - public FriendListActivity(Function friendWidgetConstructor) { + public FriendlistActivity(Function friendWidgetConstructor) { this.friendWidgetConstructor = friendWidgetConstructor; } @@ -172,7 +172,7 @@ private boolean isUserInFilter(User user) { public void onUserUpdateData(final UserUpdateDataEvent event) { if (event.phase() == Phase.POST) { this.labyAPI.minecraft().executeOnRenderThread(() -> - FriendListActivity.this.entries.reInitializeChildrenIf( + FriendlistActivity.this.entries.reInitializeChildrenIf( FriendWidget.class, widget -> widget.getFriend().getUniqueId().equals( event.gameUser().getUniqueId() diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java index a4e0ad3..649e95c 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java @@ -16,7 +16,9 @@ @AutoWidget public class FriendlistFriendWidget extends FriendWidget { + private static final Component X = Component.text("✘", NamedTextColor.RED); private boolean skipConfirmation = false; + private boolean confirmRemoval = false; public FriendlistFriendWidget(Friend friend) { super(friend); @@ -25,6 +27,26 @@ public FriendlistFriendWidget(Friend friend) { @Override public List getButtons() { + if(this.confirmRemoval) { + ButtonWidget removeConfirmationButton = ButtonWidget.icon(SpriteCommon.GREEN_CHECKED, () -> { + this.friend.remove(); + this.confirmRemoval = false; + this.reInitialize(); + }); + removeConfirmationButton.setHoverComponent(Component.translatable( + "betterfriends.settings.advancedFriendlist.removal.confirm", + NamedTextColor.GREEN + )); + ButtonWidget cancelButton = ButtonWidget.component(X, () -> { + this.confirmRemoval = false; + this.reInitialize(); + }); + cancelButton.setHoverComponent(Component.translatable( + "betterfriends.settings.advancedFriendlist.removal.cancel", + NamedTextColor.RED + )); + return List.of(removeConfirmationButton, cancelButton); + } ButtonWidget pinButton = ButtonWidget.icon(Textures.SpriteCommon.PIN, () -> { if (this.friend.isPinned()) { this.friend.unpin(); @@ -47,20 +69,23 @@ public List getButtons() { noteButton.setHoverComponent(Component.translatable( "labymod.activity.labyconnect.chat.action.note" )); - ButtonWidget removeButton = ButtonWidget.icon(Textures.SpriteCommon.X, () -> { + ButtonWidget removeButton = ButtonWidget.component(X, () -> { if (this.skipConfirmation) { - System.out.println("Removed " + this.friend.getName() + " without confirmation"); -// this.friend.remove(); + this.friend.remove(); } else { - // TODO: show confirmation - System.out.println("Open friend remove confirmation for " + this.friend.getName()); + this.confirmRemoval = true; + this.reInitialize(); } }).addId("remove-button"); removeButton.setHoverComponent( - Component.translatable("Remove friend", NamedTextColor.RED) + Component + .translatable( + "betterfriends.settings.advancedFriendlist.removal.label", + NamedTextColor.RED + ) .append(Component.newline()) .append(Component.translatable( - "(Hold shift to skip confirmation)", + "betterfriends.settings.advancedFriendlist.removal.skipConfirmation", NamedTextColor.DARK_GRAY )) ); diff --git a/core/src/main/resources/assets/betterfriends/i18n/en_us.json b/core/src/main/resources/assets/betterfriends/i18n/en_us.json index b6a24f0..7561f2e 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -24,6 +24,12 @@ }, "advancedFriendlist": { "name": "Advanced friend list", + "removal": { + "label": "Remove friend", + "skipConfirmation": "(Hold shift to skip confirmation)", + "confirm": "Confirm removal", + "cancel": "Cancel removal" + }, "sorting": { "onlineStatus": "Online status", "role": "LabyMod role", From 10fa20b1dfb32b279d2b79a51548b9d800b49c49 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Tue, 4 Nov 2025 18:23:04 +0100 Subject: [PATCH 14/27] chore: Remove unused warning suppression --- .../java/com/rappytv/betterfriends/utils/GroupHelper.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java index 0a10e09..6f5aa2e 100644 --- a/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java +++ b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java @@ -2,6 +2,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.List; import net.labymod.api.Constants.LegacyUrls; import net.labymod.api.client.component.Component; import net.labymod.api.labyconnect.protocol.model.friend.Friend; @@ -9,14 +11,11 @@ import net.labymod.api.user.group.Group; import net.labymod.api.util.GsonUtil; import net.labymod.api.util.io.web.request.Request; -import java.util.ArrayList; -import java.util.List; public class GroupHelper { private static final List groupIds = new ArrayList<>(); - @SuppressWarnings("deprecation") public static void registerGroupIds() { Request.ofGson(JsonElement.class) .url(LegacyUrls.GROUPS) From 41729c8b0f47fd42ef7e71b5b528eebc432e77d5 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Tue, 4 Nov 2025 18:24:52 +0100 Subject: [PATCH 15/27] fix: Friend message components color depends on base component --- .../betterfriends/listeners/ChatReceiveListener.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java index 15c440d..31951c6 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java @@ -47,8 +47,10 @@ public void onChatReceive(ChatReceiveEvent receiveEvent) { } receiveEvent.setMessage( - this.addon.getSerializer() - .deserialize(this.addon.configuration().friendPrefix().get()) + Component.empty() + .append(this.addon.getSerializer().deserialize( + this.addon.configuration().friendPrefix().get() + )) .append(Component.space()) .append(message) ); From 547ec12faeed58ae753a13caf69b4de0368b5032 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 22 Nov 2025 13:38:30 +0100 Subject: [PATCH 16/27] feat: Update tag rendering --- .../betterfriends/api/FriendHelper.java | 20 +++++ build.gradle.kts | 3 + .../betterfriends/BetterFriendsAddon.java | 15 +++- .../ui/badge/FriendPinBadge.java | 16 ++-- .../snapshot/BetterFriendsFriendSnapshot.java | 30 ++++++++ .../BetterFriendsFriendSnapshotProcessor.java | 26 +++++++ .../ui/snapshot/BetterFriendsKeys.java | 9 +++ .../BetterFriendsSnapshotFactory.java | 21 +++++ .../ui/tags/FriendNoteNameTag.java | 77 +++++++------------ .../ui/tags/FriendPinIconTag.java | 32 ++++---- .../utils/DefaultFriendHelper.java | 26 +++++++ 11 files changed, 194 insertions(+), 81 deletions(-) create mode 100644 api/src/main/java/com/rappytv/betterfriends/api/FriendHelper.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshotProcessor.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsKeys.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java create mode 100644 core/src/main/java/com/rappytv/betterfriends/utils/DefaultFriendHelper.java diff --git a/api/src/main/java/com/rappytv/betterfriends/api/FriendHelper.java b/api/src/main/java/com/rappytv/betterfriends/api/FriendHelper.java new file mode 100644 index 0000000..036943f --- /dev/null +++ b/api/src/main/java/com/rappytv/betterfriends/api/FriendHelper.java @@ -0,0 +1,20 @@ +package com.rappytv.betterfriends.api; + +import java.util.UUID; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import net.labymod.api.mojang.GameProfile; +import net.labymod.api.reference.annotation.Referenceable; +import org.jetbrains.annotations.Nullable; + +@Referenceable +public interface FriendHelper { + + @Nullable + default Friend getFriend(GameProfile profile) { + return this.getFriend(profile.getUniqueId()); + } + + @Nullable + Friend getFriend(UUID uuid); + +} diff --git a/build.gradle.kts b/build.gradle.kts index ce7ad63..5c52e2c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import net.labymod.labygradle.common.extension.model.labymod.ReleaseChannels + plugins { id("net.labymod.labygradle") id("net.labymod.labygradle.addon") @@ -30,6 +32,7 @@ labyMod { version = rootProject.version.toString() addon("voicechat", true) + releaseChannel.set(ReleaseChannels.SNAPSHOT) } } diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index 8298378..2d6556b 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -1,5 +1,6 @@ package com.rappytv.betterfriends; +import com.rappytv.betterfriends.api.generated.ReferenceStorage; import com.rappytv.betterfriends.command.BetterFriendsCommand; import com.rappytv.betterfriends.config.BetterFriendsConfig; import com.rappytv.betterfriends.interactions.FriendNoteEditorBullet; @@ -35,7 +36,7 @@ @AddonMain public class BetterFriendsAddon extends LabyAddon { - private final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacyAmpersand(); + private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.legacyAmpersand(); private static BetterFriendsAddon instance; @Override @@ -77,7 +78,7 @@ protected void enable() { "VoiceTag", "betterfriends_pin_icon", PositionType.RIGHT_TO_NAME, - new FriendPinIconTag(this) + new FriendPinIconTag() ); Laby.references().badgeRegistry().registerBefore( "VoiceBadge", @@ -92,6 +93,14 @@ protected Class configurationClass() { return BetterFriendsConfig.class; } + public static BetterFriendsConfig config() { + return instance.configuration(); + } + + public static ReferenceStorage references() { + return instance.referenceStorageAccessor(); + } + public static TextComponent getPrefix() { return Component.empty() .append(Component.text( @@ -104,6 +113,6 @@ public static TextComponent getPrefix() { } public LegacyComponentSerializer getSerializer() { - return this.serializer; + return SERIALIZER; } } diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java b/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java index 5afe4d9..a1e347f 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java @@ -1,12 +1,10 @@ package com.rappytv.betterfriends.ui.badge; import com.rappytv.betterfriends.BetterFriendsAddon; -import net.labymod.api.Laby; import net.labymod.api.Textures; import net.labymod.api.client.entity.player.badge.renderer.BadgeRenderer; +import net.labymod.api.client.gui.screen.ScreenContext; import net.labymod.api.client.network.NetworkPlayerInfo; -import net.labymod.api.client.render.matrix.Stack; -import net.labymod.api.labyconnect.LabyConnectSession; import net.labymod.api.labyconnect.protocol.model.friend.Friend; public class FriendPinBadge extends BadgeRenderer { @@ -18,8 +16,8 @@ public FriendPinBadge(BetterFriendsAddon addon) { } @Override - public void render(Stack stack, float x, float y, NetworkPlayerInfo player) { - Textures.SpriteCommon.PIN.render(stack, x + 2.0F, y + 0.5F, 6f); + public void render(ScreenContext context, float x, float y, NetworkPlayerInfo player) { + Textures.SpriteCommon.PIN.render(context.stack(), x + 2.0F, y + 0.5F, 6f); } @Override @@ -28,13 +26,9 @@ protected boolean isVisible(NetworkPlayerInfo player) { || !this.addon.configuration().pinIconConfig().pinBadge().get()) { return false; } + Friend friend = BetterFriendsAddon.references().friendHelper() + .getFriend(player.profile().getUniqueId()); - LabyConnectSession session = Laby.references().labyConnect().getSession(); - if (session == null || !session.isAuthenticated()) { - return false; - } - - Friend friend = session.getFriend(player.profile().getUniqueId()); return friend != null && friend.isPinned(); } } diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java new file mode 100644 index 0000000..5ef1b56 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java @@ -0,0 +1,30 @@ +package com.rappytv.betterfriends.ui.snapshot; + +import com.rappytv.betterfriends.BetterFriendsAddon; +import com.rappytv.betterfriends.config.BetterFriendsConfig; +import net.labymod.api.client.entity.player.Player; +import net.labymod.api.laby3d.renderer.snapshot.AbstractLabySnapshot; +import net.labymod.api.laby3d.renderer.snapshot.Extras; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import org.jetbrains.annotations.Nullable; + +public class BetterFriendsFriendSnapshot extends AbstractLabySnapshot { + + private final Friend friend; + private final BetterFriendsConfig config; + + public BetterFriendsFriendSnapshot(Player player, Extras extras) { + super(extras); + this.friend = BetterFriendsAddon.references().friendHelper().getFriend(player.profile()); + this.config = BetterFriendsAddon.config(); + } + + @Nullable + public Friend friend() { + return this.friend; + } + + public BetterFriendsConfig config() { + return this.config; + } +} diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshotProcessor.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshotProcessor.java new file mode 100644 index 0000000..b74bba5 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshotProcessor.java @@ -0,0 +1,26 @@ +package com.rappytv.betterfriends.ui.snapshot; + +import net.labymod.api.client.entity.Entity; +import net.labymod.api.client.entity.player.Player; +import net.labymod.api.client.render.state.entity.EntitySnapshotProcessor; +import net.labymod.api.client.render.state.entity.EntitySnapshotRegistry; +import net.labymod.api.laby3d.renderer.snapshot.ExtrasWriter; +import net.labymod.api.service.annotation.AutoService; + +@AutoService(EntitySnapshotProcessor.class) +public class BetterFriendsFriendSnapshotProcessor extends EntitySnapshotProcessor { + + public BetterFriendsFriendSnapshotProcessor(EntitySnapshotRegistry registry) { + super(registry); + } + + @Override + public boolean supports(Entity entity) { + return entity instanceof Player; + } + + @Override + public void process(Player player, float partialTicks, ExtrasWriter entityWriter) { + this.registry().captureSnapshot(entityWriter, BetterFriendsKeys.FRIEND, player); + } +} diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsKeys.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsKeys.java new file mode 100644 index 0000000..c41fd0a --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsKeys.java @@ -0,0 +1,9 @@ +package com.rappytv.betterfriends.ui.snapshot; + +import net.labymod.api.laby3d.renderer.snapshot.ExtraKey; + +public class BetterFriendsKeys { + + public static final ExtraKey FRIEND = ExtraKey.of( + "better_friends_friend", BetterFriendsFriendSnapshot.class); +} diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java new file mode 100644 index 0000000..ddf6c08 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java @@ -0,0 +1,21 @@ +package com.rappytv.betterfriends.ui.snapshot; + +import net.labymod.api.client.entity.player.Player; +import net.labymod.api.laby3d.renderer.snapshot.ExtraKey; +import net.labymod.api.laby3d.renderer.snapshot.Extras; +import net.labymod.api.laby3d.renderer.snapshot.LabySnapshotFactory; +import net.labymod.api.service.annotation.AutoService; + +@AutoService(LabySnapshotFactory.class) +public class BetterFriendsSnapshotFactory extends + LabySnapshotFactory { + + public BetterFriendsSnapshotFactory(ExtraKey extraKey) { + super(extraKey); + } + + @Override + protected BetterFriendsFriendSnapshot create(Player player, Extras extras) { + return new BetterFriendsFriendSnapshot(player, extras); + } +} diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java index 704a5cb..ff87170 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java @@ -1,20 +1,19 @@ package com.rappytv.betterfriends.ui.tags; import com.rappytv.betterfriends.BetterFriendsAddon; -import java.awt.*; -import net.labymod.api.Laby; -import net.labymod.api.client.entity.player.Player; +import com.rappytv.betterfriends.ui.snapshot.BetterFriendsFriendSnapshot; +import com.rappytv.betterfriends.ui.snapshot.BetterFriendsKeys; +import java.util.Collections; +import java.util.List; +import net.labymod.api.client.component.Component; import net.labymod.api.client.entity.player.tag.PositionType; -import net.labymod.api.client.entity.player.tag.tags.NameTag; -import net.labymod.api.client.entity.player.tag.tags.NameTagBackground; -import net.labymod.api.client.render.font.RenderableComponent; -import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.client.entity.player.tag.tags.ComponentNameTag; +import net.labymod.api.client.render.state.entity.EntitySnapshot; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; -public class FriendNoteNameTag extends NameTag { +public class FriendNoteNameTag extends ComponentNameTag { - private static final int gray = new Color(0, 0, 0, 70).getRGB(); private final BetterFriendsAddon addon; private final PositionType position; @@ -24,57 +23,39 @@ public FriendNoteNameTag(BetterFriendsAddon addon, PositionType position) { } @Override - protected @Nullable RenderableComponent getRenderableComponent() { - if (this.entity == null || !(this.entity instanceof Player)) { - return null; + protected @NotNull List buildComponents(EntitySnapshot snapshot) { + if (this.snapshot.isDiscrete() + || this.snapshot.isInvisible() + || !this.snapshot.has(BetterFriendsKeys.FRIEND)) { + return super.buildComponents(snapshot); } + BetterFriendsFriendSnapshot friendSnapshot = snapshot.get(BetterFriendsKeys.FRIEND); - LabyConnectSession session = Laby.references().labyConnect().getSession(); - if (session == null || !session.isAuthenticated()) { - return null; + boolean condition = friendSnapshot.config().enabled().get() + && friendSnapshot.config().friendNoteTagConfig().enabled().get() + && friendSnapshot.config().friendNoteTagConfig().position().get() == this.position; + + if (!condition) { + return super.buildComponents(snapshot); } - Friend friend = session.getFriend(this.entity.getUniqueId()); + Friend friend = friendSnapshot.friend(); if (friend == null) { - return null; + return super.buildComponents(snapshot); } - String note = friend.getNote(); if (note != null && !note.isBlank()) { - return RenderableComponent.of(this.addon.getSerializer().deserialize(note)); - } else { - String defaultTag = this.addon.configuration().friendNoteTagConfig().defaultTag().get(); - if (defaultTag.isBlank()) { - return null; - } - return RenderableComponent.of(this.addon.getSerializer().deserialize(defaultTag)); + return Collections.singletonList(this.addon.getSerializer().deserialize(note)); + } + String defaultTag = friendSnapshot.config().friendNoteTagConfig().defaultTag().get(); + if (defaultTag.isBlank()) { + return super.buildComponents(snapshot); } + return Collections.singletonList(this.addon.getSerializer().deserialize(defaultTag)); } @Override public float getScale() { return (float) this.addon.configuration().friendNoteTagConfig().size().get() / 10; } - - @Override - protected NameTagBackground getCustomBackground() { - boolean enabled = !this.addon.configuration().friendNoteTagConfig().hideBackground().get(); - NameTagBackground background = super.getCustomBackground(); - - if (background == null) { - background = NameTagBackground.custom(enabled, gray); - } - - background.setEnabled(enabled); - return background; - } - - @Override - public boolean isVisible() { - return this.addon.configuration().enabled().get() - && this.addon.configuration().friendNoteTagConfig().enabled().get() - && this.addon.configuration().friendNoteTagConfig().position().get() == this.position - && !this.entity.isCrouching() - && super.isVisible(); - } } diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java index 0e64ade..027161a 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java @@ -1,21 +1,15 @@ package com.rappytv.betterfriends.ui.tags; -import com.rappytv.betterfriends.BetterFriendsAddon; -import net.labymod.api.Laby; +import com.rappytv.betterfriends.ui.snapshot.BetterFriendsFriendSnapshot; +import com.rappytv.betterfriends.ui.snapshot.BetterFriendsKeys; import net.labymod.api.Textures; -import net.labymod.api.client.entity.player.Player; import net.labymod.api.client.entity.player.tag.tags.IconTag; import net.labymod.api.client.gui.icon.Icon; -import net.labymod.api.labyconnect.LabyConnectSession; -import net.labymod.api.labyconnect.protocol.model.friend.Friend; public class FriendPinIconTag extends IconTag { - private final BetterFriendsAddon addon; - - public FriendPinIconTag(BetterFriendsAddon addon) { + public FriendPinIconTag() { super(8); - this.addon = addon; } @Override @@ -25,20 +19,20 @@ public Icon getIcon() { @Override public boolean isVisible() { - if (!this.addon.configuration().enabled().get() - || !this.addon.configuration().pinIconConfig().pinIcon().get()) { - return false; - } - if (this.entity == null || !(this.entity instanceof Player)) { + if (!this.snapshot.has(BetterFriendsKeys.FRIEND)) { return false; } + BetterFriendsFriendSnapshot friendSnapshot = this.snapshot.get(BetterFriendsKeys.FRIEND); - LabyConnectSession session = Laby.references().labyConnect().getSession(); - if (session == null || !session.isAuthenticated()) { + if (!friendSnapshot.config().enabled().get() + || !friendSnapshot.config().pinIconConfig().pinIcon().get()) { return false; } - - Friend friend = session.getFriend(this.entity.getUniqueId()); - return friend != null && friend.isPinned() && super.isVisible(); + return super.isVisible() + && !this.snapshot.isDiscrete() + && !this.snapshot.isInvisible() + && friendSnapshot.config().enabled().get() + && friendSnapshot.config().pinIconConfig().pinIcon().get() + && friendSnapshot.friend().isPinned(); } } diff --git a/core/src/main/java/com/rappytv/betterfriends/utils/DefaultFriendHelper.java b/core/src/main/java/com/rappytv/betterfriends/utils/DefaultFriendHelper.java new file mode 100644 index 0000000..89d0558 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/utils/DefaultFriendHelper.java @@ -0,0 +1,26 @@ +package com.rappytv.betterfriends.utils; + +import com.rappytv.betterfriends.api.FriendHelper; +import java.util.UUID; +import javax.inject.Singleton; +import net.labymod.api.Laby; +import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import net.labymod.api.models.Implements; +import org.jetbrains.annotations.Nullable; + +@Singleton +@Implements(FriendHelper.class) +public class DefaultFriendHelper implements FriendHelper { + + @Override + @Nullable + public Friend getFriend(UUID uuid) { + LabyConnectSession session = Laby.references().labyConnect().getSession(); + if (session == null || !session.isAuthenticated()) { + return null; + } + + return session.getFriend(uuid); + } +} From f9401492f913b8e98151f9fc289f4e0daceaf97c Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 22 Nov 2025 13:41:55 +0100 Subject: [PATCH 17/27] chore: Remove redundant code in FriendPinIconTag --- .../rappytv/betterfriends/ui/tags/FriendPinIconTag.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java index 027161a..22f4f69 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java @@ -5,6 +5,7 @@ import net.labymod.api.Textures; import net.labymod.api.client.entity.player.tag.tags.IconTag; import net.labymod.api.client.gui.icon.Icon; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; public class FriendPinIconTag extends IconTag { @@ -24,15 +25,13 @@ public boolean isVisible() { } BetterFriendsFriendSnapshot friendSnapshot = this.snapshot.get(BetterFriendsKeys.FRIEND); - if (!friendSnapshot.config().enabled().get() - || !friendSnapshot.config().pinIconConfig().pinIcon().get()) { - return false; - } + Friend friend = friendSnapshot.friend(); return super.isVisible() && !this.snapshot.isDiscrete() && !this.snapshot.isInvisible() && friendSnapshot.config().enabled().get() && friendSnapshot.config().pinIconConfig().pinIcon().get() - && friendSnapshot.friend().isPinned(); + && friend != null + && friend.isPinned(); } } From 63b6b49aa01c50507b01fd04e10a02b2574c906d Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 22 Nov 2025 13:55:49 +0100 Subject: [PATCH 18/27] chore: Register newer versions --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6168956..9243d49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ org.gradle.jvmargs=-Xmx4096m -net.labymod.minecraft-versions=1.8.9;1.12.2;1.16.5;1.17.1;1.18.2;1.19.2;1.19.3;1.19.4;1.20.1;1.20.2;1.20.4;1.20.5;1.20.6;1.21;1.21.1;1.21.3;1.21.4 \ No newline at end of file +net.labymod.minecraft-versions=1.8.9;1.12.2;1.16.5;1.17.1;1.18.2;1.19.2;1.19.3;1.19.4;1.20.1;1.20.2;1.20.4;1.20.5;1.20.6;1.21;1.21.1;1.21.3;1.21.4;1.21.5;1.21.8;1.21.10 \ No newline at end of file From f437c51116548b0890bd21a7f15cf59afd322547 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Sat, 22 Nov 2025 13:56:12 +0100 Subject: [PATCH 19/27] fix: Fix errors --- .../rappytv/betterfriends/ui/tags/FriendPinIconTag.java | 8 +------- .../rappytv/betterfriends/ui/widgets/FriendWidget.java | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java index 22f4f69..cf90ee9 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendPinIconTag.java @@ -4,18 +4,12 @@ import com.rappytv.betterfriends.ui.snapshot.BetterFriendsKeys; import net.labymod.api.Textures; import net.labymod.api.client.entity.player.tag.tags.IconTag; -import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.labyconnect.protocol.model.friend.Friend; public class FriendPinIconTag extends IconTag { public FriendPinIconTag() { - super(8); - } - - @Override - public Icon getIcon() { - return Textures.SpriteCommon.PIN; + super(Textures.SpriteCommon.PIN, 8); } @Override diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index 5e8602a..fad7909 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -34,7 +34,7 @@ public void initialize(Parent parent) { UserStatus userStatus = this.friend.userStatus(); IconWidget indicatorWidget = new IconWidget(SpriteCommon.STATUS_INDICATOR); indicatorWidget.addId("indicator"); - indicatorWidget.color().set(userStatus.getColor().getRGB()); + indicatorWidget.color().set(userStatus.getColor().getValue()); Component statusComponent = Component.translatable( userStatus.getLocalTranslationKey(), userStatus.textColor() @@ -94,7 +94,7 @@ public Friend getFriend() { return this.friend; } - // Without this the comparator just doesn't work for whatever reason + // Without this, the comparator just doesn't work for whatever reason @Override public int getSortingValue() { return 1; From d57db2edee95599c2dfc8a65db12ac8bab6bddac Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 24 Nov 2025 23:03:28 +0100 Subject: [PATCH 20/27] chore: Get friend via the player profile in FriendPinBadge --- .../com/rappytv/betterfriends/ui/badge/FriendPinBadge.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java b/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java index a1e347f..0267336 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/badge/FriendPinBadge.java @@ -26,8 +26,7 @@ protected boolean isVisible(NetworkPlayerInfo player) { || !this.addon.configuration().pinIconConfig().pinBadge().get()) { return false; } - Friend friend = BetterFriendsAddon.references().friendHelper() - .getFriend(player.profile().getUniqueId()); + Friend friend = BetterFriendsAddon.references().friendHelper().getFriend(player.profile()); return friend != null && friend.isPinned(); } From dc72d4b03d71c8bc0b1300d014584fe7a3ebb4af Mon Sep 17 00:00:00 2001 From: RappyTV Date: Tue, 25 Nov 2025 17:44:57 +0100 Subject: [PATCH 21/27] idk: some widget stuff --- .../activities/config/FriendlistActivity.java | 28 ++-- .../ui/widgets/FriendWidget.java | 2 - .../themes/vanilla/lss/friend.lss | 50 ------- .../themes/vanilla/lss/friend_list.lss | 131 ++++++++++++------ 4 files changed, 102 insertions(+), 109 deletions(-) delete mode 100644 core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java index 131c123..d0ef0b6 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java @@ -1,16 +1,17 @@ package com.rappytv.betterfriends.ui.activities.config; import com.rappytv.betterfriends.ui.widgets.FriendWidget; +import com.rappytv.betterfriends.utils.GroupHelper; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Function; -import com.rappytv.betterfriends.utils.GroupHelper; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.gui.screen.Parent; import net.labymod.api.client.gui.screen.activity.AutoActivity; import net.labymod.api.client.gui.screen.activity.Link; +import net.labymod.api.client.gui.screen.activity.Links; import net.labymod.api.client.gui.screen.activity.types.SimpleActivity; import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; import net.labymod.api.client.gui.screen.widget.widgets.input.TextFieldWidget; @@ -30,7 +31,7 @@ import net.labymod.api.labyconnect.protocol.model.chat.ChatMessage; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -@Link("friend_list.lss") +@Links({@Link("friend_list.lss"), @Link("friend.lss")}) @AutoActivity public class FriendlistActivity extends SimpleActivity { @@ -123,16 +124,10 @@ private void initializeFriendlist(boolean initialized) { this.scroll.setVisible(true); List children = new ArrayList<>(); - int addedOfflineFriends = 0; for (Friend friend : session.getFriends()) { - boolean offline = !friend.isOnline(); - if ((!offline || addedOfflineFriends < 100 || friend.isPinned()) && this.isUserInFilter( - friend)) { + if (this.isUserInFilter(friend)) { children.add(this.friendWidgetConstructor.apply(friend)); - if (offline) { - addedOfflineFriends++; - } } } @@ -204,21 +199,20 @@ public void onLabyConnectFriendRemove(LabyConnectFriendRemoveEvent event) { private enum SortingStrategy { ONLINE_STATUS((a, b) -> Boolean.compare(b.isOnline(), a.isOnline())), - ROLE((a, b) -> Integer.compare( - GroupHelper.getGroupIndex(a.gameUser().visibleGroup().getIdentifier()), - GroupHelper.getGroupIndex(b.gameUser().visibleGroup().getIdentifier()) + ROLE(Comparator.comparingInt(a -> + GroupHelper.getGroupIndex(a.gameUser().visibleGroup().getIdentifier()) )), A_TO_Z((a, b) -> a.getName().compareToIgnoreCase(b.getName())), Z_TO_A((a, b) -> b.getName().compareToIgnoreCase(a.getName())); - private final BiFunction sortingFunction; + private final Comparator sortingFunction; - SortingStrategy(BiFunction sortingFunction) { - this.sortingFunction = sortingFunction; + SortingStrategy(Comparator comparator) { + this.sortingFunction = comparator; } public int compare(Friend f1, Friend f2) { - return this.sortingFunction.apply(f1, f2); + return this.sortingFunction.compare(f1, f2); } } } \ No newline at end of file diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java index fad7909..e36f2c7 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java @@ -9,7 +9,6 @@ import net.labymod.api.client.gui.icon.Icon; import net.labymod.api.client.gui.lss.property.annotation.AutoWidget; import net.labymod.api.client.gui.screen.Parent; -import net.labymod.api.client.gui.screen.activity.Link; import net.labymod.api.client.gui.screen.widget.widgets.ComponentWidget; import net.labymod.api.client.gui.screen.widget.widgets.input.ButtonWidget; import net.labymod.api.client.gui.screen.widget.widgets.layout.list.HorizontalListWidget; @@ -17,7 +16,6 @@ import net.labymod.api.labyconnect.protocol.model.UserStatus; import net.labymod.api.labyconnect.protocol.model.friend.Friend; -@Link("friend.lss") @AutoWidget public abstract class FriendWidget extends HorizontalListWidget { diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss deleted file mode 100644 index 06ddd72..0000000 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend.lss +++ /dev/null @@ -1,50 +0,0 @@ -Friend, FriendlistFriend { - width: 100%; - height: 20; - padding: 1; - - .player-head { - margin-left: 3; - width: 16; - height: width; - } - - .indicator { - width: 8; - height: width; - } - - .username { - max-width: 80%; - width: fit-content; - scale-to-fit: true; - max-lines: 1; - margin-left: 2; - top: 2; - } - - .pin-icon { - margin-left: 3; - width: 8; - height: width; - } - - .buttons { - height: fit-content; - width: fit-content; - alignment: right; - - Button { - width: 20; - height: width; - padding: 0; - } - - .pin-button { - .button-icon { - width: 50%; - height: width; - } - } - } -} \ No newline at end of file diff --git a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss index a0de43b..5eed99a 100644 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss @@ -1,45 +1,96 @@ .container { - height: 100%; - width: 100%; + height: 100%; + width: 100%; - .filter-settings { - width: 99%; - height: 20; + .filter-settings { + width: 99%; + height: 20; - TextField { - width: 60%; - } + TextField { + width: 60%; + } + + Dropdown { + width: 40%; + } + } + + Scroll { + width: 100%; + height: 100%; + + .friends { + margin-top: 5; + width: 100%; + height: fit-content; + } + + Scrollbar { + left: 0; + top: 0; + width: 5; + height: 100%; + margin-left: 5; + } + } + + .error { + font-size: 0.8; + text-color: red; + width: fit-content; + margin-top: 100; + alignment-x: center; + alignment-y: center; + } +} + +FriendlistFriend { + width: 100%; + height: 20; + padding: 1; + + .player-head { + margin-left: 3; + width: 16; + height: width; + } + + .indicator { + width: 8; + height: width; + } + + .username { + max-width: 80%; + width: fit-content; + scale-to-fit: true; + max-lines: 1; + margin-left: 2; + top: 2; + } + + .pin-icon { + margin-left: 3; + width: 8; + height: width; + } + + .buttons { + height: fit-content; + width: fit-content; + alignment: right; + + Button { + width: 20; + height: width; + padding: 0; + } - Dropdown { - width: 40%; + .pin-button { + .button-icon { + width: 50%; + height: width; } - } - - Scroll { - width: 100%; - height: 100%; - - .friends { - margin-top: 5; - width: 100%; - height: fit-content; - } - - Scrollbar { - left: 0; - top: 0; - width: 5; - height: 100%; - margin-left: 5; - } - } - - .error { - font-size: 0.8; - text-color: red; - width: fit-content; - margin-top: 100; - alignment-x: center; - alignment-y: center; - } - } \ No newline at end of file + } + } +} \ No newline at end of file From 81c22bb6c096ddfc3212c2080a33afa5d6cca318 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 21:35:04 +0100 Subject: [PATCH 22/27] fix: Make nametag work again --- .../com/rappytv/betterfriends/BetterFriendsAddon.java | 4 ---- .../ui/snapshot/BetterFriendsFriendSnapshot.java | 4 ++-- .../ui/snapshot/BetterFriendsSnapshotFactory.java | 11 +++++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index 2d6556b..d29aecc 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -93,10 +93,6 @@ protected Class configurationClass() { return BetterFriendsConfig.class; } - public static BetterFriendsConfig config() { - return instance.configuration(); - } - public static ReferenceStorage references() { return instance.referenceStorageAccessor(); } diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java index 5ef1b56..5e289ca 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsFriendSnapshot.java @@ -13,10 +13,10 @@ public class BetterFriendsFriendSnapshot extends AbstractLabySnapshot { private final Friend friend; private final BetterFriendsConfig config; - public BetterFriendsFriendSnapshot(Player player, Extras extras) { + public BetterFriendsFriendSnapshot(Player player, Extras extras, BetterFriendsAddon addon) { super(extras); this.friend = BetterFriendsAddon.references().friendHelper().getFriend(player.profile()); - this.config = BetterFriendsAddon.config(); + this.config = addon.configuration(); } @Nullable diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java index ddf6c08..92aeba7 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/snapshot/BetterFriendsSnapshotFactory.java @@ -1,7 +1,7 @@ package com.rappytv.betterfriends.ui.snapshot; +import com.rappytv.betterfriends.BetterFriendsAddon; import net.labymod.api.client.entity.player.Player; -import net.labymod.api.laby3d.renderer.snapshot.ExtraKey; import net.labymod.api.laby3d.renderer.snapshot.Extras; import net.labymod.api.laby3d.renderer.snapshot.LabySnapshotFactory; import net.labymod.api.service.annotation.AutoService; @@ -10,12 +10,15 @@ public class BetterFriendsSnapshotFactory extends LabySnapshotFactory { - public BetterFriendsSnapshotFactory(ExtraKey extraKey) { - super(extraKey); + private final BetterFriendsAddon addon; + + public BetterFriendsSnapshotFactory(BetterFriendsAddon addon) { + super(BetterFriendsKeys.FRIEND); + this.addon = addon; } @Override protected BetterFriendsFriendSnapshot create(Player player, Extras extras) { - return new BetterFriendsFriendSnapshot(player, extras); + return new BetterFriendsFriendSnapshot(player, extras, this.addon); } } From 721a02126541edb8d34ffad33555000390539292 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 21:42:44 +0100 Subject: [PATCH 23/27] fix: Make "Hide background" switch work again --- .../betterfriends/ui/tags/FriendNoteNameTag.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java index ff87170..881fe5b 100644 --- a/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java +++ b/core/src/main/java/com/rappytv/betterfriends/ui/tags/FriendNoteNameTag.java @@ -54,6 +54,17 @@ public FriendNoteNameTag(BetterFriendsAddon addon, PositionType position) { return Collections.singletonList(this.addon.getSerializer().deserialize(defaultTag)); } + @Override + protected int getBackgroundColor(EntitySnapshot snapshot) { + BetterFriendsFriendSnapshot friendSnapshot = snapshot.get(BetterFriendsKeys.FRIEND); + if (friendSnapshot == null) { + return super.getBackgroundColor(snapshot); + } + return friendSnapshot.config().friendNoteTagConfig().hideBackground().get() + ? 0 + : super.getBackgroundColor(snapshot); + } + @Override public float getScale() { return (float) this.addon.configuration().friendNoteTagConfig().size().get() / 10; From a80635b248f7c8548eaff8ba008d2e77e8d5e011 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 22:05:53 +0100 Subject: [PATCH 24/27] feat: Add option to toggle interaction buttons Resolves #30 --- .../config/BetterFriendsConfig.java | 29 +++++++++++++++++++ .../listeners/LabyChatReceiveListener.java | 10 +++---- .../assets/betterfriends/i18n/en_us.json | 4 +++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index f9a06a5..4d028ec 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -26,6 +26,7 @@ public class BetterFriendsConfig extends AddonConfig { @SpriteSlot @SwitchSetting private final ConfigProperty enabled = new ConfigProperty<>(true); + @SpriteSlot(x = 1) @ColorPickerSetting private final ConfigProperty prefixColor = new ConfigProperty<>(Color.ofRGB(255, 102, 0)); @@ -38,8 +39,10 @@ public Activity advancedFriendlist() { @SpriteSlot(size = 8, x = 4) private final PinIconConfig pinIconConfig = new PinIconConfig(); + @SpriteSlot(x = 3) private final FriendNoteTagConfig friendNoteTagConfig = new FriendNoteTagConfig(); + @SpriteSlot(x = 4) @TextFieldSetting private final ConfigProperty friendPrefix = new ConfigProperty<>("&aⒻ"); @@ -48,31 +51,42 @@ public Activity advancedFriendlist() { @SpriteSlot(x = 5) @SwitchSetting private final ConfigProperty friendRequestNotifications = new ConfigProperty<>(true); + @SettingRequires("friendRequestNotifications") @SpriteSlot(x = 6) @DropdownSetting private final ConfigProperty automaticFriendRequestReaction = new ConfigProperty<>( FriendRequestReaction.NONE); + @SpriteSlot(x = 7) @SwitchSetting private final ConfigProperty friendServerSwitchNotifications = new ConfigProperty<>(true); + @SpriteSlot(y = 1) @SwitchSetting private final ConfigProperty friendStatusUpdateNotifications = new ConfigProperty<>(true); + @SpriteSlot(x = 1, y = 1) @SwitchSetting private final ConfigProperty friendRemovalNotifications = new ConfigProperty<>(true); + @SpriteSlot(x = 2, y = 1) @SwitchSetting private final ConfigProperty friendRequestRemovalNotifications = new ConfigProperty<>(true); + @SpriteSlot(x = 3, y = 1) @SwitchSetting private final ConfigProperty labyChatMessageNotifications = new ConfigProperty<>(true); + @SettingRequires("labyChatMessageNotifications") @SpriteSlot(x = 4, y = 1) @SwitchSetting private final ConfigProperty ownLabyChatMessages = new ConfigProperty<>(true); + @SettingRequires("labyChatMessageNotifications") + @SwitchSetting + private final ConfigProperty showInteractionButtons = new ConfigProperty<>(true); + @SettingSection(value = "interactions", center = true) // @SpriteSlot(x = 5, y = 1) // @SwitchSetting @@ -90,15 +104,18 @@ public Activity advancedFriendlist() { public ConfigProperty enabled() { return this.enabled; } + public ConfigProperty prefixColor() { return this.prefixColor; } + public PinIconConfig pinIconConfig() { return this.pinIconConfig; } public FriendNoteTagConfig friendNoteTagConfig() { return this.friendNoteTagConfig; } + public ConfigProperty friendPrefix() { return this.friendPrefix; } @@ -106,34 +123,46 @@ public ConfigProperty friendPrefix() { public ConfigProperty friendRequestNotifications() { return this.friendRequestNotifications; } + public ConfigProperty automaticFriendRequestReaction() { return this.automaticFriendRequestReaction; } + public ConfigProperty friendServerSwitchNotifications() { return this.friendServerSwitchNotifications; } + public ConfigProperty friendStatusUpdateNotifications() { return this.friendStatusUpdateNotifications; } + public ConfigProperty friendRemovalNotifications() { return this.friendRemovalNotifications; } + public ConfigProperty friendRequestRemovalNotifications() { return this.friendRequestRemovalNotifications; } + public ConfigProperty labyChatMessageNotifications() { return this.labyChatMessageNotifications; } + public ConfigProperty ownLabyChatMessages() { return this.ownLabyChatMessages; } + public ConfigProperty showInteractionButtons() { + return this.showInteractionButtons; + } + // public ConfigProperty noteEditorBullet() { // return this.noteEditorBullet; // } public ConfigProperty togglePinBullet() { return this.togglePinBullet; } + public ConfigProperty restartWhenMuted() { return this.restartWhenMuted; } diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java index 760fde3..85d0936 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java @@ -2,20 +2,19 @@ import com.rappytv.betterfriends.BetterFriendsAddon; import com.rappytv.betterfriends.utils.GroupHelper; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.event.ClickEvent; import net.labymod.api.client.component.event.HoverEvent; import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.event.Subscribe; - import net.labymod.api.event.labymod.labyconnect.session.chat.LabyConnectChatMessageEvent; import net.labymod.api.labyconnect.LabyConnectSession; import net.labymod.api.labyconnect.protocol.model.User; import net.labymod.api.labyconnect.protocol.model.chat.TextChatMessage; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; public class LabyChatReceiveListener { @@ -68,7 +67,8 @@ public void onChatReceive(LabyConnectChatMessageEvent event) { )); } - if(receiver.getName().equals(Laby.labyAPI().getName())) { + if (receiver.getName().equals(Laby.labyAPI().getName()) + && this.addon.configuration().showInteractionButtons().get()) { component .append(Component .text(" ✔", NamedTextColor.GREEN) diff --git a/core/src/main/resources/assets/betterfriends/i18n/en_us.json b/core/src/main/resources/assets/betterfriends/i18n/en_us.json index 7561f2e..3ff6e5c 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -110,6 +110,10 @@ "name": "Own LabyChat Messages", "description": "If you also want to see your own sent messages in chat." }, + "showInteractionButtons": { + "name": "Show interaction buttons", + "description": "If you want to have LabyChat messages to have interactable buttons" + }, "noteEditorBullet": { "name": "Show friend note editor bullet", "description": "Toggles the visibility of the interaction bullet which can open the note editor of a friend." From 77e594407ed49cf426a27d6a034e5debdb4ed070 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 22:09:25 +0100 Subject: [PATCH 25/27] chore: Bump and register version --- build.gradle.kts | 2 +- .../com/rappytv/betterfriends/BetterFriendsAddon.java | 11 +++++++++++ .../betterfriends/config/BetterFriendsConfig.java | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5c52e2c..201b7a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { val versions = providers.gradleProperty("net.labymod.minecraft-versions").get().split(";") group = "org.example" -version = providers.environmentVariable("VERSION").getOrElse("1.0.0") +version = providers.environmentVariable("VERSION").getOrElse("1.0.1") labyMod { defaultPackageName = "com.rappytv.betterfriends" diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index d29aecc..0a2fa12 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -32,6 +32,8 @@ import net.labymod.api.client.entity.player.tag.PositionType; import net.labymod.api.client.gui.hud.binding.category.HudWidgetCategory; import net.labymod.api.models.addon.annotation.AddonMain; +import net.labymod.api.revision.SimpleRevision; +import net.labymod.api.util.version.SemanticVersion; @AddonMain public class BetterFriendsAddon extends LabyAddon { @@ -39,6 +41,15 @@ public class BetterFriendsAddon extends LabyAddon { private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.legacyAmpersand(); private static BetterFriendsAddon instance; + @Override + protected void preConfigurationLoad() { + Laby.references().revisionRegistry().register(new SimpleRevision( + "betterfriends", + new SemanticVersion("1.0.1"), + "2025-12-10" + )); + } + @Override protected void enable() { instance = this; diff --git a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java index 4d028ec..5f860e2 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -11,6 +11,7 @@ import net.labymod.api.client.gui.screen.widget.widgets.input.TextFieldWidget.TextFieldSetting; import net.labymod.api.client.gui.screen.widget.widgets.input.color.ColorPickerWidget.ColorPickerSetting; import net.labymod.api.client.gui.screen.widget.widgets.input.dropdown.DropdownWidget.DropdownSetting; +import net.labymod.api.configuration.loader.annotation.IntroducedIn; import net.labymod.api.configuration.loader.annotation.SpriteSlot; import net.labymod.api.configuration.loader.annotation.SpriteTexture; import net.labymod.api.configuration.loader.property.ConfigProperty; @@ -84,6 +85,7 @@ public Activity advancedFriendlist() { private final ConfigProperty ownLabyChatMessages = new ConfigProperty<>(true); @SettingRequires("labyChatMessageNotifications") + @IntroducedIn(namespace = "betterfriends", value = "1.0.1") @SwitchSetting private final ConfigProperty showInteractionButtons = new ConfigProperty<>(true); From 577da5e0fea88871adadd6f2554386f749beadbc Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 22:13:51 +0100 Subject: [PATCH 26/27] chore: Use production release channel --- build.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 201b7a5..4e9c89b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,3 @@ -import net.labymod.labygradle.common.extension.model.labymod.ReleaseChannels - plugins { id("net.labymod.labygradle") id("net.labymod.labygradle.addon") @@ -32,7 +30,6 @@ labyMod { version = rootProject.version.toString() addon("voicechat", true) - releaseChannel.set(ReleaseChannels.SNAPSHOT) } } From b54d339abb1cc81998d36653d0ab46c2395a5248 Mon Sep 17 00:00:00 2001 From: RappyTV Date: Mon, 8 Dec 2025 22:15:25 +0100 Subject: [PATCH 27/27] fix: Don't use deprecated SemanticVersion constructor --- .../main/java/com/rappytv/betterfriends/BetterFriendsAddon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index 0a2fa12..8fbc046 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -45,7 +45,7 @@ public class BetterFriendsAddon extends LabyAddon { protected void preConfigurationLoad() { Laby.references().revisionRegistry().register(new SimpleRevision( "betterfriends", - new SemanticVersion("1.0.1"), + new SemanticVersion(1, 0, 1), "2025-12-10" )); }