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 {