Merge pull request #11 from informatik-ag-ngl/f/contact_control
Extract ContactControl from ChatControl + Chat -> User Refactorings
This commit is contained in:
commit
abd0113588
File diff suppressed because one or more lines are too long
@ -12,7 +12,7 @@ import envoy.client.event.SendEvent;
|
|||||||
import envoy.data.*;
|
import envoy.data.*;
|
||||||
import envoy.event.*;
|
import envoy.event.*;
|
||||||
import envoy.event.contact.ContactOperation;
|
import envoy.event.contact.ContactOperation;
|
||||||
import envoy.event.contact.ContactSearchResult;
|
import envoy.event.contact.UserSearchResult;
|
||||||
import envoy.util.EnvoyLog;
|
import envoy.util.EnvoyLog;
|
||||||
import envoy.util.SerializationUtils;
|
import envoy.util.SerializationUtils;
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ public class Client implements Closeable {
|
|||||||
receiver.registerProcessor(NameChange.class, evt -> { localDB.replaceContactName(evt); eventBus.dispatch(evt); });
|
receiver.registerProcessor(NameChange.class, evt -> { localDB.replaceContactName(evt); eventBus.dispatch(evt); });
|
||||||
|
|
||||||
// Process contact searches
|
// Process contact searches
|
||||||
receiver.registerProcessor(ContactSearchResult.class, eventBus::dispatch);
|
receiver.registerProcessor(UserSearchResult.class, eventBus::dispatch);
|
||||||
|
|
||||||
// Process contact operations
|
// Process contact operations
|
||||||
receiver.registerProcessor(ContactOperation.class, eventBus::dispatch);
|
receiver.registerProcessor(ContactOperation.class, eventBus::dispatch);
|
||||||
|
@ -34,9 +34,9 @@ import envoy.client.net.WriteProxy;
|
|||||||
import envoy.client.ui.IconUtil;
|
import envoy.client.ui.IconUtil;
|
||||||
import envoy.client.ui.Restorable;
|
import envoy.client.ui.Restorable;
|
||||||
import envoy.client.ui.SceneContext;
|
import envoy.client.ui.SceneContext;
|
||||||
import envoy.client.ui.listcell.ContactListCellFactory;
|
import envoy.client.ui.listcell.ChatControl;
|
||||||
|
import envoy.client.ui.listcell.ListCellFactory;
|
||||||
import envoy.client.ui.listcell.MessageControl;
|
import envoy.client.ui.listcell.MessageControl;
|
||||||
import envoy.client.ui.listcell.MessageListCellFactory;
|
|
||||||
import envoy.data.*;
|
import envoy.data.*;
|
||||||
import envoy.data.Attachment.AttachmentType;
|
import envoy.data.Attachment.AttachmentType;
|
||||||
import envoy.event.*;
|
import envoy.event.*;
|
||||||
@ -124,8 +124,8 @@ public final class ChatScene implements Restorable {
|
|||||||
private void initialize() {
|
private void initialize() {
|
||||||
|
|
||||||
// Initialize message and user rendering
|
// Initialize message and user rendering
|
||||||
messageList.setCellFactory(MessageListCellFactory::new);
|
messageList.setCellFactory(new ListCellFactory<>(MessageControl::new));
|
||||||
chatList.setCellFactory(ContactListCellFactory::new);
|
chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
|
||||||
|
|
||||||
settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE)));
|
settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE)));
|
||||||
voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE)));
|
voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE)));
|
||||||
@ -151,8 +151,6 @@ public final class ChatScene implements Restorable {
|
|||||||
chatList.getItems().remove(chat);
|
chatList.getItems().remove(chat);
|
||||||
chatList.getItems().add(0, chat);
|
chatList.getItems().add(0, chat);
|
||||||
if (chat.equals(currentChat)) chatList.getSelectionModel().select(0);
|
if (chat.equals(currentChat)) chatList.getSelectionModel().select(0);
|
||||||
localDB.getChats().remove(chat);
|
|
||||||
localDB.getChats().add(0, chat);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -187,13 +185,11 @@ public final class ChatScene implements Restorable {
|
|||||||
case ADD:
|
case ADD:
|
||||||
localDB.getUsers().put(contact.getName(), contact);
|
localDB.getUsers().put(contact.getName(), contact);
|
||||||
Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
|
Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
|
||||||
localDB.getChats().add(chat);
|
|
||||||
Platform.runLater(() -> chatList.getItems().add(chat));
|
Platform.runLater(() -> chatList.getItems().add(chat));
|
||||||
break;
|
break;
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
localDB.getUsers().remove(contact.getName());
|
localDB.getUsers().remove(contact.getName());
|
||||||
localDB.getChats().removeIf(c -> c.getRecipient().getID() == contact.getID());
|
Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().equals(contact)));
|
||||||
Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().getID() == contact.getID()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -233,6 +229,8 @@ public final class ChatScene implements Restorable {
|
|||||||
*/
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void chatListClicked() {
|
private void chatListClicked() {
|
||||||
|
if (chatList.getSelectionModel().isEmpty()) return;
|
||||||
|
|
||||||
final Contact user = chatList.getSelectionModel().getSelectedItem().getRecipient();
|
final Contact user = chatList.getSelectionModel().getSelectedItem().getRecipient();
|
||||||
if (user != null && (currentChat == null || !user.equals(currentChat.getRecipient()))) {
|
if (user != null && (currentChat == null || !user.equals(currentChat.getRecipient()))) {
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package envoy.client.ui.controller;
|
|||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@ -11,22 +10,32 @@ import javafx.scene.control.Alert.AlertType;
|
|||||||
import javafx.scene.control.ButtonType;
|
import javafx.scene.control.ButtonType;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
|
|
||||||
import envoy.client.data.Chat;
|
|
||||||
import envoy.client.data.LocalDB;
|
import envoy.client.data.LocalDB;
|
||||||
import envoy.client.event.SendEvent;
|
import envoy.client.event.SendEvent;
|
||||||
import envoy.client.ui.ClearableTextField;
|
import envoy.client.ui.ClearableTextField;
|
||||||
import envoy.client.ui.SceneContext;
|
import envoy.client.ui.SceneContext;
|
||||||
import envoy.client.ui.listcell.ContactListCellFactory;
|
import envoy.client.ui.listcell.ContactControl;
|
||||||
|
import envoy.client.ui.listcell.ListCellFactory;
|
||||||
|
import envoy.data.User;
|
||||||
import envoy.event.ElementOperation;
|
import envoy.event.ElementOperation;
|
||||||
import envoy.event.EventBus;
|
import envoy.event.EventBus;
|
||||||
import envoy.event.contact.ContactOperation;
|
import envoy.event.contact.ContactOperation;
|
||||||
import envoy.event.contact.ContactSearchRequest;
|
import envoy.event.contact.UserSearchRequest;
|
||||||
import envoy.event.contact.ContactSearchResult;
|
import envoy.event.contact.UserSearchResult;
|
||||||
import envoy.util.EnvoyLog;
|
import envoy.util.EnvoyLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Provides a search bar in which a user name (substring) can be entered. The
|
||||||
|
* users with a matching name are then displayed inside a list view. A
|
||||||
|
* {@link UserSearchRequest} is sent on every keystroke.
|
||||||
|
* <p>
|
||||||
|
* <i>The actual search algorithm is implemented on the server.
|
||||||
|
* <p>
|
||||||
|
* To create a group, a button is available that loads the
|
||||||
|
* {@link GroupCreationScene}.
|
||||||
|
* <p>
|
||||||
* Project: <strong>envoy-client</strong><br>
|
* Project: <strong>envoy-client</strong><br>
|
||||||
* File: <strong>ContactSearchSceneController.java</strong><br>
|
* File: <strong>ContactSearchScene.java</strong><br>
|
||||||
* Created: <strong>07.06.2020</strong><br>
|
* Created: <strong>07.06.2020</strong><br>
|
||||||
*
|
*
|
||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
@ -38,7 +47,7 @@ public class ContactSearchScene {
|
|||||||
private ClearableTextField searchBar;
|
private ClearableTextField searchBar;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Chat> chatList;
|
private ListView<User> userList;
|
||||||
|
|
||||||
private SceneContext sceneContext;
|
private SceneContext sceneContext;
|
||||||
|
|
||||||
@ -59,13 +68,10 @@ public class ContactSearchScene {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
chatList.setCellFactory(ContactListCellFactory::new);
|
userList.setCellFactory(new ListCellFactory<>(ContactControl::new));
|
||||||
searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); chatList.getItems().clear(); });
|
searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); userList.getItems().clear(); });
|
||||||
eventBus.register(ContactSearchResult.class,
|
eventBus.register(UserSearchResult.class,
|
||||||
response -> Platform.runLater(() -> {
|
response -> Platform.runLater(() -> { userList.getItems().clear(); userList.getItems().addAll(response.get()); }));
|
||||||
chatList.getItems().clear();
|
|
||||||
chatList.getItems().addAll(response.get().stream().map(Chat::new).collect(Collectors.toList()));
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,8 +82,8 @@ public class ContactSearchScene {
|
|||||||
@FXML
|
@FXML
|
||||||
private void sendRequest() {
|
private void sendRequest() {
|
||||||
final var text = searchBar.getTextField().getText().strip();
|
final var text = searchBar.getTextField().getText().strip();
|
||||||
if (!text.isBlank()) eventBus.dispatch(new SendEvent(new ContactSearchRequest(text)));
|
if (!text.isBlank()) eventBus.dispatch(new SendEvent(new UserSearchRequest(text)));
|
||||||
else chatList.getItems().clear();
|
else userList.getItems().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,32 +95,32 @@ public class ContactSearchScene {
|
|||||||
@FXML
|
@FXML
|
||||||
private void clear() {
|
private void clear() {
|
||||||
searchBar.getTextField().setText(null);
|
searchBar.getTextField().setText(null);
|
||||||
chatList.getItems().clear();
|
userList.getItems().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an {@link ContactOperation} for every selected contact to the
|
* Sends an {@link ContactOperation} for the selected user to the
|
||||||
* server.
|
* server.
|
||||||
*
|
*
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void chatListClicked() {
|
private void userListClicked() {
|
||||||
final var chat = chatList.getSelectionModel().getSelectedItem();
|
final var user = userList.getSelectionModel().getSelectedItem();
|
||||||
if (chat != null) {
|
if (user != null) {
|
||||||
final var alert = new Alert(AlertType.CONFIRMATION);
|
final var alert = new Alert(AlertType.CONFIRMATION);
|
||||||
alert.setTitle("Add Contact to Contact List");
|
alert.setTitle("Add Contact to Contact List");
|
||||||
alert.setHeaderText("Add the user " + chat.getRecipient().getName() + " to your contact list?");
|
alert.setHeaderText("Add the user " + user.getName() + " to your contact list?");
|
||||||
// Normally, this would be total BS (we are already on the FX Thread), however
|
// Normally, this would be total BS (we are already on the FX Thread), however
|
||||||
// it could be proven that the creation of this dialog wrapped in
|
// it could be proven that the creation of this dialog wrapped in
|
||||||
// Platform.runLater is less error-prone than without it
|
// Platform.runLater is less error-prone than without it
|
||||||
Platform.runLater(() -> alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> {
|
Platform.runLater(() -> alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> {
|
||||||
final var event = new ContactOperation(chat.getRecipient(), ElementOperation.ADD);
|
final var event = new ContactOperation(user, ElementOperation.ADD);
|
||||||
// Sends the event to the server
|
// Sends the event to the server
|
||||||
eventBus.dispatch(new SendEvent(event));
|
eventBus.dispatch(new SendEvent(event));
|
||||||
// Updates the UI
|
// Updates the UI
|
||||||
eventBus.dispatch(event);
|
eventBus.dispatch(event);
|
||||||
logger.log(Level.INFO, "Added contact " + chat.getRecipient());
|
logger.log(Level.INFO, "Added user " + user);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package envoy.client.ui.controller;
|
package envoy.client.ui.controller;
|
||||||
|
|
||||||
|
import static java.util.function.Predicate.not;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@ -12,15 +14,24 @@ import envoy.client.data.LocalDB;
|
|||||||
import envoy.client.event.SendEvent;
|
import envoy.client.event.SendEvent;
|
||||||
import envoy.client.ui.ClearableTextField;
|
import envoy.client.ui.ClearableTextField;
|
||||||
import envoy.client.ui.SceneContext;
|
import envoy.client.ui.SceneContext;
|
||||||
import envoy.client.ui.listcell.ContactListCellFactory;
|
import envoy.client.ui.listcell.ContactControl;
|
||||||
import envoy.data.Group;
|
import envoy.client.ui.listcell.ListCellFactory;
|
||||||
|
import envoy.data.User;
|
||||||
import envoy.event.EventBus;
|
import envoy.event.EventBus;
|
||||||
import envoy.event.GroupCreation;
|
import envoy.event.GroupCreation;
|
||||||
import envoy.util.Bounds;
|
import envoy.util.Bounds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Provides a group creation interface. A group name can be entered in the text
|
||||||
|
* field at the top. Available users (local chat recipients) are displayed
|
||||||
|
* inside a list and can be selected (multiple selection available).
|
||||||
|
* <p>
|
||||||
|
* When the group creation button is pressed, a {@link GroupCreation} is sent to
|
||||||
|
* the server. This controller enforces a valid group name and a non-empty
|
||||||
|
* member list (excluding the client user).
|
||||||
|
* <p>
|
||||||
* Project: <strong>envoy-client</strong><br>
|
* Project: <strong>envoy-client</strong><br>
|
||||||
* File: <strong>ContactSearchSceneController.java</strong><br>
|
* File: <strong>GroupCreationScene.java</strong><br>
|
||||||
* Created: <strong>07.06.2020</strong><br>
|
* Created: <strong>07.06.2020</strong><br>
|
||||||
*
|
*
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
@ -35,7 +46,7 @@ public class GroupCreationScene {
|
|||||||
private ClearableTextField groupNameField;
|
private ClearableTextField groupNameField;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Chat> chatList;
|
private ListView<User> userList;
|
||||||
|
|
||||||
private SceneContext sceneContext;
|
private SceneContext sceneContext;
|
||||||
|
|
||||||
@ -43,8 +54,8 @@ public class GroupCreationScene {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
chatList.setCellFactory(ContactListCellFactory::new);
|
userList.setCellFactory(new ListCellFactory<>(ContactControl::new));
|
||||||
chatList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
userList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
groupNameField.setClearButtonListener(e -> { groupNameField.getTextField().clear(); createButton.setDisable(true); });
|
groupNameField.setClearButtonListener(e -> { groupNameField.getTextField().clear(); createButton.setDisable(true); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +67,13 @@ public class GroupCreationScene {
|
|||||||
*/
|
*/
|
||||||
public void initializeData(SceneContext sceneContext, LocalDB localDB) {
|
public void initializeData(SceneContext sceneContext, LocalDB localDB) {
|
||||||
this.sceneContext = sceneContext;
|
this.sceneContext = sceneContext;
|
||||||
Platform.runLater(() -> chatList.getItems()
|
Platform.runLater(() -> userList.getItems()
|
||||||
.addAll(localDB.getChats()
|
.addAll(localDB.getChats()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(c -> !(c.getRecipient() instanceof Group))
|
.map(Chat::getRecipient)
|
||||||
.filter(c -> c.getRecipient().getID() != localDB.getUser().getID())
|
.filter(User.class::isInstance)
|
||||||
|
.filter(not(localDB.getUser()::equals))
|
||||||
|
.map(User.class::cast)
|
||||||
.collect(Collectors.toList())));
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,13 +83,13 @@ public class GroupCreationScene {
|
|||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void chatListClicked() {
|
private void userListClicked() {
|
||||||
createButton.setDisable(chatList.getSelectionModel().isEmpty() || groupNameField.getTextField().getText().isBlank());
|
createButton.setDisable(userList.getSelectionModel().isEmpty() || groupNameField.getTextField().getText().isBlank());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks, whether the {@code createButton} can be enabled because text is
|
* Checks, whether the {@code createButton} can be enabled because text is
|
||||||
* present in the textfield.
|
* present in the text field.
|
||||||
*
|
*
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@ -97,8 +110,8 @@ public class GroupCreationScene {
|
|||||||
new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
|
new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
|
||||||
groupNameField.getTextField().clear();
|
groupNameField.getTextField().clear();
|
||||||
} else {
|
} else {
|
||||||
eventBus.dispatch(new SendEvent(new GroupCreation(name,
|
eventBus.dispatch(new SendEvent(
|
||||||
chatList.getSelectionModel().getSelectedItems().stream().map(c -> c.getRecipient().getID()).collect(Collectors.toSet()))));
|
new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet()))));
|
||||||
new Alert(AlertType.INFORMATION, String.format("Group '%s' successfully created.", name)).showAndWait();
|
new Alert(AlertType.INFORMATION, String.format("Group '%s' successfully created.", name)).showAndWait();
|
||||||
sceneContext.pop();
|
sceneContext.pop();
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,16 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
|
|
||||||
import envoy.client.data.Chat;
|
import envoy.client.data.Chat;
|
||||||
import envoy.data.Contact;
|
|
||||||
import envoy.data.Group;
|
|
||||||
import envoy.data.User;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class formats a single {@link Contact} into a UI component.
|
* Displays a chat using a contact control for the recipient and a label for the
|
||||||
|
* unread message count.
|
||||||
* <p>
|
* <p>
|
||||||
* Project: <strong>envoy-client</strong><br>
|
* Project: <strong>envoy-client</strong><br>
|
||||||
* File: <strong>ContactControl.java</strong><br>
|
* File: <strong>ContactControl.java</strong><br>
|
||||||
* Created: <strong>01.07.2020</strong><br>
|
* Created: <strong>01.07.2020</strong><br>
|
||||||
*
|
*
|
||||||
|
* @see ContactControl
|
||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@ -26,21 +25,11 @@ public class ChatControl extends HBox {
|
|||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public ChatControl(Chat chat) {
|
public ChatControl(Chat chat) {
|
||||||
// Container with contact name
|
|
||||||
final var vBox = new VBox();
|
// Contact control
|
||||||
final var nameLabel = new Label(chat.getRecipient().getName());
|
getChildren().add(new ContactControl(chat.getRecipient()));
|
||||||
nameLabel.setWrapText(true);
|
|
||||||
vBox.getChildren().add(nameLabel);
|
// Unread messages
|
||||||
if (chat.getRecipient() instanceof User) {
|
|
||||||
// Online status
|
|
||||||
final var user = (User) chat.getRecipient();
|
|
||||||
final var statusLabel = new Label(user.getStatus().toString());
|
|
||||||
statusLabel.getStyleClass().add(user.getStatus().toString().toLowerCase());
|
|
||||||
vBox.getChildren().add(statusLabel);
|
|
||||||
} else // Member count
|
|
||||||
vBox.getChildren().add(new Label(((Group) chat.getRecipient()).getContacts().size() + " members"));
|
|
||||||
|
|
||||||
getChildren().add(vBox);
|
|
||||||
if (chat.getUnreadAmount() != 0) {
|
if (chat.getUnreadAmount() != 0) {
|
||||||
Region spacing = new Region();
|
Region spacing = new Region();
|
||||||
setHgrow(spacing, Priority.ALWAYS);
|
setHgrow(spacing, Priority.ALWAYS);
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package envoy.client.ui.listcell;
|
||||||
|
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import envoy.data.Contact;
|
||||||
|
import envoy.data.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays information about a contact in two rows. The first row contains the
|
||||||
|
* name. The second row contains the online status (user) or the member count
|
||||||
|
* (group).
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>ContactControl.java</strong><br>
|
||||||
|
* Created: <strong>13.07.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public class ContactControl extends VBox {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param contact the contact to display
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public ContactControl(Contact contact) {
|
||||||
|
|
||||||
|
// Name label
|
||||||
|
final var nameLabel = new Label(contact.getName());
|
||||||
|
getChildren().add(nameLabel);
|
||||||
|
|
||||||
|
// Online status (user) or member count (group)
|
||||||
|
if (contact instanceof User) {
|
||||||
|
final var status = ((User) contact).getStatus().toString();
|
||||||
|
final var statusLabel = new Label(status);
|
||||||
|
statusLabel.getStyleClass().add(status.toLowerCase());
|
||||||
|
getChildren().add(statusLabel);
|
||||||
|
} else {
|
||||||
|
getChildren().add(new Label(contact.getContacts().size() + " members"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,44 +0,0 @@
|
|||||||
package envoy.client.ui.listcell;
|
|
||||||
|
|
||||||
import javafx.scene.control.ListCell;
|
|
||||||
import javafx.scene.control.ListView;
|
|
||||||
|
|
||||||
import envoy.client.data.Chat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Project: <strong>envoy-client</strong><br>
|
|
||||||
* File: <strong>UserListCell.java</strong><br>
|
|
||||||
* Created: <strong>28.03.2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Kai S. K. Engelbart
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public class ContactListCellFactory extends ListCell<Chat> {
|
|
||||||
|
|
||||||
private final ListView<Chat> listView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param listView the list view inside which this cell is contained
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public ContactListCellFactory(ListView<Chat> listView) { this.listView = listView; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the name of a contact. If the contact is a user, their online status
|
|
||||||
* is displayed as well.
|
|
||||||
*
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void updateItem(Chat chat, boolean empty) {
|
|
||||||
super.updateItem(chat, empty);
|
|
||||||
if (empty || chat.getRecipient() == null) {
|
|
||||||
setText(null);
|
|
||||||
setGraphic(null);
|
|
||||||
} else {
|
|
||||||
final var control = new ChatControl(chat);
|
|
||||||
prefWidthProperty().bind(listView.widthProperty().subtract(40));
|
|
||||||
setGraphic(control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package envoy.client.ui.listcell;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a creation mechanism for generic list cells given a list view and a
|
||||||
|
* conversion function.
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>ListCellFactory.java</strong><br>
|
||||||
|
* Created: <strong>13.07.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @param <T> the type of object to display
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public final class ListCellFactory<T> implements Callback<ListView<T>, ListCell<T>> {
|
||||||
|
|
||||||
|
private final class GenericListCell extends ListCell<T> {
|
||||||
|
|
||||||
|
private ListView<? extends T> listView;
|
||||||
|
|
||||||
|
private GenericListCell(ListView<? extends T> listView) { this.listView = listView; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(T item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
|
setText(null);
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
final var control = converter.apply(item);
|
||||||
|
prefWidthProperty().bind(listView.widthProperty().subtract(40));
|
||||||
|
setGraphic(control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Function<? super T, ? extends Node> converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param converter a function converting the type to display into a node
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public ListCellFactory(Function<? super T, ? extends Node> converter) { this.converter = converter; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListCell<T> call(ListView<T> listView) { return new GenericListCell(listView); }
|
||||||
|
}
|
@ -1,52 +0,0 @@
|
|||||||
package envoy.client.ui.listcell;
|
|
||||||
|
|
||||||
import javafx.scene.control.ListCell;
|
|
||||||
import javafx.scene.control.ListView;
|
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
import javafx.stage.PopupWindow.AnchorLocation;
|
|
||||||
|
|
||||||
import envoy.data.Message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a single message inside the message list.
|
|
||||||
* <p>
|
|
||||||
* Project: <strong>envoy-client</strong><br>
|
|
||||||
* File: <strong>MessageListCellFactory.java</strong><br>
|
|
||||||
* Created: <strong>28.03.2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Kai S. K. Engelbart
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public class MessageListCellFactory extends ListCell<Message> {
|
|
||||||
|
|
||||||
private final ListView<Message> listView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param listView the list view inside which this cell is contained
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public MessageListCellFactory(ListView<Message> listView) { this.listView = listView; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the text, the data of creation and the status of a message.
|
|
||||||
*
|
|
||||||
* @since Envoy v0.1-beta
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void updateItem(Message message, boolean empty) {
|
|
||||||
super.updateItem(message, empty);
|
|
||||||
if (empty || message == null) {
|
|
||||||
setText(null);
|
|
||||||
setGraphic(null);
|
|
||||||
} else {
|
|
||||||
final var control = new MessageControl(message);
|
|
||||||
control.prefWidthProperty().bind(listView.widthProperty().subtract(40));
|
|
||||||
// Creating the Tooltip to deselect a message
|
|
||||||
final var tooltip = new Tooltip("You can select a message by clicking on it \nand deselect it by pressing \"ctrl\" and clicking on it");
|
|
||||||
tooltip.setWrapText(true);
|
|
||||||
tooltip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT);
|
|
||||||
setTooltip(tooltip);
|
|
||||||
setGraphic(control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -46,9 +46,8 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<ListView fx:id="chatList"
|
<ListView fx:id="userList" onMouseClicked="#userListClicked"
|
||||||
onMouseClicked="#chatListClicked" prefHeight="314.0"
|
prefHeight="314.0" prefWidth="600.0">
|
||||||
prefWidth="600.0">
|
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||||
</padding>
|
</padding>
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
|
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
|
||||||
<children>
|
<children>
|
||||||
<ClearableTextField fx:id="groupNameField">
|
<ClearableTextField fx:id="groupNameField">
|
||||||
<textField prefColumnCount="22"
|
<textField onInputMethodTextChanged="#textUpdated"
|
||||||
promptText="Enter Group Name"
|
onKeyTyped="#textUpdated" prefColumnCount="22"
|
||||||
onInputMethodTextChanged="#textUpdated" onKeyTyped="#textUpdated" />
|
promptText="Enter Group Name" />
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
@ -45,9 +45,8 @@
|
|||||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Label>
|
</Label>
|
||||||
<ListView fx:id="chatList"
|
<ListView fx:id="userList" onMouseClicked="#userListClicked"
|
||||||
onMouseClicked="#chatListClicked" prefHeight="314.0"
|
prefHeight="314.0" prefWidth="600.0">
|
||||||
prefWidth="600.0">
|
|
||||||
<VBox.margin>
|
<VBox.margin>
|
||||||
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
|
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
|
||||||
</VBox.margin>
|
</VBox.margin>
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
package envoy.event.contact;
|
|
||||||
|
|
||||||
import envoy.event.Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests a contact search from the server.<br>
|
|
||||||
* <br>
|
|
||||||
* Project: <strong>envoy-common</strong><br>
|
|
||||||
* File: <strong>ContactSearchRequest.java</strong><br>
|
|
||||||
* Created: <strong>05.02.2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Maximilian Käfer
|
|
||||||
* @since Envoy Common v0.2-alpha
|
|
||||||
*/
|
|
||||||
public class ContactSearchRequest extends Event<String> {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a {@link ContactSearchRequest}.
|
|
||||||
*
|
|
||||||
* @param searchPhrase the search phrase to use in the contact search
|
|
||||||
* @since Envoy Common v0.2-alpha
|
|
||||||
*/
|
|
||||||
public ContactSearchRequest(String searchPhrase) { super(searchPhrase); }
|
|
||||||
}
|
|
@ -0,0 +1,26 @@
|
|||||||
|
package envoy.event.contact;
|
||||||
|
|
||||||
|
import envoy.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a user search from the server.
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-common</strong><br>
|
||||||
|
* File: <strong>UserSearchRequest.java</strong><br>
|
||||||
|
* Created: <strong>05.02.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Maximilian Käfer
|
||||||
|
* @since Envoy Common v0.2-alpha
|
||||||
|
*/
|
||||||
|
public class UserSearchRequest extends Event<String> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a {@link UserSearchRequest}.
|
||||||
|
*
|
||||||
|
* @param searchPhrase the search phrase to use in the user search
|
||||||
|
* @since Envoy Common v0.2-alpha
|
||||||
|
*/
|
||||||
|
public UserSearchRequest(String searchPhrase) { super(searchPhrase); }
|
||||||
|
}
|
@ -2,28 +2,28 @@ package envoy.event.contact;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import envoy.data.Contact;
|
import envoy.data.User;
|
||||||
import envoy.event.Event;
|
import envoy.event.Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a list of {@link Contact}s for which a search was performed.<br>
|
* Contains a list of users for which a search has been requested.
|
||||||
* <br>
|
* <p>
|
||||||
* Project: <strong>envoy-common</strong><br>
|
* Project: <strong>envoy-common</strong><br>
|
||||||
* File: <strong>ContactSearchResult.java</strong><br>
|
* File: <strong>UserSearchResult.java</strong><br>
|
||||||
* Created: <strong>11 Feb 2020</strong><br>
|
* Created: <strong>11 Feb 2020</strong><br>
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since Envoy Common v0.2-alpha
|
* @since Envoy Common v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public class ContactSearchResult extends Event<List<Contact>> {
|
public class UserSearchResult extends Event<List<User>> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of {@link ContactSearchResult}.
|
* Creates an instance of {@link UserSearchResult}.
|
||||||
*
|
*
|
||||||
* @param users the users found during the search
|
* @param users the users found during the search
|
||||||
* @since Envoy Common v0.2-alpha
|
* @since Envoy Common v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public ContactSearchResult(List<Contact> users) { super(users); }
|
public UserSearchResult(List<User> users) { super(users); }
|
||||||
}
|
}
|
@ -68,7 +68,7 @@ public class Startup {
|
|||||||
new GroupMessageStatusChangeProcessor(),
|
new GroupMessageStatusChangeProcessor(),
|
||||||
new UserStatusChangeProcessor(),
|
new UserStatusChangeProcessor(),
|
||||||
new IDGeneratorRequestProcessor(),
|
new IDGeneratorRequestProcessor(),
|
||||||
new ContactSearchProcessor(),
|
new UserSearchProcessor(),
|
||||||
new ContactOperationProcessor())));
|
new ContactOperationProcessor())));
|
||||||
|
|
||||||
// Initialize the current message ID
|
// Initialize the current message ID
|
||||||
|
@ -4,8 +4,8 @@ import java.io.IOException;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import envoy.data.Contact;
|
import envoy.data.Contact;
|
||||||
import envoy.event.contact.ContactSearchRequest;
|
import envoy.event.contact.UserSearchRequest;
|
||||||
import envoy.event.contact.ContactSearchResult;
|
import envoy.event.contact.UserSearchResult;
|
||||||
import envoy.server.data.PersistenceManager;
|
import envoy.server.data.PersistenceManager;
|
||||||
import envoy.server.data.User;
|
import envoy.server.data.User;
|
||||||
import envoy.server.net.ConnectionManager;
|
import envoy.server.net.ConnectionManager;
|
||||||
@ -13,14 +13,14 @@ import envoy.server.net.ObjectWriteProxy;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>envoy-server-standalone</strong><br>
|
* Project: <strong>envoy-server-standalone</strong><br>
|
||||||
* File: <strong>ContactSearchProcessor.java</strong><br>
|
* File: <strong>UserSearchProcessor.java</strong><br>
|
||||||
* Created: <strong>08.02.2020</strong><br>
|
* Created: <strong>08.02.2020</strong><br>
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
* @since Envoy Server Standalone v0.1-alpha
|
* @since Envoy Server Standalone v0.1-alpha
|
||||||
*/
|
*/
|
||||||
public class ContactSearchProcessor implements ObjectProcessor<ContactSearchRequest> {
|
public class UserSearchProcessor implements ObjectProcessor<UserSearchRequest> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a list of contacts to the client containing all {@link Contact}s
|
* Writes a list of contacts to the client containing all {@link Contact}s
|
||||||
@ -30,9 +30,9 @@ public class ContactSearchProcessor implements ObjectProcessor<ContactSearchRequ
|
|||||||
* @since Envoy Server Standalone v0.1-alpha
|
* @since Envoy Server Standalone v0.1-alpha
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void process(ContactSearchRequest request, long socketID, ObjectWriteProxy writeProxy) throws IOException {
|
public void process(UserSearchRequest request, long socketID, ObjectWriteProxy writeProxy) throws IOException {
|
||||||
writeProxy.write(socketID,
|
writeProxy.write(socketID,
|
||||||
new ContactSearchResult(PersistenceManager.getInstance()
|
new UserSearchResult(PersistenceManager.getInstance()
|
||||||
.searchUsers(request.get(), ConnectionManager.getInstance().getUserIDBySocketID(socketID))
|
.searchUsers(request.get(), ConnectionManager.getInstance().getUserIDBySocketID(socketID))
|
||||||
.stream()
|
.stream()
|
||||||
.map(User::toCommon)
|
.map(User::toCommon)
|
||||||
@ -40,5 +40,5 @@ public class ContactSearchProcessor implements ObjectProcessor<ContactSearchRequ
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<ContactSearchRequest> getInputClass() { return ContactSearchRequest.class; }
|
public Class<UserSearchRequest> getInputClass() { return UserSearchRequest.class; }
|
||||||
}
|
}
|
Reference in New Issue
Block a user