Apply code review suggestions from @CyB3RC0nN0R

Additionally added Tooltips to all current items in the SettingsScene,
added ReflectionUtil, changed the cursor on listcells and merged develop
into this branch
This commit is contained in:
delvh
2020-08-02 20:26:22 +02:00
34 changed files with 1003 additions and 422 deletions

View File

@ -10,17 +10,16 @@ import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javafx.animation.RotateTransition;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
@ -29,6 +28,7 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.FileChooser;
import javafx.util.Duration;
@ -41,9 +41,8 @@ import envoy.client.event.SendEvent;
import envoy.client.net.Client;
import envoy.client.net.WriteProxy;
import envoy.client.ui.*;
import envoy.client.ui.listcell.ChatControl;
import envoy.client.ui.listcell.ListCellFactory;
import envoy.client.ui.listcell.MessageControl;
import envoy.client.ui.listcell.*;
import envoy.client.util.ReflectionUtil;
import envoy.data.*;
import envoy.data.Attachment.AttachmentType;
import envoy.event.*;
@ -103,6 +102,24 @@ public final class ChatScene implements Restorable {
@FXML
private ImageView attachmentView;
@FXML
private Label topBarContactLabel;
@FXML
private Label topBarStatusLabel;
@FXML
private Button messageSearchButton;
@FXML
private ImageView clientProfilePic;
@FXML
private ImageView recipientProfilePic;
@FXML
private TextArea contactSearch;
private LocalDB localDB;
private Client client;
private WriteProxy writeProxy;
@ -124,6 +141,8 @@ public final class ChatScene implements Restorable {
private static final int MAX_MESSAGE_LENGTH = 255;
private static final int DEFAULT_ICON_SIZE = 16;
private FilteredList<Chat> chats;
/**
* Initializes the appearance of certain visual components.
*
@ -131,9 +150,8 @@ public final class ChatScene implements Restorable {
*/
@FXML
private void initialize() {
// Initialize message and user rendering
messageList.setCellFactory(new ListCellFactory<>(MessageControl::new));
messageList.setCellFactory(MessageListCell::new);
chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE)));
@ -141,6 +159,14 @@ public final class ChatScene implements Restorable {
attachmentButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("attachment", DEFAULT_ICON_SIZE)));
attachmentView.setImage(DEFAULT_ATTACHMENT_VIEW_IMAGE);
rotateButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("rotate", (int) (DEFAULT_ICON_SIZE * 1.5))));
messageSearchButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("search", DEFAULT_ICON_SIZE)));
clientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
final Rectangle clip = new Rectangle();
clip.setWidth(43);
clip.setHeight(43);
clip.setArcHeight(43);
clip.setArcWidth(43);
clientProfilePic.setClip(clip);
// Listen to received messages
eventBus.register(MessageCreationEvent.class, e -> {
@ -165,8 +191,9 @@ public final class ChatScene implements Restorable {
// Move chat with most recent unread messages to the top
Platform.runLater(() -> {
chatList.getItems().remove(chat);
chatList.getItems().add(0, chat);
chats.getSource().remove(chat);
((ObservableList<Chat>) chats.getSource()).add(0, chat);
if (chat.equals(currentChat)) chatList.getSelectionModel().select(0);
});
});
@ -189,7 +216,7 @@ public final class ChatScene implements Restorable {
// Listen to user status changes
eventBus.register(UserStatusChange.class,
e -> chatList.getItems()
e -> chats.getSource()
.stream()
.filter(c -> c.getRecipient().getID() == e.getID())
.findAny()
@ -203,10 +230,10 @@ public final class ChatScene implements Restorable {
case ADD:
if (contact instanceof User) localDB.getUsers().put(contact.getName(), (User) contact);
final var chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
Platform.runLater(() -> chatList.getItems().add(chat));
Platform.runLater(() -> ((ObservableList<Chat>) chats.getSource()).add(0, chat));
break;
case REMOVE:
Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().equals(contact)));
Platform.runLater(() -> chats.getSource().removeIf(c -> c.getRecipient().equals(contact)));
break;
}
});
@ -244,10 +271,12 @@ public final class ChatScene implements Restorable {
this.client = client;
this.writeProxy = writeProxy;
MessageControl.setUser(localDB.getUser());
MessageControl.setSceneContext(sceneContext);
chatList.setItems(FXCollections.observableList(localDB.getChats()));
chats = new FilteredList<>(FXCollections.observableList(localDB.getChats()));
chatList.setItems(chats);
contactLabel.setText(localDB.getUser().getName());
MessageControl.setLocalDB(localDB);
MessageControl.setSceneContext(sceneContext);
if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info");
recorder = new AudioRecorder();
@ -275,7 +304,7 @@ public final class ChatScene implements Restorable {
currentChat = localDB.getChat(user.getID()).get();
messageList.setItems(FXCollections.observableList(currentChat.getMessages()));
final var scrollIndex = messageList.getItems().size() - currentChat.getUnreadAmount() - 1;
final var scrollIndex = messageList.getItems().size() - currentChat.getUnreadAmount();
messageList.scrollTo(scrollIndex);
logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex);
deleteContactMenuItem.setText("Delete " + user.getName());
@ -303,6 +332,27 @@ public final class ChatScene implements Restorable {
voiceButton.setDisable(!recorder.isSupported());
attachmentButton.setDisable(false);
chatList.refresh();
if (currentChat != null) {
topBarContactLabel.setText(currentChat.getRecipient().getName());
if (currentChat.getRecipient() instanceof User) {
final String status = ((User) currentChat.getRecipient()).getStatus().toString();
topBarStatusLabel.setText(status);
topBarStatusLabel.getStyleClass().add(status.toLowerCase());
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
} else {
topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members");
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
}
final Rectangle clip = new Rectangle();
clip.setWidth(43);
clip.setHeight(43);
clip.setArcHeight(43);
clip.setArcWidth(43);
recipientProfilePic.setClip(clip);
messageSearchButton.setVisible(true);
}
}
/**
@ -313,7 +363,7 @@ public final class ChatScene implements Restorable {
@FXML
private void settingsButtonClicked() {
sceneContext.load(SceneContext.SceneInfo.SETTINGS_SCENE);
sceneContext.<SettingsScene>getController().initializeData(sceneContext, localDB.getUser());
sceneContext.<SettingsScene>getController().initializeData(sceneContext, client);
}
/**
@ -430,16 +480,9 @@ public final class ChatScene implements Restorable {
rotations = Math.max(rotations, 1);
animationTime = Math.min(animationTime, 150);
animationTime = Math.max(animationTime, 0.25);
// contains all Node objects in ChatScene
final var rotatableNodes = Arrays.stream(ChatScene.class.getDeclaredFields()).map(field -> {
try {
return field.get(this);
} catch (IllegalArgumentException | IllegalAccessException e1) {
// In this case, this option can never be executed
return null;
}
}).filter(Node.class::isInstance).map(Node.class::cast).collect(Collectors.toList());
final var rotatableNodes = ReflectionUtil.getAllDeclaredNodeVariables(this);
for (final var node : rotatableNodes) {
// Sets the animation duration to {animationTime}
final var rotateTransition = new RotateTransition(Duration.seconds(animationTime), node);
@ -575,8 +618,8 @@ public final class ChatScene implements Restorable {
currentChat.insert(message);
// Moving currentChat to the top
Platform.runLater(() -> {
chatList.getItems().remove(currentChat);
chatList.getItems().add(0, currentChat);
chats.getSource().remove(currentChat);
((ObservableList<Chat>) chats.getSource()).add(0, currentChat);
chatList.getSelectionModel().select(0);
localDB.getChats().remove(currentChat);
localDB.getChats().add(0, currentChat);
@ -651,4 +694,10 @@ public final class ChatScene implements Restorable {
if (attachmentView.getImage() != null) attachmentView.setVisible(true);
pendingAttachment = messageAttachment;
}
@FXML
private void searchContacts() {
chats.setPredicate(contactSearch.getText().isBlank() ? c -> true
: c -> c.getRecipient().getName().toLowerCase().contains(contactSearch.getText().toLowerCase()));
}
}