diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6092110..c8a49e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,18 +11,32 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v4 + - uses: actions/checkout@v5 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: 'corretto' - java-version: '21' + java-version: '25' + - name: Cache Gradle dependencies + uses: actions/cache@v5 + with: + path: ~/.gradle/caches + key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + gradle-${{ runner.os }}- + - name: Cache Gradle wrapper + uses: actions/cache@v5 + with: + path: ~/.gradle/wrapper + key: gradle-wrapper-${{ runner.os }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + gradle-wrapper-${{ runner.os }}- - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build --full-stacktrace - name: Upload Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: Artifacts path: build/libs/*-release.jar diff --git a/.gitignore b/.gitignore index 47d9f66..69ec47e 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,8 @@ run/ # LabyGradle | Addon Plugin build-data.txt .assetsroot +resources_index.json +access_widener_index.json # Don't ignore libraries !libs/*.jar \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 41f0680..0061055 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { val versions = providers.gradleProperty("net.labymod.minecraft-versions").get().split(";") group = "org.example" -version = providers.environmentVariable("VERSION").getOrElse("1.0.2") +version = providers.environmentVariable("VERSION").getOrElse("1.1.0") labyMod { defaultPackageName = "com.rappytv.betterfriends" @@ -39,4 +39,9 @@ subprojects { group = rootProject.group version = rootProject.version + + extensions.findByType(JavaPluginExtension::class.java)?.apply { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } } \ No newline at end of file diff --git a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java index 8fbc046..ce0e43a 100644 --- a/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java +++ b/core/src/main/java/com/rappytv/betterfriends/BetterFriendsAddon.java @@ -6,13 +6,11 @@ import com.rappytv.betterfriends.interactions.FriendNoteEditorBullet; import com.rappytv.betterfriends.interactions.FriendTogglePinBullet; import com.rappytv.betterfriends.listeners.ChatReceiveListener; -import com.rappytv.betterfriends.listeners.FriendAddListener; -import com.rappytv.betterfriends.listeners.FriendRemoveListener; -import com.rappytv.betterfriends.listeners.FriendRequestReceiveListener; -import com.rappytv.betterfriends.listeners.FriendRequestRemoveListener; -import com.rappytv.betterfriends.listeners.FriendServerStateListener; -import com.rappytv.betterfriends.listeners.FriendStatusUpdateListener; +import com.rappytv.betterfriends.listeners.ConfigVersionListener; +import com.rappytv.betterfriends.listeners.FriendListener; +import com.rappytv.betterfriends.listeners.FriendRequestListener; import com.rappytv.betterfriends.listeners.LabyChatReceiveListener; +import com.rappytv.betterfriends.listeners.TemporaryPinListener; import com.rappytv.betterfriends.ui.badge.FriendPinBadge; import com.rappytv.betterfriends.ui.hud.FriendCountHudWidget; import com.rappytv.betterfriends.ui.hud.IncomingFriendRequestCountHudWidget; @@ -20,15 +18,9 @@ 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; -import net.labymod.api.client.component.TextComponent; -import net.labymod.api.client.component.format.NamedTextColor; -import net.labymod.api.client.component.format.TextColor; -import net.labymod.api.client.component.format.TextDecoration; -import net.labymod.api.client.component.serializer.legacy.LegacyComponentSerializer; 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; @@ -38,34 +30,35 @@ @AddonMain public class BetterFriendsAddon extends LabyAddon { - private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.legacyAmpersand(); - private static BetterFriendsAddon instance; + private static BetterFriendsAddon INSTANCE; @Override protected void preConfigurationLoad() { + this.registerListener(new ConfigVersionListener()); Laby.references().revisionRegistry().register(new SimpleRevision( "betterfriends", new SemanticVersion(1, 0, 1), "2025-12-10" )); + Laby.references().revisionRegistry().register(new SimpleRevision( + "betterfriends", + new SemanticVersion(1, 1, 0), + "2026-04-30" + )); } @Override protected void enable() { - instance = this; + INSTANCE = this; this.registerSettingCategory(); - GroupHelper.registerGroupIds(); this.registerCommand(new BetterFriendsCommand()); this.registerListener(new ChatReceiveListener(this)); - this.registerListener(new FriendAddListener(this)); - this.registerListener(new FriendRemoveListener(this)); - this.registerListener(new FriendRequestReceiveListener(this)); - this.registerListener(new FriendRequestRemoveListener(this)); - this.registerListener(new FriendServerStateListener(this)); - this.registerListener(new FriendStatusUpdateListener(this)); + this.registerListener(new FriendListener(this)); + this.registerListener(new FriendRequestListener(this)); this.registerListener(new LabyChatReceiveListener(this)); + this.registerListener(new TemporaryPinListener(this)); this.labyAPI().interactionMenuRegistry().register(new FriendNoteEditorBullet(this)); this.labyAPI().interactionMenuRegistry().register(new FriendTogglePinBullet(this)); @@ -105,21 +98,10 @@ protected Class configurationClass() { } public static ReferenceStorage references() { - return instance.referenceStorageAccessor(); - } - - public static TextComponent getPrefix() { - return Component.empty() - .append(Component.text( - "BF", - TextColor.color(instance.configuration().prefixColor().get().get()) - ).decorate(TextDecoration.BOLD)) - .append(Component.space()) - .append(Component.text("»", NamedTextColor.DARK_GRAY)) - .append(Component.space()); + return INSTANCE.referenceStorageAccessor(); } - public LegacyComponentSerializer getSerializer() { - return SERIALIZER; + public static Component getPrefix() { + return INSTANCE.configuration().prefixCustomizationConfig().buildPrefix(); } } 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 5f860e2..56e89ca 100644 --- a/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java +++ b/core/src/main/java/com/rappytv/betterfriends/config/BetterFriendsConfig.java @@ -2,23 +2,21 @@ 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.widgets.FriendlistFriendWidget; +import com.rappytv.betterfriends.config.subconfig.PrefixCustomizationConfig; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; 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; import net.labymod.api.client.gui.screen.widget.widgets.input.dropdown.DropdownWidget.DropdownSetting; +import net.labymod.api.configuration.loader.annotation.Exclude; 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; 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 { @@ -28,22 +26,22 @@ public class BetterFriendsConfig extends AddonConfig { @SwitchSetting private final ConfigProperty enabled = new ConfigProperty<>(true); + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") @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); - } + private final PrefixCustomizationConfig prefixCustomizationConfig = new PrefixCustomizationConfig(); + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") @SpriteSlot(size = 8, x = 4) - private final PinIconConfig pinIconConfig = new PinIconConfig(); + @SwitchSetting + private final ConfigProperty temporaryPinsEnabled = new ConfigProperty<>(false); + @SettingSection(value = "indicators", center = true) @SpriteSlot(x = 3) private final FriendNoteTagConfig friendNoteTagConfig = new FriendNoteTagConfig(); + @SpriteSlot(size = 8, x = 4) + private final PinIconConfig pinIconConfig = new PinIconConfig(); + @SpriteSlot(x = 4) @TextFieldSetting private final ConfigProperty friendPrefix = new ConfigProperty<>("&aⒻ"); @@ -93,6 +91,7 @@ public Activity advancedFriendlist() { // @SpriteSlot(x = 5, y = 1) // @SwitchSetting // private final ConfigProperty noteEditorBullet = new ConfigProperty<>(true); + @SpriteSlot(size = 8, x = 4) @SwitchSetting private final ConfigProperty togglePinBullet = new ConfigProperty<>(true); @@ -102,22 +101,30 @@ public Activity advancedFriendlist() { @SwitchSetting private final ConfigProperty restartWhenMuted = new ConfigProperty<>(true); + @Exclude + private final List temporaryPins = new ArrayList<>(); + @Override public ConfigProperty enabled() { return this.enabled; } - public ConfigProperty prefixColor() { - return this.prefixColor; + public PrefixCustomizationConfig prefixCustomizationConfig() { + return this.prefixCustomizationConfig; } - public PinIconConfig pinIconConfig() { - return this.pinIconConfig; + public ConfigProperty temporaryPinsEnabled() { + return this.temporaryPinsEnabled; } + public FriendNoteTagConfig friendNoteTagConfig() { return this.friendNoteTagConfig; } + public PinIconConfig pinIconConfig() { + return this.pinIconConfig; + } + public ConfigProperty friendPrefix() { return this.friendPrefix; } @@ -161,6 +168,7 @@ public ConfigProperty showInteractionButtons() { // public ConfigProperty noteEditorBullet() { // return this.noteEditorBullet; // } + public ConfigProperty togglePinBullet() { return this.togglePinBullet; } @@ -169,7 +177,16 @@ public ConfigProperty restartWhenMuted() { return this.restartWhenMuted; } + public List temporaryPins() { + return this.temporaryPins; + } + public enum FriendRequestReaction { NONE, ACCEPT, DECLINE } + + @Override + public int getConfigVersion() { + return 2; + } } diff --git a/core/src/main/java/com/rappytv/betterfriends/config/subconfig/PrefixCustomizationConfig.java b/core/src/main/java/com/rappytv/betterfriends/config/subconfig/PrefixCustomizationConfig.java new file mode 100644 index 0000000..0105f90 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/config/subconfig/PrefixCustomizationConfig.java @@ -0,0 +1,86 @@ +package com.rappytv.betterfriends.config.subconfig; + +import com.rappytv.betterfriends.ui.widget.config.PrefixPreviewWidget.PrefixPreviewSetting; +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.component.format.TextDecoration; +import net.labymod.api.client.component.serializer.legacy.LegacyComponentSerializer; +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; +import net.labymod.api.configuration.loader.Config; +import net.labymod.api.configuration.loader.annotation.IntroducedIn; +import net.labymod.api.configuration.loader.property.ConfigProperty; +import net.labymod.api.configuration.settings.annotation.CustomTranslation; +import net.labymod.api.configuration.settings.annotation.SettingRequires; +import net.labymod.api.configuration.settings.annotation.SettingSection; +import net.labymod.api.util.Color; + +public class PrefixCustomizationConfig extends Config { + + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") + @PrefixPreviewSetting + private final ConfigProperty preview = new ConfigProperty<>(false); + + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") + @SwitchSetting + private final ConfigProperty enableManualPrefix = new ConfigProperty<>(false); + + @SettingSection(value = "options", center = true) + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") + @CustomTranslation("betterfriends.settings.prefixCustomizationConfig.prefix") + @TextFieldSetting + private final ConfigProperty manualPrefix = new ConfigProperty<>("&6&lBF&8 » ") + .visibilitySupplier(this.enableManualPrefix::get); + + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") + @TextFieldSetting + private final ConfigProperty prefix = new ConfigProperty<>("BF") + .visibilitySupplier(() -> !this.enableManualPrefix.get()); + + @IntroducedIn(namespace = "betterfriends", value = "1.1.0") + @SettingRequires(value = "prefix", required = "", invert = true) + @ColorPickerSetting + private final ConfigProperty prefixColor = new ConfigProperty<>(Color.ofRGB(255, 102, 0)) + .visibilitySupplier(() -> !this.enableManualPrefix.get()); + + public ConfigProperty enableManualPrefix() { + return this.enableManualPrefix; + } + + public ConfigProperty manualPrefix() { + return this.manualPrefix; + } + + public ConfigProperty prefix() { + return this.prefix; + } + + public ConfigProperty prefixColor() { + return this.prefixColor; + } + + public Component buildPrefix() { + if (this.enableManualPrefix.get()) { + return LegacyComponentSerializer.legacyAmpersand() + .deserialize(this.manualPrefix.get()); + } + Component component = Component.empty(); + + String prefix = this.prefix.get(); + if (!prefix.isEmpty()) { + component + .append( + Component.text( + prefix, + TextColor.color(this.prefixColor.get().get()) + ).decorate(TextDecoration.BOLD) + ) + .append(Component.space()) + .append(Component.text("»", NamedTextColor.DARK_GRAY)) + .append(Component.space()); + } + return component; + } +} 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 31951c6..2d9054b 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/ChatReceiveListener.java @@ -5,6 +5,7 @@ import net.labymod.api.Laby; import net.labymod.api.client.component.Component; import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.client.component.serializer.legacy.LegacyComponentSerializer; import net.labymod.api.event.Subscribe; import net.labymod.api.event.client.chat.ChatReceiveEvent; import net.labymod.api.labyconnect.LabyConnectSession; @@ -48,7 +49,7 @@ public void onChatReceive(ChatReceiveEvent receiveEvent) { receiveEvent.setMessage( Component.empty() - .append(this.addon.getSerializer().deserialize( + .append(LegacyComponentSerializer.legacyAmpersand().deserialize( this.addon.configuration().friendPrefix().get() )) .append(Component.space()) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/ConfigVersionListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/ConfigVersionListener.java new file mode 100644 index 0000000..0cd4e55 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/ConfigVersionListener.java @@ -0,0 +1,26 @@ +package com.rappytv.betterfriends.listeners; + +import com.google.gson.JsonObject; +import com.rappytv.betterfriends.config.BetterFriendsConfig; +import net.labymod.api.event.Subscribe; +import net.labymod.api.event.labymod.config.ConfigurationVersionUpdateEvent; + +public class ConfigVersionListener { + + @Subscribe + public void onConfigVersionUpdate(ConfigurationVersionUpdateEvent event) { + if (event.getConfigClass() != BetterFriendsConfig.class || event.getUsedVersion() != 1) { + return; + } + JsonObject config = event.getJsonObject(); + if (!config.has("prefixColor")) { + return; + } + JsonObject prefixCustomizationConfig = new JsonObject(); + prefixCustomizationConfig.add("prefixColor", config.get("prefixColor")); + config.add("prefixCustomizationConfig", prefixCustomizationConfig); + + event.setJsonObject(config); + } + +} diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendAddListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendAddListener.java deleted file mode 100644 index aac122b..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendAddListener.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.rappytv.betterfriends.listeners; - -import com.rappytv.betterfriends.BetterFriendsAddon; -import net.labymod.addons.voicechat.api.audio.stream.AudioStreamState; -import net.labymod.addons.voicechat.api.client.VoiceConnector; -import net.labymod.addons.voicechat.core.VoiceChatAddon; -import net.labymod.api.Laby; -import net.labymod.api.event.Subscribe; -import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendAddEvent; - -public class FriendAddListener { - - private final BetterFriendsAddon addon; - - public FriendAddListener(BetterFriendsAddon addon) { - this.addon = addon; - } - - @Subscribe - public void onFriendAdd(LabyConnectFriendAddEvent event) { - if (!this.addon.configuration().restartWhenMuted().get()) { - return; - } - - if (!Laby.labyAPI().addonService().isEnabled("voicechat")) { - return; - } - - VoiceConnector client = VoiceChatAddon.INSTANCE.client(); - if (!client.isAuthenticated() || !this.isSelfMuted()) { - return; - } - - client.disconnect(); - client.connect(); - } - - private boolean isSelfMuted() { - return VoiceChatAddon.INSTANCE - .referenceStorage() - .audioStreamRegistry() - .getState(Laby.labyAPI().getUniqueId(), false) == AudioStreamState.INPUT_GLOBAL_MUTED; - } - -} diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendListener.java new file mode 100644 index 0000000..a4c2e06 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendListener.java @@ -0,0 +1,160 @@ +package com.rappytv.betterfriends.listeners; + +import com.rappytv.betterfriends.BetterFriendsAddon; +import com.rappytv.betterfriends.utils.GroupHelper; +import net.labymod.addons.voicechat.api.audio.stream.AudioStreamState; +import net.labymod.addons.voicechat.api.client.VoiceConnector; +import net.labymod.addons.voicechat.core.VoiceChatAddon; +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.client.gui.icon.Icon; +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.friend.LabyConnectFriendServerEvent; +import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendStatusEvent; +import net.labymod.api.labyconnect.protocol.model.UserStatus; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; +import net.labymod.api.labyconnect.protocol.model.friend.ServerInfo; +import net.labymod.api.notification.Notification; +import net.labymod.api.util.time.TimeUtil; + +public class FriendListener { + + private final BetterFriendsAddon addon; + + public FriendListener(BetterFriendsAddon addon) { + this.addon = addon; + } + + @Subscribe + public void onFriendAdd(LabyConnectFriendAddEvent event) { + if (!this.addon.configuration().restartWhenMuted().get()) { + return; + } + + if (!Laby.labyAPI().addonService().isEnabled("voicechat")) { + return; + } + + VoiceConnector client = VoiceChatAddon.INSTANCE.client(); + if (!client.isAuthenticated() || !this.isSelfMuted()) { + return; + } + + client.disconnect(); + client.connect(); + } + + @Subscribe + public void onFriendRemove(LabyConnectFriendRemoveEvent event) { + if (!this.addon.configuration().friendRemovalNotifications().get()) { + return; + } + Notification.builder() + .title(Component.translatable("betterfriends.notifications.friendRemoval.title")) + .text(Component.translatable( + "betterfriends.notifications.friendRemoval.description", + GroupHelper.getColoredName(event.friend()) + )) + .icon(Icon.head(event.friend().getUniqueId(), true)) + .duration(15000) + .buildAndPush(); + } + + @Subscribe + public void onServerUpdate(LabyConnectFriendServerEvent event) { + if (!this.addon.configuration().friendServerSwitchNotifications().get()) { + return; + } + ServerInfo info = event.serverInfo(); + if (info == null || info.getAddress() == null) { + return; + } + + Friend friend = event.friend(); + if (friend == null) { + return; + } + + Component address = Component.text(info.getAddress()) + .color(NamedTextColor.AQUA) + .clickEvent(ClickEvent.runCommand("/bf join " + info.getDisplayInfo())) + .hoverEvent(HoverEvent.showText(Component.translatable( + "betterfriends.notifications.serverUpdate.hover", + NamedTextColor.DARK_PURPLE + ))); + + String gameModeName = info.getGameModeName(); + Component text; + if (gameModeName == null) { + text = Component.translatable("labymod.activity.labyconnect.notifications.server", + NamedTextColor.GRAY, + address + ); + } else if (TimeUtil.getCurrentTimeMillis() - event.friend().getLastServerChange() < 1000L) { + text = Component.translatable( + "labymod.activity.labyconnect.notifications.gameModeAndServer", + NamedTextColor.GRAY, + Component.text(gameModeName, NamedTextColor.AQUA), + address + ); + } else { + text = Component.translatable( + "labymod.activity.labyconnect.notifications.gameMode", + NamedTextColor.GRAY, + Component.text(gameModeName, NamedTextColor.AQUA) + ); + } + + this.addon.displayMessage( + Component.empty() + .append(BetterFriendsAddon.getPrefix()) + .append(GroupHelper.getColoredName(friend)) + .append(Component.space()) + .append(text) + .color(NamedTextColor.GRAY) + ); + } + + @Subscribe + public void onStatusUpdate(LabyConnectFriendStatusEvent event) { + if (!this.addon.configuration().friendStatusUpdateNotifications().get()) { + return; + } + UserStatus state = event.getStatus(); + Component stateComponent = Component.translatable( + state.getLocalTranslationKey(), + state.textColor() + ); + + if (state == UserStatus.OFFLINE) { + stateComponent = Component.translatable( + "betterfriends.notifications.statusUpdate.offline", + NamedTextColor.DARK_GRAY + ); + } + + this.addon.displayMessage( + Component.empty() + .append(BetterFriendsAddon.getPrefix()) + .append(Component.translatable( + "betterfriends.notifications.statusUpdate.message", + GroupHelper.getColoredName(event.friend()), + stateComponent + )) + .color(NamedTextColor.GRAY) + ); + } + + private boolean isSelfMuted() { + return VoiceChatAddon.INSTANCE + .referenceStorage() + .audioStreamRegistry() + .getState(Laby.labyAPI().getUniqueId(), false) == AudioStreamState.INPUT_GLOBAL_MUTED; + } + +} diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java deleted file mode 100644 index a849989..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRemoveListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.rappytv.betterfriends.listeners; - -import com.rappytv.betterfriends.BetterFriendsAddon; -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; -import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendRemoveEvent; -import net.labymod.api.notification.Notification; - -public class FriendRemoveListener { - - private final BetterFriendsAddon addon; - - public FriendRemoveListener(BetterFriendsAddon addon) { - this.addon = addon; - } - - @Subscribe - public void onFriendRemove(LabyConnectFriendRemoveEvent event) { - if (!this.addon.configuration().friendRemovalNotifications().get()) { - return; - } - Notification.builder() - .title(Component.translatable("betterfriends.notifications.friendRemoval.title")) - .text(Component.translatable( - "betterfriends.notifications.friendRemoval.description", - GroupHelper.getColoredName(event.friend()) - )) - .icon(Icon.head(event.friend().getUniqueId(), true)) - .duration(15000) - .buildAndPush(); - } -} diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestListener.java similarity index 75% rename from core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java rename to core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestListener.java index 066d751..21b0713 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestListener.java @@ -7,15 +7,19 @@ 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.client.gui.icon.Icon; import net.labymod.api.event.Subscribe; import net.labymod.api.event.labymod.labyconnect.session.request.LabyConnectIncomingFriendRequestAddEvent; +import net.labymod.api.event.labymod.labyconnect.session.request.LabyConnectOutgoingFriendRequestRemoveEvent; +import net.labymod.api.labyconnect.LabyConnectSession; import net.labymod.api.labyconnect.protocol.model.request.IncomingFriendRequest; +import net.labymod.api.notification.Notification; -public class FriendRequestReceiveListener { +public class FriendRequestListener { private final BetterFriendsAddon addon; - public FriendRequestReceiveListener(BetterFriendsAddon addon) { + public FriendRequestListener(BetterFriendsAddon addon) { this.addon = addon; } @@ -100,4 +104,28 @@ public void onFriendRequestReceive(LabyConnectIncomingFriendRequestAddEvent even ); } + @Subscribe + public void onFriendRequestRemove(LabyConnectOutgoingFriendRequestRemoveEvent event) { + if (!this.addon.configuration().friendRequestRemovalNotifications().get()) { + return; + } + LabyConnectSession session = event.labyConnect().getSession(); + if (session == null || !session.isAuthenticated()) { + return; + } + if (session.getFriend(event.request().getUniqueId()) != null) { + return; + } + + Notification.builder() + .title(Component.translatable("betterfriends.notifications.friendRequestRemoval.title")) + .text(Component.translatable( + "betterfriends.notifications.friendRequestRemoval.description", + GroupHelper.getColoredName(event.request().getName(), event.request().gameUser()) + )) + .icon(Icon.head(event.request().getUniqueId(), true)) + .duration(15000) + .buildAndPush(); + } + } diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java deleted file mode 100644 index 65b385c..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendRequestRemoveListener.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.rappytv.betterfriends.listeners; - -import com.rappytv.betterfriends.BetterFriendsAddon; -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; -import net.labymod.api.event.labymod.labyconnect.session.request.LabyConnectOutgoingFriendRequestRemoveEvent; -import net.labymod.api.labyconnect.LabyConnectSession; -import net.labymod.api.notification.Notification; - -public class FriendRequestRemoveListener { - - private final BetterFriendsAddon addon; - - public FriendRequestRemoveListener(BetterFriendsAddon addon) { - this.addon = addon; - } - - @Subscribe - public void onFriendRequestRemove(LabyConnectOutgoingFriendRequestRemoveEvent event) { - if (!this.addon.configuration().friendRequestRemovalNotifications().get()) { - return; - } - LabyConnectSession session = event.labyConnect().getSession(); - if(session == null || !session.isAuthenticated()) { - return; - } - if(session.getFriend(event.request().getUniqueId()) != null) { - return; - } - - Notification.builder() - .title(Component.translatable("betterfriends.notifications.friendRequestRemoval.title")) - .text(Component.translatable( - "betterfriends.notifications.friendRequestRemoval.description", - GroupHelper.getColoredName(event.request().getName(), event.request().gameUser()) - )) - .icon(Icon.head(event.request().getUniqueId(), true)) - .duration(15000) - .buildAndPush(); - } -} diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java deleted file mode 100644 index a7418f5..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendServerStateListener.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.rappytv.betterfriends.listeners; - -import com.rappytv.betterfriends.BetterFriendsAddon; -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; -import net.labymod.api.client.component.format.NamedTextColor; -import net.labymod.api.event.Subscribe; -import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendServerEvent; -import net.labymod.api.labyconnect.protocol.model.friend.Friend; -import net.labymod.api.labyconnect.protocol.model.friend.ServerInfo; -import net.labymod.api.util.time.TimeUtil; - -public class FriendServerStateListener { - - private final BetterFriendsAddon addon; - - public FriendServerStateListener(BetterFriendsAddon addon) { - this.addon = addon; - } - - @Subscribe - public void onServerUpdate(LabyConnectFriendServerEvent event) { - if (!this.addon.configuration().friendServerSwitchNotifications().get()) { - return; - } - ServerInfo info = event.serverInfo(); - if (info == null || info.getAddress() == null) { - return; - } - - Friend friend = event.friend(); - if (friend == null) { - return; - } - - Component address = Component.text(info.getAddress()) - .color(NamedTextColor.AQUA) - .clickEvent(ClickEvent.runCommand("/bf join " + info.getDisplayInfo())) - .hoverEvent(HoverEvent.showText(Component.translatable( - "betterfriends.notifications.serverUpdate.hover", - NamedTextColor.DARK_PURPLE - ))); - - String gameModeName = info.getGameModeName(); - Component text; - if (gameModeName == null) { - text = Component.translatable("labymod.activity.labyconnect.notifications.server", - NamedTextColor.GRAY, - address - ); - } else if (TimeUtil.getCurrentTimeMillis() - event.friend().getLastServerChange() < 1000L) { - text = Component.translatable( - "labymod.activity.labyconnect.notifications.gameModeAndServer", - NamedTextColor.GRAY, - Component.text(gameModeName, NamedTextColor.AQUA), - address - ); - } else { - text = Component.translatable( - "labymod.activity.labyconnect.notifications.gameMode", - NamedTextColor.GRAY, - Component.text(gameModeName, NamedTextColor.AQUA) - ); - } - - this.addon.displayMessage( - Component.empty() - .append(BetterFriendsAddon.getPrefix()) - .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 deleted file mode 100644 index 064e7b5..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/FriendStatusUpdateListener.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.rappytv.betterfriends.listeners; - -import com.rappytv.betterfriends.BetterFriendsAddon; -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; -import net.labymod.api.event.labymod.labyconnect.session.friend.LabyConnectFriendStatusEvent; -import net.labymod.api.labyconnect.protocol.model.UserStatus; - -public class FriendStatusUpdateListener { - - private final BetterFriendsAddon addon; - - public FriendStatusUpdateListener(BetterFriendsAddon addon) { - this.addon = addon; - } - - @Subscribe - public void onStatusUpdate(LabyConnectFriendStatusEvent event) { - if (!this.addon.configuration().friendStatusUpdateNotifications().get()) { - return; - } - UserStatus state = event.getStatus(); - Component stateComponent = Component.translatable( - state.getLocalTranslationKey(), - state.textColor() - ); - - if (state == UserStatus.OFFLINE) { - stateComponent = Component.translatable( - "betterfriends.notifications.statusUpdate.offline", - NamedTextColor.DARK_GRAY - ); - } - - this.addon.displayMessage( - Component.empty() - .append(BetterFriendsAddon.getPrefix()) - .append(Component.translatable( - "betterfriends.notifications.statusUpdate.message", - 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 85d0936..c9b7ebc 100644 --- a/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/LabyChatReceiveListener.java @@ -48,23 +48,34 @@ public void onChatReceive(LabyConnectChatMessageEvent event) { return; } + boolean hasContent = !message.getMessage().isEmpty(); + Component component = Component.empty() .append(BetterFriendsAddon.getPrefix()) .append(GroupHelper.getColoredName(sender.getName(), sender.gameUser())) .append(Component.text(" → ", NamedTextColor.DARK_GRAY)) .append(GroupHelper.getColoredName(receiver.getName(), receiver.gameUser())) - .append(Component.text(" » ", NamedTextColor.DARK_GRAY)) - .append(Component.text(message.getMessage(), NamedTextColor.WHITE)); + .append(Component.text(" » ", NamedTextColor.DARK_GRAY)); + + if (hasContent) { + component.append(Component.text(message.getMessage(), NamedTextColor.WHITE)); + } int attachments = message.getAttachments().size(); if(attachments > 0) { - component - .append(Component.space()) - .append(Component.translatable( - "betterfriends.notifications.chats.attachments", - NamedTextColor.AQUA, - Component.text(attachments) - )); + Component attachmentComponent = Component.empty().color(NamedTextColor.AQUA); + if (hasContent) { + attachmentComponent.append(Component.text("[")); + } + attachmentComponent.append(Component.translatable( + "betterfriends.notifications.chats.attachment" + (attachments == 1 ? "" : "s"), + Component.text(attachments) + )); + if (hasContent) { + attachmentComponent.append(Component.text("]")); + component.append(Component.space()); + } + component.append(attachmentComponent); } if (receiver.getName().equals(Laby.labyAPI().getName()) diff --git a/core/src/main/java/com/rappytv/betterfriends/listeners/TemporaryPinListener.java b/core/src/main/java/com/rappytv/betterfriends/listeners/TemporaryPinListener.java new file mode 100644 index 0000000..86f8eff --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/listeners/TemporaryPinListener.java @@ -0,0 +1,105 @@ +package com.rappytv.betterfriends.listeners; + +import com.rappytv.betterfriends.BetterFriendsAddon; +import com.rappytv.betterfriends.config.BetterFriendsConfig; +import java.util.UUID; +import net.labymod.api.event.Subscribe; +import net.labymod.api.event.labymod.labyconnect.LabyConnectEvent; +import net.labymod.api.event.labymod.labyconnect.session.chat.LabyConnectChatMessageEvent; +import net.labymod.api.event.labymod.labyconnect.session.chat.LabyConnectChatMessageReadEvent; +import net.labymod.api.labyconnect.LabyConnect; +import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.chat.ChatMessage; +import net.labymod.api.labyconnect.protocol.model.friend.Friend; + +public class TemporaryPinListener { + + private final BetterFriendsConfig config; + + public TemporaryPinListener(BetterFriendsAddon addon) { + this.config = addon.configuration(); + } + + @Subscribe + public void onLabyConnect(LabyConnectEvent event) { + LabyConnect connect = event.labyConnect(); + if (!connect.isAuthenticated()) { + return; + } + + LabyConnectSession session = connect.getSession(); + if (session == null || !session.isAuthenticated()) { + return; + } + + for (UUID uuid : this.config.temporaryPins()) { + Friend friend = session.getFriend(uuid); + if (friend == null || !friend.isPinned()) { + continue; + } + + friend.unpin(); + } + this.config.temporaryPins().clear(); + + if (!this.config.temporaryPinsEnabled().get()) { + return; + } + for (Friend friend : session.getFriends()) { + for (ChatMessage message : friend.chat().getMessages()) { + if (message.isRead() || friend.isPinned()) { + continue; + } + + this.config.temporaryPins().add(friend.getUniqueId()); + friend.pin(); + break; + } + } + } + + @Subscribe + public void onLabyConnectChatMessage(LabyConnectChatMessageEvent event) { + if (!this.config.temporaryPinsEnabled().get()) { + return; + } + LabyConnectSession session = event.labyConnect().getSession(); + if (session == null || !session.isAuthenticated()) { + return; + } + + UUID uniqueId = event.message().sender().getUniqueId(); + Friend friend = session.getFriend(uniqueId); + if (friend == null || friend.isPinned()) { + return; + } + + this.config.temporaryPins().add(uniqueId); + friend.pin(); + } + + @Subscribe + public void onLabyConnectChatMessageRead(LabyConnectChatMessageReadEvent event) { + if (this.config.temporaryPins().isEmpty()) { + return; + } + + UUID uniqueId = event.message().sender().getUniqueId(); + if (!this.config.temporaryPins().contains(uniqueId)) { + return; + } + + LabyConnectSession session = event.labyConnect().getSession(); + if (session == null || !session.isAuthenticated()) { + return; + } + + Friend friend = session.getFriend(uniqueId); + if (friend == null || !friend.isPinned()) { + return; + } + + this.config.temporaryPins().remove(uniqueId); + friend.unpin(); + } +} 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 deleted file mode 100644 index d0ef0b6..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/ui/activities/config/FriendlistActivity.java +++ /dev/null @@ -1,218 +0,0 @@ -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.Function; -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; -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; -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.User; -import net.labymod.api.labyconnect.protocol.model.chat.ChatMessage; -import net.labymod.api.labyconnect.protocol.model.friend.Friend; - -@Links({@Link("friend_list.lss"), @Link("friend.lss")}) -@AutoActivity -public class FriendlistActivity extends SimpleActivity { - - private final Function friendWidgetConstructor; - private final VerticalListWidget entries = new VerticalListWidget<>() - .addId("friends"); - 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; - } - - @Override - public void initialize(Parent parent) { - super.initialize(parent); - - FlexibleContentWidget container = new FlexibleContentWidget().addId("container"); - - HorizontalListWidget filterSettings = new HorizontalListWidget() - .addId("filter-settings"); - - TextFieldWidget searchField = new TextFieldWidget(); - searchField.addId("search-field"); - searchField.placeholder(Component.translatable("labymod.ui.textfield.search")); - 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; - } - Friend friend1 = friendWidget1.getFriend(); - Friend friend2 = friendWidget2.getFriend(); - int comparePin = Boolean.compare(friend2.isPinned(), friend1.isPinned()); - if (comparePin != 0) { - return comparePin; - } - 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); - - container.addContent(filterSettings); - container.addContent(this.error); - 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()) { - this.handleError("betterfriends.errors.notConnected"); - return; - } - if (session.getFriends().isEmpty()) { - this.handleError("betterfriends.errors.emptyList"); - return; - } - this.error.setVisible(false); - this.scroll.setVisible(true); - - List children = new ArrayList<>(); - - for (Friend friend : session.getFriends()) { - if (this.isUserInFilter(friend)) { - children.add(this.friendWidgetConstructor.apply(friend)); - } - } - - if (initialized) { - this.entries.addChildrenInitialized(children, true); - } else { - this.entries.addChildren(children, true); - } - } - - 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(); - } - - private boolean isUserInFilter(User user) { - return !this.hasFilter() || user.getName().toLowerCase() - .contains(this.filterQuery.toLowerCase()); - } - - @Subscribe - public void onUserUpdateData(final UserUpdateDataEvent event) { - if (event.phase() == Phase.POST) { - this.labyAPI.minecraft().executeOnRenderThread(() -> - FriendlistActivity.this.entries.reInitializeChildrenIf( - FriendWidget.class, - widget -> widget.getFriend().getUniqueId().equals( - event.gameUser().getUniqueId() - ) - ) - ); - } - } - - @Subscribe - public void onLabyConnectFriendAdd(LabyConnectFriendAddEvent event) { - this.entries.addChildAsync(this.friendWidgetConstructor.apply(event.friend())); - } - - @Subscribe - public void onLabyConnectFriendAddBulk(LabyConnectFriendAddBulkEvent event) { - for (Friend friend : event.getFriends()) { - this.entries.addChildAsync(this.friendWidgetConstructor.apply(friend)); - } - } - - @Subscribe - public void onLabyConnectFriendRemove(LabyConnectFriendRemoveEvent event) { - this.entries.removeChildIf( - FriendWidget.class, - widget -> widget.getFriend().getUniqueId().equals(event.friend().getUniqueId()) - ); - } - - private enum SortingStrategy { - ONLINE_STATUS((a, b) -> Boolean.compare(b.isOnline(), a.isOnline())), - 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 Comparator sortingFunction; - - SortingStrategy(Comparator comparator) { - this.sortingFunction = comparator; - } - - public int compare(Friend f1, Friend f2) { - return this.sortingFunction.compare(f1, f2); - } - } -} \ No newline at end of file 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 881fe5b..4efa265 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 @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.List; import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.serializer.legacy.LegacyComponentSerializer; import net.labymod.api.client.entity.player.tag.PositionType; import net.labymod.api.client.entity.player.tag.tags.ComponentNameTag; import net.labymod.api.client.render.state.entity.EntitySnapshot; @@ -16,6 +17,7 @@ public class FriendNoteNameTag extends ComponentNameTag { private final BetterFriendsAddon addon; private final PositionType position; + private final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacyAmpersand(); public FriendNoteNameTag(BetterFriendsAddon addon, PositionType position) { this.addon = addon; @@ -45,13 +47,13 @@ public FriendNoteNameTag(BetterFriendsAddon addon, PositionType position) { } String note = friend.getNote(); if (note != null && !note.isBlank()) { - return Collections.singletonList(this.addon.getSerializer().deserialize(note)); + return Collections.singletonList(this.serializer.deserialize(note)); } String defaultTag = friendSnapshot.config().friendNoteTagConfig().defaultTag().get(); if (defaultTag.isBlank()) { return super.buildComponents(snapshot); } - return Collections.singletonList(this.addon.getSerializer().deserialize(defaultTag)); + return Collections.singletonList(this.serializer.deserialize(defaultTag)); } @Override diff --git a/core/src/main/java/com/rappytv/betterfriends/ui/widget/config/PrefixPreviewWidget.java b/core/src/main/java/com/rappytv/betterfriends/ui/widget/config/PrefixPreviewWidget.java new file mode 100644 index 0000000..708b0c7 --- /dev/null +++ b/core/src/main/java/com/rappytv/betterfriends/ui/widget/config/PrefixPreviewWidget.java @@ -0,0 +1,80 @@ +package com.rappytv.betterfriends.ui.widget.config; + +import com.rappytv.betterfriends.config.subconfig.PrefixCustomizationConfig; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +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.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.layout.list.HorizontalListWidget; +import net.labymod.api.configuration.settings.Setting; +import net.labymod.api.configuration.settings.accessor.SettingAccessor; +import net.labymod.api.configuration.settings.annotation.SettingElement; +import net.labymod.api.configuration.settings.annotation.SettingFactory; +import net.labymod.api.configuration.settings.annotation.SettingWidget; +import net.labymod.api.configuration.settings.widget.WidgetFactory; + +@Link("prefix-preview.lss") +@AutoWidget +@SettingWidget +public class PrefixPreviewWidget extends HorizontalListWidget { + + private final static Component CONTENT_PLACEHOLDER = Component.translatable( + "betterfriends.settings.prefixCustomizationConfig.contentPlaceholder", + NamedTextColor.GRAY + ); + + private final PrefixCustomizationConfig config; + + private ComponentWidget prefixWidget; + + public PrefixPreviewWidget(PrefixCustomizationConfig config) { + this.config = config; + config.enableManualPrefix().addChangeListener(this::update); + config.manualPrefix().addChangeListener(this::update); + config.prefix().addChangeListener(this::update); + config.prefixColor().addChangeListener(this::update); + } + + @Override + public void initialize(Parent parent) { + super.initialize(parent); + this.addEntry(this.prefixWidget = ComponentWidget.empty()); + this.update(); + } + + private void update() { + this.prefixWidget.setComponent(this.config.buildPrefix().append(CONTENT_PLACEHOLDER)); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @SettingElement(extended = true) + public @interface PrefixPreviewSetting { + + } + + @SettingFactory + public static class Factory implements WidgetFactory { + + @Override + public PrefixPreviewWidget[] create(Setting setting, PrefixPreviewSetting annotation, + SettingAccessor accessor) { + if (!(accessor.config() instanceof PrefixCustomizationConfig config)) { + return new PrefixPreviewWidget[0]; + } + + return new PrefixPreviewWidget[]{new PrefixPreviewWidget(config)}; + } + + @Override + public Class[] types() { + return new Class[0]; + } + } +} 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 deleted file mode 100644 index e36f2c7..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendWidget.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.rappytv.betterfriends.ui.widgets; - -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.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; -import net.labymod.api.client.gui.screen.Parent; -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.UserStatus; -import net.labymod.api.labyconnect.protocol.model.friend.Friend; - -@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); - - UserStatus userStatus = this.friend.userStatus(); - IconWidget indicatorWidget = new IconWidget(SpriteCommon.STATUS_INDICATOR); - indicatorWidget.addId("indicator"); - indicatorWidget.color().set(userStatus.getColor().getValue()); - 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("betterfriends.general.labynet")); - 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("betterfriends.general.copyUuid")); - usernameWidget.setPressable(() -> - Laby.references().chatExecutor().copyToClipboard(this.friend.getUniqueId().toString()) - ); - - this.addEntry(indicatorWidget); - 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()) { - HorizontalListWidget buttonWrapper = new HorizontalListWidget().addId("buttons"); - - for(ButtonWidget button : buttons) { - buttonWrapper.addEntry(button); - } - - this.addEntry(buttonWrapper); - } - } - - 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(); -} 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 deleted file mode 100644 index 649e95c..0000000 --- a/core/src/main/java/com/rappytv/betterfriends/ui/widgets/FriendlistFriendWidget.java +++ /dev/null @@ -1,112 +0,0 @@ -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; -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; - -@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); - Laby.labyAPI().eventBus().registerListener(this); - } - - @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(); - } else { - this.friend.pin(); - } - this.reInitialize(); - }).addId("pin-button"); - 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 - ).addId("note-button"); - noteButton.setHoverComponent(Component.translatable( - "labymod.activity.labyconnect.chat.action.note" - )); - ButtonWidget removeButton = ButtonWidget.component(X, () -> { - if (this.skipConfirmation) { - this.friend.remove(); - } else { - this.confirmRemoval = true; - this.reInitialize(); - } - }).addId("remove-button"); - removeButton.setHoverComponent( - Component - .translatable( - "betterfriends.settings.advancedFriendlist.removal.label", - NamedTextColor.RED - ) - .append(Component.newline()) - .append(Component.translatable( - "betterfriends.settings.advancedFriendlist.removal.skipConfirmation", - NamedTextColor.DARK_GRAY - )) - ); - return List.of(pinButton, noteButton, removeButton); - } - - @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/java/com/rappytv/betterfriends/utils/GroupHelper.java b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java index 6efb161..35604bc 100644 --- a/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java +++ b/core/src/main/java/com/rappytv/betterfriends/utils/GroupHelper.java @@ -1,47 +1,11 @@ package com.rappytv.betterfriends.utils; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import java.util.ArrayList; -import java.util.List; -import net.labymod.api.Constants.Urls; 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; public class GroupHelper { - private static final List groupIds = new ArrayList<>(); - - public static void registerGroupIds() { - Request.ofGson(JsonElement.class) - .url(Urls.LABYNET_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()); } 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 3ff6e5c..3fe4c5a 100644 --- a/core/src/main/resources/assets/betterfriends/i18n/en_us.json +++ b/core/src/main/resources/assets/betterfriends/i18n/en_us.json @@ -5,6 +5,9 @@ "general": { "name": "General" }, + "indicators": { + "name": "Friend indicators" + }, "notifications": { "name": "Notifications" }, @@ -22,23 +25,33 @@ "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", - "removal": { - "label": "Remove friend", - "skipConfirmation": "(Hold shift to skip confirmation)", - "confirm": "Confirm removal", - "cancel": "Cancel removal" + "prefixCustomizationConfig": { + "header": { + "options": { + "name": "Options" + } + }, + "name": "Prefix customization", + "contentPlaceholder": "Message content", + "preview": { + "name": "Preview" }, - "sorting": { - "onlineStatus": "Online status", - "role": "LabyMod role", - "aToZ": "A-Z", - "zToA": "Z-A" + "enableManualPrefix": { + "name": "Enter prefix manually" + }, + "prefix": { + "name": "Prefix" + }, + "prefixColor": { + "name": "Prefix color" } }, + "temporaryPinsEnabled": { + "name": "Temporarily pin friends on chat message", + "description": "This will pin friends to the top of your friend list when they send you a text message. The friend will be unpinned as soon as you read the message or mark it as read. This will also work when receiving messages while offline." + }, "pinIconConfig": { - "name": "Friend pin icon", + "name": "Pinned friend badge", "pinIcon": { "name": "Nametag icon" }, @@ -212,7 +225,8 @@ "hover": "Click to join" }, "chats": { - "attachments": "[%s Attachments]", + "attachments": "%s Attachments", + "attachment": "%s Attachment", "read": "Mark chat as read", "reply": "Reply to %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 deleted file mode 100644 index 5eed99a..0000000 --- a/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/friend_list.lss +++ /dev/null @@ -1,96 +0,0 @@ -.container { - height: 100%; - width: 100%; - - .filter-settings { - width: 99%; - height: 20; - - 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; - } - - .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/prefix-preview.lss b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/prefix-preview.lss new file mode 100644 index 0000000..3559c78 --- /dev/null +++ b/core/src/main/resources/assets/betterfriends/themes/vanilla/lss/prefix-preview.lss @@ -0,0 +1,8 @@ +PrefixPreview { + height: fit-content; + width: 100%; + + Component { + margin: 3 0 5 1; + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 9243d49..6326517 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;1.21.5;1.21.8;1.21.10 \ 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.4;1.20.1;1.20.6;1.21;1.21.1;1.21.3;1.21.4;1.21.5;1.21.8;1.21.10;1.21.11 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e1adfb4..ac57dd1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle.kts b/settings.gradle.kts index 470ff09..6e38e19 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ rootProject.name = "betterfriends" pluginManagement { - val labyGradlePluginVersion = "0.5.7" + val labyGradlePluginVersion = "0.6.2" buildscript { repositories { maven("https://dist.labymod.net/api/v1/maven/release/")