Merge branch 'develop' into f/logout
Conflicts: client/src/main/java/envoy/client/data/CacheMap.java client/src/main/java/envoy/client/data/commands/SystemCommandsMap.java client/src/main/java/envoy/client/net/Client.java client/src/main/java/envoy/client/ui/Startup.java client/src/main/java/envoy/client/ui/StatusTrayIcon.java client/src/main/java/envoy/client/ui/controller/ChatScene.java client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java
This commit is contained in:
@ -9,10 +9,6 @@ import envoy.util.EnvoyLog;
|
||||
|
||||
/**
|
||||
* Stores elements in a queue to process them later.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>Cache.java</strong><br>
|
||||
* Created: <strong>6 Feb 2020</strong><br>
|
||||
*
|
||||
* @param <T> the type of cached elements
|
||||
* @author Kai S. K. Engelbart
|
||||
|
@ -6,10 +6,6 @@ import java.util.*;
|
||||
/**
|
||||
* Stores a heterogeneous map of {@link Cache} objects with different type
|
||||
* parameters.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>CacheMap.java</strong><br>
|
||||
* Created: <strong>09.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
@ -50,8 +46,10 @@ public final class CacheMap implements Serializable {
|
||||
*/
|
||||
public <T> Cache<? super T> getApplicable(Class<T> key) {
|
||||
Cache<? super T> cache = get(key);
|
||||
if (cache == null) for (final var e : map.entrySet())
|
||||
if (e.getKey().isAssignableFrom(key)) cache = (Cache<? super T>) e.getValue();
|
||||
if (cache == null)
|
||||
for (final var e : map.entrySet())
|
||||
if (e.getKey().isAssignableFrom(key))
|
||||
cache = (Cache<? super T>) e.getValue();
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,18 @@
|
||||
package envoy.client.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javafx.collections.*;
|
||||
|
||||
import envoy.client.net.WriteProxy;
|
||||
import envoy.data.Contact;
|
||||
import envoy.data.Message;
|
||||
import envoy.data.*;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
import envoy.data.User;
|
||||
import envoy.event.MessageStatusChange;
|
||||
|
||||
/**
|
||||
* Represents a chat between two {@link User}s
|
||||
* as a list of {@link Message} objects.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>Chat.java</strong><br>
|
||||
* Created: <strong>19 Oct 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @author Leon Hofmeister
|
||||
@ -28,8 +21,9 @@ import envoy.event.MessageStatusChange;
|
||||
*/
|
||||
public class Chat implements Serializable {
|
||||
|
||||
protected final Contact recipient;
|
||||
protected final List<Message> messages = new ArrayList<>();
|
||||
protected final Contact recipient;
|
||||
|
||||
protected transient ObservableList<Message> messages = FXCollections.observableArrayList();
|
||||
|
||||
protected int unreadAmount;
|
||||
|
||||
@ -38,7 +32,7 @@ public class Chat implements Serializable {
|
||||
*/
|
||||
protected transient long lastWritingEvent;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
/**
|
||||
* Provides the list of messages that the recipient receives.
|
||||
@ -50,8 +44,18 @@ public class Chat implements Serializable {
|
||||
*/
|
||||
public Chat(Contact recipient) { this.recipient = recipient; }
|
||||
|
||||
private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException {
|
||||
stream.defaultReadObject();
|
||||
messages = FXCollections.observableList((List<Message>) stream.readObject());
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(new ArrayList<>(messages));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return String.format("Chat[recipient=%s,messages=%d]", recipient, messages.size()); }
|
||||
public String toString() { return String.format("%s[recipient=%s,messages=%d]", getClass().getSimpleName(), recipient, messages.size()); }
|
||||
|
||||
/**
|
||||
* Generates a hash code based on the recipient.
|
||||
@ -81,11 +85,9 @@ public class Chat implements Serializable {
|
||||
*
|
||||
* @param writeProxy the write proxy instance used to notify the server about
|
||||
* the message status changes
|
||||
* @throws IOException if a {@link MessageStatusChange} could not be
|
||||
* delivered to the server
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void read(WriteProxy writeProxy) throws IOException {
|
||||
public void read(WriteProxy writeProxy) {
|
||||
for (int i = messages.size() - 1; i >= 0; --i) {
|
||||
final Message m = messages.get(i);
|
||||
if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
|
||||
@ -136,7 +138,7 @@ public class Chat implements Serializable {
|
||||
* @return all messages in the current chat
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public List<Message> getMessages() { return messages; }
|
||||
public ObservableList<Message> getMessages() { return messages; }
|
||||
|
||||
/**
|
||||
* @return the recipient of a message
|
||||
|
@ -7,10 +7,6 @@ import envoy.data.Config;
|
||||
/**
|
||||
* Implements a configuration specific to the Envoy Client with default values
|
||||
* and convenience methods.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>ClientConfig.java</strong><br>
|
||||
* Created: <strong>01.03.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
|
@ -2,16 +2,11 @@ package envoy.client.data;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import envoy.client.net.Client;
|
||||
import envoy.client.net.WriteProxy;
|
||||
import envoy.client.net.*;
|
||||
import envoy.client.ui.SceneContext;
|
||||
|
||||
/**
|
||||
* Provides access to commonly used objects.
|
||||
* <p>
|
||||
* Project: <strong>client</strong><br>
|
||||
* File: <strong>Context.java</strong><br>
|
||||
* Created: <strong>01.09.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
@ -1,22 +1,15 @@
|
||||
package envoy.client.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
|
||||
import envoy.client.net.WriteProxy;
|
||||
import envoy.data.Contact;
|
||||
import envoy.data.GroupMessage;
|
||||
import envoy.data.*;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
import envoy.data.User;
|
||||
import envoy.event.GroupMessageStatusChange;
|
||||
|
||||
/**
|
||||
* Represents a chat between a user and a group
|
||||
* as a list of messages.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>GroupChat.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.1-beta
|
||||
@ -38,7 +31,7 @@ public final class GroupChat extends Chat {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(WriteProxy writeProxy) throws IOException {
|
||||
public void read(WriteProxy writeProxy) {
|
||||
for (int i = messages.size() - 1; i >= 0; --i) {
|
||||
final GroupMessage gmsg = (GroupMessage) messages.get(i);
|
||||
if (gmsg.getSenderID() != sender.getID()) if (gmsg.getMemberStatuses().get(sender.getID()) == MessageStatus.READ) break;
|
||||
|
@ -5,10 +5,13 @@ import java.nio.channels.*;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.*;
|
||||
|
||||
import javafx.collections.*;
|
||||
|
||||
import envoy.client.event.*;
|
||||
import envoy.data.*;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
import envoy.event.*;
|
||||
import envoy.exception.EnvoyException;
|
||||
import envoy.util.*;
|
||||
@ -22,10 +25,6 @@ import dev.kske.eventbus.EventListener;
|
||||
* For message ID generation a {@link IDGenerator} is stored as well.
|
||||
* <p>
|
||||
* The managed objects are stored inside a folder in the local file system.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>LocalDB.java</strong><br>
|
||||
* Created: <strong>3 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.3-alpha
|
||||
@ -33,12 +32,12 @@ import dev.kske.eventbus.EventListener;
|
||||
public final class LocalDB implements EventListener {
|
||||
|
||||
// Data
|
||||
private User user;
|
||||
private Map<String, User> users = Collections.synchronizedMap(new HashMap<>());
|
||||
private List<Chat> chats = Collections.synchronizedList(new ArrayList<>());
|
||||
private IDGenerator idGenerator;
|
||||
private CacheMap cacheMap = new CacheMap();
|
||||
private String authToken;
|
||||
private User user;
|
||||
private Map<String, User> users = Collections.synchronizedMap(new HashMap<>());
|
||||
private ObservableList<Chat> chats = FXCollections.observableArrayList();
|
||||
private IDGenerator idGenerator;
|
||||
private CacheMap cacheMap = new CacheMap();
|
||||
private String authToken;
|
||||
|
||||
// Auto save timer
|
||||
private Timer autoSaver;
|
||||
@ -53,6 +52,8 @@ public final class LocalDB implements EventListener {
|
||||
|
||||
private final File dbDir, idGeneratorFile, lastLoginFile, usersFile;
|
||||
|
||||
private static final Logger logger = EnvoyLog.getLogger(LocalDB.class);
|
||||
|
||||
/**
|
||||
* Constructs an empty local database.
|
||||
*
|
||||
@ -134,7 +135,7 @@ public final class LocalDB implements EventListener {
|
||||
if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
|
||||
userFile = new File(dbDir, user.getID() + ".db");
|
||||
try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
|
||||
chats = (List<Chat>) in.readObject();
|
||||
chats = FXCollections.observableList((List<Chat>) in.readObject());
|
||||
cacheMap = (CacheMap) in.readObject();
|
||||
lastSync = (Instant) in.readObject();
|
||||
} finally {
|
||||
@ -201,8 +202,8 @@ public final class LocalDB implements EventListener {
|
||||
SerializationUtils.write(usersFile, users);
|
||||
|
||||
// Save user data and last sync time stamp
|
||||
if (user != null)
|
||||
SerializationUtils.write(userFile, chats, cacheMap, Context.getInstance().getClient().isOnline() ? Instant.now() : lastSync);
|
||||
if (user != null) SerializationUtils
|
||||
.write(userFile, new ArrayList<>(chats), cacheMap, Context.getInstance().getClient().isOnline() ? Instant.now() : lastSync);
|
||||
|
||||
// Save last login information
|
||||
if (authToken != null) SerializationUtils.write(lastLoginFile, user, authToken);
|
||||
@ -214,6 +215,37 @@ public final class LocalDB implements EventListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onMessage(Message msg) { if (msg.getStatus() == MessageStatus.SENT) msg.nextStatus(); }
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onGroupMessage(GroupMessage msg) {
|
||||
// TODO: Cancel event once EventBus is updated
|
||||
if (msg.getStatus() == MessageStatus.WAITING || msg.getStatus() == MessageStatus.READ)
|
||||
logger.warning("The groupMessage has the unexpected status " + msg.getStatus());
|
||||
}
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onMessageStatusChange(MessageStatusChange evt) { getMessage(evt.getID()).ifPresent(msg -> msg.setStatus(evt.get())); }
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onGroupMessageStatusChange(GroupMessageStatusChange evt) {
|
||||
this.<GroupMessage>getMessage(evt.getID()).ifPresent(msg -> msg.getMemberStatuses().replace(evt.getMemberID(), evt.get()));
|
||||
}
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onUserStatusChange(UserStatusChange evt) {
|
||||
this.getChat(evt.getID()).map(Chat::getRecipient).map(User.class::cast).ifPresent(u -> u.setStatus(evt.get()));
|
||||
}
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onGroupResize(GroupResize evt) { getChat(evt.getGroupID()).map(Chat::getRecipient).map(Group.class::cast).ifPresent(evt::apply); }
|
||||
|
||||
@Event(priority = 150)
|
||||
private void onNameChange(NameChange evt) {
|
||||
chats.stream().map(Chat::getRecipient).filter(c -> c.getID() == evt.getID()).findAny().ifPresent(c -> c.setName(evt.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a new authentication token.
|
||||
*
|
||||
@ -248,17 +280,32 @@ public final class LocalDB implements EventListener {
|
||||
*/
|
||||
public Map<String, User> getUsers() { return users; }
|
||||
|
||||
/**
|
||||
* Searches for a message by ID.
|
||||
*
|
||||
* @param id the ID of the message to search for
|
||||
* @return an optional containing the message
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public <T extends Message> Optional<T> getMessage(long id) {
|
||||
return (Optional<T>) chats.stream().map(Chat::getMessages).flatMap(List::stream).filter(m -> m.getID() == id).findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a chat by recipient ID.
|
||||
*
|
||||
* @param recipientID the ID of the chat's recipient
|
||||
* @return an optional containing the chat
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public Optional<Chat> getChat(long recipientID) { return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny(); }
|
||||
|
||||
/**
|
||||
* @return all saved {@link Chat} objects that list the client user as the
|
||||
* sender
|
||||
* @since Envoy Client v0.1-alpha
|
||||
**/
|
||||
public List<Chat> getChats() { return chats; }
|
||||
|
||||
/**
|
||||
* @param chats the chats to set
|
||||
*/
|
||||
public void setChats(List<Chat> chats) { this.chats = chats; }
|
||||
public ObservableList<Chat> getChats() { return chats; }
|
||||
|
||||
/**
|
||||
* @return the {@link User} who initialized the local database
|
||||
@ -282,6 +329,7 @@ public final class LocalDB implements EventListener {
|
||||
* @param idGenerator the message ID generator to set
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
@Event(priority = 150)
|
||||
public void setIDGenerator(IDGenerator idGenerator) { this.idGenerator = idGenerator; }
|
||||
|
||||
/**
|
||||
@ -307,59 +355,4 @@ public final class LocalDB implements EventListener {
|
||||
* @since Envoy Client v0.2-beta
|
||||
*/
|
||||
public String getAuthToken() { return authToken; }
|
||||
|
||||
/**
|
||||
* Searches for a message by ID.
|
||||
*
|
||||
* @param id the ID of the message to search for
|
||||
* @return an optional containing the message
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public Optional<Message> getMessage(long id) {
|
||||
return chats.stream().map(Chat::getMessages).flatMap(List::stream).filter(m -> m.getID() == id).findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a chat by recipient ID.
|
||||
*
|
||||
* @param recipientID the ID of the chat's recipient
|
||||
* @return an optional containing the chat
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public Optional<Chat> getChat(long recipientID) { return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny(); }
|
||||
|
||||
/**
|
||||
* Performs a contact name change if the corresponding contact is present.
|
||||
*
|
||||
* @param event the {@link NameChange} to process
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void replaceContactName(NameChange event) {
|
||||
chats.stream().map(Chat::getRecipient).filter(c -> c.getID() == event.getID()).findAny().ifPresent(c -> c.setName(event.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a group resize operation if the corresponding group is present.
|
||||
*
|
||||
* @param event the {@link GroupResize} to process
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void updateGroup(GroupResize event) {
|
||||
chats.stream()
|
||||
.map(Chat::getRecipient)
|
||||
.filter(Group.class::isInstance)
|
||||
.filter(g -> g.getID() == event.getGroupID() && g.getID() != user.getID())
|
||||
.map(Group.class::cast)
|
||||
.findAny()
|
||||
.ifPresent(group -> {
|
||||
switch (event.getOperation()) {
|
||||
case ADD:
|
||||
group.getContacts().add(event.get());
|
||||
break;
|
||||
case REMOVE:
|
||||
group.getContacts().remove(event.get());
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,6 @@ import dev.kske.eventbus.EventListener;
|
||||
* Manages all application settings, which are different objects that can be
|
||||
* changed during runtime and serialized them by using either the file system or
|
||||
* the {@link Preferences} API.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>Settings.java</strong><br>
|
||||
* Created: <strong>11 Nov 2019</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
|
@ -8,10 +8,6 @@ import javax.swing.JComponent;
|
||||
/**
|
||||
* Encapsulates a persistent value that is directly or indirectly mutable by the
|
||||
* user.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>SettingsItem.java</strong><br>
|
||||
* Created: <strong>23.12.2019</strong><br>
|
||||
*
|
||||
* @param <T> the type of this {@link SettingsItem}'s value
|
||||
* @author Kai S. K. Engelbart
|
||||
|
@ -6,10 +6,6 @@ import envoy.exception.EnvoyException;
|
||||
|
||||
/**
|
||||
* Plays back audio from a byte array.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>AudioPlayer.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
|
@ -1,8 +1,7 @@
|
||||
package envoy.client.data.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.*;
|
||||
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
@ -10,10 +9,6 @@ import envoy.exception.EnvoyException;
|
||||
|
||||
/**
|
||||
* Records audio and exports it as a byte array.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>AudioRecorder.java</strong><br>
|
||||
* Created: <strong>02.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
|
@ -1,9 +1,5 @@
|
||||
/**
|
||||
* Contains classes related to recording and playing back audio clips.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>package-info.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
|
@ -5,10 +5,6 @@ import java.util.function.Supplier;
|
||||
/**
|
||||
* This interface defines an action that should be performed when a system
|
||||
* command gets called.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>OnCall.java</strong><br>
|
||||
* Created: <strong>23.07.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
@ -1,10 +1,7 @@
|
||||
package envoy.client.data.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
|
||||
/**
|
||||
* This class is the base class of all {@code SystemCommands} and contains an
|
||||
@ -16,10 +13,6 @@ import java.util.function.Supplier;
|
||||
* function. This approach has one limitation:<br>
|
||||
* <b>Order matters!</b> Changing the order of arguments will likely result in
|
||||
* unexpected behavior.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>SystemCommand.java</strong><br>
|
||||
* Created: <strong>16.07.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
@ -5,10 +5,6 @@ import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class acts as a builder for {@link SystemCommand}s.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>SystemCommandBuilder.java</strong><br>
|
||||
* Created: <strong>23.07.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
@ -10,10 +10,6 @@ import envoy.util.EnvoyLog;
|
||||
|
||||
/**
|
||||
* This class stores all {@link SystemCommand}s used.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>SystemCommandMap.java</strong><br>
|
||||
* Created: <strong>17.07.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
@ -1,10 +1,6 @@
|
||||
/**
|
||||
* This package contains all classes that can be used as system commands.<br>
|
||||
* Every system command can be called using a specific syntax:"/<command>"
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>package-info.java</strong><br>
|
||||
* Created: <strong>16.07.2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy Client v0.2-beta
|
||||
|
Reference in New Issue
Block a user