diff --git a/acceptance/src/test/java/net/silthus/schat/cucumber/ChatterSteps.java b/acceptance/src/test/java/net/silthus/schat/cucumber/ChatterSteps.java index 9d891a58d..69a0c31b3 100644 --- a/acceptance/src/test/java/net/silthus/schat/cucumber/ChatterSteps.java +++ b/acceptance/src/test/java/net/silthus/schat/cucumber/ChatterSteps.java @@ -59,14 +59,14 @@ public void sendMessage(Chatter chatter) { @Then("{chatter} receives the message") public void receiveMessage(Chatter chatter) { - assertThat(chatter.lastMessage()).isPresent() - .get().extracting(Message::text) + assertThat(chatter.messages().last()).isNotNull() + .extracting(Message::text) .isEqualTo(context.lastMessageText()); } @Then("{chatter} does not receive a message") public void playerDoesNotReceiveAMessage(Chatter chatter) { - assertThat(chatter.lastMessage()).isEmpty(); + assertThat(chatter.messages().last()).isNull(); } @Then("{chatter} am/is a member of the {channel} channel") diff --git a/acceptance/src/test/java/net/silthus/schat/cucumber/UserSteps.java b/acceptance/src/test/java/net/silthus/schat/cucumber/UserSteps.java index f097005e0..5e32553ff 100644 --- a/acceptance/src/test/java/net/silthus/schat/cucumber/UserSteps.java +++ b/acceptance/src/test/java/net/silthus/schat/cucumber/UserSteps.java @@ -34,7 +34,7 @@ import net.silthus.schat.channel.Channel; import net.silthus.schat.cucumber.models.User; import net.silthus.schat.platform.sender.SenderMock; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; import static net.kyori.adventure.text.Component.text; import static net.silthus.schat.identity.Identity.identity; diff --git a/acceptance/src/test/java/net/silthus/schat/cucumber/models/User.java b/acceptance/src/test/java/net/silthus/schat/cucumber/models/User.java index 4fcd84ee4..0dffa2508 100644 --- a/acceptance/src/test/java/net/silthus/schat/cucumber/models/User.java +++ b/acceptance/src/test/java/net/silthus/schat/cucumber/models/User.java @@ -29,9 +29,8 @@ import lombok.experimental.Accessors; import net.silthus.schat.channel.Channel; import net.silthus.schat.chatter.Chatter; -import net.silthus.schat.message.Message; import net.silthus.schat.platform.sender.SenderMock; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; @Getter @Setter @@ -86,10 +85,6 @@ public View view() { return server().plugin().viewProvider().view(chatter()); } - public Message lastMessage() { - return chatter().lastMessage().orElse(null); - } - @Override public String toString() { return name + "@" + server(); diff --git a/bukkit/src/main/java/net/silthus/schat/bukkit/SChatBukkitServer.java b/bukkit/src/main/java/net/silthus/schat/bukkit/SChatBukkitServer.java index d118699f6..22fe5ff71 100644 --- a/bukkit/src/main/java/net/silthus/schat/bukkit/SChatBukkitServer.java +++ b/bukkit/src/main/java/net/silthus/schat/bukkit/SChatBukkitServer.java @@ -47,7 +47,7 @@ import net.silthus.schat.platform.messaging.GatewayProviderRegistry; import net.silthus.schat.platform.plugin.AbstractSChatServerPlugin; import net.silthus.schat.platform.sender.Sender; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewProvider; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; diff --git a/bukkit/src/main/java/net/silthus/schat/bukkit/adapter/BukkitChatterFactory.java b/bukkit/src/main/java/net/silthus/schat/bukkit/adapter/BukkitChatterFactory.java index 84fa5ec14..7f623bd64 100644 --- a/bukkit/src/main/java/net/silthus/schat/bukkit/adapter/BukkitChatterFactory.java +++ b/bukkit/src/main/java/net/silthus/schat/bukkit/adapter/BukkitChatterFactory.java @@ -29,9 +29,9 @@ import net.silthus.schat.chatter.Chatter; import net.silthus.schat.identity.Identity; import net.silthus.schat.platform.chatter.AbstractChatterFactory; +import net.silthus.schat.ui.DynamicViewConnector; import net.silthus.schat.ui.ViewConnector; -import net.silthus.schat.ui.view.DynamicViewConnector; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewProvider; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; diff --git a/bukkit/src/main/java/net/silthus/schat/bukkit/protocollib/ChatPacketListener.java b/bukkit/src/main/java/net/silthus/schat/bukkit/protocollib/ChatPacketListener.java index b2b0b5999..b3d5f8162 100644 --- a/bukkit/src/main/java/net/silthus/schat/bukkit/protocollib/ChatPacketListener.java +++ b/bukkit/src/main/java/net/silthus/schat/bukkit/protocollib/ChatPacketListener.java @@ -43,8 +43,8 @@ import net.silthus.schat.chatter.Chatter; import net.silthus.schat.chatter.ChatterRepository; import net.silthus.schat.message.Message; -import net.silthus.schat.ui.view.View; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.View; +import net.silthus.schat.ui.ViewProvider; import org.bukkit.plugin.Plugin; import static net.silthus.schat.message.Message.message; diff --git a/bukkit/src/test/java/net/silthus/schat/bukkit/adapter/PlayerChatListenerTest.java b/bukkit/src/test/java/net/silthus/schat/bukkit/adapter/PlayerChatListenerTest.java index 094c147eb..9be34bba4 100644 --- a/bukkit/src/test/java/net/silthus/schat/bukkit/adapter/PlayerChatListenerTest.java +++ b/bukkit/src/test/java/net/silthus/schat/bukkit/adapter/PlayerChatListenerTest.java @@ -24,6 +24,7 @@ package net.silthus.schat.bukkit.adapter; import be.seeseemelk.mockbukkit.entity.PlayerMock; +import java.util.Optional; import lombok.SneakyThrows; import net.kyori.adventure.text.Component; import net.silthus.schat.bukkit.BukkitTests; @@ -49,7 +50,7 @@ class PlayerChatListenerTest extends BukkitTests { @BeforeEach void setUp() { player = server.addPlayer(); - chatter = Chatter.chatter(identity(player)) + chatter = Chatter.chatterBuilder(identity(player)) .viewConnector(c -> () -> handleMessage(c)) .create(); PlayerChatListener listener = new PlayerChatListener(createInMemoryChatterRepository()); @@ -57,7 +58,9 @@ void setUp() { } private void handleMessage(Chatter chatter) { - lastMessage = chatter.lastMessage().map(Message::text).orElse(null); + lastMessage = Optional.ofNullable(chatter.messages().last()) + .map(Message::text) + .orElse(null); } private void chat() { diff --git a/core/src/main/java/net/silthus/schat/channel/ChannelPrototype.java b/core/src/main/java/net/silthus/schat/channel/ChannelPrototype.java index 9e5c098cf..7f71437d6 100644 --- a/core/src/main/java/net/silthus/schat/channel/ChannelPrototype.java +++ b/core/src/main/java/net/silthus/schat/channel/ChannelPrototype.java @@ -24,9 +24,25 @@ package net.silthus.schat.channel; import net.silthus.schat.eventbus.EventBus; +import org.jetbrains.annotations.ApiStatus; +/** + * Internal utility for configuring the prototype of channels. + * + * @since next + */ +@ApiStatus.Internal public final class ChannelPrototype { + /** + * Configures the prototype for creating new channels. + * + *

This is internal functionality and should not be used.

+ * + * @param eventBus the event bus to use + * @since next + */ + @ApiStatus.Internal public static void configure(EventBus eventBus) { ChannelImpl.prototype(builder -> builder.eventBus(eventBus)); } diff --git a/core/src/main/java/net/silthus/schat/chatter/Chatter.java b/core/src/main/java/net/silthus/schat/chatter/Chatter.java index f4f519d14..9bc40063d 100644 --- a/core/src/main/java/net/silthus/schat/chatter/Chatter.java +++ b/core/src/main/java/net/silthus/schat/chatter/Chatter.java @@ -25,19 +25,21 @@ import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.UUID; import lombok.NonNull; import net.kyori.adventure.text.Component; import net.silthus.schat.channel.Channel; +import net.silthus.schat.eventbus.EventBus; import net.silthus.schat.identity.Identified; import net.silthus.schat.identity.Identity; import net.silthus.schat.message.Message; import net.silthus.schat.message.MessageTarget; +import net.silthus.schat.message.Messages; import net.silthus.schat.pointer.Pointer; import net.silthus.schat.repository.Entity; import net.silthus.schat.ui.ViewConnector; import net.silthus.schat.util.Permissable; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; @@ -55,11 +57,25 @@ static Chatter empty() { return ChatterImpl.EMPTY; } - static Chatter createChatter(@NonNull Identity identity) { - return chatter(identity).create(); + /** + * Creates a new chatter for the given identity. + * + * @param identity the identity of the chatter + * @return the created chatter + * @since next + */ + static Chatter chatter(@NonNull Identity identity) { + return chatterBuilder(identity).create(); } - static Builder chatter(@NonNull Identity identity) { + /** + * Creates a new chatter builder that allows modifying details of the underlying chatter implementation. + * + * @param identity the identity of the chatter + * @return the builder + * @since next + */ + static Builder chatterBuilder(@NonNull Identity identity) { return ChatterImpl.builder(identity); } @@ -84,11 +100,9 @@ default boolean isActiveChannel(@Nullable Channel channel) { boolean isJoined(@Nullable Channel channel); - void leave(Channel channel); - - @NotNull @Unmodifiable Set messages(); + void leave(@NonNull Channel channel); - Optional lastMessage(); + @NotNull @Unmodifiable Messages messages(); void updateView(); @@ -101,10 +115,39 @@ default Message.Draft message(Component text) { } interface Builder { + /** + * Sets the event bus to use by this chatter. + * + *

This should be set for all chatters using the {@link ChatterPrototype}.

+ * + * @param eventBus the event bus + * @return this builder + * @since next + */ + @ApiStatus.Internal + @NotNull Builder eventBus(EventBus eventBus); + + @ApiStatus.Internal @NotNull Builder viewConnector(@NonNull ViewConnector.Factory viewConnectorFactory); + /** + * Sets the permission handler used by this chatter. + * + *

This should be done by the {@link ChatterFactory} of the implementing platform.

+ * + * @param permissionHandler the permission handler + * @return this builder + * @since next + */ + @ApiStatus.Internal @NotNull Builder permissionHandler(@NonNull PermissionHandler permissionHandler); + /** + * Creates the chatter. + * + * @return the newly created chatter + * @since next + */ @NotNull Chatter create(); } diff --git a/core/src/main/java/net/silthus/schat/chatter/ChatterImpl.java b/core/src/main/java/net/silthus/schat/chatter/ChatterImpl.java index aaec09c06..8614f55c8 100644 --- a/core/src/main/java/net/silthus/schat/chatter/ChatterImpl.java +++ b/core/src/main/java/net/silthus/schat/chatter/ChatterImpl.java @@ -24,11 +24,10 @@ package net.silthus.schat.chatter; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Optional; -import java.util.Queue; import java.util.Set; +import java.util.function.Function; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -37,8 +36,14 @@ import lombok.experimental.Accessors; import net.silthus.schat.channel.Channel; import net.silthus.schat.commands.SendMessageResult; +import net.silthus.schat.eventbus.EventBus; +import net.silthus.schat.events.chatter.ChatterChangedActiveChannelEvent; +import net.silthus.schat.events.chatter.ChatterJoinedChannelEvent; +import net.silthus.schat.events.chatter.ChatterLeftChannelEvent; +import net.silthus.schat.events.chatter.ChatterReceivedMessageEvent; import net.silthus.schat.identity.Identity; import net.silthus.schat.message.Message; +import net.silthus.schat.message.Messages; import net.silthus.schat.pointer.Pointers; import net.silthus.schat.ui.ViewConnector; import org.jetbrains.annotations.NotNull; @@ -56,23 +61,28 @@ non-sealed class ChatterImpl implements Chatter { static final Chatter EMPTY = new EmptyChatter(); + @Getter + @Setter + static Function prototype = builder -> builder; - static ChatterImpl.Builder builder(Identity identity) { - return new Builder(identity); + static Builder builder(Identity identity) { + return prototype().apply(new Builder(identity)); } private final Identity identity; - private final transient ViewConnector viewConnector; - private final transient PermissionHandler permissionHandler; - private final transient Pointers pointers; + private final transient @NonNull EventBus eventBus; + private final transient @NonNull ViewConnector viewConnector; + private final transient @NonNull PermissionHandler permissionHandler; + private final transient @NonNull Pointers pointers; private final Set channels = new HashSet<>(); - private final transient Queue messages = new LinkedList<>(); + private final transient Messages messages = new Messages(); private @Nullable Channel activeChannel; protected ChatterImpl(Builder builder) { this.identity = builder.identity(); + this.eventBus = builder.eventBus(); this.viewConnector = builder.viewConnector().create(this); this.permissionHandler = builder.permissionHandler(); this.pointers = Pointers.pointersBuilder() @@ -88,10 +98,16 @@ public void activeChannel(@Nullable Channel activeChannel) { if (isActiveChannel(activeChannel)) return; if (activeChannel != null) join(activeChannel); + Channel oldChannel = this.activeChannel; this.activeChannel = activeChannel; + fireChangedActiveChannelEvent(oldChannel, activeChannel); this.updateView(); } + private void fireChangedActiveChannelEvent(@Nullable Channel oldChannel, @Nullable Channel newChannel) { + eventBus().post(new ChatterChangedActiveChannelEvent(this, oldChannel, newChannel)); + } + @Override public @NotNull Optional activeChannel() { return Optional.ofNullable(activeChannel); @@ -110,8 +126,14 @@ public void activeChannel(@Nullable Channel activeChannel) { @Override public void join(@NonNull Channel channel) { channel.addTarget(this); - if (this.channels.add(channel)) + if (this.channels.add(channel)) { + fireJoinedChannelEvent(channel); updateView(); + } + } + + private void fireJoinedChannelEvent(@NotNull Channel channel) { + eventBus.post(new ChatterJoinedChannelEvent(this, channel)); } @Override @@ -121,34 +143,40 @@ public boolean isJoined(@Nullable Channel channel) { } @Override - public void leave(Channel channel) { + public void leave(@NonNull Channel channel) { channel.removeTarget(this); - this.channels.remove(channel); + if (this.channels.remove(channel)) + fireLeftChannelEvent(channel); if (channel.equals(activeChannel)) activeChannel = null; } - public boolean hasPermission(String permission) { - return permissionHandler.hasPermission(permission); + private void fireLeftChannelEvent(@NotNull Channel channel) { + eventBus().post(new ChatterLeftChannelEvent(this, channel)); } - @Override - public @NotNull @Unmodifiable Set messages() { - return Set.copyOf(messages); + public boolean hasPermission(String permission) { + return permissionHandler.hasPermission(permission); } @Override - public Optional lastMessage() { - return Optional.ofNullable(messages.peek()); + public @NotNull @Unmodifiable Messages messages() { + return Messages.unmodifiable(messages); } @Override public SendMessageResult sendMessage(@NonNull Message message) { - messages.add(message); - updateView(); + if (messages.add(message)) { + fireReceivedMessageEvent(message); + updateView(); + } return success(message); } + private void fireReceivedMessageEvent(@NotNull Message message) { + eventBus().post(new ChatterReceivedMessageEvent(this, message)); + } + @Override public void updateView() { viewConnector.update(); @@ -162,6 +190,7 @@ static final class Builder implements Chatter.Builder { private final Identity identity; private @NonNull ViewConnector.Factory viewConnector = chatter -> () -> {}; private @NonNull PermissionHandler permissionHandler = permission -> false; + private @NonNull EventBus eventBus = EventBus.empty(); private Builder(Identity identity) { this.identity = identity; @@ -211,18 +240,13 @@ public boolean isJoined(@Nullable Channel channel) { } @Override - public void leave(Channel channel) { + public void leave(@NonNull Channel channel) { } @Override - public @NotNull @Unmodifiable Set messages() { - return Set.of(); - } - - @Override - public Optional lastMessage() { - return Optional.empty(); + public @NotNull @Unmodifiable Messages messages() { + return Messages.of(); } @Override diff --git a/core/src/main/java/net/silthus/schat/chatter/ChatterPrototype.java b/core/src/main/java/net/silthus/schat/chatter/ChatterPrototype.java new file mode 100644 index 000000000..34a882d7c --- /dev/null +++ b/core/src/main/java/net/silthus/schat/chatter/ChatterPrototype.java @@ -0,0 +1,51 @@ +/* + * This file is part of sChat, licensed under the MIT License. + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.silthus.schat.chatter; + +import net.silthus.schat.eventbus.EventBus; +import org.jetbrains.annotations.ApiStatus; + +/** + * Internal utility for configuring the prototype of chatters. + * + * @since next + */ +@ApiStatus.Internal +public final class ChatterPrototype { + /** + * Configures the prototype for creating new chatters. + * + *

This is internal functionality and should not be used.

+ * + * @param eventBus the event bus to use + * @since next + */ + @ApiStatus.Internal + public static void configure(EventBus eventBus) { + ChatterImpl.prototype(builder -> builder.eventBus(eventBus)); + } + + private ChatterPrototype() { + } +} diff --git a/core/src/main/java/net/silthus/schat/commands/JoinChannelCommand.java b/core/src/main/java/net/silthus/schat/commands/JoinChannelCommand.java index 5d8c237c9..5870ff8cd 100644 --- a/core/src/main/java/net/silthus/schat/commands/JoinChannelCommand.java +++ b/core/src/main/java/net/silthus/schat/commands/JoinChannelCommand.java @@ -35,7 +35,6 @@ import net.silthus.schat.command.Result; import net.silthus.schat.eventbus.EventBus; import net.silthus.schat.events.channel.JoinChannelEvent; -import net.silthus.schat.events.channel.JoinedChannelEvent; import static net.silthus.schat.command.Result.error; import static net.silthus.schat.command.Result.success; @@ -82,7 +81,6 @@ private Result joinChannelAndUpdateView(Chatter chatter, Channel channel) { if (chatter.isJoined(channel)) return success(); chatter.join(channel); - eventBus.post(new JoinedChannelEvent(chatter, channel)); return success(); } diff --git a/core/src/main/java/net/silthus/schat/commands/LeaveChannelCommand.java b/core/src/main/java/net/silthus/schat/commands/LeaveChannelCommand.java index a5a20af33..35664b9a5 100644 --- a/core/src/main/java/net/silthus/schat/commands/LeaveChannelCommand.java +++ b/core/src/main/java/net/silthus/schat/commands/LeaveChannelCommand.java @@ -35,7 +35,7 @@ import net.silthus.schat.command.Result; import net.silthus.schat.eventbus.EventBus; import net.silthus.schat.events.channel.LeaveChannelEvent; -import net.silthus.schat.events.channel.LeftChannelEvent; +import net.silthus.schat.events.chatter.ChatterLeftChannelEvent; import static net.silthus.schat.command.Result.failure; import static net.silthus.schat.command.Result.success; @@ -86,7 +86,7 @@ private LeaveChannelEvent fireLeaveChannelEvent() { } private void fireLeftChannelEvent() { - eventBus.post(new LeftChannelEvent(chatter, channel)); + eventBus.post(new ChatterLeftChannelEvent(chatter, channel)); } @Getter diff --git a/core/src/main/java/net/silthus/schat/events/chatter/ChatterChangedActiveChannelEvent.java b/core/src/main/java/net/silthus/schat/events/chatter/ChatterChangedActiveChannelEvent.java new file mode 100644 index 000000000..933366d66 --- /dev/null +++ b/core/src/main/java/net/silthus/schat/events/chatter/ChatterChangedActiveChannelEvent.java @@ -0,0 +1,42 @@ +/* + * This file is part of sChat, licensed under the MIT License. + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.silthus.schat.events.chatter; + +import lombok.NonNull; +import net.silthus.schat.channel.Channel; +import net.silthus.schat.chatter.Chatter; +import net.silthus.schat.events.SChatEvent; +import org.jetbrains.annotations.Nullable; + +/** + * This event is fired after a chatter changed his active channel. + * + * @since next + */ +public record ChatterChangedActiveChannelEvent( + @NonNull Chatter chatter, + @Nullable Channel oldChannel, + @Nullable Channel newChannel +) implements SChatEvent { +} diff --git a/core/src/main/java/net/silthus/schat/events/channel/JoinedChannelEvent.java b/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedChannelEvent.java similarity index 83% rename from core/src/main/java/net/silthus/schat/events/channel/JoinedChannelEvent.java rename to core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedChannelEvent.java index 91c52dc76..9b9a295aa 100644 --- a/core/src/main/java/net/silthus/schat/events/channel/JoinedChannelEvent.java +++ b/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedChannelEvent.java @@ -21,18 +21,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.events.channel; +package net.silthus.schat.events.chatter; import net.silthus.schat.channel.Channel; import net.silthus.schat.chatter.Chatter; import net.silthus.schat.events.SChatEvent; +import net.silthus.schat.events.channel.JoinChannelEvent; /** * The event is fired after a chatter has joined a channel. * *

Not to be mistaken by {@link JoinChannelEvent} which is fired before a chatter joins the channel.

* - *

The event will not fire on subsequent joins to a channel the chatter is already a member of.

+ *

The event will not fire on subsequent joins to a channel if chatter is already a member.

+ * + * @since next */ -public record JoinedChannelEvent(Chatter chatter, Channel channel) implements SChatEvent { +public record ChatterJoinedChannelEvent(Chatter chatter, Channel channel) implements SChatEvent { } diff --git a/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedServerEvent.java b/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedServerEvent.java index 1a2bb5707..fdf59ad46 100644 --- a/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedServerEvent.java +++ b/core/src/main/java/net/silthus/schat/events/chatter/ChatterJoinedServerEvent.java @@ -28,6 +28,8 @@ /** * The {@code ChatterJoinedServerEvent} is fired when a chatter has joined the server. + * + * @since next */ public record ChatterJoinedServerEvent(Chatter chatter) implements SChatEvent { } diff --git a/core/src/main/java/net/silthus/schat/events/channel/LeftChannelEvent.java b/core/src/main/java/net/silthus/schat/events/chatter/ChatterLeftChannelEvent.java similarity index 88% rename from core/src/main/java/net/silthus/schat/events/channel/LeftChannelEvent.java rename to core/src/main/java/net/silthus/schat/events/chatter/ChatterLeftChannelEvent.java index 0e97e32ca..92423431c 100644 --- a/core/src/main/java/net/silthus/schat/events/channel/LeftChannelEvent.java +++ b/core/src/main/java/net/silthus/schat/events/chatter/ChatterLeftChannelEvent.java @@ -21,17 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.events.channel; +package net.silthus.schat.events.chatter; import net.silthus.schat.channel.Channel; import net.silthus.schat.chatter.Chatter; import net.silthus.schat.commands.LeaveChannelCommand; import net.silthus.schat.events.SChatEvent; +import net.silthus.schat.events.channel.LeaveChannelEvent; /** * The event is fired after a chatter has left a channel. * *

The event will not fire if {@link LeaveChannelCommand#leaveChannel(Chatter, Channel)} fails or {@link LeaveChannelEvent} is cancelled.

+ * + * @since next */ -public record LeftChannelEvent(Chatter chatter, Channel channel) implements SChatEvent { +public record ChatterLeftChannelEvent(Chatter chatter, Channel channel) implements SChatEvent { } diff --git a/ui/src/main/java/net/silthus/schat/ui/Click.java b/core/src/main/java/net/silthus/schat/events/chatter/ChatterReceivedMessageEvent.java similarity index 74% rename from ui/src/main/java/net/silthus/schat/ui/Click.java rename to core/src/main/java/net/silthus/schat/events/chatter/ChatterReceivedMessageEvent.java index 960e332a9..e84ae9d99 100644 --- a/ui/src/main/java/net/silthus/schat/ui/Click.java +++ b/core/src/main/java/net/silthus/schat/events/chatter/ChatterReceivedMessageEvent.java @@ -21,15 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui; +package net.silthus.schat.events.chatter; -import net.kyori.adventure.text.event.ClickEvent; +import net.silthus.schat.chatter.Chatter; +import net.silthus.schat.events.SChatEvent; +import net.silthus.schat.message.Message; -@FunctionalInterface -public interface Click { - - ClickEvent onClick(T type); - - interface Channel extends Click { - } +/** + * The event is fired after a chatter received and accepted a new message. + * + *

The event will not fire multiple times for the same message.

+ * + * @since next + */ +public record ChatterReceivedMessageEvent(Chatter chatter, Message message) implements SChatEvent { } diff --git a/core/src/test/java/net/silthus/schat/chatter/ChatterTest.java b/core/src/test/java/net/silthus/schat/chatter/ChatterTest.java index 62458b1f5..9a1541521 100644 --- a/core/src/test/java/net/silthus/schat/chatter/ChatterTest.java +++ b/core/src/test/java/net/silthus/schat/chatter/ChatterTest.java @@ -24,6 +24,11 @@ package net.silthus.schat.chatter; import net.silthus.schat.channel.Channel; +import net.silthus.schat.eventbus.EventBusMock; +import net.silthus.schat.events.chatter.ChatterChangedActiveChannelEvent; +import net.silthus.schat.events.chatter.ChatterJoinedChannelEvent; +import net.silthus.schat.events.chatter.ChatterLeftChannelEvent; +import net.silthus.schat.events.chatter.ChatterReceivedMessageEvent; import net.silthus.schat.identity.Identity; import net.silthus.schat.message.Message; import net.silthus.schat.ui.ViewConnectorMock; @@ -33,26 +38,29 @@ import static net.silthus.schat.AssertionHelper.assertNPE; import static net.silthus.schat.channel.ChannelHelper.randomChannel; -import static net.silthus.schat.chatter.Chatter.chatter; +import static net.silthus.schat.eventbus.EventBusMock.eventBusMock; import static net.silthus.schat.identity.IdentityHelper.randomIdentity; import static net.silthus.schat.message.MessageHelper.randomMessage; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; class ChatterTest { - private Chatter chatter; + private ChatterMock chatter; private Identity identity; + private EventBusMock eventBus; @BeforeEach void setUp() { identity = randomIdentity(); - chatter = Chatter.createChatter(identity); + eventBus = eventBusMock(); + ChatterPrototype.configure(eventBus); + chatter = ChatterMock.chatterMock(identity); } @Test @SuppressWarnings("ConstantConditions") void given_null_identity_then_create_throws() { - assertNPE(() -> Chatter.createChatter(null)); + assertNPE(() -> Chatter.chatter(null)); } @Test @@ -112,6 +120,20 @@ void sets_active_channel() { .isPresent().get().isEqualTo(channel); } + @Test + void fires_ActiveChannelChangedEvent() { + setActiveChannel(channel); + eventBus.assertEventFired(new ChatterChangedActiveChannelEvent(chatter, null, channel)); + } + + @Test + void given_channel_is_active_when_it_is_set_active_then_ActiveChannelChangedEvent_is_not_fired() { + setActiveChannel(channel); + eventBus.reset(); + setActiveChannel(channel); + eventBus.assertNoEventFired(ChatterChangedActiveChannelEvent.class); + } + @Test void leave_clears_active_channel() { setActiveChannel(channel); @@ -128,7 +150,7 @@ void joins_channel() { } } - @Nested class when_channel_set_as_active_channel { + @Nested class when_channel_is_active_channel { @BeforeEach void setUp() { setActiveChannel(channel); @@ -174,6 +196,41 @@ void then_isJoined_returns_true() { joinChannel(); assertThat(chatter.isJoined(channel)).isTrue(); } + + @Test + void fires_JoinedChannelEvent() { + joinChannel(); + eventBus.assertEventFired(new ChatterJoinedChannelEvent(chatter, channel)); + } + } + + @Nested class leave { + @Test + void chatter_is_not_joined_then_left_event_is_not_fired() { + chatter.leave(channel); + eventBus.assertNoEventFired(ChatterLeftChannelEvent.class); + } + + @Test + void chatter_has_joined_channel_then_left_event_is_fired() { + chatter.join(channel); + chatter.leave(channel); + eventBus.assertEventFired(new ChatterLeftChannelEvent(chatter, channel)); + } + + @Test + void removes_chatter_from_channel_targets() { + channel.addTarget(chatter); + chatter.leave(channel); + assertThat(channel.targets()).doesNotContain(chatter); + } + + @Test + void removes_channel_from_chatter_channels() { + chatter.join(channel); + chatter.leave(channel); + chatter.assertNotJoinedChannel(channel); + } } @Test @@ -209,13 +266,19 @@ void then_message_is_added() { assertThat(chatter.messages()).contains(message); } + @Test + void ReceivedMessage_event_is_fired() { + final Message message = randomMessage(); + chatter.sendMessage(message); + eventBus.assertEventFired(new ChatterReceivedMessageEvent(chatter, message)); + } + @Nested class given_valid_view_connector { private final ViewConnectorMock view = new ViewConnectorMock(); @BeforeEach void setUp() { - chatter = chatter(randomIdentity()) - .viewConnector(c -> view).create(); + chatter = ChatterMock.chatterMock(identity, builder -> builder.viewConnector(c -> view)); } private void assertViewUpdated() { @@ -227,7 +290,7 @@ private void assertViewNotUpdated() { } private void assertLastMessageIs(Message message) { - assertThat(chatter.lastMessage()).isPresent().get().isEqualTo(message); + assertThat(chatter.messages().last()).isEqualTo(message); } @Test @@ -268,7 +331,7 @@ void when_channel_is_already_joined_then_view_is_not_updated() { void given_no_messages_when_update_is_called_then_context_has_no_last_message() { chatter.updateView(); assertViewUpdated(); - assertThat(chatter.lastMessage()).isNotPresent(); + assertThat(chatter.messages().last()).isNull(); } @Test @@ -296,11 +359,12 @@ void given_no_permission_handler_does_not_throw() { @Nested class given_permission_handler { + private Chatter chatter; private boolean permissionHandlerCalled = false; @BeforeEach void setUp() { - chatter = chatter(randomIdentity()).permissionHandler(permission -> { + chatter = Chatter.chatterBuilder(randomIdentity()).permissionHandler(permission -> { permissionHandlerCalled = true; return false; }).create(); diff --git a/core/src/test/java/net/silthus/schat/commands/JoinChannelCommandTests.java b/core/src/test/java/net/silthus/schat/commands/JoinChannelCommandTests.java index 0289ae46d..be74e1269 100644 --- a/core/src/test/java/net/silthus/schat/commands/JoinChannelCommandTests.java +++ b/core/src/test/java/net/silthus/schat/commands/JoinChannelCommandTests.java @@ -25,10 +25,11 @@ import net.silthus.schat.channel.Channel; import net.silthus.schat.chatter.ChatterMock; +import net.silthus.schat.chatter.ChatterPrototype; import net.silthus.schat.command.Result; import net.silthus.schat.eventbus.EventBusMock; import net.silthus.schat.events.channel.JoinChannelEvent; -import net.silthus.schat.events.channel.JoinedChannelEvent; +import net.silthus.schat.events.chatter.ChatterJoinedChannelEvent; import net.silthus.schat.policies.JoinChannelPolicy; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -55,9 +56,11 @@ class JoinChannelCommandTests { @BeforeEach void setUp() { eventBus = EventBusMock.eventBusMock(); + JoinChannelCommand.prototype(builder -> builder.eventBus(eventBus)); + ChatterPrototype.configure(eventBus); + chatter = randomChatter(); channel = channelWith(builder -> builder.policy(JoinChannelPolicy.class, ALLOW)); - JoinChannelCommand.prototype(builder -> builder.eventBus(eventBus)); } private void assertJoinChannelError() { @@ -109,7 +112,7 @@ void then_view_is_updated() { @Test void then_the_post_join_channel_event_is_fired() { joinChannel(); - eventBus.assertEventFired(new JoinedChannelEvent(chatter, channel)); + eventBus.assertEventFired(new ChatterJoinedChannelEvent(chatter, channel)); } @Nested class given_already_joined { @@ -148,7 +151,7 @@ void then_throws_access_defined_exception() { @Test void then_no_post_join_channel_event_is_fired() { assertJoinChannelError(); - eventBus.assertNoEventFired(new JoinedChannelEvent(chatter, channel)); + eventBus.assertNoEventFired(new ChatterJoinedChannelEvent(chatter, channel)); } @Nested class given_already_joined { diff --git a/core/src/test/java/net/silthus/schat/commands/LeaveChannelCommandTest.java b/core/src/test/java/net/silthus/schat/commands/LeaveChannelCommandTest.java index 862dce69e..9023a73f5 100644 --- a/core/src/test/java/net/silthus/schat/commands/LeaveChannelCommandTest.java +++ b/core/src/test/java/net/silthus/schat/commands/LeaveChannelCommandTest.java @@ -28,7 +28,7 @@ import net.silthus.schat.command.Result; import net.silthus.schat.eventbus.EventBusMock; import net.silthus.schat.events.channel.LeaveChannelEvent; -import net.silthus.schat.events.channel.LeftChannelEvent; +import net.silthus.schat.events.chatter.ChatterLeftChannelEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -106,6 +106,6 @@ void cancelled_event_then_leave_channel_command_fails() { @Test void left_channel_event_is_fired() { assertCanLeaveChannel(); - eventBus.assertEventFired(new LeftChannelEvent(chatter, channel)); + eventBus.assertEventFired(new ChatterLeftChannelEvent(chatter, channel)); } } diff --git a/core/src/testFixtures/java/net/silthus/schat/chatter/ChatterMock.java b/core/src/testFixtures/java/net/silthus/schat/chatter/ChatterMock.java index 9c1205526..41d2f65bc 100644 --- a/core/src/testFixtures/java/net/silthus/schat/chatter/ChatterMock.java +++ b/core/src/testFixtures/java/net/silthus/schat/chatter/ChatterMock.java @@ -49,11 +49,15 @@ public static Chatter randomChatter(UUID id) { } public static @NotNull ChatterMock chatterMock(Identity identity) { - return new ChatterMock((Builder) Chatter.chatter(identity)); + return new ChatterMock((Builder) Chatter.chatterBuilder(identity)); } public static @NotNull ChatterMock chatterMock(Consumer builder) { - final Chatter.Builder chatter = Chatter.chatter(randomIdentity()); + return chatterMock(randomIdentity(), builder); + } + + public static @NotNull ChatterMock chatterMock(Identity identity, Consumer builder) { + final Chatter.Builder chatter = Chatter.chatterBuilder(identity); builder.accept(chatter); return new ChatterMock((Builder) chatter); } diff --git a/core/src/testFixtures/java/net/silthus/schat/eventbus/EventBusMock.java b/core/src/testFixtures/java/net/silthus/schat/eventbus/EventBusMock.java index 795bff67f..17c0c76aa 100644 --- a/core/src/testFixtures/java/net/silthus/schat/eventbus/EventBusMock.java +++ b/core/src/testFixtures/java/net/silthus/schat/eventbus/EventBusMock.java @@ -58,4 +58,12 @@ public void assertEventFired(E event) { public void assertNoEventFired(E event) { assertThat(events).doesNotContain(event); } + + public void assertNoEventFired(Class type) { + assertThat(events).doesNotHaveAnyElementsOfTypes(type); + } + + public void reset() { + events.clear(); + } } diff --git a/platform/src/main/java/net/silthus/schat/platform/chatter/AbstractChatterFactory.java b/platform/src/main/java/net/silthus/schat/platform/chatter/AbstractChatterFactory.java index f3d6ca9ce..387dbded5 100644 --- a/platform/src/main/java/net/silthus/schat/platform/chatter/AbstractChatterFactory.java +++ b/platform/src/main/java/net/silthus/schat/platform/chatter/AbstractChatterFactory.java @@ -28,10 +28,10 @@ import net.silthus.schat.chatter.ChatterFactory; import net.silthus.schat.identity.Identity; import net.silthus.schat.ui.ViewConnector; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewProvider; import org.jetbrains.annotations.NotNull; -import static net.silthus.schat.chatter.Chatter.chatter; +import static net.silthus.schat.chatter.Chatter.chatterBuilder; public abstract class AbstractChatterFactory implements ChatterFactory { protected final ViewProvider viewProvider; @@ -42,7 +42,7 @@ public AbstractChatterFactory(ViewProvider viewProvider) { @Override public final Chatter createChatter(UUID id) { - return chatter(createIdentity(id)) + return chatterBuilder(createIdentity(id)) .viewConnector(createViewConnector(id)) .permissionHandler(createPermissionHandler(id)) .create(); diff --git a/platform/src/main/java/net/silthus/schat/platform/plugin/AbstractSChatServerPlugin.java b/platform/src/main/java/net/silthus/schat/platform/plugin/AbstractSChatServerPlugin.java index e50c32258..c6267b23d 100644 --- a/platform/src/main/java/net/silthus/schat/platform/plugin/AbstractSChatServerPlugin.java +++ b/platform/src/main/java/net/silthus/schat/platform/plugin/AbstractSChatServerPlugin.java @@ -31,6 +31,7 @@ import net.silthus.schat.channel.ChannelPrototype; import net.silthus.schat.channel.ChannelRepository; import net.silthus.schat.chatter.ChatterFactory; +import net.silthus.schat.chatter.ChatterPrototype; import net.silthus.schat.chatter.ChatterRepository; import net.silthus.schat.commands.CreatePrivateChannelCommand; import net.silthus.schat.commands.JoinChannelCommand; @@ -51,6 +52,8 @@ import net.silthus.schat.ui.view.ViewController; import net.silthus.schat.ui.view.ViewFactory; import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewFactory; +import net.silthus.schat.ui.ViewProvider; import net.silthus.schat.ui.views.Views; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -60,6 +63,7 @@ import static net.silthus.schat.platform.commands.parser.ChannelArgument.registerChannelArgument; import static net.silthus.schat.platform.commands.parser.ChatterArgument.registerChatterArgument; import static net.silthus.schat.platform.config.ConfigKeys.DEBUG; +import static net.silthus.schat.ui.ViewProvider.cachingViewProvider; import static net.silthus.schat.platform.config.ConfigKeys.VIEW_CONFIG; import static net.silthus.schat.ui.view.ViewProvider.cachingViewProvider; import static net.silthus.schat.util.gson.types.ChannelSerializer.CHANNEL_TYPE; @@ -162,7 +166,9 @@ private void setupPrototypes() { LeaveChannelCommand.prototype(builder -> builder .eventBus(eventBus()) ); + ChannelPrototype.configure(eventBus()); + ChatterPrototype.configure(eventBus()); } private void loadFeatures() { diff --git a/platform/src/test/java/net/silthus/schat/platform/config/ConfigTests.java b/platform/src/test/java/net/silthus/schat/platform/config/ConfigTests.java index c3e5fae5b..3a2c73444 100644 --- a/platform/src/test/java/net/silthus/schat/platform/config/ConfigTests.java +++ b/platform/src/test/java/net/silthus/schat/platform/config/ConfigTests.java @@ -30,7 +30,7 @@ import net.silthus.schat.channel.Channel; import net.silthus.schat.identity.Identity; import net.silthus.schat.platform.config.adapter.ConfigurationAdapter; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; diff --git a/platform/src/testFixtures/java/net/silthus/schat/platform/chatter/ChatterFactoryStub.java b/platform/src/testFixtures/java/net/silthus/schat/platform/chatter/ChatterFactoryStub.java index 4749345cc..8e3a481b4 100644 --- a/platform/src/testFixtures/java/net/silthus/schat/platform/chatter/ChatterFactoryStub.java +++ b/platform/src/testFixtures/java/net/silthus/schat/platform/chatter/ChatterFactoryStub.java @@ -30,11 +30,11 @@ import net.silthus.schat.identity.Identity; import net.silthus.schat.platform.sender.SenderMock; import net.silthus.schat.ui.ViewConnector; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewProvider; import org.jetbrains.annotations.NotNull; -import static net.silthus.schat.ui.view.ViewFactory.empty; -import static net.silthus.schat.ui.view.ViewProvider.cachingViewProvider; +import static net.silthus.schat.ui.ViewFactory.empty; +import static net.silthus.schat.ui.ViewProvider.cachingViewProvider; import static net.silthus.schat.util.StringUtil.randomString; public class ChatterFactoryStub extends AbstractChatterFactory { diff --git a/platform/src/testFixtures/java/net/silthus/schat/platform/plugin/TestServer.java b/platform/src/testFixtures/java/net/silthus/schat/platform/plugin/TestServer.java index 7e78742c8..775fc93fb 100644 --- a/platform/src/testFixtures/java/net/silthus/schat/platform/plugin/TestServer.java +++ b/platform/src/testFixtures/java/net/silthus/schat/platform/plugin/TestServer.java @@ -41,7 +41,7 @@ import net.silthus.schat.platform.messaging.MockMessagingGatewayProvider; import net.silthus.schat.platform.sender.Sender; import net.silthus.schat.platform.sender.SenderMock; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.ViewProvider; import static net.silthus.schat.platform.commands.CommandTestUtils.createCommandManager; import static net.silthus.schat.platform.config.TestConfigurationAdapter.testConfigAdapter; diff --git a/ui/src/main/java/net/silthus/schat/ui/view/CachingViewProvider.java b/ui/src/main/java/net/silthus/schat/ui/CachingViewProvider.java similarity index 98% rename from ui/src/main/java/net/silthus/schat/ui/view/CachingViewProvider.java rename to ui/src/main/java/net/silthus/schat/ui/CachingViewProvider.java index 82f4cb237..570cbcf33 100644 --- a/ui/src/main/java/net/silthus/schat/ui/view/CachingViewProvider.java +++ b/ui/src/main/java/net/silthus/schat/ui/CachingViewProvider.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import java.util.Map; import java.util.WeakHashMap; diff --git a/ui/src/main/java/net/silthus/schat/ui/view/DynamicViewConnector.java b/ui/src/main/java/net/silthus/schat/ui/DynamicViewConnector.java similarity index 95% rename from ui/src/main/java/net/silthus/schat/ui/view/DynamicViewConnector.java rename to ui/src/main/java/net/silthus/schat/ui/DynamicViewConnector.java index 2678b8d18..fb1873540 100644 --- a/ui/src/main/java/net/silthus/schat/ui/view/DynamicViewConnector.java +++ b/ui/src/main/java/net/silthus/schat/ui/DynamicViewConnector.java @@ -21,10 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import net.silthus.schat.chatter.Chatter; -import net.silthus.schat.ui.ViewConnector; public record DynamicViewConnector(Chatter chatter, ViewProvider viewProvider, diff --git a/ui/src/main/java/net/silthus/schat/ui/view/EmptyView.java b/ui/src/main/java/net/silthus/schat/ui/EmptyView.java similarity index 100% rename from ui/src/main/java/net/silthus/schat/ui/view/EmptyView.java rename to ui/src/main/java/net/silthus/schat/ui/EmptyView.java diff --git a/ui/src/main/java/net/silthus/schat/ui/view/View.java b/ui/src/main/java/net/silthus/schat/ui/View.java similarity index 98% rename from ui/src/main/java/net/silthus/schat/ui/view/View.java rename to ui/src/main/java/net/silthus/schat/ui/View.java index c6a850295..d3a60b912 100644 --- a/ui/src/main/java/net/silthus/schat/ui/view/View.java +++ b/ui/src/main/java/net/silthus/schat/ui/View.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; diff --git a/ui/src/main/java/net/silthus/schat/ui/view/ViewConfig.java b/ui/src/main/java/net/silthus/schat/ui/ViewConfig.java similarity index 100% rename from ui/src/main/java/net/silthus/schat/ui/view/ViewConfig.java rename to ui/src/main/java/net/silthus/schat/ui/ViewConfig.java diff --git a/ui/src/main/java/net/silthus/schat/ui/view/ViewController.java b/ui/src/main/java/net/silthus/schat/ui/ViewController.java similarity index 100% rename from ui/src/main/java/net/silthus/schat/ui/view/ViewController.java rename to ui/src/main/java/net/silthus/schat/ui/ViewController.java diff --git a/ui/src/main/java/net/silthus/schat/ui/view/ViewFactory.java b/ui/src/main/java/net/silthus/schat/ui/ViewFactory.java similarity index 97% rename from ui/src/main/java/net/silthus/schat/ui/view/ViewFactory.java rename to ui/src/main/java/net/silthus/schat/ui/ViewFactory.java index 0a8ed29de..23810f884 100644 --- a/ui/src/main/java/net/silthus/schat/ui/view/ViewFactory.java +++ b/ui/src/main/java/net/silthus/schat/ui/ViewFactory.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import net.silthus.schat.chatter.Chatter; diff --git a/ui/src/main/java/net/silthus/schat/ui/view/ViewProvider.java b/ui/src/main/java/net/silthus/schat/ui/ViewProvider.java similarity index 97% rename from ui/src/main/java/net/silthus/schat/ui/view/ViewProvider.java rename to ui/src/main/java/net/silthus/schat/ui/ViewProvider.java index fc0bb9b89..b3772a34c 100644 --- a/ui/src/main/java/net/silthus/schat/ui/view/ViewProvider.java +++ b/ui/src/main/java/net/silthus/schat/ui/ViewProvider.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import lombok.NonNull; import net.silthus.schat.chatter.Chatter; diff --git a/ui/src/main/java/net/silthus/schat/ui/format/Format.java b/ui/src/main/java/net/silthus/schat/ui/format/Format.java index 345f13cce..1435c5639 100644 --- a/ui/src/main/java/net/silthus/schat/ui/format/Format.java +++ b/ui/src/main/java/net/silthus/schat/ui/format/Format.java @@ -31,7 +31,7 @@ import net.silthus.schat.message.Message; import net.silthus.schat.pointer.Pointered; import net.silthus.schat.pointer.Setting; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; diff --git a/ui/src/main/java/net/silthus/schat/ui/format/MiniMessageFormat.java b/ui/src/main/java/net/silthus/schat/ui/format/MiniMessageFormat.java index 009359f1a..56ae04996 100644 --- a/ui/src/main/java/net/silthus/schat/ui/format/MiniMessageFormat.java +++ b/ui/src/main/java/net/silthus/schat/ui/format/MiniMessageFormat.java @@ -32,7 +32,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.silthus.schat.pointer.Pointer; import net.silthus.schat.pointer.Pointered; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; import org.jetbrains.annotations.NotNull; @Getter diff --git a/ui/src/main/java/net/silthus/schat/ui/views/Views.java b/ui/src/main/java/net/silthus/schat/ui/views/Views.java index 420606c14..b268fc37c 100644 --- a/ui/src/main/java/net/silthus/schat/ui/views/Views.java +++ b/ui/src/main/java/net/silthus/schat/ui/views/Views.java @@ -25,8 +25,8 @@ import lombok.NonNull; import net.silthus.schat.chatter.Chatter; -import net.silthus.schat.ui.view.View; -import net.silthus.schat.ui.view.ViewConfig; +import net.silthus.schat.ui.View; +import net.silthus.schat.ui.ViewConfig; import net.silthus.schat.ui.views.tabbed.TabbedChannelsView; public final class Views { diff --git a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/AbstractTab.java b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/AbstractTab.java index 5bbc1e62a..96a41c82d 100644 --- a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/AbstractTab.java +++ b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/AbstractTab.java @@ -30,6 +30,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.silthus.schat.message.Message; +import net.silthus.schat.ui.View; import net.silthus.schat.ui.format.Format; import org.jetbrains.annotations.NotNull; @@ -61,12 +62,12 @@ public Component renderContent() { protected List renderMessages() { return messages().stream() - .map(this::formatMessage) + .map(this::renderMessage) .toList(); } - private Component formatMessage(Message message) { - return message.getOrDefault(FORMATTED, messageFormat().format(view, message)); + protected Component renderMessage(Message message) { + return messageFormat().format(view, message); } protected @NotNull Collection messages() { diff --git a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChannelTab.java b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChannelTab.java index f71d10239..76a61973d 100644 --- a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChannelTab.java +++ b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChannelTab.java @@ -30,7 +30,6 @@ import net.silthus.schat.channel.Channel; import net.silthus.schat.message.Message; import net.silthus.schat.ui.format.Format; -import net.silthus.schat.ui.model.ChatterViewModel; import static net.kyori.adventure.text.Component.empty; import static net.kyori.adventure.text.Component.translatable; @@ -46,7 +45,7 @@ @Accessors(fluent = true) public class ChannelTab extends AbstractTab { - private static final Component CLOSE_CHAR = Component.text("\u274C", RED); + private static final Component CLOSE_CHAR = Component.text("\u274C", RED); // ❌ private final Channel channel; diff --git a/ui/src/main/java/net/silthus/schat/ui/model/ChatterViewModel.java b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChatterViewModel.java similarity index 99% rename from ui/src/main/java/net/silthus/schat/ui/model/ChatterViewModel.java rename to ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChatterViewModel.java index c8b9b35f6..9278f6393 100644 --- a/ui/src/main/java/net/silthus/schat/ui/model/ChatterViewModel.java +++ b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/ChatterViewModel.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.model; +package net.silthus.schat.ui.views.tabbed; import java.util.Collection; import java.util.Comparator; diff --git a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsView.java b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsView.java index 52ddc4030..090e323fc 100644 --- a/ui/src/main/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsView.java +++ b/ui/src/main/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsView.java @@ -32,10 +32,11 @@ import net.silthus.schat.chatter.Chatter; import net.silthus.schat.pointer.Setting; import net.silthus.schat.pointer.Settings; +import net.silthus.schat.ui.View; import net.silthus.schat.ui.format.Format; import net.silthus.schat.ui.model.ChatterViewModel; -import net.silthus.schat.ui.view.View; -import net.silthus.schat.ui.view.ViewConfig; +import net.silthus.schat.ui.View; +import net.silthus.schat.ui.ViewConfig; import org.jetbrains.annotations.NotNull; import static java.util.stream.Collectors.toList; diff --git a/ui/src/test/java/net/silthus/schat/ui/view/CachingViewProviderTests.java b/ui/src/test/java/net/silthus/schat/ui/CachingViewProviderTests.java similarity index 95% rename from ui/src/test/java/net/silthus/schat/ui/view/CachingViewProviderTests.java rename to ui/src/test/java/net/silthus/schat/ui/CachingViewProviderTests.java index ba93e4fd2..a8350c259 100644 --- a/ui/src/test/java/net/silthus/schat/ui/view/CachingViewProviderTests.java +++ b/ui/src/test/java/net/silthus/schat/ui/CachingViewProviderTests.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.view; +package net.silthus.schat.ui; import net.silthus.schat.chatter.ChatterMock; import org.junit.jupiter.api.BeforeEach; @@ -30,7 +30,7 @@ import static net.silthus.schat.AssertionHelper.assertNPE; import static net.silthus.schat.chatter.ChatterMock.randomChatter; -import static net.silthus.schat.ui.view.ViewProvider.cachingViewProvider; +import static net.silthus.schat.ui.ViewProvider.cachingViewProvider; import static org.assertj.core.api.Assertions.assertThat; class CachingViewProviderTests { diff --git a/ui/src/test/java/net/silthus/schat/ui/DynamicViewConnectorTest.java b/ui/src/test/java/net/silthus/schat/ui/DynamicViewConnectorTest.java new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/test/java/net/silthus/schat/ui/view/ViewControllerTest.java b/ui/src/test/java/net/silthus/schat/ui/ViewControllerTest.java similarity index 100% rename from ui/src/test/java/net/silthus/schat/ui/view/ViewControllerTest.java rename to ui/src/test/java/net/silthus/schat/ui/ViewControllerTest.java diff --git a/ui/src/test/java/net/silthus/schat/ui/format/MiniMessageFormatTest.java b/ui/src/test/java/net/silthus/schat/ui/format/MiniMessageFormatTest.java index b7acd3355..3e320ab3f 100644 --- a/ui/src/test/java/net/silthus/schat/ui/format/MiniMessageFormatTest.java +++ b/ui/src/test/java/net/silthus/schat/ui/format/MiniMessageFormatTest.java @@ -27,7 +27,8 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import net.silthus.schat.chatter.ChatterMock; import net.silthus.schat.message.Message; -import net.silthus.schat.ui.view.View; +import net.silthus.schat.ui.View; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static net.kyori.adventure.text.Component.text; diff --git a/ui/src/test/java/net/silthus/schat/ui/model/ChatterViewModelTests.java b/ui/src/test/java/net/silthus/schat/ui/views/tabbed/ChatterViewModelTests.java similarity index 97% rename from ui/src/test/java/net/silthus/schat/ui/model/ChatterViewModelTests.java rename to ui/src/test/java/net/silthus/schat/ui/views/tabbed/ChatterViewModelTests.java index 1fac3740d..5caa8ae08 100644 --- a/ui/src/test/java/net/silthus/schat/ui/model/ChatterViewModelTests.java +++ b/ui/src/test/java/net/silthus/schat/ui/views/tabbed/ChatterViewModelTests.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.model; +package net.silthus.schat.ui.views.tabbed; import lombok.SneakyThrows; import net.silthus.schat.channel.Channel; @@ -37,7 +37,7 @@ import static net.silthus.schat.channel.ChannelHelper.randomChannel; import static net.silthus.schat.channel.ChannelSettings.PRIORITY; import static net.silthus.schat.chatter.ChatterMock.randomChatter; -import static net.silthus.schat.ui.model.ChatterViewModel.of; +import static net.silthus.schat.ui.views.tabbed.ChatterViewModel.of; import static org.assertj.core.api.Assertions.assertThat; class ChatterViewModelTests { diff --git a/ui/src/test/java/net/silthus/schat/ui/views/TabbedChannelsViewTests.java b/ui/src/test/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsViewTests.java similarity index 99% rename from ui/src/test/java/net/silthus/schat/ui/views/TabbedChannelsViewTests.java rename to ui/src/test/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsViewTests.java index d33ee279c..fb91d4c4e 100644 --- a/ui/src/test/java/net/silthus/schat/ui/views/TabbedChannelsViewTests.java +++ b/ui/src/test/java/net/silthus/schat/ui/views/tabbed/TabbedChannelsViewTests.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package net.silthus.schat.ui.views; +package net.silthus.schat.ui.views.tabbed; import lombok.SneakyThrows; import net.kyori.adventure.text.Component; @@ -37,8 +37,8 @@ import net.silthus.schat.eventbus.EventBus; import net.silthus.schat.identity.Identity; import net.silthus.schat.message.Message; -import net.silthus.schat.ui.view.View; -import net.silthus.schat.ui.view.ViewConfig; +import net.silthus.schat.ui.View; +import net.silthus.schat.ui.ViewConfig; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; diff --git a/ui/src/testFixtures/java/net/silthus/schat/ui/ViewProviderStub.java b/ui/src/testFixtures/java/net/silthus/schat/ui/ViewProviderStub.java index 91efeb045..a633cc31c 100644 --- a/ui/src/testFixtures/java/net/silthus/schat/ui/ViewProviderStub.java +++ b/ui/src/testFixtures/java/net/silthus/schat/ui/ViewProviderStub.java @@ -25,9 +25,9 @@ import lombok.NonNull; import net.silthus.schat.chatter.Chatter; -import net.silthus.schat.ui.view.View; -import net.silthus.schat.ui.view.ViewConfig; -import net.silthus.schat.ui.view.ViewProvider; +import net.silthus.schat.ui.View; +import net.silthus.schat.ui.ViewConfig; +import net.silthus.schat.ui.ViewProvider; import net.silthus.schat.ui.views.Views; public class ViewProviderStub implements ViewProvider {